diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-05 11:53:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-05 11:53:34 -0700 |
commit | e8403b493fd5180e351ca67eb66406d95dadcd0b (patch) | |
tree | e413c0017a861a2f74e54a3084140b5a9f1100ec /drivers | |
parent | e02d37bf55a9a36f22427fd6dd733fe104d817b6 (diff) | |
parent | 9931753b6c5ebf78ad0b8cb056234369f0b3c561 (diff) | |
download | linux-e8403b493fd5180e351ca67eb66406d95dadcd0b.tar.bz2 |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina:
- 3rd generation Wacom Intuos BT device support from Aaron Armstrong
Skomra
- support for NSG-MR5U and NSG-MR7U devices from Todd Kelner
- multitouch Razer Blade Stealth support from Benjamin Tissoires
- Elantech touchpad support from Alexandrov Stansilav
- a few other scattered-around fixes and cleanups to drivers and
generic code
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (31 commits)
HID: google: Enable PM Full On mode when adjusting backlight
HID: google: add google hammer HID driver
HID: core: reset the quirks before calling probe again
HID: multitouch: do not set HID_QUIRK_NO_INIT_REPORTS
HID: core: remove the need for HID_QUIRK_NO_EMPTY_INPUT
HID: use BIT() macro for quirks too
HID: use BIT macro instead of plain integers for flags
HID: multitouch: remove dead zones of Razer Blade Stealth
HID: multitouch: export a quirk for the button handling of touchpads
HID: usbhid: extend the polling interval configuration to keyboards
HID: ntrig: document sysfs interface
HID: wacom: wacom_wac_collection() is local to wacom_wac.c
HID: wacom: generic: add the "Report Valid" usage
HID: wacom: generic: Support multiple tools per report
HID: wacom: Add support for 3rd generation Intuos BT
HID: core: rewrite the hid-generic automatic unbind
HID: sony: Add touchpad support for NSG-MR5U and NSG-MR7U remotes
HID: hid-multitouch: Use true and false for boolean values
HID: hid-ntrig: use true and false for boolean values
HID: logitech-hidpp: document sysfs interface
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/Kconfig | 20 | ||||
-rw-r--r-- | drivers/hid/Makefile | 2 | ||||
-rw-r--r-- | drivers/hid/hid-asus.c | 7 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 47 | ||||
-rw-r--r-- | drivers/hid/hid-corsair.c | 24 | ||||
-rw-r--r-- | drivers/hid/hid-elan.c | 421 | ||||
-rw-r--r-- | drivers/hid/hid-elecom.c | 32 | ||||
-rw-r--r-- | drivers/hid/hid-generic.c | 33 | ||||
-rw-r--r-- | drivers/hid/hid-google-hammer.c | 138 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 21 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 13 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 68 | ||||
-rw-r--r-- | drivers/hid/hid-ntrig.c | 12 | ||||
-rw-r--r-- | drivers/hid/hid-quirks.c | 20 | ||||
-rw-r--r-- | drivers/hid/hid-rmi.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-sony.c | 131 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic.c | 1 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 17 | ||||
-rw-r--r-- | drivers/hid/uhid.c | 12 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 12 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 4 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.c | 223 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.h | 4 |
23 files changed, 1052 insertions, 214 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 19c499f5623d..60252fd796f6 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -274,15 +274,23 @@ config HID_EMS_FF Currently the following devices are known to be supported: - Trio Linker Plus II +config HID_ELAN + tristate "ELAN USB Touchpad Support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y to enable support for the USB ELAN touchpad + Currently the following devices are known to be supported: + - HP Pavilion X2 10-p0XX. + config HID_ELECOM tristate "ELECOM HID devices" depends on HID ---help--- Support for ELECOM devices: - BM084 Bluetooth Mouse - - EX-G Trackball (Wired and wireless) - - DEFT Trackball (Wired and wireless) - - HUGE Trackball (Wired and wireless) + - EX-G Trackballs (M-XT3DRBK, M-XT3URBK) + - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK) + - HUGE Trackballs (M-HT1DRBK, M-HT1URBK) config HID_ELO tristate "ELO USB 4000/4500 touchscreen" @@ -331,6 +339,12 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GOOGLE_HAMMER + tristate "Google Hammer Keyboard" + depends on USB_HID && LEDS_CLASS + ---help--- + Say Y here if you have a Google Hammer device. + config HID_GT683R tristate "MSI GT68xR LED support" depends on LEDS_CLASS && USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index eb13b9e92d85..17a8bd97da9d 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -39,11 +39,13 @@ obj-$(CONFIG_HID_CP2112) += hid-cp2112.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o +obj-$(CONFIG_HID_ELAN) += hid-elan.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o obj-$(CONFIG_HID_GFRM) += hid-gfrm.o +obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 88b9703318e4..88a5672f42cd 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -570,7 +570,9 @@ static int asus_input_mapping(struct hid_device *hdev, static int asus_start_multitouch(struct hid_device *hdev) { int ret; - const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 }; + static const unsigned char buf[] = { + FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 + }; unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL); if (!dmabuf) { @@ -644,8 +646,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) * All functionality is on a single HID interface and for * userspace the touchpad must be a separate input_dev. */ - hdev->quirks |= HID_QUIRK_MULTI_INPUT | - HID_QUIRK_NO_EMPTY_INPUT; + hdev->quirks |= HID_QUIRK_MULTI_INPUT; drvdata->tp = &asus_t100chi_tp; } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c2560aae5542..5d7cc6bbbac6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1365,7 +1365,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags) * of implement() working on 8 byte chunks */ - int len = hid_report_len(report) + 7; + u32 len = hid_report_len(report) + 7; return kmalloc(len, flags); } @@ -1430,7 +1430,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, { char *buf; int ret; - int len; + u32 len; buf = hid_alloc_report_buf(report, GFP_KERNEL); if (!buf) @@ -1456,14 +1456,14 @@ out: } EXPORT_SYMBOL_GPL(__hid_request); -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) { struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; struct hid_driver *hdrv; unsigned int a; - int rsize, csize = size; + u32 rsize, csize = size; u8 *cdata = data; int ret = 0; @@ -1521,7 +1521,7 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); * * This is data entry for lower layers. */ -int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) +int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; @@ -1966,6 +1966,8 @@ static int hid_device_probe(struct device *dev) } } + /* reset the quirks that has been previously set */ + hdev->quirks = hid_lookup_quirk(hdev); hdev->driver = hdrv; if (hdrv->probe) { ret = hdrv->probe(hdev, id); @@ -2197,31 +2199,40 @@ void hid_destroy_device(struct hid_device *hdev) EXPORT_SYMBOL_GPL(hid_destroy_device); -static int __bus_add_driver(struct device_driver *drv, void *data) +static int __hid_bus_reprobe_drivers(struct device *dev, void *data) { - struct hid_driver *added_hdrv = data; - struct hid_driver *hdrv = to_hid_driver(drv); + struct hid_driver *hdrv = data; + struct hid_device *hdev = to_hid_device(dev); - if (hdrv->bus_add_driver) - hdrv->bus_add_driver(added_hdrv); + if (hdev->driver == hdrv && + !hdrv->match(hdev, hid_ignore_special_drivers)) + return device_reprobe(dev); return 0; } -static int __bus_removed_driver(struct device_driver *drv, void *data) +static int __hid_bus_driver_added(struct device_driver *drv, void *data) { - struct hid_driver *removed_hdrv = data; struct hid_driver *hdrv = to_hid_driver(drv); - if (hdrv->bus_removed_driver) - hdrv->bus_removed_driver(removed_hdrv); + if (hdrv->match) { + bus_for_each_dev(&hid_bus_type, NULL, hdrv, + __hid_bus_reprobe_drivers); + } return 0; } +static int __bus_removed_driver(struct device_driver *drv, void *data) +{ + return bus_rescan_devices(&hid_bus_type); +} + int __hid_register_driver(struct hid_driver *hdrv, struct module *owner, const char *mod_name) { + int ret; + hdrv->driver.name = hdrv->name; hdrv->driver.bus = &hid_bus_type; hdrv->driver.owner = owner; @@ -2230,9 +2241,13 @@ int __hid_register_driver(struct hid_driver *hdrv, struct module *owner, INIT_LIST_HEAD(&hdrv->dyn_list); spin_lock_init(&hdrv->dyn_lock); - bus_for_each_drv(&hid_bus_type, NULL, hdrv, __bus_add_driver); + ret = driver_register(&hdrv->driver); + + if (ret == 0) + bus_for_each_drv(&hid_bus_type, NULL, NULL, + __hid_bus_driver_added); - return driver_register(&hdrv->driver); + return ret; } EXPORT_SYMBOL_GPL(__hid_register_driver); diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c index 9ba5d98a1180..ec9e060ec46c 100644 --- a/drivers/hid/hid-corsair.c +++ b/drivers/hid/hid-corsair.c @@ -2,11 +2,14 @@ * HID driver for Corsair devices * * Supported devices: + * - Vengeance K70 Keyboard + * - K70 RAPIDFIRE Keyboard * - Vengeance K90 Keyboard * - Scimitar PRO RGB Gaming Mouse * * Copyright (c) 2015 Clement Vuchener * Copyright (c) 2017 Oscar Campos + * Copyright (c) 2017 Aaron Bottegal */ /* @@ -673,7 +676,7 @@ static int corsair_input_mapping(struct hid_device *dev, } /* - * The report descriptor of Corsair Scimitar RGB Pro gaming mouse is + * The report descriptor of some of the Corsair gaming mice is * non parseable as they define two consecutive Logical Minimum for * the Usage Page (Consumer) in rdescs bytes 75 and 77 being 77 0x16 * that should be obviousy 0x26 for Logical Magimum of 16 bits. This @@ -681,7 +684,8 @@ static int corsair_input_mapping(struct hid_device *dev, * Minimum being larger than Logical Maximum. * * This driver fixes the report descriptor for: - * - USB ID b1c:1b3e, sold as Scimitar RGB Pro Gaming mouse + * - USB ID 1b1c:1b34, sold as GLAIVE RGB Gaming mouse + * - USB ID 1b1c:1b3e, sold as Scimitar RGB Pro Gaming mouse */ static __u8 *corsair_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -691,13 +695,14 @@ static __u8 *corsair_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { /* - * Corsair Scimitar RGB Pro report descriptor is broken and - * defines two different Logical Minimum for the Consumer - * Application. The byte 77 should be a 0x26 defining a 16 - * bits integer for the Logical Maximum but it is a 0x16 + * Corsair GLAIVE RGB and Scimitar RGB Pro report descriptor is + * broken and defines two different Logical Minimum for the + * Consumer Application. The byte 77 should be a 0x26 defining + * a 16 bits integer for the Logical Maximum but it is a 0x16 * instead (Logical Minimum) */ switch (hdev->product) { + case USB_DEVICE_ID_CORSAIR_GLAIVE_RGB: case USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB: if (*rsize >= 172 && rdesc[75] == 0x15 && rdesc[77] == 0x16 && rdesc[78] == 0xff && rdesc[79] == 0x0f) { @@ -716,7 +721,14 @@ static const struct hid_device_id corsair_devices[] = { .driver_data = CORSAIR_USE_K90_MACRO | CORSAIR_USE_K90_BACKLIGHT }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, + USB_DEVICE_ID_CORSAIR_GLAIVE_RGB) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) }, + /* + * Vengeance K70 and K70 RAPIDFIRE share product IDs. + */ + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, + USB_DEVICE_ID_CORSAIR_K70R) }, {} }; diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c new file mode 100644 index 000000000000..803a725785cf --- /dev/null +++ b/drivers/hid/hid-elan.c @@ -0,0 +1,421 @@ +/* + * HID Driver for ELAN Touchpad + * + * Currently only supports touchpad found on HP Pavilion X2 10 + * + * Copyright (c) 2016 Alexandrov Stanislav <neko@nya.ai> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <linux/hid.h> +#include <linux/input/mt.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/usb.h> + +#include "hid-ids.h" + +#define ELAN_SINGLE_FINGER 0x81 +#define ELAN_MT_FIRST_FINGER 0x82 +#define ELAN_MT_SECOND_FINGER 0x83 +#define ELAN_INPUT_REPORT_SIZE 8 + +#define ELAN_MUTE_LED_REPORT 0xBC +#define ELAN_LED_REPORT_SIZE 8 + +struct elan_touchpad_settings { + u8 max_fingers; + u16 max_x; + u16 max_y; + u8 max_area_x; + u8 max_area_y; + u8 max_w; + int usb_bInterfaceNumber; +}; + +struct elan_drvdata { + struct input_dev *input; + u8 prev_report[ELAN_INPUT_REPORT_SIZE]; + struct led_classdev mute_led; + u8 mute_led_state; + struct elan_touchpad_settings *settings; +}; + +static int is_not_elan_touchpad(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + + return (intf->altsetting->desc.bInterfaceNumber != drvdata->settings->usb_bInterfaceNumber); +} + +static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (is_not_elan_touchpad(hdev)) + return 0; + + if (field->report->id == ELAN_SINGLE_FINGER || + field->report->id == ELAN_MT_FIRST_FINGER || + field->report->id == ELAN_MT_SECOND_FINGER) + return -1; + + return 0; +} + +static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi) +{ + int ret; + struct input_dev *input; + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + + if (is_not_elan_touchpad(hdev)) + return 0; + + input = devm_input_allocate_device(&hdev->dev); + if (!input) + return -ENOMEM; + + input->name = "Elan Touchpad"; + input->phys = hdev->phys; + input->uniq = hdev->uniq; + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + input->dev.parent = &hdev->dev; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, + drvdata->settings->max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, + drvdata->settings->max_y, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, + drvdata->settings->max_fingers, 0, 0); + input_set_abs_params(input, ABS_TOOL_WIDTH, 0, + drvdata->settings->max_w, 0, 0); + + __set_bit(BTN_LEFT, input->keybit); + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + + ret = input_mt_init_slots(input, drvdata->settings->max_fingers, + INPUT_MT_POINTER); + if (ret) { + hid_err(hdev, "Failed to init elan MT slots: %d\n", ret); + return ret; + } + + ret = input_register_device(input); + if (ret) { + hid_err(hdev, "Failed to register elan input device: %d\n", + ret); + input_free_device(input); + return ret; + } + + drvdata->input = input; + + return 0; +} + +static void elan_report_mt_slot(struct elan_drvdata *drvdata, u8 *data, + unsigned int slot_num) +{ + struct input_dev *input = drvdata->input; + int x, y, w; + + bool active = !!data; + + input_mt_slot(input, slot_num); + input_mt_report_slot_state(input, MT_TOOL_FINGER, active); + if (active) { + x = ((data[0] & 0xF0) << 4) | data[1]; + y = drvdata->settings->max_y - + (((data[0] & 0x07) << 8) | data[2]); + w = data[4]; + + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + input_report_abs(input, ABS_TOOL_WIDTH, w); + } +} + +static void elan_report_input(struct elan_drvdata *drvdata, u8 *data) +{ + int i; + struct input_dev *input = drvdata->input; + + /* + * There is 3 types of reports: for single touch, + * for multitouch - first finger and for multitouch - second finger + * + * packet structure for ELAN_SINGLE_FINGER and ELAN_MT_FIRST_FINGER: + * + * byte 1: 1 0 0 0 0 0 0 1 // 0x81 or 0x82 + * byte 2: 0 0 0 0 0 0 0 0 // looks like unused + * byte 3: f5 f4 f3 f2 f1 0 0 L + * byte 4: x12 x11 x10 x9 0? y11 y10 y9 + * byte 5: x8 x7 x6 x5 x4 x3 x2 x1 + * byte 6: y8 y7 y6 y5 y4 y3 y2 y1 + * byte 7: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1 + * byte 8: w8 w7 w6 w5 w4 w3 w2 w1 + * + * packet structure for ELAN_MT_SECOND_FINGER: + * + * byte 1: 1 0 0 0 0 0 1 1 // 0x83 + * byte 2: x12 x11 x10 x9 0 y11 y10 y9 + * byte 3: x8 x7 x6 x5 x4 x3 x2 x1 + * byte 4: y8 y7 y6 y5 y4 y3 y2 y1 + * byte 5: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1 + * byte 6: w8 w7 w6 w5 w4 w3 w2 w1 + * byte 7: 0 0 0 0 0 0 0 0 + * byte 8: 0 0 0 0 0 0 0 0 + * + * f5-f1: finger touch bits + * L: clickpad button + * sy / sx: not sure yet, but this looks like rectangular + * area for finger + * w: looks like finger width + */ + + if (data[0] == ELAN_SINGLE_FINGER) { + for (i = 0; i < drvdata->settings->max_fingers; i++) { + if (data[2] & BIT(i + 3)) + elan_report_mt_slot(drvdata, data + 3, i); + else + elan_report_mt_slot(drvdata, NULL, i); + } + input_report_key(input, BTN_LEFT, data[2] & 0x01); + } + /* + * When touched with two fingers Elan touchpad will emit two HID reports + * first is ELAN_MT_FIRST_FINGER and second is ELAN_MT_SECOND_FINGER + * we will save ELAN_MT_FIRST_FINGER report and wait for + * ELAN_MT_SECOND_FINGER to finish multitouch + */ + if (data[0] == ELAN_MT_FIRST_FINGER) { + memcpy(drvdata->prev_report, data, + sizeof(drvdata->prev_report)); + return; + } + + if (data[0] == ELAN_MT_SECOND_FINGER) { + int first = 0; + u8 *prev_report = drvdata->prev_report; + + if (prev_report[0] != ELAN_MT_FIRST_FINGER) + return; + + for (i = 0; i < drvdata->settings->max_fingers; i++) { + if (prev_report[2] & BIT(i + 3)) { + if (!first) { + first = 1; + elan_report_mt_slot(drvdata, prev_report + 3, i); + } else { + elan_report_mt_slot(drvdata, data + 1, i); + } + } else { + elan_report_mt_slot(drvdata, NULL, i); + } + } + input_report_key(input, BTN_LEFT, prev_report[2] & 0x01); + } + + input_mt_sync_frame(input); + input_sync(input); +} + +static int elan_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + + if (is_not_elan_touchpad(hdev)) + return 0; + + if (data[0] == ELAN_SINGLE_FINGER || + data[0] == ELAN_MT_FIRST_FINGER || + data[0] == ELAN_MT_SECOND_FINGER) { + if (size == ELAN_INPUT_REPORT_SIZE) { + elan_report_input(drvdata, data); + return 1; + } + } + + return 0; +} + +static int elan_start_multitouch(struct hid_device *hdev) +{ + int ret; + + /* + * This byte sequence will enable multitouch mode and disable + * mouse emulation + */ + const unsigned char buf[] = { 0x0D, 0x00, 0x03, 0x21, 0x00 }; + unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL); + + if (!dmabuf) + return -ENOMEM; + + ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf), + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + + kfree(dmabuf); + + if (ret != sizeof(buf)) { + hid_err(hdev, "Failed to start multitouch: %d\n", ret); + return ret; + } + + return 0; +} + +static enum led_brightness elan_mute_led_get_brigtness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = to_hid_device(dev); + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + + return drvdata->mute_led_state; +} + +static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + int ret; + u8 led_state; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = to_hid_device(dev); + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + + unsigned char *dmabuf = kzalloc(ELAN_LED_REPORT_SIZE, GFP_KERNEL); + + if (!dmabuf) + return -ENOMEM; + + led_state = !!value; + + dmabuf[0] = ELAN_MUTE_LED_REPORT; + dmabuf[1] = 0x02; + dmabuf[2] = led_state; + + ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, ELAN_LED_REPORT_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + + kfree(dmabuf); + + if (ret != ELAN_LED_REPORT_SIZE) { + hid_err(hdev, "Failed to set mute led brightness: %d\n", ret); + return ret; + } + + drvdata->mute_led_state = led_state; + return 0; +} + +static int elan_init_mute_led(struct hid_device *hdev) +{ + struct elan_drvdata *drvdata = hid_get_drvdata(hdev); + struct led_classdev *mute_led = &drvdata->mute_led; + + mute_led->name = "elan:red:mute"; + mute_led->brightness_get = elan_mute_led_get_brigtness; + mute_led->brightness_set_blocking = elan_mute_led_set_brigtness; + mute_led->max_brightness = LED_ON; + mute_led->dev = &hdev->dev; + + return devm_led_classdev_register(&hdev->dev, mute_led); +} + +static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct elan_drvdata *drvdata; + + drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); + + if (!drvdata) + return -ENOMEM; + + drvdata->settings = (struct elan_touchpad_settings *)id->driver_data; + hid_set_drvdata(hdev, drvdata); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "Hid Parse failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "Hid hw start failed\n"); + return ret; + } + + if (is_not_elan_touchpad(hdev)) + return 0; + + if (!drvdata->input) { + hid_err(hdev, "Input device is not registred\n"); + ret = -ENAVAIL; + goto err; + } + + ret = elan_start_multitouch(hdev); + if (ret) + goto err; + + ret = elan_init_mute_led(hdev); + if (ret) + goto err; + + return 0; +err: + hid_hw_stop(hdev); + return ret; +} + +static void elan_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); +} + +static const struct elan_touchpad_settings hp_x2_10_touchpad_data = { + .max_fingers = 5, + .max_x = 2930, + .max_y = 1250, + .max_area_x = 15, + .max_area_y = 15, + .max_w = 255, + .usb_bInterfaceNumber = 1, +}; + +static const struct hid_device_id elan_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER), + (kernel_ulong_t)&hp_x2_10_touchpad_data}, + { } +}; + +MODULE_DEVICE_TABLE(hid, elan_devices); + +static struct hid_driver elan_driver = { + .name = "elan", + .id_table = elan_devices, + .input_mapping = elan_input_mapping, + .input_configured = elan_input_configured, + .raw_event = elan_raw_event, + .probe = elan_probe, + .remove = elan_remove, +}; + +module_hid_driver(elan_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexandrov Stanislav"); +MODULE_DESCRIPTION("Driver for HID ELAN Touchpads"); diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 1a1ecc491c02..ae8e9413c79d 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -1,9 +1,9 @@ /* * HID driver for ELECOM devices: * - BM084 Bluetooth Mouse - * - EX-G Trackball (Wired and wireless) - * - DEFT Trackball (Wired and wireless) - * - HUGE Trackball (Wired and wireless) + * - EX-G Trackballs (M-XT3DRBK, M-XT3URBK, M-XT4DRBK) + * - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK) + * - HUGE Trackballs (M-HT1DRBK, M-HT1URBK) * * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com> * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com> @@ -65,14 +65,15 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[47] = 0x00; } break; - case USB_DEVICE_ID_ELECOM_EX_G_WIRED: - case USB_DEVICE_ID_ELECOM_EX_G_WIRELESS: + case USB_DEVICE_ID_ELECOM_M_XT3URBK: + case USB_DEVICE_ID_ELECOM_M_XT3DRBK: + case USB_DEVICE_ID_ELECOM_M_XT4DRBK: mouse_button_fixup(hdev, rdesc, *rsize, 6); break; - case USB_DEVICE_ID_ELECOM_DEFT_WIRED: - case USB_DEVICE_ID_ELECOM_DEFT_WIRELESS: - case USB_DEVICE_ID_ELECOM_HUGE_WIRED: - case USB_DEVICE_ID_ELECOM_HUGE_WIRELESS: + case USB_DEVICE_ID_ELECOM_M_DT1URBK: + case USB_DEVICE_ID_ELECOM_M_DT1DRBK: + case USB_DEVICE_ID_ELECOM_M_HT1URBK: + case USB_DEVICE_ID_ELECOM_M_HT1DRBK: mouse_button_fixup(hdev, rdesc, *rsize, 8); break; } @@ -81,12 +82,13 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, static const struct hid_device_id elecom_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRELESS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) }, { } }; MODULE_DEVICE_TABLE(hid, elecom_devices); diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c index 3c0a1bf433d7..c25b4718de44 100644 --- a/drivers/hid/hid-generic.c +++ b/drivers/hid/hid-generic.c @@ -26,37 +26,6 @@ static struct hid_driver hid_generic; -static int __unmap_hid_generic(struct device *dev, void *data) -{ - struct hid_driver *hdrv = data; - struct hid_device *hdev = to_hid_device(dev); - - /* only unbind matching devices already bound to hid-generic */ - if (hdev->driver != &hid_generic || - hid_match_device(hdev, hdrv) == NULL) - return 0; - - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - device_release_driver(dev); - if (dev->parent) - device_unlock(dev->parent); - - return 0; -} - -static void hid_generic_add_driver(struct hid_driver *hdrv) -{ - bus_for_each_dev(&hid_bus_type, NULL, hdrv, __unmap_hid_generic); -} - -static void hid_generic_removed_driver(struct hid_driver *hdrv) -{ - int ret; - - ret = driver_attach(&hid_generic.driver); -} - static int __check_hid_generic(struct device_driver *drv, void *data) { struct hid_driver *hdrv = to_hid_driver(drv); @@ -97,8 +66,6 @@ static struct hid_driver hid_generic = { .name = "hid-generic", .id_table = hid_table, .match = hid_generic_match, - .bus_add_driver = hid_generic_add_driver, - .bus_removed_driver = hid_generic_removed_driver, }; module_hid_driver(hid_generic); diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c new file mode 100644 index 000000000000..7b8e17b03cb8 --- /dev/null +++ b/drivers/hid/hid-google-hammer.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID driver for Google Hammer device. + * + * Copyright (c) 2017 Google Inc. + * Author: Wei-Ning Huang <wnhuang@google.com> + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <linux/hid.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define MAX_BRIGHTNESS 100 + +/* HID usage for keyboard backlight (Alphanumeric display brightness) */ +#define HID_AD_BRIGHTNESS 0x00140046 + +struct hammer_kbd_leds { + struct led_classdev cdev; + struct hid_device *hdev; + u8 buf[2] ____cacheline_aligned; +}; + +static int hammer_kbd_brightness_set_blocking(struct led_classdev *cdev, + enum led_brightness br) +{ + struct hammer_kbd_leds *led = container_of(cdev, + struct hammer_kbd_leds, + cdev); + int ret; + + led->buf[0] = 0; + led->buf[1] = br; + + /* + * Request USB HID device to be in Full On mode, so that sending + * hardware output report and hardware raw request won't fail. + */ + ret = hid_hw_power(led->hdev, PM_HINT_FULLON); + if (ret < 0) { + hid_err(led->hdev, "failed: device not resumed %d\n", ret); + return ret; + } + + ret = hid_hw_output_report(led->hdev, led->buf, sizeof(led->buf)); + if (ret == -ENOSYS) + ret = hid_hw_raw_request(led->hdev, 0, led->buf, + sizeof(led->buf), + HID_OUTPUT_REPORT, + HID_REQ_SET_REPORT); + if (ret < 0) + hid_err(led->hdev, "failed to set keyboard backlight: %d\n", + ret); + + /* Request USB HID device back to Normal Mode. */ + hid_hw_power(led->hdev, PM_HINT_NORMAL); + + return ret; +} + +static int hammer_register_leds(struct hid_device *hdev) +{ + struct hammer_kbd_leds *kbd_backlight; + + kbd_backlight = devm_kzalloc(&hdev->dev, + sizeof(*kbd_backlight), + GFP_KERNEL); + if (!kbd_backlight) + return -ENOMEM; + + kbd_backlight->hdev = hdev; + kbd_backlight->cdev.name = "hammer::kbd_backlight"; + kbd_backlight->cdev.max_brightness = MAX_BRIGHTNESS; + kbd_backlight->cdev.brightness_set_blocking = + hammer_kbd_brightness_set_blocking; + kbd_backlight->cdev.flags = LED_HW_PLUGGABLE; + + /* Set backlight to 0% initially. */ + hammer_kbd_brightness_set_blocking(&kbd_backlight->cdev, 0); + + return devm_led_classdev_register(&hdev->dev, &kbd_backlight->cdev); +} + +static int hammer_input_configured(struct hid_device *hdev, + struct hid_input *hi) +{ + struct list_head *report_list = + &hdev->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report; + + if (list_empty(report_list)) + return 0; + + report = list_first_entry(report_list, struct hid_report, list); + + if (report->maxfield == 1 && + report->field[0]->application == HID_GD_KEYBOARD && + report->field[0]->maxusage == 1 && + report->field[0]->usage[0].hid == HID_AD_BRIGHTNESS) { + int err = hammer_register_leds(hdev); + + if (err) + hid_warn(hdev, + "Failed to register keyboard backlight: %d\n", + err); + } + + return 0; +} + +static const struct hid_device_id hammer_devices[] = { + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) }, + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STAFF) }, + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WAND) }, + { } +}; +MODULE_DEVICE_TABLE(hid, hammer_devices); + +static struct hid_driver hammer_driver = { + .name = "hammer", + .id_table = hammer_devices, + .input_configured = hammer_input_configured, +}; +module_hid_driver(hammer_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9454ac134ce2..5a3a7ead3012 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -291,6 +291,7 @@ #define USB_DEVICE_ID_CORSAIR_K70RGB 0x1b13 #define USB_DEVICE_ID_CORSAIR_STRAFE 0x1b15 #define USB_DEVICE_ID_CORSAIR_K65RGB 0x1b17 +#define USB_DEVICE_ID_CORSAIR_GLAIVE_RGB 0x1b34 #define USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE 0x1b38 #define USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE 0x1b39 #define USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB 0x1b3e @@ -368,15 +369,17 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_VENDOR_ID_ELAN 0x04f3 +#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755 #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 -#define USB_DEVICE_ID_ELECOM_EX_G_WIRED 0x00fb -#define USB_DEVICE_ID_ELECOM_EX_G_WIRELESS 0x00fc -#define USB_DEVICE_ID_ELECOM_DEFT_WIRED 0x00fe -#define USB_DEVICE_ID_ELECOM_DEFT_WIRELESS 0x00ff -#define USB_DEVICE_ID_ELECOM_HUGE_WIRED 0x010c -#define USB_DEVICE_ID_ELECOM_HUGE_WIRELESS 0x010d +#define USB_DEVICE_ID_ELECOM_M_XT3URBK 0x00fb +#define USB_DEVICE_ID_ELECOM_M_XT3DRBK 0x00fc +#define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd +#define USB_DEVICE_ID_ELECOM_M_DT1URBK 0x00fe +#define USB_DEVICE_ID_ELECOM_M_DT1DRBK 0x00ff +#define USB_DEVICE_ID_ELECOM_M_HT1URBK 0x010c +#define USB_DEVICE_ID_ELECOM_M_HT1DRBK 0x010d #define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 #define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004 @@ -445,7 +448,10 @@ #define USB_DEVICE_ID_GOODTOUCH_000f 0x000f #define USB_VENDOR_ID_GOOGLE 0x18d1 +#define USB_DEVICE_ID_GOOGLE_HAMMER 0x5022 #define USB_DEVICE_ID_GOOGLE_TOUCH_ROSE 0x5028 +#define USB_DEVICE_ID_GOOGLE_STAFF 0x502b +#define USB_DEVICE_ID_GOOGLE_WAND 0x502d #define USB_VENDOR_ID_GOTOP 0x08f2 #define USB_DEVICE_ID_SUPER_Q2 0x007f @@ -961,6 +967,9 @@ #define USB_VENDOR_ID_SMK 0x0609 #define USB_DEVICE_ID_SMK_PS3_BDREMOTE 0x0306 +#define USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE 0x0368 +#define USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE 0x0369 + #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 04d01b57d94c..6836a856c243 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1368,7 +1368,8 @@ static void hidinput_led_worker(struct work_struct *work) led_work); struct hid_field *field; struct hid_report *report; - int len, ret; + int ret; + u32 len; __u8 *buf; field = hidinput_get_led_field(hid); @@ -1656,16 +1657,16 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { - if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && - !hidinput_has_been_populated(hidinput)) { + if (drv->input_configured && + drv->input_configured(hid, hidinput)) + goto out_unwind; + + if (!hidinput_has_been_populated(hidinput)) { /* no need to register an input device not populated */ hidinput_cleanup_hidinput(hid, hidinput); continue; } - if (drv->input_configured && - drv->input_configured(hid, hidinput)) - goto out_unwind; if (input_register_device(hidinput->input)) goto out_unwind; hidinput->registered = true; diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3b4739bde05d..dad2fbb0e3f8 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -74,6 +74,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15) #define MT_QUIRK_STICKY_FINGERS BIT(16) #define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) +#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -126,7 +127,6 @@ struct mt_device { int left_button_state; /* left button state */ unsigned last_slot_field; /* the last field of a slot */ unsigned mt_report_id; /* the report ID of the multitouch device */ - unsigned long initial_quirks; /* initial quirks state */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, @@ -183,6 +183,7 @@ static void mt_post_parse(struct mt_device *td); #define MT_CLS_ASUS 0x010b #define MT_CLS_VTL 0x0110 #define MT_CLS_GOOGLE 0x0111 +#define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_DEFAULT_MAXCONTACT 10 #define MT_MAX_MAXCONTACT 250 @@ -241,7 +242,8 @@ static struct mt_class mt_classes[] = { MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_STICKY_FINGERS }, + MT_QUIRK_STICKY_FINGERS | + MT_QUIRK_WIN8_PTP_BUTTONS }, { .name = MT_CLS_EXPORT_ALL_INPUTS, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, @@ -250,7 +252,8 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | - MT_QUIRK_CONTACT_CNT_ACCURATE, + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, /* @@ -323,6 +326,13 @@ static struct mt_class mt_classes[] = { MT_QUIRK_SLOT_IS_CONTACTID | MT_QUIRK_HOVERING }, + { .name = MT_CLS_RAZER_BLADE_STEALTH, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_WIN8_PTP_BUTTONS, + }, { } }; @@ -369,15 +379,15 @@ static const struct attribute_group mt_attribute_group = { static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) { - struct mt_device *td = hid_get_drvdata(hdev); - int ret, size = hid_report_len(report); + int ret; + u32 size = hid_report_len(report); u8 *buf; /* * Do not fetch the feature report if the device has been explicitly * marked as non-capable. */ - if (td->initial_quirks & HID_QUIRK_NO_INIT_REPORTS) + if (hdev->quirks & HID_QUIRK_NO_INIT_REPORTS) return; buf = hid_alloc_report_buf(report, GFP_KERNEL); @@ -659,8 +669,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, * MS PTP spec says that external buttons left and right have * usages 2 and 3. */ - if ((cls->name == MT_CLS_WIN_8 || - cls->name == MT_CLS_WIN_8_DUAL) && + if ((cls->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && field->application == HID_DG_TOUCHPAD && (usage->hid & HID_USAGE) > 1) code--; @@ -722,7 +731,7 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) } if (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE)) - s->confidence_state = 1; + s->confidence_state = true; active = (s->touch_state || s->inrange_state) && s->confidence_state; @@ -772,9 +781,7 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) */ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) { - __s32 cls = td->mtclass.name; - - if (cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) + if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) input_event(input, EV_KEY, BTN_LEFT, td->left_button_state); input_mt_sync_frame(input); @@ -826,7 +833,6 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, bool first_packet) { struct mt_device *td = hid_get_drvdata(hid); - __s32 cls = td->mtclass.name; __s32 quirks = td->mtclass.quirks; struct input_dev *input = field->hidinput->input; @@ -904,7 +910,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, * non finger/touch events in the first_packet of * a (possible) multi-packet frame. */ - if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && + if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && !first_packet) return; @@ -915,7 +921,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, * BTN_LEFT if either is pressed, so we or all values * together and report the result in mt_sync_frame(). */ - if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && + if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && usage->type == EV_KEY && usage->code == BTN_LEFT) { td->left_button_state |= value; return; @@ -939,7 +945,6 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, static void mt_touch_report(struct hid_device *hid, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hid); - __s32 cls = td->mtclass.name; struct hid_field *field; bool first_packet; unsigned count; @@ -968,7 +973,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) * of a possible multi-packet frame be checking that the * timestamp has changed. */ - if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && + if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && td->num_received == 0 && td->prev_scantime != scantime) td->num_expected = value; /* A non 0 contact count always indicates a first packet */ @@ -1183,7 +1188,7 @@ static void mt_set_input_mode(struct hid_device *hdev) struct hid_report_enum *re; struct mt_class *cls = &td->mtclass; char *buf; - int report_len; + u32 report_len; if (td->inputmode < 0) return; @@ -1447,11 +1452,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) td->serial_maybe = true; - /* - * Store the initial quirk state - */ - td->initial_quirks = hdev->quirks; - /* This allows the driver to correctly support devices * that emit events over several HID messages. */ @@ -1463,22 +1463,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) * device. */ hdev->quirks |= HID_QUIRK_MULTI_INPUT; - hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; - - /* - * Some multitouch screens do not like to be polled for input - * reports. Fortunately, the Win8 spec says that all touches - * should be sent during each report, making the initialization - * of input reports unnecessary. For Win7 devices, well, let's hope - * they will still be happy (this is only be a problem if a touch - * was already there while probing the device). - * - * In addition some touchpads do not behave well if we read - * all feature reports from them. Instead we prevent - * initial report fetching and then selectively fetch each - * report we are interested in. - */ - hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; timer_setup(&td->release_timer, mt_expired_timeout, 0); @@ -1537,7 +1521,6 @@ static void mt_remove(struct hid_device *hdev) sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); hid_hw_stop(hdev); - hdev->quirks = td->initial_quirks; } /* @@ -1793,6 +1776,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, + /* Razer touchpads */ + { .driver_data = MT_CLS_RAZER_BLADE_STEALTH, + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_SYNAPTICS, 0x8323) }, + /* Stantum panels */ { .driver_data = MT_CLS_CONFIDENCE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 3d121d8ee980..43b1c7234316 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -591,8 +591,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, switch (usage->hid) { case 0xff000001: /* Tag indicating the start of a multitouch group */ - nd->reading_mt = 1; - nd->first_contact_touch = 0; + nd->reading_mt = true; + nd->first_contact_touch = false; break; case HID_DG_TIPSWITCH: nd->tipswitch = value; @@ -663,7 +663,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, * even if deactivation slack is turned off. */ nd->act_state = deactivate_slack - 1; - nd->confidence = 0; + nd->confidence = false; break; } @@ -679,7 +679,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, */ if (nd->w < nd->min_width || nd->h < nd->min_height) - nd->confidence = 0; + nd->confidence = false; } else break; @@ -758,7 +758,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, if (!nd->reading_mt) /* Just to be sure */ break; - nd->reading_mt = 0; + nd->reading_mt = false; /* @@ -910,7 +910,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENOMEM; } - nd->reading_mt = 0; + nd->reading_mt = false; nd->min_width = 0; nd->min_height = 0; nd->activate_slack = activate_slack; diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index e92b77fa574a..587e2681a53f 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -62,6 +62,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70R), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_M65RGB), HID_QUIRK_NO_INIT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51), HID_QUIRK_NOGET }, @@ -317,6 +318,7 @@ static const struct hid_device_id hid_have_special_driver[] = { #endif #if IS_ENABLED(CONFIG_HID_CORSAIR) { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB) }, { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) }, #endif #if IS_ENABLED(CONFIG_HID_CP2112) @@ -333,14 +335,18 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, #endif +#if IS_ENABLED(CONFIG_HID_ELAN) + { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER) }, +#endif #if IS_ENABLED(CONFIG_HID_ELECOM) { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRELESS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) }, #endif #if IS_ENABLED(CONFIG_HID_ELO) { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, @@ -608,6 +614,8 @@ static const struct hid_device_id hid_have_special_driver[] = { #if IS_ENABLED(CONFIG_HID_SONY) { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index c6c05df3e8d2..9c9362149641 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -89,8 +89,8 @@ struct rmi_data { u8 *writeReport; u8 *readReport; - int input_report_size; - int output_report_size; + u32 input_report_size; + u32 output_report_size; unsigned long flags; diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ccdc5f2d01b1..e475c5073c99 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -9,6 +9,7 @@ * Copyright (c) 2006-2013 Jiri Kosina * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> + * Copyright (c) 2018 Todd Kelner */ /* @@ -55,6 +56,8 @@ #define NAVIGATION_CONTROLLER_BT BIT(11) #define SINO_LITE_CONTROLLER BIT(12) #define FUTUREMAX_DANCE_MAT BIT(13) +#define NSG_MR5U_REMOTE_BT BIT(14) +#define NSG_MR7U_REMOTE_BT BIT(15) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) @@ -72,8 +75,11 @@ MOTION_CONTROLLER) #define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\ MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT) +#define NSG_MRXU_REMOTE (NSG_MR5U_REMOTE_BT | NSG_MR7U_REMOTE_BT) #define MAX_LEDS 4 +#define NSG_MRXU_MAX_X 1667 +#define NSG_MRXU_MAX_Y 1868 /* PS/3 Motion controller */ @@ -1098,6 +1104,80 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) } } +static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size) +{ + int n, offset, relx, rely; + u8 active; + + /* + * The NSG-MRxU multi-touch trackpad data starts at offset 1 and + * the touch-related data starts at offset 2. + * For the first byte, bit 0 is set when touchpad button is pressed. + * Bit 2 is set when a touch is active and the drag (Fn) key is pressed. + * This drag key is mapped to BTN_LEFT. It is operational only when a + * touch point is active. + * Bit 4 is set when only the first touch point is active. + * Bit 6 is set when only the second touch point is active. + * Bits 5 and 7 are set when both touch points are active. + * The next 3 bytes are two 12 bit X/Y coordinates for the first touch. + * The following byte, offset 5, has the touch width and length. + * Bits 0-4=X (width), bits 5-7=Y (length). + * A signed relative X coordinate is at offset 6. + * The bytes at offset 7-9 are the second touch X/Y coordinates. + * Offset 10 has the second touch width and length. + * Offset 11 has the relative Y coordinate. + */ + offset = 1; + + input_report_key(sc->touchpad, BTN_LEFT, rd[offset] & 0x0F); + active = (rd[offset] >> 4); + relx = (s8) rd[offset+5]; + rely = ((s8) rd[offset+10]) * -1; + + offset++; + + for (n = 0; n < 2; n++) { + u16 x, y; + u8 contactx, contacty; + + x = rd[offset] | ((rd[offset+1] & 0x0F) << 8); + y = ((rd[offset+1] & 0xF0) >> 4) | (rd[offset+2] << 4); + + input_mt_slot(sc->touchpad, n); + input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active & 0x03); + + if (active & 0x03) { + contactx = rd[offset+3] & 0x0F; + contacty = rd[offset+3] >> 4; + input_report_abs(sc->touchpad, ABS_MT_TOUCH_MAJOR, + max(contactx, contacty)); + input_report_abs(sc->touchpad, ABS_MT_TOUCH_MINOR, + min(contactx, contacty)); + input_report_abs(sc->touchpad, ABS_MT_ORIENTATION, + (bool) (contactx > contacty)); + input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x); + input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, + NSG_MRXU_MAX_Y - y); + /* + * The relative coordinates belong to the first touch + * point, when present, or to the second touch point + * when the first is not active. + */ + if ((n == 0) || ((n == 1) && (active & 0x01))) { + input_report_rel(sc->touchpad, REL_X, relx); + input_report_rel(sc->touchpad, REL_Y, rely); + } + } + + offset += 5; + active >>= 2; + } + + input_mt_sync_frame(sc->touchpad); + + input_sync(sc->touchpad); +} + static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *rd, int size) { @@ -1206,6 +1286,10 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, } dualshock4_parse_report(sc, rd, size); + + } else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) { + nsg_mrxu_parse_report(sc, rd, size); + return 1; } if (sc->defer_initialization) { @@ -1263,7 +1347,7 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, } static int sony_register_touchpad(struct sony_sc *sc, int touch_count, - int w, int h) + int w, int h, int touch_major, int touch_minor, int orientation) { size_t name_sz; char *name; @@ -1294,10 +1378,6 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); sc->touchpad->name = name; - ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER); - if (ret < 0) - goto err; - /* We map the button underneath the touchpad to BTN_LEFT. */ __set_bit(EV_KEY, sc->touchpad->evbit); __set_bit(BTN_LEFT, sc->touchpad->keybit); @@ -1306,6 +1386,25 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, input_set_abs_params(sc->touchpad, ABS_MT_POSITION_X, 0, w, 0, 0); input_set_abs_params(sc->touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0); + if (touch_major > 0) { + input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MAJOR, + 0, touch_major, 0, 0); + if (touch_minor > 0) + input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MINOR, + 0, touch_minor, 0, 0); + if (orientation > 0) + input_set_abs_params(sc->touchpad, ABS_MT_ORIENTATION, + 0, orientation, 0, 0); + } + + if (sc->quirks & NSG_MRXU_REMOTE) { + __set_bit(EV_REL, sc->touchpad->evbit); + } + + ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER); + if (ret < 0) + goto err; + ret = input_register_device(sc->touchpad); if (ret < 0) goto err; @@ -2690,7 +2789,7 @@ static int sony_input_configured(struct hid_device *hdev, * The Dualshock 4 touchpad supports 2 touches and has a * resolution of 1920x942 (44.86 dots/mm). */ - ret = sony_register_touchpad(sc, 2, 1920, 942); + ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0); if (ret) { hid_err(sc->hdev, "Unable to initialize multi-touch slots: %d\n", @@ -2721,6 +2820,20 @@ static int sony_input_configured(struct hid_device *hdev, } sony_init_output_report(sc, dualshock4_send_output_report); + } else if (sc->quirks & NSG_MRXU_REMOTE) { + /* + * The NSG-MRxU touchpad supports 2 touches and has a + * resolution of 1667x1868 + */ + ret = sony_register_touchpad(sc, 2, + NSG_MRXU_MAX_X, NSG_MRXU_MAX_Y, 15, 15, 1); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize multi-touch slots: %d\n", + ret); + goto err_stop; + } + } else if (sc->quirks & MOTION_CONTROLLER) { sony_init_output_report(sc, motion_send_output_report); } else { @@ -2969,6 +3082,12 @@ static const struct hid_device_id sony_devices[] = { /* Nyko Core Controller for PS3 */ { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB | SINO_LITE_CONTROLLER }, + /* SMK-Link NSG-MR5U Remote Control */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE), + .driver_data = NSG_MR5U_REMOTE_BT }, + /* SMK-Link NSG-MR7U Remote Control */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE), + .driver_data = NSG_MR7U_REMOTE_BT }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index e3e6e5c893cc..56b196d60041 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -946,7 +946,6 @@ static int uclogic_probe(struct hid_device *hdev, * than the pen, so use QUIRK_MULTI_INPUT for all tablets. */ hdev->quirks |= HID_QUIRK_MULTI_INPUT; - hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; /* Allocate and assign driver data */ drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 7230243b94d3..97689e98e53f 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -144,10 +144,10 @@ struct i2c_hid { * register of the HID * descriptor. */ unsigned int bufsize; /* i2c buffer size */ - char *inbuf; /* Input buffer */ - char *rawbuf; /* Raw Input buffer */ - char *cmdbuf; /* Command buffer */ - char *argsbuf; /* Command arguments buffer */ + u8 *inbuf; /* Input buffer */ + u8 *rawbuf; /* Raw Input buffer */ + u8 *cmdbuf; /* Command buffer */ + u8 *argsbuf; /* Command arguments buffer */ unsigned long flags; /* device flags */ unsigned long quirks; /* Various quirks */ @@ -455,7 +455,8 @@ out_unlock: static void i2c_hid_get_input(struct i2c_hid *ihid) { - int ret, ret_size; + int ret; + u32 ret_size; int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); if (size > ihid->bufsize) @@ -480,7 +481,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) return; } - if (ret_size > size) { + if ((ret_size > size) || (ret_size <= 2)) { dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", __func__, size, ret_size); return; @@ -891,10 +892,10 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, static void i2c_hid_acpi_fix_up_power(struct device *dev) { - acpi_handle handle = ACPI_HANDLE(dev); struct acpi_device *adev; - if (handle && acpi_bus_get_device(handle, &adev) == 0) + adev = ACPI_COMPANION(dev); + if (adev) acpi_device_fix_up_power(adev); } diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 4e0e7baf8513..3c5507313606 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -496,12 +496,12 @@ static int uhid_dev_create2(struct uhid_device *uhid, goto err_free; } - len = min(sizeof(hid->name), sizeof(ev->u.create2.name)) - 1; - strncpy(hid->name, ev->u.create2.name, len); - len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)) - 1; - strncpy(hid->phys, ev->u.create2.phys, len); - len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)) - 1; - strncpy(hid->uniq, ev->u.create2.uniq, len); + len = min(sizeof(hid->name), sizeof(ev->u.create2.name)); + strlcpy(hid->name, ev->u.create2.name, len); + len = min(sizeof(hid->phys), sizeof(ev->u.create2.phys)); + strlcpy(hid->phys, ev->u.create2.phys, len); + len = min(sizeof(hid->uniq), sizeof(ev->u.create2.uniq)); + strlcpy(hid->uniq, ev->u.create2.uniq, len); hid->ll_driver = &uhid_hid_driver; hid->bus = ev->u.create2.bus; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 77c50cdfff97..af0e0d061b15 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -56,6 +56,10 @@ static unsigned int hid_jspoll_interval; module_param_named(jspoll, hid_jspoll_interval, uint, 0644); MODULE_PARM_DESC(jspoll, "Polling interval of joysticks"); +static unsigned int hid_kbpoll_interval; +module_param_named(kbpoll, hid_kbpoll_interval, uint, 0644); +MODULE_PARM_DESC(kbpoll, "Polling interval of keyboards"); + static unsigned int ignoreled; module_param_named(ignoreled, ignoreled, uint, 0644); MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds"); @@ -1094,7 +1098,9 @@ static int usbhid_start(struct hid_device *hid) hid->name, endpoint->bInterval, interval); } - /* Change the polling interval of mice and joysticks. */ + /* Change the polling interval of mice, joysticks + * and keyboards. + */ switch (hid->collection->usage) { case HID_GD_MOUSE: if (hid_mousepoll_interval > 0) @@ -1104,6 +1110,10 @@ static int usbhid_start(struct hid_device *hid) if (hid_jspoll_interval > 0) interval = hid_jspoll_interval; break; + case HID_GD_KEYBOARD: + if (hid_kbpoll_interval > 0) + interval = hid_kbpoll_interval; + break; } ret = -ENOMEM; diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 409543160af7..b54ef1ffcbec 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -219,7 +219,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); u8 *data; int ret; - int n; + u32 n; switch (equivalent_usage) { case HID_DG_CONTACTMAX: @@ -519,7 +519,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, u8 *rep_data; struct hid_report *r; struct hid_report_enum *re; - int length; + u32 length; int error = -ENOMEM, limit = 0; if (wacom_wac->mode_report < 0) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 90c38a0523e9..6da16a879c9f 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1202,15 +1202,24 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) { - const int pen_frame_len = 14; - const int pen_frames = 7; + int pen_frame_len, pen_frames; struct input_dev *pen_input = wacom->pen_input; unsigned char *data = wacom->data; int i; - wacom->serial[0] = get_unaligned_le64(&data[99]); - wacom->id[0] = get_unaligned_le16(&data[107]); + if (wacom->features.type == INTUOSP2_BT) { + wacom->serial[0] = get_unaligned_le64(&data[99]); + wacom->id[0] = get_unaligned_le16(&data[107]); + pen_frame_len = 14; + pen_frames = 7; + } else { + wacom->serial[0] = get_unaligned_le64(&data[33]); + wacom->id[0] = get_unaligned_le16(&data[41]); + pen_frame_len = 8; + pen_frames = 4; + } + if (wacom->serial[0] >> 52 == 1) { /* Add back in missing bits of ID for non-USI pens */ wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF; @@ -1227,21 +1236,35 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) continue; if (range) { - /* Fix rotation alignment: userspace expects zero at left */ - int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]); - rotation += 1800/4; - if (rotation > 899) - rotation -= 1800; - input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3])); - input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]); - input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]); - input_report_abs(pen_input, ABS_Z, rotation); - input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11])); + + if (wacom->features.type == INTUOSP2_BT) { + /* Fix rotation alignment: userspace expects zero at left */ + int16_t rotation = + (int16_t)get_unaligned_le16(&frame[9]); + rotation += 1800/4; + + if (rotation > 899) + rotation -= 1800; + + input_report_abs(pen_input, ABS_TILT_X, + (char)frame[7]); + input_report_abs(pen_input, ABS_TILT_Y, + (char)frame[8]); + input_report_abs(pen_input, ABS_Z, rotation); + input_report_abs(pen_input, ABS_WHEEL, + get_unaligned_le16(&frame[11])); + } } input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); - input_report_abs(pen_input, ABS_DISTANCE, range ? frame[13] : wacom->features.distance_max); + if (wacom->features.type == INTUOSP2_BT) { + input_report_abs(pen_input, ABS_DISTANCE, + range ? frame[13] : wacom->features.distance_max); + } else { + input_report_abs(pen_input, ABS_DISTANCE, + range ? frame[7] : wacom->features.distance_max); + } input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01); input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02); @@ -1357,20 +1380,52 @@ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom) battery_status, chg, 1, chg); } +static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom) +{ + struct input_dev *pad_input = wacom->pad_input; + unsigned char *data = wacom->data; + + int buttons = data[44]; + + wacom_report_numbered_buttons(pad_input, 4, buttons); + + input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0); + input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0); + input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff); + + input_sync(pad_input); +} + +static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom) +{ + unsigned char *data = wacom->data; + + bool chg = data[45] & 0x80; + int battery_status = data[45] & 0x7F; + + wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, + battery_status, chg, 1, chg); +} + static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len) { unsigned char *data = wacom->data; - if (data[0] != 0x80) { + if (data[0] != 0x80 && data[0] != 0x81) { dev_dbg(wacom->pen_input->dev.parent, "%s: received unknown report #%d\n", __func__, data[0]); return 0; } wacom_intuos_pro2_bt_pen(wacom); - wacom_intuos_pro2_bt_touch(wacom); - wacom_intuos_pro2_bt_pad(wacom); - wacom_intuos_pro2_bt_battery(wacom); + if (wacom->features.type == INTUOSP2_BT) { + wacom_intuos_pro2_bt_touch(wacom); + wacom_intuos_pro2_bt_pad(wacom); + wacom_intuos_pro2_bt_battery(wacom); + } else { + wacom_intuos_gen3_bt_pad(wacom); + wacom_intuos_gen3_bt_battery(wacom); + } return 0; } @@ -1660,7 +1715,8 @@ int wacom_equivalent_usage(int usage) usage == WACOM_HID_WD_TOUCHSTRIP || usage == WACOM_HID_WD_TOUCHSTRIP2 || usage == WACOM_HID_WD_TOUCHRING || - usage == WACOM_HID_WD_TOUCHRINGSTATUS) { + usage == WACOM_HID_WD_TOUCHRINGSTATUS || + usage == WACOM_HID_WD_REPORT_VALID) { return usage; } @@ -2017,7 +2073,7 @@ static void wacom_wac_pad_pre_report(struct hid_device *hdev, } static void wacom_wac_pad_report(struct hid_device *hdev, - struct hid_report *report) + struct hid_report *report, struct hid_field *field) { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; @@ -2025,7 +2081,7 @@ static void wacom_wac_pad_report(struct hid_device *hdev, bool active = wacom_wac->hid_data.inrange_state != 0; /* report prox for expresskey events */ - if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) && + if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) && wacom_wac->hid_data.pad_input_event_flag) { input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0); input_sync(input); @@ -2144,6 +2200,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field struct input_dev *input = wacom_wac->pen_input; unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); + if (wacom_wac->is_invalid_bt_frame) + return; + switch (equivalent_usage) { case HID_GD_Z: /* @@ -2240,6 +2299,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field features->offset_bottom); features->offset_bottom = value; return; + case WACOM_HID_WD_REPORT_VALID: + wacom_wac->is_invalid_bt_frame = !value; + return; } /* send pen events only when touch is up or forced out @@ -2258,6 +2320,10 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field static void wacom_wac_pen_pre_report(struct hid_device *hdev, struct hid_report *report) { + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + + wacom_wac->is_invalid_bt_frame = false; return; } @@ -2270,6 +2336,9 @@ static void wacom_wac_pen_report(struct hid_device *hdev, bool range = wacom_wac->hid_data.inrange_state; bool sense = wacom_wac->hid_data.sense_state; + if (wacom_wac->is_invalid_bt_frame) + return; + if (!wacom_wac->tool[0] && range) { /* first in range */ /* Going into range select tool */ if (wacom_wac->hid_data.invert_state) @@ -2572,11 +2641,13 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field, wacom_wac_finger_event(hdev, field, usage, value); } -static void wacom_report_events(struct hid_device *hdev, struct hid_report *report) +static void wacom_report_events(struct hid_device *hdev, + struct hid_report *report, int collection_index, + int field_index) { int r; - for (r = 0; r < report->maxfield; r++) { + for (r = field_index; r < report->maxfield; r++) { struct hid_field *field; unsigned count, n; @@ -2586,30 +2657,23 @@ static void wacom_report_events(struct hid_device *hdev, struct hid_report *repo if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) continue; - for (n = 0; n < count; n++) - wacom_wac_event(hdev, field, &field->usage[n], field->value[n]); + for (n = 0 ; n < count; n++) { + if (field->usage[n].collection_index == collection_index) + wacom_wac_event(hdev, field, &field->usage[n], + field->value[n]); + else + return; + } } } -void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) +static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report, + int collection_index, struct hid_field *field, + int field_index) { struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct hid_field *field = report->field[0]; - if (wacom_wac->features.type != HID_GENERIC) - return; - - wacom_wac_battery_pre_report(hdev, report); - - if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) - wacom_wac_pad_pre_report(hdev, report); - else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) - wacom_wac_pen_pre_report(hdev, report); - else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input) - wacom_wac_finger_pre_report(hdev, report); - - wacom_report_events(hdev, report); + wacom_report_events(hdev, report, collection_index, field_index); /* * Non-input reports may be sent prior to the device being @@ -2619,16 +2683,63 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) * processing functions. */ if (report->type != HID_INPUT_REPORT) - return; - - wacom_wac_battery_report(hdev, report); + return -1; if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) - wacom_wac_pad_report(hdev, report); + wacom_wac_pad_report(hdev, report, field); else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) wacom_wac_pen_report(hdev, report); else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input) wacom_wac_finger_report(hdev, report); + + return 0; +} + +void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) +{ + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct hid_field *field; + bool pad_in_hid_field = false, pen_in_hid_field = false, + finger_in_hid_field = false; + int r; + int prev_collection = -1; + + if (wacom_wac->features.type != HID_GENERIC) + return; + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + + if (WACOM_PAD_FIELD(field)) + pad_in_hid_field = true; + if (WACOM_PEN_FIELD(field)) + pen_in_hid_field = true; + if (WACOM_FINGER_FIELD(field)) + finger_in_hid_field = true; + } + + wacom_wac_battery_pre_report(hdev, report); + + if (pad_in_hid_field && wacom->wacom_wac.pad_input) + wacom_wac_pad_pre_report(hdev, report); + if (pen_in_hid_field && wacom->wacom_wac.pen_input) + wacom_wac_pen_pre_report(hdev, report); + if (finger_in_hid_field && wacom->wacom_wac.touch_input) + wacom_wac_finger_pre_report(hdev, report); + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + + if (field->usage[0].collection_index != prev_collection) { + if (wacom_wac_collection(hdev, report, + field->usage[0].collection_index, field, r) < 0) + return; + prev_collection = field->usage[0].collection_index; + } + } + + wacom_wac_battery_report(hdev, report); } static int wacom_bpt_touch(struct wacom_wac *wacom) @@ -3093,6 +3204,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) break; case INTUOSP2_BT: + case INTUOSHT3_BT: sync = wacom_intuos_pro2_bt_irq(wacom_wac, len); break; @@ -3272,6 +3384,12 @@ void wacom_setup_device_quirks(struct wacom *wacom) features->quirks |= WACOM_QUIRK_BATTERY; } + if (features->type == INTUOSHT3_BT) { + features->device_type |= WACOM_DEVICETYPE_PEN | + WACOM_DEVICETYPE_PAD; + features->quirks |= WACOM_QUIRK_BATTERY; + } + switch (features->type) { case PL: case DTU: @@ -3466,7 +3584,9 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case BAMBOO_PT: case BAMBOO_PEN: case INTUOSHT2: - if (features->type == INTUOSHT2) { + case INTUOSHT3_BT: + if (features->type == INTUOSHT2 || + features->type == INTUOSHT3_BT) { wacom_setup_basic_pro_pen(wacom_wac); } else { __clear_bit(ABS_MISC, input_dev->absbit); @@ -3887,6 +4007,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; + case INTUOSHT3_BT: case HID_GENERIC: break; @@ -4415,6 +4536,12 @@ static const struct wacom_features wacom_features_0x360 = static const struct wacom_features wacom_features_0x361 = { "Wacom Intuos Pro L", 62200, 43200, 8191, 63, INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 }; +static const struct wacom_features wacom_features_0x377 = + { "Wacom Intuos BT S", 15200, 9500, 4095, 63, + INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; +static const struct wacom_features wacom_features_0x379 = + { "Wacom Intuos BT M", 21600, 13500, 4095, 63, + INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; static const struct wacom_features wacom_features_0x37A = { "Wacom One by Wacom S", 15200, 9500, 2047, 63, BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -4589,6 +4716,8 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x343) }, { BT_DEVICE_WACOM(0x360) }, { BT_DEVICE_WACOM(0x361) }, + { BT_DEVICE_WACOM(0x377) }, + { BT_DEVICE_WACOM(0x379) }, { USB_DEVICE_WACOM(0x37A) }, { USB_DEVICE_WACOM(0x37B) }, { USB_DEVICE_WACOM(0x4001) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 15d9c14fbdf7..295fd3718caa 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -118,6 +118,7 @@ #define WACOM_HID_WD_TOUCHSTRIP2 (WACOM_HID_UP_WACOMDIGITIZER | 0x0137) #define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138) #define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139) +#define WACOM_HID_WD_REPORT_VALID (WACOM_HID_UP_WACOMDIGITIZER | 0x01d0) #define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401) #define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402) #define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403) @@ -213,6 +214,7 @@ enum { INTUOSPM, INTUOSPL, INTUOSP2_BT, + INTUOSHT3_BT, WACOM_21UX2, WACOM_22HD, DTK, @@ -352,7 +354,7 @@ struct wacom_wac { bool has_mute_touch_switch; bool has_mode_change; bool is_direct_mode; - + bool is_invalid_bt_frame; }; #endif |