From 0e2073e3282c9e84b3cea8e7e9a59f4915052d5a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 18 Oct 2006 12:35:24 -0400 Subject: [PATCH] --- yaml --- r: 41237 b: refs/heads/master c: 6d8fc4d28deaf828606c19fb743fbe94aeab4caf h: refs/heads/master i: 41235: 1a90b9875927c95bd5d2865645f31980d80dd446 v: v3 --- [refs] | 2 +- trunk/drivers/usb/input/hid-core.c | 39 ++++++++++++++++++++---------- trunk/drivers/usb/input/hid.h | 1 + 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/[refs] b/[refs] index 0fa8244c7e48..9aea265ee807 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 88fafff9d73c0a506c0b08e7cd637c89d8b604e1 +refs/heads/master: 6d8fc4d28deaf828606c19fb743fbe94aeab4caf diff --git a/trunk/drivers/usb/input/hid-core.c b/trunk/drivers/usb/input/hid-core.c index 6d08a3bcc952..5de931cf4cfb 100644 --- a/trunk/drivers/usb/input/hid-core.c +++ b/trunk/drivers/usb/input/hid-core.c @@ -968,20 +968,29 @@ static void hid_retry_timeout(unsigned long _hid) hid_io_error(hid); } -/* Workqueue routine to reset the device */ +/* Workqueue routine to reset the device or clear a halt */ static void hid_reset(void *_hid) { struct hid_device *hid = (struct hid_device *) _hid; - int rc_lock, rc; - - dev_dbg(&hid->intf->dev, "resetting device\n"); - rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); - if (rc_lock >= 0) { - rc = usb_reset_composite_device(hid->dev, hid->intf); - if (rc_lock) - usb_unlock_device(hid->dev); + int rc_lock, rc = 0; + + if (test_bit(HID_CLEAR_HALT, &hid->iofl)) { + dev_dbg(&hid->intf->dev, "clear halt\n"); + rc = usb_clear_halt(hid->dev, hid->urbin->pipe); + clear_bit(HID_CLEAR_HALT, &hid->iofl); + hid_start_in(hid); + } + + else if (test_bit(HID_RESET_PENDING, &hid->iofl)) { + dev_dbg(&hid->intf->dev, "resetting device\n"); + rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); + if (rc_lock >= 0) { + rc = usb_reset_composite_device(hid->dev, hid->intf); + if (rc_lock) + usb_unlock_device(hid->dev); + } + clear_bit(HID_RESET_PENDING, &hid->iofl); } - clear_bit(HID_RESET_PENDING, &hid->iofl); switch (rc) { case 0: @@ -1023,9 +1032,8 @@ static void hid_io_error(struct hid_device *hid) /* Retries failed, so do a port reset */ if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { - if (schedule_work(&hid->reset_work)) - goto done; - clear_bit(HID_RESET_PENDING, &hid->iofl); + schedule_work(&hid->reset_work); + goto done; } } @@ -1049,6 +1057,11 @@ static void hid_irq_in(struct urb *urb) hid->retry_delay = 0; hid_input_report(HID_INPUT_REPORT, urb, 1); break; + case -EPIPE: /* stall */ + clear_bit(HID_IN_RUNNING, &hid->iofl); + set_bit(HID_CLEAR_HALT, &hid->iofl); + schedule_work(&hid->reset_work); + return; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: /* unplug */ diff --git a/trunk/drivers/usb/input/hid.h b/trunk/drivers/usb/input/hid.h index 0e76e6dcac37..2a9bf07944c0 100644 --- a/trunk/drivers/usb/input/hid.h +++ b/trunk/drivers/usb/input/hid.h @@ -385,6 +385,7 @@ struct hid_control_fifo { #define HID_IN_RUNNING 3 #define HID_RESET_PENDING 4 #define HID_SUSPENDED 5 +#define HID_CLEAR_HALT 6 struct hid_input { struct list_head list;