Hi,

this implements autosuspend for the trancevibrator driver. I hope this can
serve as a model for PID devices. Could you please test this patch?

        Regards
                Oliver

----

--- linux-2.6.24-ser/drivers/usb/misc/trancevibrator.c.alt2     2008-01-30 
16:18:27.000000000 +0100
+++ linux-2.6.24-ser/drivers/usb/misc/trancevibrator.c  2008-01-30 
17:10:43.000000000 +0100
@@ -71,6 +71,12 @@ static ssize_t set_speed(struct device *
 
        dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
 
+       if (!old) {
+               /* device asleep, must be woken */
+               retval = usb_autopm_get_interface(intf);
+               if (retval < 0)
+                       goto error_bail_out;
+       }
        /* Set speed */
        retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
                                 0x01, /* vendor request: set speed */
@@ -78,9 +84,17 @@ static ssize_t set_speed(struct device *
                                 tv->speed, /* speed value */
                                 0, NULL, 0, USB_CTRL_GET_TIMEOUT);
        if (retval) {
+error_bail_out:
                tv->speed = old;
                dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
                return retval;
+       } else {
+               /*
+                * the device can go back to sleep,
+                * if it isn't vibrating
+                */
+               if (!temp)
+                       usb_autopm_put_interface(intf);
        }
        return count;
 }
@@ -128,12 +142,49 @@ static void tv_disconnect(struct usb_int
        kfree(dev);
 }
 
+static int tv_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct trancevibrator *tv = usb_get_intfdata(intf);
+       int     retval;
+
+       if (tv->udev->auto_pm)
+               return 0;
+
+       /* Set speed to 0 to stop vibrating */
+       retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
+                                0x01, /* vendor request: set speed */
+                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                                0, /* speed value */
+                                0, NULL, 0, USB_CTRL_GET_TIMEOUT);
+
+       return retval;
+}
+
+static int tv_resume(struct usb_interface *intf)
+{
+       struct trancevibrator *tv = usb_get_intfdata(intf);
+       int     retval;
+
+       if (tv->udev->auto_pm)
+               return 0;
+
+       retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
+                                0x01, /* vendor request: set speed */
+                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                                tv->speed, /* restore speed value */
+                                0, NULL, 0, USB_CTRL_GET_TIMEOUT);
+       return retval;
+}
+
 /* USB subsystem object */
 static struct usb_driver tv_driver = {
        .name =         "trancevibrator",
        .probe =        tv_probe,
        .disconnect =   tv_disconnect,
+       .suspend =      tv_suspend,
+       .resume =       tv_resume,
        .id_table =     id_table,
+       .supports_autosuspend = 1,
 };
 
 static int __init tv_init(void)
-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to