summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig20
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-corsair.c24
-rw-r--r--drivers/hid/hid-elan.c421
-rw-r--r--drivers/hid/hid-elecom.c32
-rw-r--r--drivers/hid/hid-google-hammer.c138
-rw-r--r--drivers/hid/hid-ids.h18
-rw-r--r--drivers/hid/hid-input.c3
-rw-r--r--drivers/hid/hid-multitouch.c5
-rw-r--r--drivers/hid/hid-quirks.c18
-rw-r--r--drivers/hid/hid-rmi.c4
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c13
-rw-r--r--drivers/hid/wacom_sys.c4
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)