diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 20 | ||||
-rw-r--r-- | drivers/hid/Makefile | 2 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 10 | ||||
-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-google-hammer.c | 138 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 18 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 5 | ||||
-rw-r--r-- | drivers/hid/hid-quirks.c | 18 | ||||
-rw-r--r-- | drivers/hid/hid-rmi.c | 4 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 13 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 4 |
14 files changed, 658 insertions, 54 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-core.c b/drivers/hid/hid-core.c index c2560aae5542..4fc08c38bc0e 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; 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-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 43ddcdfbd0da..18933074e59a 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 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 04d01b57d94c..d86398755b0d 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); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3b4739bde05d..2e1736ba2444 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -370,7 +370,8 @@ 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; /* @@ -1183,7 +1184,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; diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 5f6035a5ce36..0176a927070a 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) }, 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/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 0d3ca542e987..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; 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) |