aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2012-03-28 07:16:19 -0400
committerJiri Kosina <jkosina@suse.cz>2012-03-30 09:14:27 -0400
commita8c52b662cef520815ed43cb3305f8b45b452694 (patch)
tree409aa82687d6380a85c63a6d2e121150de8eb3c1
parentd464c92b5234227c1698862a1906827e2e398ae0 (diff)
HID: usbhid: fix error handling of not enough bandwidth
In case IO cannot be started because there is a lack of bandwidth on the bus, it makes no sense to reset the device. If IO is requested because the device is opened, user space should be notified with an error right away. If the lack of bandwidth arises later, for example after resume, there's no other choice but to retry in the hope that bandwidth will be freed. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/usbhid/hid-core.c37
-rw-r--r--drivers/hid/usbhid/usbhid.h1
2 files changed, 28 insertions, 10 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 5bf91dbad59d..c1a1dd54601c 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -86,8 +86,13 @@ static int hid_start_in(struct hid_device *hid)
86 !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && 86 !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
87 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { 87 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
88 rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); 88 rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
89 if (rc != 0) 89 if (rc != 0) {
90 clear_bit(HID_IN_RUNNING, &usbhid->iofl); 90 clear_bit(HID_IN_RUNNING, &usbhid->iofl);
91 if (rc == -ENOSPC)
92 set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
93 } else {
94 clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
95 }
91 } 96 }
92 spin_unlock_irqrestore(&usbhid->lock, flags); 97 spin_unlock_irqrestore(&usbhid->lock, flags);
93 return rc; 98 return rc;
@@ -173,8 +178,10 @@ static void hid_io_error(struct hid_device *hid)
173 178
174 if (time_after(jiffies, usbhid->stop_retry)) { 179 if (time_after(jiffies, usbhid->stop_retry)) {
175 180
176 /* Retries failed, so do a port reset */ 181 /* Retries failed, so do a port reset unless we lack bandwidth*/
177 if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { 182 if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
183 && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
184
178 schedule_work(&usbhid->reset_work); 185 schedule_work(&usbhid->reset_work);
179 goto done; 186 goto done;
180 } 187 }
@@ -700,7 +707,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
700int usbhid_open(struct hid_device *hid) 707int usbhid_open(struct hid_device *hid)
701{ 708{
702 struct usbhid_device *usbhid = hid->driver_data; 709 struct usbhid_device *usbhid = hid->driver_data;
703 int res; 710 int res = 0;
704 711
705 mutex_lock(&hid_open_mut); 712 mutex_lock(&hid_open_mut);
706 if (!hid->open++) { 713 if (!hid->open++) {
@@ -708,17 +715,27 @@ int usbhid_open(struct hid_device *hid)
708 /* the device must be awake to reliably request remote wakeup */ 715 /* the device must be awake to reliably request remote wakeup */
709 if (res < 0) { 716 if (res < 0) {
710 hid->open--; 717 hid->open--;
711 mutex_unlock(&hid_open_mut); 718 res = -EIO;
712 return -EIO; 719 goto done;
713 } 720 }
714 usbhid->intf->needs_remote_wakeup = 1; 721 usbhid->intf->needs_remote_wakeup = 1;
715 if (hid_start_in(hid)) 722 res = hid_start_in(hid);
716 hid_io_error(hid); 723 if (res) {
717 724 if (res != -ENOSPC) {
725 hid_io_error(hid);
726 res = 0;
727 } else {
728 /* no use opening if resources are insufficient */
729 hid->open--;
730 res = -EBUSY;
731 usbhid->intf->needs_remote_wakeup = 0;
732 }
733 }
718 usb_autopm_put_interface(usbhid->intf); 734 usb_autopm_put_interface(usbhid->intf);
719 } 735 }
736done:
720 mutex_unlock(&hid_open_mut); 737 mutex_unlock(&hid_open_mut);
721 return 0; 738 return res;
722} 739}
723 740
724void usbhid_close(struct hid_device *hid) 741void usbhid_close(struct hid_device *hid)
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index cb8f703efde5..1883d7b94870 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);
55#define HID_STARTED 8 55#define HID_STARTED 8
56#define HID_REPORTED_IDLE 9 56#define HID_REPORTED_IDLE 9
57#define HID_KEYS_PRESSED 10 57#define HID_KEYS_PRESSED 10
58#define HID_NO_BANDWIDTH 11
58 59
59/* 60/*
60 * USB-specific HID struct, to be pointed to 61 * USB-specific HID struct, to be pointed to