diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 04:21:48 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-23 04:21:48 +0200 |
commit | 3c2c4b73aa79e4a1b601710b59e092441175f4bb (patch) | |
tree | fbd08c3e18517871b25fe9c886caae423947d578 /drivers/hid/usbhid | |
parent | Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kerne... (diff) | |
parent | Merge branches 'upstream-fixes', 'wacom' and 'waltop' into for-linus (diff) | |
download | linux-3c2c4b73aa79e4a1b601710b59e092441175f4bb.tar.xz linux-3c2c4b73aa79e4a1b601710b59e092441175f4bb.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID subsystem updates from Jiri Kosina:
"Apart from various driver updates and added support for a number of
new devices (mostly multitouch ones, but not limited to), there is one
change that is worth pointing out explicitly: creation of HID device
groups and proper autoloading of hid-multitouch, implemented by Henrik
Rydberg."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (50 commits)
HID: wacom: fix build breakage without CONFIG_LEDS_CLASS
HID: waltop: Extend barrel button fix
HID: hyperv: Set the hid drvdata correctly
HID: wacom: Unify speed setting
HID: wacom: Add speed setting for Intuos4 WL
HID: wacom: Move Graphire raport header check.
HID: uclogic: Add support for UC-Logic TWHL850
HID: explain the signed/unsigned handling in hid_add_field()
HID: handle logical min/max signedness properly in parser
HID: logitech: read all 32 bits of report type bitfield
HID: wacom: Add LED selector control for Wacom Intuos4 WL
HID: hid-multitouch: fix wrong protocol detection
HID: wiimote: Fix IR data parser
HID: wacom: Add tilt reporting for Intuos4 WL
HID: multitouch: MT interface matching for Baanto
HID: hid-multitouch: Only match MT interfaces
HID: Create a common generic driver
HID: hid-multitouch: Switch to device groups
HID: Create a generic device group
HID: Allow bus wildcard matching
...
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 81 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 9 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbhid.h | 1 |
4 files changed, 62 insertions, 30 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 340d6ae646ed..482f936fc29b 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -28,6 +28,7 @@ #include <linux/input.h> #include <linux/wait.h> #include <linux/workqueue.h> +#include <linux/string.h> #include <linux/usb.h> @@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid) !test_bit(HID_REPORTED_IDLE, &usbhid->iofl) && !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); - if (rc != 0) + if (rc != 0) { clear_bit(HID_IN_RUNNING, &usbhid->iofl); + if (rc == -ENOSPC) + set_bit(HID_NO_BANDWIDTH, &usbhid->iofl); + } else { + clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl); + } } spin_unlock_irqrestore(&usbhid->lock, flags); return rc; @@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid) if (time_after(jiffies, usbhid->stop_retry)) { - /* Retries failed, so do a port reset */ - if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { + /* Retries failed, so do a port reset unless we lack bandwidth*/ + if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) + && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { + schedule_work(&usbhid->reset_work); goto done; } @@ -749,7 +757,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, int usbhid_open(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - int res; + int res = 0; mutex_lock(&hid_open_mut); if (!hid->open++) { @@ -757,17 +765,27 @@ int usbhid_open(struct hid_device *hid) /* the device must be awake to reliably request remote wakeup */ if (res < 0) { hid->open--; - mutex_unlock(&hid_open_mut); - return -EIO; + res = -EIO; + goto done; } usbhid->intf->needs_remote_wakeup = 1; - if (hid_start_in(hid)) - hid_io_error(hid); - + res = hid_start_in(hid); + if (res) { + if (res != -ENOSPC) { + hid_io_error(hid); + res = 0; + } else { + /* no use opening if resources are insufficient */ + hid->open--; + res = -EBUSY; + usbhid->intf->needs_remote_wakeup = 0; + } + } usb_autopm_put_interface(usbhid->intf); } +done: mutex_unlock(&hid_open_mut); - return 0; + return res; } void usbhid_close(struct hid_device *hid) @@ -1396,7 +1414,34 @@ static int hid_post_reset(struct usb_interface *intf) struct usb_device *dev = interface_to_usbdev (intf); struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; + struct usb_host_interface *interface = intf->cur_altsetting; int status; + char *rdesc; + + /* Fetch and examine the HID report descriptor. If this + * has changed, then rebind. Since usbcore's check of the + * configuration descriptors passed, we already know that + * the size of the HID report descriptor has not changed. + */ + rdesc = kmalloc(hid->rsize, GFP_KERNEL); + if (!rdesc) { + dbg_hid("couldn't allocate rdesc memory (post_reset)\n"); + return 1; + } + status = hid_get_class_descriptor(dev, + interface->desc.bInterfaceNumber, + HID_DT_REPORT, rdesc, hid->rsize); + if (status < 0) { + dbg_hid("reading report descriptor failed (post_reset)\n"); + kfree(rdesc); + return 1; + } + status = memcmp(rdesc, hid->rdesc, hid->rsize); + kfree(rdesc); + if (status != 0) { + dbg_hid("report descriptor changed\n"); + return 1; + } spin_lock_irq(&usbhid->lock); clear_bit(HID_RESET_PENDING, &usbhid->iofl); @@ -1553,28 +1598,15 @@ static struct usb_driver hid_driver = { .supports_autosuspend = 1, }; -static const struct hid_device_id hid_usb_table[] = { - { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) }, - { } -}; - struct usb_interface *usbhid_find_interface(int minor) { return usb_find_interface(&hid_driver, minor); } -static struct hid_driver hid_usb_driver = { - .name = "generic-usb", - .id_table = hid_usb_table, -}; - static int __init hid_init(void) { int retval = -ENOMEM; - retval = hid_register_driver(&hid_usb_driver); - if (retval) - goto hid_register_fail; retval = usbhid_quirks_init(quirks_param); if (retval) goto usbhid_quirks_init_fail; @@ -1587,8 +1619,6 @@ static int __init hid_init(void) usb_register_fail: usbhid_quirks_exit(); usbhid_quirks_init_fail: - hid_unregister_driver(&hid_usb_driver); -hid_register_fail: return retval; } @@ -1596,7 +1626,6 @@ static void __exit hid_exit(void) { usb_deregister(&hid_driver); usbhid_quirks_exit(); - hid_unregister_driver(&hid_usb_driver); } module_init(hid_init); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 782c63955f29..0597ee604f6e 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -88,6 +88,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, 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 @@ #include <linux/hid.h> #include <linux/hiddev.h> #include <linux/compat.h> +#include <linux/vmalloc.h> #include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file) } else { mutex_unlock(&list->hiddev->existancelock); kfree(list->hiddev); - kfree(list); + vfree(list); return 0; } } mutex_unlock(&list->hiddev->existancelock); - kfree(list); + vfree(list); return 0; } @@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file) hid = usb_get_intfdata(intf); hiddev = hid->hiddev; - if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) + if (!(list = vzalloc(sizeof(struct hiddev_list)))) return -ENOMEM; mutex_init(&list->thread_lock); list->hiddev = hiddev; @@ -322,7 +323,7 @@ bail_unlock: mutex_unlock(&hiddev->existancelock); bail: file->private_data = NULL; - kfree(list); + vfree(list); return res; } 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); #define HID_STARTED 8 #define HID_REPORTED_IDLE 9 #define HID_KEYS_PRESSED 10 +#define HID_NO_BANDWIDTH 11 /* * USB-specific HID struct, to be pointed to |