diff options
author | Jiri Kosina <jkosina@suse.cz> | 2012-05-22 05:32:31 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-05-22 05:32:31 -0400 |
commit | 56ccd186f1837dd418cd094f0e96b3196bbab9ef (patch) | |
tree | 195cdd3973a1288eb84f51f0ec28a947b333c2c5 /drivers/hid/usbhid | |
parent | b3d07e0344ea36dd3f3a2fdbfaab883e1c5ca69e (diff) | |
parent | d1257081aecf44455fcab8675f1d54e8b242faa1 (diff) |
Merge branch 'upstream' into for-linus
Conflicts:
drivers/hid/hid-core.c
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 65 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 9 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbhid.h | 1 |
3 files changed, 61 insertions, 14 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 9cba5006b5ed..df3789f5d9a5 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/input.h> | 28 | #include <linux/input.h> |
29 | #include <linux/wait.h> | 29 | #include <linux/wait.h> |
30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
31 | #include <linux/string.h> | ||
31 | 32 | ||
32 | #include <linux/usb.h> | 33 | #include <linux/usb.h> |
33 | 34 | ||
@@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid) | |||
86 | !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && | 87 | !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && |
87 | !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { | 88 | !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { |
88 | rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); | 89 | rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); |
89 | if (rc != 0) | 90 | if (rc != 0) { |
90 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); | 91 | clear_bit(HID_IN_RUNNING, &usbhid->iofl); |
92 | if (rc == -ENOSPC) | ||
93 | set_bit(HID_NO_BANDWIDTH, &usbhid->iofl); | ||
94 | } else { | ||
95 | clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl); | ||
96 | } | ||
91 | } | 97 | } |
92 | spin_unlock_irqrestore(&usbhid->lock, flags); | 98 | spin_unlock_irqrestore(&usbhid->lock, flags); |
93 | return rc; | 99 | return rc; |
@@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid) | |||
173 | 179 | ||
174 | if (time_after(jiffies, usbhid->stop_retry)) { | 180 | if (time_after(jiffies, usbhid->stop_retry)) { |
175 | 181 | ||
176 | /* Retries failed, so do a port reset */ | 182 | /* Retries failed, so do a port reset unless we lack bandwidth*/ |
177 | if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { | 183 | if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) |
184 | && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { | ||
185 | |||
178 | schedule_work(&usbhid->reset_work); | 186 | schedule_work(&usbhid->reset_work); |
179 | goto done; | 187 | goto done; |
180 | } | 188 | } |
@@ -700,7 +708,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, | |||
700 | int usbhid_open(struct hid_device *hid) | 708 | int usbhid_open(struct hid_device *hid) |
701 | { | 709 | { |
702 | struct usbhid_device *usbhid = hid->driver_data; | 710 | struct usbhid_device *usbhid = hid->driver_data; |
703 | int res; | 711 | int res = 0; |
704 | 712 | ||
705 | mutex_lock(&hid_open_mut); | 713 | mutex_lock(&hid_open_mut); |
706 | if (!hid->open++) { | 714 | if (!hid->open++) { |
@@ -708,17 +716,27 @@ int usbhid_open(struct hid_device *hid) | |||
708 | /* the device must be awake to reliably request remote wakeup */ | 716 | /* the device must be awake to reliably request remote wakeup */ |
709 | if (res < 0) { | 717 | if (res < 0) { |
710 | hid->open--; | 718 | hid->open--; |
711 | mutex_unlock(&hid_open_mut); | 719 | res = -EIO; |
712 | return -EIO; | 720 | goto done; |
713 | } | 721 | } |
714 | usbhid->intf->needs_remote_wakeup = 1; | 722 | usbhid->intf->needs_remote_wakeup = 1; |
715 | if (hid_start_in(hid)) | 723 | res = hid_start_in(hid); |
716 | hid_io_error(hid); | 724 | if (res) { |
717 | 725 | if (res != -ENOSPC) { | |
726 | hid_io_error(hid); | ||
727 | res = 0; | ||
728 | } else { | ||
729 | /* no use opening if resources are insufficient */ | ||
730 | hid->open--; | ||
731 | res = -EBUSY; | ||
732 | usbhid->intf->needs_remote_wakeup = 0; | ||
733 | } | ||
734 | } | ||
718 | usb_autopm_put_interface(usbhid->intf); | 735 | usb_autopm_put_interface(usbhid->intf); |
719 | } | 736 | } |
737 | done: | ||
720 | mutex_unlock(&hid_open_mut); | 738 | mutex_unlock(&hid_open_mut); |
721 | return 0; | 739 | return res; |
722 | } | 740 | } |
723 | 741 | ||
724 | void usbhid_close(struct hid_device *hid) | 742 | void usbhid_close(struct hid_device *hid) |
@@ -1347,7 +1365,34 @@ static int hid_post_reset(struct usb_interface *intf) | |||
1347 | struct usb_device *dev = interface_to_usbdev (intf); | 1365 | struct usb_device *dev = interface_to_usbdev (intf); |
1348 | struct hid_device *hid = usb_get_intfdata(intf); | 1366 | struct hid_device *hid = usb_get_intfdata(intf); |
1349 | struct usbhid_device *usbhid = hid->driver_data; | 1367 | struct usbhid_device *usbhid = hid->driver_data; |
1368 | struct usb_host_interface *interface = intf->cur_altsetting; | ||
1350 | int status; | 1369 | int status; |
1370 | char *rdesc; | ||
1371 | |||
1372 | /* Fetch and examine the HID report descriptor. If this | ||
1373 | * has changed, then rebind. Since usbcore's check of the | ||
1374 | * configuration descriptors passed, we already know that | ||
1375 | * the size of the HID report descriptor has not changed. | ||
1376 | */ | ||
1377 | rdesc = kmalloc(hid->rsize, GFP_KERNEL); | ||
1378 | if (!rdesc) { | ||
1379 | dbg_hid("couldn't allocate rdesc memory (post_reset)\n"); | ||
1380 | return 1; | ||
1381 | } | ||
1382 | status = hid_get_class_descriptor(dev, | ||
1383 | interface->desc.bInterfaceNumber, | ||
1384 | HID_DT_REPORT, rdesc, hid->rsize); | ||
1385 | if (status < 0) { | ||
1386 | dbg_hid("reading report descriptor failed (post_reset)\n"); | ||
1387 | kfree(rdesc); | ||
1388 | return 1; | ||
1389 | } | ||
1390 | status = memcmp(rdesc, hid->rdesc, hid->rsize); | ||
1391 | kfree(rdesc); | ||
1392 | if (status != 0) { | ||
1393 | dbg_hid("report descriptor changed\n"); | ||
1394 | return 1; | ||
1395 | } | ||
1351 | 1396 | ||
1352 | spin_lock_irq(&usbhid->lock); | 1397 | spin_lock_irq(&usbhid->lock); |
1353 | clear_bit(HID_RESET_PENDING, &usbhid->iofl); | 1398 | clear_bit(HID_RESET_PENDING, &usbhid->iofl); |
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index b1ec0e2aeb57..14599e256791 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/hid.h> | 34 | #include <linux/hid.h> |
35 | #include <linux/hiddev.h> | 35 | #include <linux/hiddev.h> |
36 | #include <linux/compat.h> | 36 | #include <linux/compat.h> |
37 | #include <linux/vmalloc.h> | ||
37 | #include "usbhid.h" | 38 | #include "usbhid.h" |
38 | 39 | ||
39 | #ifdef CONFIG_USB_DYNAMIC_MINORS | 40 | #ifdef CONFIG_USB_DYNAMIC_MINORS |
@@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file) | |||
250 | } else { | 251 | } else { |
251 | mutex_unlock(&list->hiddev->existancelock); | 252 | mutex_unlock(&list->hiddev->existancelock); |
252 | kfree(list->hiddev); | 253 | kfree(list->hiddev); |
253 | kfree(list); | 254 | vfree(list); |
254 | return 0; | 255 | return 0; |
255 | } | 256 | } |
256 | } | 257 | } |
257 | 258 | ||
258 | mutex_unlock(&list->hiddev->existancelock); | 259 | mutex_unlock(&list->hiddev->existancelock); |
259 | kfree(list); | 260 | vfree(list); |
260 | 261 | ||
261 | return 0; | 262 | return 0; |
262 | } | 263 | } |
@@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
278 | hid = usb_get_intfdata(intf); | 279 | hid = usb_get_intfdata(intf); |
279 | hiddev = hid->hiddev; | 280 | hiddev = hid->hiddev; |
280 | 281 | ||
281 | if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) | 282 | if (!(list = vzalloc(sizeof(struct hiddev_list)))) |
282 | return -ENOMEM; | 283 | return -ENOMEM; |
283 | mutex_init(&list->thread_lock); | 284 | mutex_init(&list->thread_lock); |
284 | list->hiddev = hiddev; | 285 | list->hiddev = hiddev; |
@@ -322,7 +323,7 @@ bail_unlock: | |||
322 | mutex_unlock(&hiddev->existancelock); | 323 | mutex_unlock(&hiddev->existancelock); |
323 | bail: | 324 | bail: |
324 | file->private_data = NULL; | 325 | file->private_data = NULL; |
325 | kfree(list); | 326 | vfree(list); |
326 | return res; | 327 | return res; |
327 | } | 328 | } |
328 | 329 | ||
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 |