diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-10-18 12:35:24 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-12-01 17:23:27 -0500 |
commit | 6d8fc4d28deaf828606c19fb743fbe94aeab4caf (patch) | |
tree | 677eac24fac15cc68307a39011ec6ebed4d01ba0 /drivers | |
parent | 88fafff9d73c0a506c0b08e7cd637c89d8b604e1 (diff) |
USB HID: Handle STALL on interrupt endpoint
The USB HID driver doesn't include any code to handle a STALL on the
interrupt endpoint. While this may be uncommon, it does happen
sometimes. This patch (as805) adds a fix.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/input/hid-core.c | 39 | ||||
-rw-r--r-- | drivers/usb/input/hid.h | 1 |
2 files changed, 27 insertions, 13 deletions
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6d08a3bcc952..5de931cf4cfb 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
@@ -968,20 +968,29 @@ static void hid_retry_timeout(unsigned long _hid) | |||
968 | hid_io_error(hid); | 968 | hid_io_error(hid); |
969 | } | 969 | } |
970 | 970 | ||
971 | /* Workqueue routine to reset the device */ | 971 | /* Workqueue routine to reset the device or clear a halt */ |
972 | static void hid_reset(void *_hid) | 972 | static void hid_reset(void *_hid) |
973 | { | 973 | { |
974 | struct hid_device *hid = (struct hid_device *) _hid; | 974 | struct hid_device *hid = (struct hid_device *) _hid; |
975 | int rc_lock, rc; | 975 | int rc_lock, rc = 0; |
976 | 976 | ||
977 | dev_dbg(&hid->intf->dev, "resetting device\n"); | 977 | if (test_bit(HID_CLEAR_HALT, &hid->iofl)) { |
978 | rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); | 978 | dev_dbg(&hid->intf->dev, "clear halt\n"); |
979 | if (rc_lock >= 0) { | 979 | rc = usb_clear_halt(hid->dev, hid->urbin->pipe); |
980 | rc = usb_reset_composite_device(hid->dev, hid->intf); | 980 | clear_bit(HID_CLEAR_HALT, &hid->iofl); |
981 | if (rc_lock) | 981 | hid_start_in(hid); |
982 | usb_unlock_device(hid->dev); | 982 | } |
983 | |||
984 | else if (test_bit(HID_RESET_PENDING, &hid->iofl)) { | ||
985 | dev_dbg(&hid->intf->dev, "resetting device\n"); | ||
986 | rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); | ||
987 | if (rc_lock >= 0) { | ||
988 | rc = usb_reset_composite_device(hid->dev, hid->intf); | ||
989 | if (rc_lock) | ||
990 | usb_unlock_device(hid->dev); | ||
991 | } | ||
992 | clear_bit(HID_RESET_PENDING, &hid->iofl); | ||
983 | } | 993 | } |
984 | clear_bit(HID_RESET_PENDING, &hid->iofl); | ||
985 | 994 | ||
986 | switch (rc) { | 995 | switch (rc) { |
987 | case 0: | 996 | case 0: |
@@ -1023,9 +1032,8 @@ static void hid_io_error(struct hid_device *hid) | |||
1023 | 1032 | ||
1024 | /* Retries failed, so do a port reset */ | 1033 | /* Retries failed, so do a port reset */ |
1025 | if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { | 1034 | if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { |
1026 | if (schedule_work(&hid->reset_work)) | 1035 | schedule_work(&hid->reset_work); |
1027 | goto done; | 1036 | goto done; |
1028 | clear_bit(HID_RESET_PENDING, &hid->iofl); | ||
1029 | } | 1037 | } |
1030 | } | 1038 | } |
1031 | 1039 | ||
@@ -1049,6 +1057,11 @@ static void hid_irq_in(struct urb *urb) | |||
1049 | hid->retry_delay = 0; | 1057 | hid->retry_delay = 0; |
1050 | hid_input_report(HID_INPUT_REPORT, urb, 1); | 1058 | hid_input_report(HID_INPUT_REPORT, urb, 1); |
1051 | break; | 1059 | break; |
1060 | case -EPIPE: /* stall */ | ||
1061 | clear_bit(HID_IN_RUNNING, &hid->iofl); | ||
1062 | set_bit(HID_CLEAR_HALT, &hid->iofl); | ||
1063 | schedule_work(&hid->reset_work); | ||
1064 | return; | ||
1052 | case -ECONNRESET: /* unlink */ | 1065 | case -ECONNRESET: /* unlink */ |
1053 | case -ENOENT: | 1066 | case -ENOENT: |
1054 | case -ESHUTDOWN: /* unplug */ | 1067 | case -ESHUTDOWN: /* unplug */ |
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 0e76e6dcac37..2a9bf07944c0 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h | |||
@@ -385,6 +385,7 @@ struct hid_control_fifo { | |||
385 | #define HID_IN_RUNNING 3 | 385 | #define HID_IN_RUNNING 3 |
386 | #define HID_RESET_PENDING 4 | 386 | #define HID_RESET_PENDING 4 |
387 | #define HID_SUSPENDED 5 | 387 | #define HID_SUSPENDED 5 |
388 | #define HID_CLEAR_HALT 6 | ||
388 | 389 | ||
389 | struct hid_input { | 390 | struct hid_input { |
390 | struct list_head list; | 391 | struct list_head list; |