From afdb5cce979b7d3100d58bdce70c8be6093a8915 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Oct 2014 23:11:00 +0200 Subject: [PATCH 1/9] HID: input: Map unknown consumer page codes to KEY_UNKNOWN Currently unknown consumer page codes are ignored, which means that they cannot later be mapped from userspace using udev / hwdb. Map them to KEY_UNKNOWN, so that userspace can remap them for keyboards which make up their own consumer page codes. Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 2df7fddbd119..7ea582be9c9a 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -862,7 +862,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; case 0x28c: map_key_clear(KEY_SEND); break; - default: goto ignore; + default: map_key_clear(KEY_UNKNOWN); } break; From c241c5eea822344639898512780cff823fc7d730 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 30 Sep 2014 13:18:23 -0400 Subject: [PATCH 2/9] HID: fix merge from wacom into the HID tree While merging wacom from the input to the hid tree, some comments have been duplicated. We can also integrate the test for Synaptics devices in the switch case below, so it is clear that there will be only one place for such quirks. No functional changes are expected in this commit. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 17 +++++++---------- include/linux/hid.h | 4 ---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 73bd9e2e42bc..aef7c56ca5e7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -779,16 +779,6 @@ static int hid_scan_report(struct hid_device *hid) (hid->group == HID_GROUP_MULTITOUCH)) hid->group = HID_GROUP_MULTITOUCH_WIN_8; - /* - * Vendor specific handlings - */ - if ((hid->vendor == USB_VENDOR_ID_SYNAPTICS) && - (hid->group == HID_GROUP_GENERIC) && - /* only bind to the mouse interface of composite USB devices */ - (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE)) - /* hid-rmi should take care of them, not hid-generic */ - hid->group = HID_GROUP_RMI; - /* * Vendor specific handlings */ @@ -796,6 +786,13 @@ static int hid_scan_report(struct hid_device *hid) case USB_VENDOR_ID_WACOM: hid->group = HID_GROUP_WACOM; break; + case USB_VENDOR_ID_SYNAPTICS: + if ((hid->group == HID_GROUP_GENERIC) && + (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE)) + /* hid-rmi should only bind to the mouse interface of + * composite USB devices */ + hid->group = HID_GROUP_RMI; + break; } vfree(parser); diff --git a/include/linux/hid.h b/include/linux/hid.h index 78ea9bf941cd..5b1ff6110e25 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -312,10 +312,6 @@ struct hid_item { * Vendor specific HID device groups */ #define HID_GROUP_RMI 0x0100 - -/* - * Vendor specific HID device groups - */ #define HID_GROUP_WACOM 0x0101 /* From 9578f41aeaee5010384f4f8484da1566e2ce4901 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 30 Sep 2014 13:18:24 -0400 Subject: [PATCH 3/9] HID: core: do not scan reports if the group is already set This allows the transport layer (I have in mind hid-logitech-dj and uhid) to set the group before it is added to the hid bus. This way, it can bypass the hid_scan_report() call, and choose in advance which driver will handle the newly created hid device. Signed-off-by: Benjamin Tisssoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aef7c56ca5e7..946540e1764d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2535,7 +2535,8 @@ int hid_add_device(struct hid_device *hdev) * Scan generic devices for group information */ if (hid_ignore_special_drivers || - !hid_match_id(hdev, hid_have_special_driver)) { + (!hdev->group && + !hid_match_id(hdev, hid_have_special_driver))) { ret = hid_scan_report(hdev); if (ret) hid_warn(hdev, "bad device descriptor (%d)\n", ret); From b905811a49bcd6e6726ce5bbb591f57aaddfd3be Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 30 Sep 2014 14:28:22 -0400 Subject: [PATCH 4/9] HID: usbhid: prevent unwanted events to be sent when re-opening the device When events occurs while no one is listening to the node (hid->open == 0 and usb_kill_urb() called) some events are still stacked somewhere in the USB (kernel or device?) stack. When the node gets reopened, these events are drained, and this results in spurious touch down/up, or mouse button clicks. The problem was spotted with touchscreens in fdo bug #81781 [1], but it actually occurs with any mouse using hid-generic or touchscreen. A way to reproduce it is to call: $ xinput disable 9 ; sleep 5 ; xinput enable 9 With 9 being the device ID for the touchscreen/mouse. During the "sleep", produce some touch events or click events. When "xinput enable" is called, at least one click is generated. This patch tries to fix this by draining the queue for 50 msec and during this time frame, not forwarding these old events to the hid layer. Hans completed the explanation: """ Devices like mice (basically any hid device) will have a fifo on the device side, when we stop submitting urbs to get hid reports from it, that fifo will fill up, and when we resume we will get whatever is there in that fifo. """ [1] https://bugs.freedesktop.org/show_bug.cgi?id=81781 Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 36 +++++++++++++++++++++++------------ drivers/hid/usbhid/usbhid.h | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ca6849a0121e..04e34b917045 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -278,18 +278,20 @@ static void hid_irq_in(struct urb *urb) usbhid->retry_delay = 0; if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open) break; - hid_input_report(urb->context, HID_INPUT_REPORT, - urb->transfer_buffer, - urb->actual_length, 1); - /* - * autosuspend refused while keys are pressed - * because most keyboards don't wake up when - * a key is released - */ - if (hid_check_keys_pressed(hid)) - set_bit(HID_KEYS_PRESSED, &usbhid->iofl); - else - clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); + if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) { + hid_input_report(urb->context, HID_INPUT_REPORT, + urb->transfer_buffer, + urb->actual_length, 1); + /* + * autosuspend refused while keys are pressed + * because most keyboards don't wake up when + * a key is released + */ + if (hid_check_keys_pressed(hid)) + set_bit(HID_KEYS_PRESSED, &usbhid->iofl); + else + clear_bit(HID_KEYS_PRESSED, &usbhid->iofl); + } break; case -EPIPE: /* stall */ usbhid_mark_busy(usbhid); @@ -688,6 +690,7 @@ int usbhid_open(struct hid_device *hid) goto done; } usbhid->intf->needs_remote_wakeup = 1; + set_bit(HID_RESUME_RUNNING, &usbhid->iofl); res = hid_start_in(hid); if (res) { if (res != -ENOSPC) { @@ -701,6 +704,15 @@ int usbhid_open(struct hid_device *hid) } } usb_autopm_put_interface(usbhid->intf); + + /* + * In case events are generated while nobody was listening, + * some are released when the device is re-opened. + * Wait 50 msec for the queue to empty before allowing events + * to go through hid. + */ + msleep(50); + clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); } done: mutex_unlock(&hid_open_mut); diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index f633c24ce28b..807922b49aa4 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -52,6 +52,7 @@ struct usb_interface *usbhid_find_interface(int minor); #define HID_STARTED 8 #define HID_KEYS_PRESSED 10 #define HID_NO_BANDWIDTH 11 +#define HID_RESUME_RUNNING 12 /* * USB-specific HID struct, to be pointed to From 6354b7e25b7617f71a2b544be82c399013b13917 Mon Sep 17 00:00:00 2001 From: Hans Duedal Date: Sat, 11 Oct 2014 17:01:49 +0200 Subject: [PATCH 5/9] HID: roccat: Fix code style issues Missing whitespace, semi-colon after macro, and a duplicated out of memory message. Signed-off-by: Hans Duedal Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 6101816a7ddd..c29265055ac1 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -46,6 +46,7 @@ static void kone_profile_activated(struct kone_device *kone, uint new_profile) static void kone_profile_report(struct kone_device *kone, uint new_profile) { struct kone_roccat_report roccat_report; + roccat_report.event = kone_mouse_event_switch_profile; roccat_report.value = new_profile; roccat_report.key = 0; @@ -163,6 +164,7 @@ static int kone_set_settings(struct usb_device *usb_dev, struct kone_settings const *settings) { int retval; + retval = kone_send(usb_dev, kone_command_settings, settings, sizeof(struct kone_settings)); if (retval) @@ -387,7 +389,7 @@ static struct bin_attribute bin_attr_profile##number = { \ .read = kone_sysfs_read_profilex, \ .write = kone_sysfs_write_profilex, \ .private = &profile_numbers[number-1], \ -}; +} PROFILE_ATTR(1); PROFILE_ATTR(2); PROFILE_ATTR(3); @@ -456,6 +458,7 @@ static ssize_t kone_sysfs_show_tcu(struct device *dev, static int kone_tcu_command(struct usb_device *usb_dev, int number) { unsigned char value; + value = number; return kone_send(usb_dev, kone_command_calibrate, &value, 1); } @@ -697,10 +700,8 @@ static int kone_init_specials(struct hid_device *hdev) == USB_INTERFACE_PROTOCOL_MOUSE) { kone = kzalloc(sizeof(*kone), GFP_KERNEL); - if (!kone) { - hid_err(hdev, "can't alloc device descriptor\n"); + if (!kone) return -ENOMEM; - } hid_set_drvdata(hdev, kone); retval = kone_init_kone_device_struct(usb_dev, kone); From 7bb9d643651180f081cfcc1ed43ff685eda8a358 Mon Sep 17 00:00:00 2001 From: Ville Aakko Date: Wed, 5 Nov 2014 15:13:51 +0100 Subject: [PATCH 6/9] HID: saitek: quirk for Saitek R.A.T.7 works with R.A.T.9 too I have tested HID quirk for Saitek R.A.T.7 with my R.A.T. 9. It works fine for me. Attached patch makes the necessary changes to use the quirk on the R.A.T.9 too, and necessary Kconfig changes too. I have stylized the Kconfig option name to include Mad Catz in the option name, as (at least some of) the devices are marketed under Mad Catz brand. Signed-off-by: Ville Aakko Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 3 ++- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-saitek.c | 4 +++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index f42df4dd58d2..3a3f29c0cc36 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -629,7 +629,7 @@ config HID_ROCCAT support for its special functionalities. config HID_SAITEK - tristate "Saitek non-fully HID-compliant devices" + tristate "Saitek (Mad Catz) non-fully HID-compliant devices" depends on HID ---help--- Support for Saitek devices that are not fully compliant with the @@ -637,6 +637,7 @@ config HID_SAITEK Supported devices: - PS1000 Dual Analog Pad + - R.A.T.9 Gaming Mouse - R.A.T.7 Gaming Mouse - M.M.O.7 Gaming Mouse diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 946540e1764d..1af93ca42226 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1906,6 +1906,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) }, #endif { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index cd9c9e96cf0e..08cf4e75c3bb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -617,6 +617,7 @@ #define USB_VENDOR_ID_MADCATZ 0x0738 #define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540 +#define USB_DEVICE_ID_MADCATZ_RAT9 0x1709 #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c index 69cca1476a0c..5632c54eadf0 100644 --- a/drivers/hid/hid-saitek.c +++ b/drivers/hid/hid-saitek.c @@ -7,7 +7,7 @@ * (This module is based on "hid-ortek".) * Copyright (c) 2012 Andreas Hübner * - * R.A.T.7, M.M.O.7 (USB gaming mice): + * R.A.T.7, R.A.T.9, M.M.O.7 (USB gaming mice): * Fixes the mode button which cycles through three constantly pressed * buttons. All three press events are mapped to one button and the * missing release event is generated immediately. @@ -179,6 +179,8 @@ static const struct hid_device_id saitek_devices[] = { .driver_data = SAITEK_FIX_PS1000 }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7), .driver_data = SAITEK_RELEASE_MODE_RAT7 }, + { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9), + .driver_data = SAITEK_RELEASE_MODE_RAT7 }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7), .driver_data = SAITEK_RELEASE_MODE_MMO7 }, { } From 00d6f227a5905be47006abcc1f417d069ecc3711 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 1 Dec 2014 11:52:39 -0500 Subject: [PATCH 7/9] HID: wacom: re-add accidentally dropped Lenovo PID Dropped in the following commit: commit a3e6f6543d19 ("Input: wacom - keep wacom_ids ordered") Reported-by: Hans Spath CC: stable@vger.kernel.org # v3.17+ Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 586b2405b0d4..7cf998cdd011 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -3026,6 +3026,7 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, { USB_DEVICE_WACOM(0x5002) }, + { USB_DEVICE_LENOVO(0x6004) }, { USB_DEVICE_WACOM(HID_ANY_ID) }, { } From dff674168878fe7b6d8b9ad60d62295ec517de79 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 1 Dec 2014 11:52:40 -0500 Subject: [PATCH 8/9] HID: wacom: fix freeze on open when autosuspend is on Since the conversion from USB to HID (in v3.17), some people reported a freeze on boot with the wacom driver. Hans managed to get a stacktrace: [ 240.272331] Call Trace: [ 240.272338] [] ? usb_hcd_submit_urb+0xa9/0xb10 [ 240.272347] [] schedule+0x29/0x70 [ 240.272355] [] schedule_preempt_disabled+0x16/0x20 [ 240.272363] [] __mutex_lock_slowpath+0xe5/0x230 [ 240.272372] [] mutex_lock+0x17/0x30 [ 240.272380] [] wacom_resume+0x22/0x50 [wacom] [ 240.272396] [] hid_resume_common+0xba/0x110 [usbhid] [ 240.272404] [] ? usb_runtime_suspend+0x80/0x80 [ 240.272417] [] hid_resume+0x3d/0x70 [usbhid] [ 240.272425] [] usb_resume_interface.isra.6+0xb6/0x120 [ 240.272432] [] usb_resume_both+0x74/0x140 [ 240.272439] [] usb_runtime_resume+0x1a/0x20 [ 240.272446] [] __rpm_callback+0x32/0x70 [ 240.272453] [] rpm_callback+0x26/0xa0 [ 240.272460] [] rpm_resume+0x4b1/0x690 [ 240.272468] [] ? radix_tree_lookup_slot+0x22/0x50 [ 240.272475] [] rpm_resume+0x35a/0x690 [ 240.272482] [] ? zone_statistics+0x89/0xa0 [ 240.272489] [] __pm_runtime_resume+0x40/0x60 [ 240.272497] [] usb_autopm_get_interface+0x22/0x60 [ 240.272509] [] usbhid_open+0x59/0xe0 [usbhid] [ 240.272517] [] wacom_open+0x35/0x50 [wacom] [ 240.272525] [] input_open_device+0x79/0xa0 [ 240.272534] [] evdev_open+0x1b1/0x200 [evdev] [ 240.272543] [] chrdev_open+0xae/0x1f0 [ 240.272549] [] ? cdev_put+0x30/0x30 [ 240.272556] [] do_dentry_open+0x1d2/0x320 [ 240.272562] [] finish_open+0x31/0x50 [ 240.272571] [] do_last.isra.36+0x652/0xe50 [ 240.272579] [] path_openat+0xc7/0x6f0 [ 240.272586] [] ? final_putname+0x22/0x50 [ 240.272594] [] ? user_path_at_empty+0x72/0xd0 [ 240.272602] [] do_filp_open+0x4d/0xc0 [...] So here, wacom_open is called, and then wacom_resume is called by the PM system. However, wacom_open already took the lock when wacom_resume tries to get it. Freeze. A little bit of history shows that this already happened in the past - commit f6cd378372bf ("Input: wacom - fix runtime PM related deadlock"), and the solution was to call first the PM function before taking the lock. The lock was introduced in commit commit e722409445fb ("Input: wacom - implement suspend and autosuspend") when the autosuspend feature has been added. Given that usbhid already takes care of this very same locking between suspend/resume, I think we can simply kill the lock in open/close. The lock is now used also with LEDs, so we can not remove it completely. Reported-by: Hans Spath Tested-by: Hans Spath CC: stable@vger.kernel.org # v3.17+ Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 8593047bb726..b6bcd251c4a8 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -70,22 +70,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, static int wacom_open(struct input_dev *dev) { struct wacom *wacom = input_get_drvdata(dev); - int retval; - mutex_lock(&wacom->lock); - retval = hid_hw_open(wacom->hdev); - mutex_unlock(&wacom->lock); - - return retval; + return hid_hw_open(wacom->hdev); } static void wacom_close(struct input_dev *dev) { struct wacom *wacom = input_get_drvdata(dev); - mutex_lock(&wacom->lock); hid_hw_close(wacom->hdev); - mutex_unlock(&wacom->lock); } /* From d1c7e29e8d276c669e8790bb8be9f505ddc48888 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Thu, 11 Dec 2014 16:02:45 -0800 Subject: [PATCH 9/9] HID: i2c-hid: prevent buffer overflow in early IRQ Before ->start() is called, bufsize size is set to HID_MIN_BUFFER_SIZE, 64 bytes. While processing the IRQ, we were asking to receive up to wMaxInputLength bytes, which can be bigger than 64 bytes. Later, when ->start is run, a proper bufsize will be calculated. Given wMaxInputLength is said to be unreliable in other part of the code, set to receive only what we can even if it results in truncated reports. Signed-off-by: Gwendal Grignou Reviewed-by: Benjamin Tissoires Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 747d54421e73..9c014803b460 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -369,7 +369,7 @@ static int i2c_hid_hwreset(struct i2c_client *client) static void i2c_hid_get_input(struct i2c_hid *ihid) { int ret, ret_size; - int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); + int size = ihid->bufsize; ret = i2c_master_recv(ihid->client, ihid->inbuf, size); if (ret != size) {