Am Dienstag, 15. Mai 2007 16:37 schrieb Alan Stern:
> Can you break this up into two patches?  If the first adds the queuing 
> code and the second adds autosuspend support, it will be much easier to 
> appraise and test them.

Here's part #2, the core autosuspend.

        Regards
                Oliver
-- 

--- linux-2.6.22-rc1/drivers/hid/usbhid/hid-core.c      2007-05-16 
12:23:26.000000000 +0200
+++ linux-2.6.22-rc1-autosuspend/drivers/hid/usbhid/hid-core.c  2007-05-15 
19:22:13.000000000 +0200
@@ -64,6 +64,8 @@ MODULE_PARM_DESC(quirks, "Add/modify USB
 /*
  * Input submission and I/O error handler.
  */
+static DEFINE_MUTEX(hid_open_mut);
+
 static void hid_io_error(struct hid_device *hid);
 static int hid_submit_out(struct hid_device *hid);
 static int hid_submit_ctrl(struct hid_device *hid);
@@ -180,6 +182,13 @@ done:
        spin_unlock_irqrestore(&usbhid->inlock, flags);
 }
 
+static void usbhid_mark_busy(struct usbhid_device *usbhid)
+{
+       struct usb_interface *intf = usbhid->intf;
+
+       usb_mark_last_busy(interface_to_usbdev(intf));
+}
+
 static int usbhid_restart_out_queue(struct usbhid_device *usbhid)
 {
        struct hid_device *hid = usb_get_intfdata(usbhid->intf);
@@ -230,12 +239,14 @@ static void hid_irq_in(struct urb *urb)
 
        switch (urb->status) {
                case 0:                 /* success */
+                       usbhid_mark_busy(usbhid);       
                        usbhid->retry_delay = 0;
                        hid_input_report(urb->context, HID_INPUT_REPORT,
                                         urb->transfer_buffer,
                                         urb->actual_length, 1);
                        break;
                case -EPIPE:            /* stall */
+                       usbhid_mark_busy(usbhid);
                        clear_bit(HID_IN_RUNNING, &usbhid->iofl);
                        set_bit(HID_CLEAR_HALT, &usbhid->iofl);
                        schedule_work(&usbhid->reset_work);
@@ -249,6 +260,7 @@ static void hid_irq_in(struct urb *urb)
                case -EPROTO:           /* protocol error or unplug */
                case -ETIME:            /* protocol error or unplug */
                case -ETIMEDOUT:        /* Should never happen, but... */
+                       usbhid_mark_busy(usbhid);
                        clear_bit(HID_IN_RUNNING, &usbhid->iofl);
                        hid_io_error(hid);
                        return;
@@ -592,8 +604,21 @@ static int hid_get_class_descriptor(stru
 int usbhid_open(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
+       int res;
 
-       hid->open++;
+       mutex_lock(&hid_open_mut);
+       if (!hid->open++) {
+               res = usb_autopm_get_interface(usbhid->intf);
+               /* the device must be awake to reliable request remote wakeup */
+               if (res < 0) {
+                       hid->open--;
+                       mutex_unlock(&hid_open_mut);
+                       return -EIO;
+               }
+               usbhid->intf->needs_remote_wakeup = 1;
+               usb_autopm_put_interface(usbhid->intf);
+       }
+       mutex_unlock(&hid_open_mut);
        if (hid_start_in(hid))
                hid_io_error(hid);
        return 0;
@@ -603,10 +628,13 @@ void usbhid_close(struct hid_device *hid
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
+       mutex_lock(&hid_open_mut);
        if (!--hid->open) {
                usb_kill_urb(usbhid->urbin);
                flush_scheduled_work();
+               usbhid->intf->needs_remote_wakeup = 0;
        }
+       mutex_unlock(&hid_open_mut);
 }
 
 /*
@@ -730,7 +758,9 @@ static void __usbhid_restart_queues(stru
        struct usbhid_device *usbhid =
                container_of(work, struct usbhid_device, restart_work);
 
+       usb_autopm_get_interface(usbhid->intf);
        usbhid_restart_queues(usbhid);
+       usb_autopm_put_interface(usbhid->intf);
 }
 
 static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
@@ -1154,13 +1184,26 @@ static int hid_suspend(struct usb_interf
        struct usbhid_device *usbhid = hid->driver_data;
        struct usb_device *udev = interface_to_usbdev(intf);
 
-
-       spin_lock_irq(&usbhid->inlock);
-       set_bit(HID_REPORTED_IDLE, &usbhid->iofl);
-       spin_unlock_irq(&usbhid->inlock);
-       if (usbhid_wait_io(hid) < 0)
-               return -EIO;
-
+       if (udev->auto_pm) {
+               spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+               if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
+                   && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
+                   && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
+                   && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+               {
+                       set_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+                       spin_unlock_irq(&usbhid->inlock);
+               } else {
+                       spin_unlock_irq(&usbhid->inlock);
+                       return -EBUSY;
+               }
+       } else {
+               spin_lock_irq(&usbhid->inlock);
+               set_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+               spin_unlock_irq(&usbhid->inlock);
+               if (usbhid_wait_io(hid) < 0)
+                       return -EIO;
+       }
        del_timer(&usbhid->io_retry);
        usb_kill_urb(usbhid->urbin);
        flush_scheduled_work();
@@ -1175,6 +1218,7 @@ static int hid_resume(struct usb_interfa
        int status;
 
        clear_bit(HID_REPORTED_IDLE, &usbhid->iofl);
+       usbhid_mark_busy(usbhid);
        usbhid->retry_delay = 0;
        status = hid_start_in(hid);
        usbhid_restart_queues(usbhid);
@@ -1216,6 +1260,7 @@ static struct usb_driver hid_driver = {
        .pre_reset =    hid_pre_reset,
        .post_reset =   hid_post_reset,
        .id_table =     hid_usb_ids,
+       .supports_autosuspend = 1,
 };
 
 static int __init hid_init(void)

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to