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/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel