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