diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 7 | ||||
-rw-r--r-- | drivers/hid/Makefile | 1 | ||||
-rw-r--r-- | drivers/hid/hid-apple.c | 6 | ||||
-rw-r--r-- | drivers/hid/hid-chicony.c | 26 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 27 | ||||
-rw-r--r-- | drivers/hid/hid-cp2112.c | 109 | ||||
-rw-r--r-- | drivers/hid/hid-gembird.c | 116 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 18 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 7 | ||||
-rw-r--r-- | drivers/hid/hid-lenovo.c | 59 | ||||
-rw-r--r-- | drivers/hid/hid-lg.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 15 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_backlight.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_cir.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_lcd.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-rmi.c | 163 | ||||
-rw-r--r-- | drivers/hid/hid-sensor-hub.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-sony.c | 22 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic.c | 2 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 28 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 2 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 6 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 76 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.c | 3 |
24 files changed, 606 insertions, 101 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cc4c6649d195..6ab51ae3c39d 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -251,6 +251,12 @@ config HID_EZKEY ---help--- Support for Ezkey BTC 8193 keyboard. +config HID_GEMBIRD + tristate "Gembird Joypad" + depends on HID + ---help--- + Support for Gembird JPD-DualForce 2. + config HID_HOLTEK tristate "Holtek HID devices" depends on USB_HID @@ -480,6 +486,7 @@ config HID_MULTITOUCH - Atmel panels - Cando dual touch panels - Chunghwa panels + - CJTouch panels - CVTouch panels - Cypress TrueTouch panels - Elan Microelectronics touch panels diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 2f8a41dc3cc8..e6441bc7dae4 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.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_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-apple.c b/drivers/hid/hid-apple.c index f822fd2a1ada..884d82f9190e 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -546,6 +546,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index b613d5a79684..bc3cec199fee 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -20,6 +20,7 @@ #include <linux/input.h> #include <linux/hid.h> #include <linux/module.h> +#include <linux/usb.h> #include "hid-ids.h" @@ -57,10 +58,34 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } +static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + /* Change usage maximum and logical maximum from 0x7fff to + * 0x2fff, so they don't exceed HID_MAX_USAGES */ + switch (hdev->product) { + case USB_DEVICE_ID_CHICONY_ACER_SWITCH12: + if (*rsize >= 128 && rdesc[64] == 0xff && rdesc[65] == 0x7f + && rdesc[69] == 0xff && rdesc[70] == 0x7f) { + hid_info(hdev, "Fixing up report descriptor\n"); + rdesc[65] = rdesc[70] = 0x2f; + } + break; + } + + } + return rdesc; +} + + static const struct hid_device_id ch_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) }, { } }; MODULE_DEVICE_TABLE(hid, ch_devices); @@ -68,6 +93,7 @@ MODULE_DEVICE_TABLE(hid, ch_devices); static struct hid_driver ch_driver = { .name = "chicony", .id_table = ch_devices, + .report_fixup = ch_switch12_report_fixup, .input_mapping = ch_input_mapping, }; module_hid_driver(ch_driver); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 157c62775053..8d9cb755e08a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -427,6 +427,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) { __u32 data; unsigned n; + __u32 count; data = item_udata(item); @@ -490,6 +491,24 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) if (item->size <= 2) data = (parser->global.usage_page << 16) + data; + count = data - parser->local.usage_minimum; + if (count + parser->local.usage_index >= HID_MAX_USAGES) { + /* + * We do not warn if the name is not set, we are + * actually pre-scanning the device. + */ + if (dev_name(&parser->device->dev)) + hid_warn(parser->device, + "ignoring exceeding usage max\n"); + data = HID_MAX_USAGES - parser->local.usage_index + + parser->local.usage_minimum - 1; + if (data <= 0) { + hid_err(parser->device, + "no more usage index available\n"); + return -1; + } + } + for (n = parser->local.usage_minimum; n <= data; n++) if (hid_add_usage(parser, n)) { dbg_hid("hid_add_usage failed\n"); @@ -1782,6 +1801,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, @@ -1804,6 +1826,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, @@ -1820,6 +1843,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, @@ -2463,6 +2487,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 3318de690e00..7afc3fcc122c 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -156,6 +156,7 @@ struct cp2112_device { wait_queue_head_t wait; u8 read_data[61]; u8 read_length; + u8 hwversion; int xfer_status; atomic_t read_avail; atomic_t xfer_avail; @@ -356,6 +357,8 @@ static int cp2112_read(struct cp2112_device *dev, u8 *data, size_t size) struct cp2112_force_read_report report; int ret; + if (size > sizeof(dev->read_data)) + size = sizeof(dev->read_data); report.report = CP2112_DATA_READ_FORCE_SEND; report.length = cpu_to_be16(size); @@ -444,6 +447,24 @@ static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data, return data_length + 3; } +static int cp2112_i2c_write_read_req(void *buf, u8 slave_address, + u8 *addr, int addr_length, + int read_length) +{ + struct cp2112_write_read_req_report *report = buf; + + if (read_length < 1 || read_length > 512 || + addr_length > sizeof(report->target_address)) + return -EINVAL; + + report->report = CP2112_DATA_WRITE_READ_REQUEST; + report->slave_address = slave_address << 1; + report->length = cpu_to_be16(read_length); + report->target_address_length = addr_length; + memcpy(report->target_address, addr, addr_length); + return addr_length + 5; +} + static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { @@ -451,26 +472,46 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, struct hid_device *hdev = dev->hdev; u8 buf[64]; ssize_t count; + ssize_t read_length = 0; + u8 *read_buf = NULL; unsigned int retries; int ret; hid_dbg(hdev, "I2C %d messages\n", num); - if (num != 1) { + if (num == 1) { + if (msgs->flags & I2C_M_RD) { + hid_dbg(hdev, "I2C read %#04x len %d\n", + msgs->addr, msgs->len); + read_length = msgs->len; + read_buf = msgs->buf; + count = cp2112_read_req(buf, msgs->addr, msgs->len); + } else { + hid_dbg(hdev, "I2C write %#04x len %d\n", + msgs->addr, msgs->len); + count = cp2112_i2c_write_req(buf, msgs->addr, + msgs->buf, msgs->len); + } + if (count < 0) + return count; + } else if (dev->hwversion > 1 && /* no repeated start in rev 1 */ + num == 2 && + msgs[0].addr == msgs[1].addr && + !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { + hid_dbg(hdev, "I2C write-read %#04x wlen %d rlen %d\n", + msgs[0].addr, msgs[0].len, msgs[1].len); + read_length = msgs[1].len; + read_buf = msgs[1].buf; + count = cp2112_i2c_write_read_req(buf, msgs[0].addr, + msgs[0].buf, msgs[0].len, msgs[1].len); + if (count < 0) + return count; + } else { hid_err(hdev, "Multi-message I2C transactions not supported\n"); return -EOPNOTSUPP; } - if (msgs->flags & I2C_M_RD) - count = cp2112_read_req(buf, msgs->addr, msgs->len); - else - count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf, - msgs->len); - - if (count < 0) - return count; - ret = hid_hw_power(hdev, PM_HINT_FULLON); if (ret < 0) { hid_err(hdev, "power management error: %d\n", ret); @@ -506,21 +547,34 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto power_normal; } - if (!(msgs->flags & I2C_M_RD)) - goto finish; - - ret = cp2112_read(dev, msgs->buf, msgs->len); - if (ret < 0) - goto power_normal; - if (ret != msgs->len) { - hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len); - ret = -EIO; - goto power_normal; + for (count = 0; count < read_length;) { + ret = cp2112_read(dev, read_buf + count, read_length - count); + if (ret < 0) + goto power_normal; + if (ret == 0) { + hid_err(hdev, "read returned 0\n"); + ret = -EIO; + goto power_normal; + } + count += ret; + if (count > read_length) { + /* + * The hardware returned too much data. + * This is mostly harmless because cp2112_read() + * has a limit check so didn't overrun our + * buffer. Nevertheless, we return an error + * because something is seriously wrong and + * it shouldn't go unnoticed. + */ + hid_err(hdev, "long read: %d > %zd\n", + ret, read_length - count + ret); + ret = -EIO; + goto power_normal; + } } -finish: /* return the number of transferred messages */ - ret = 1; + ret = num; power_normal: hid_hw_power(hdev, PM_HINT_NORMAL); @@ -535,7 +589,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data; struct hid_device *hdev = dev->hdev; u8 buf[64]; - __be16 word; + __le16 word; ssize_t count; size_t read_length = 0; unsigned int retries; @@ -552,7 +606,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, if (I2C_SMBUS_READ == read_write) count = cp2112_read_req(buf, addr, read_length); else - count = cp2112_write_req(buf, addr, data->byte, NULL, + count = cp2112_write_req(buf, addr, command, NULL, 0); break; case I2C_SMBUS_BYTE_DATA: @@ -567,7 +621,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, break; case I2C_SMBUS_WORD_DATA: read_length = 2; - word = cpu_to_be16(data->word); + word = cpu_to_le16(data->word); if (I2C_SMBUS_READ == read_write) count = cp2112_write_read_req(buf, addr, read_length, @@ -580,7 +634,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, size = I2C_SMBUS_WORD_DATA; read_write = I2C_SMBUS_READ; read_length = 2; - word = cpu_to_be16(data->word); + word = cpu_to_le16(data->word); count = cp2112_write_read_req(buf, addr, read_length, command, (u8 *)&word, 2); @@ -673,7 +727,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, data->byte = buf[0]; break; case I2C_SMBUS_WORD_DATA: - data->word = be16_to_cpup((__be16 *)buf); + data->word = le16_to_cpup((__le16 *)buf); break; case I2C_SMBUS_BLOCK_DATA: if (read_length > I2C_SMBUS_BLOCK_MAX) { @@ -1028,6 +1082,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) dev->adap.dev.parent = &hdev->dev; snprintf(dev->adap.name, sizeof(dev->adap.name), "CP2112 SMBus Bridge on hiddev%d", hdev->minor); + dev->hwversion = buf[2]; init_waitqueue_head(&dev->wait); hid_device_io_start(hdev); diff --git a/drivers/hid/hid-gembird.c b/drivers/hid/hid-gembird.c new file mode 100644 index 000000000000..e55e519f311e --- /dev/null +++ b/drivers/hid/hid-gembird.c @@ -0,0 +1,116 @@ +/* + * HID driver for Gembird Joypad, "PC Game Controller" + * + * Copyright (c) 2015 Red Hat, Inc + * Copyright (c) 2015 Benjamin Tissoires + */ + +/* + * 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/device.h> +#include <linux/hid.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GEMBIRD_START_FAULTY_RDESC 8 + +static const __u8 gembird_jpd_faulty_rdesc[] = { + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x05, /* Report Count (5) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x26, 0xff, 0x00, /* Logical Maximum (255) */ + 0x35, 0x00, /* Physical Minimum (0) */ + 0x46, 0xff, 0x00, /* Physical Maximum (255) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x09, 0x32, /* Usage (Z) */ + 0x09, 0x32, /* Usage (Z) */ + 0x09, 0x35, /* Usage (Rz) */ + 0x81, 0x02, /* Input (Data,Var,Abs) */ +}; + +/* + * we fix the report descriptor by: + * - marking the first Z axis as constant (so it is ignored by HID) + * - assign the original second Z to Rx + * - assign the original Rz to Ry + */ +static const __u8 gembird_jpd_fixed_rdesc[] = { + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x02, /* Report Count (2) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x26, 0xff, 0x00, /* Logical Maximum (255) */ + 0x35, 0x00, /* Physical Minimum (0) */ + 0x46, 0xff, 0x00, /* Physical Maximum (255) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x81, 0x02, /* Input (Data,Var,Abs) */ + 0x95, 0x01, /* Report Count (1) */ + 0x09, 0x32, /* Usage (Z) */ + 0x81, 0x01, /* Input (Cnst,Arr,Abs) */ + 0x95, 0x02, /* Report Count (2) */ + 0x09, 0x33, /* Usage (Rx) */ + 0x09, 0x34, /* Usage (Ry) */ + 0x81, 0x02, /* Input (Data,Var,Abs) */ +}; + +static __u8 *gembird_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + __u8 *new_rdesc; + /* delta_size is > 0 */ + size_t delta_size = sizeof(gembird_jpd_fixed_rdesc) - + sizeof(gembird_jpd_faulty_rdesc); + size_t new_size = *rsize + delta_size; + + if (*rsize >= 31 && !memcmp(&rdesc[GEMBIRD_START_FAULTY_RDESC], + gembird_jpd_faulty_rdesc, + sizeof(gembird_jpd_faulty_rdesc))) { + new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL); + if (new_rdesc == NULL) + return rdesc; + + dev_info(&hdev->dev, + "fixing Gembird JPD-DualForce 2 report descriptor.\n"); + + /* start by copying the end of the rdesc */ + memcpy(new_rdesc + delta_size, rdesc, *rsize); + + /* add the correct beginning */ + memcpy(new_rdesc, rdesc, GEMBIRD_START_FAULTY_RDESC); + + /* replace the faulty part with the fixed one */ + memcpy(new_rdesc + GEMBIRD_START_FAULTY_RDESC, + gembird_jpd_fixed_rdesc, + sizeof(gembird_jpd_fixed_rdesc)); + + *rsize = new_size; + rdesc = new_rdesc; + } + + return rdesc; +} + +static const struct hid_device_id gembird_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, + USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) }, + { } +}; +MODULE_DEVICE_TABLE(hid, gembird_devices); + +static struct hid_driver gembird_driver = { + .name = "gembird", + .id_table = gembird_devices, + .report_fixup = gembird_report_fixup, +}; +module_hid_driver(gembird_driver); + +MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); +MODULE_DESCRIPTION("HID Gembird joypad driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d816..814f76fdc7da 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -142,6 +142,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292 +#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272 +#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273 +#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 @@ -230,12 +233,17 @@ #define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053 #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 #define USB_DEVICE_ID_CHICONY_AK1D 0x1125 +#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421 #define USB_VENDOR_ID_CHUNGHWAT 0x2247 #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 #define USB_VENDOR_ID_CIDC 0x1677 +#define USB_VENDOR_ID_CJTOUCH 0x24b8 +#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020 +#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040 + #define USB_VENDOR_ID_CMEDIA 0x0d8c #define USB_DEVICE_ID_CM109 0x000e @@ -355,6 +363,9 @@ #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 +#define USB_VENDOR_ID_GEMBIRD 0x11ff +#define USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2 0x3331 + #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc #define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100 @@ -497,6 +508,9 @@ #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 +#define USB_VENDOR_ID_ITE 0x048d +#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386 + #define USB_VENDOR_ID_JABRA 0x0b0e #define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412 #define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420 @@ -599,6 +613,7 @@ #define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 +#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 @@ -922,7 +937,8 @@ #define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 #define USB_VENDOR_ID_TPV 0x25aa -#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN 0x8883 +#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882 0x8882 +#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883 0x8883 #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 14aebe483219..53aeaf6252c7 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -462,12 +462,15 @@ out: static void hidinput_cleanup_battery(struct hid_device *dev) { + const struct power_supply_desc *psy_desc; + if (!dev->battery) return; + psy_desc = dev->battery->desc; power_supply_unregister(dev->battery); - kfree(dev->battery->desc->name); - kfree(dev->battery->desc); + kfree(psy_desc->name); + kfree(psy_desc); dev->battery = NULL; } #else /* !CONFIG_HID_BATTERY_STRENGTH */ diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 4f59bffd0205..e4bc6cb6d7fa 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd { }; struct lenovo_drvdata_cptkbd { + u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */ bool fn_lock; int sensitivity; }; @@ -146,10 +147,10 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, switch (usage->hid & HID_USAGE) { case 0x0000: - hid_map_usage(hi, usage, bit, max, EV_REL, 0x06); + hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL); return 1; case 0x0001: - hid_map_usage(hi, usage, bit, max, EV_REL, 0x08); + hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL); return 1; default: return -1; @@ -207,9 +208,12 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev) struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); - ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); if (ret) hid_err(hdev, "Fn-lock setting failed: %d\n", ret); + + ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); + if (ret) + hid_err(hdev, "Sensitivity setting failed: %d\n", ret); } static ssize_t attr_fn_lock_show_cptkbd(struct device *dev, @@ -313,6 +317,53 @@ static int lenovo_raw_event(struct hid_device *hdev, return 0; } +static int lenovo_event_cptkbd(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage, __s32 value) +{ + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + + /* "wheel" scroll events */ + if (usage->type == EV_REL && (usage->code == REL_WHEEL || + usage->code == REL_HWHEEL)) { + /* Scroll events disable middle-click event */ + cptkbd_data->middlebutton_state = 2; + return 0; + } + + /* Middle click events */ + if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) { + if (value == 1) { + cptkbd_data->middlebutton_state = 1; + } else if (value == 0) { + if (cptkbd_data->middlebutton_state == 1) { + /* No scrolling inbetween, send middle-click */ + input_event(field->hidinput->input, + EV_KEY, BTN_MIDDLE, 1); + input_sync(field->hidinput->input); + input_event(field->hidinput->input, + EV_KEY, BTN_MIDDLE, 0); + input_sync(field->hidinput->input); + } + cptkbd_data->middlebutton_state = 0; + } + return 1; + } + + return 0; +} + +static int lenovo_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_CUSBKBD: + case USB_DEVICE_ID_LENOVO_CBTKBD: + return lenovo_event_cptkbd(hdev, field, usage, value); + default: + return 0; + } +} + static int lenovo_features_set_tpkbd(struct hid_device *hdev) { struct hid_report *report; @@ -705,6 +756,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) hid_warn(hdev, "Failed to switch middle button: %d\n", ret); /* Set keyboard settings to known state */ + cptkbd_data->middlebutton_state = 0; cptkbd_data->fn_lock = true; cptkbd_data->sensitivity = 0x05; lenovo_features_set_cptkbd(hdev); @@ -832,6 +884,7 @@ static struct hid_driver lenovo_driver = { .probe = lenovo_probe, .remove = lenovo_remove, .raw_event = lenovo_raw_event, + .event = lenovo_event, .report_fixup = lenovo_report_fixup, }; module_hid_driver(lenovo_driver); diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 429340d809b5..5332fb7d072a 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -776,6 +776,8 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL), + .driver_data = LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6a9b05b328a9..426b2f1a3450 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -778,9 +778,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" * for the stylus. + * The check for mt_report_id ensures we don't process + * HID_DG_CONTACTCOUNT from the pen report as it is outside the physical + * collection, but within the report ID. */ if (field->physical == HID_DG_STYLUS) return 0; + else if ((field->physical == 0) && + (field->report->id != td->mt_report_id) && + (td->mt_report_id != -1)) + return 0; if (field->application == HID_DG_TOUCHSCREEN || field->application == HID_DG_TOUCHPAD) @@ -1138,6 +1145,14 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, + /* CJTouch panels */ + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, + USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, + USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, + /* CVTouch panels */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c index a32c5f86b0b3..808807ad388f 100644 --- a/drivers/hid/hid-picolcd_backlight.c +++ b/drivers/hid/hid-picolcd_backlight.c @@ -94,8 +94,7 @@ void picolcd_exit_backlight(struct picolcd_data *data) struct backlight_device *bdev = data->backlight; data->backlight = NULL; - if (bdev) - backlight_device_unregister(bdev); + backlight_device_unregister(bdev); } int picolcd_resume_backlight(struct picolcd_data *data) diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c index 045f8ebf16b5..96286510f42e 100644 --- a/drivers/hid/hid-picolcd_cir.c +++ b/drivers/hid/hid-picolcd_cir.c @@ -145,7 +145,6 @@ void picolcd_exit_cir(struct picolcd_data *data) struct rc_dev *rdev = data->rc_dev; data->rc_dev = NULL; - if (rdev) - rc_unregister_device(rdev); + rc_unregister_device(rdev); } diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c index 89821c2da6d7..22dcbe13da89 100644 --- a/drivers/hid/hid-picolcd_lcd.c +++ b/drivers/hid/hid-picolcd_lcd.c @@ -92,8 +92,7 @@ void picolcd_exit_lcd(struct picolcd_data *data) struct lcd_device *ldev = data->lcd; data->lcd = NULL; - if (ldev) - lcd_device_unregister(ldev); + lcd_device_unregister(ldev); } int picolcd_resume_lcd(struct picolcd_data *data) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 4cf80bb276dc..2c148129beb2 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -33,10 +33,21 @@ #define RMI_READ_DATA_PENDING 1 #define RMI_STARTED 2 +#define RMI_SLEEP_NORMAL 0x0 +#define RMI_SLEEP_DEEP_SLEEP 0x1 + /* device flags */ #define RMI_DEVICE BIT(0) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) +/* + * retrieve the ctrl registers + * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, + * and there is no way to know if the first 20 bytes are here or not. + * We use only the first 12 bytes, so get only them. + */ +#define RMI_F11_CTRL_REG_COUNT 12 + enum rmi_mode_type { RMI_MODE_OFF = 0, RMI_MODE_ATTN_REPORTS = 1, @@ -113,6 +124,8 @@ struct rmi_data { unsigned int max_y; unsigned int x_size_mm; unsigned int y_size_mm; + bool read_f11_ctrl_regs; + u8 f11_ctrl_regs[RMI_F11_CTRL_REG_COUNT]; unsigned int gpio_led_count; unsigned int button_count; @@ -126,6 +139,10 @@ struct rmi_data { unsigned long device_flags; unsigned long firmware_id; + + u8 f01_ctrl0; + u8 interrupt_enable_mask; + bool restore_interrupt_mask; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -346,13 +363,34 @@ static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, } } +static int rmi_reset_attn_mode(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret) + return ret; + + if (data->restore_interrupt_mask) { + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write F01 control register\n"); + return ret; + } + } + + return 0; +} + static void rmi_reset_work(struct work_struct *work) { struct rmi_data *hdata = container_of(work, struct rmi_data, reset_work); /* switch the device to RMI if we receive a generic mouse report */ - rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS); + rmi_reset_attn_mode(hdata->hdev); } static inline int rmi_schedule_reset(struct hid_device *hdev) @@ -532,14 +570,77 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, } #ifdef CONFIG_PM +static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + u8 f01_ctrl0; + + f01_ctrl0 = (data->f01_ctrl0 & ~0x3) | sleep_mode; + + ret = rmi_write(hdev, data->f01.control_base_addr, + &f01_ctrl0); + if (ret) { + hid_err(hdev, "can not write sleep mode\n"); + return ret; + } + + return 0; +} + +static int rmi_suspend(struct hid_device *hdev, pm_message_t message) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + u8 buf[RMI_F11_CTRL_REG_COUNT]; + + ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, + RMI_F11_CTRL_REG_COUNT); + if (ret) + hid_warn(hdev, "can not read F11 control registers\n"); + else + memcpy(data->f11_ctrl_regs, buf, RMI_F11_CTRL_REG_COUNT); + + + if (!device_may_wakeup(hdev->dev.parent)) + return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP); + + return 0; +} + static int rmi_post_reset(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + + ret = rmi_reset_attn_mode(hdev); + if (ret) { + hid_err(hdev, "can not set rmi mode\n"); + return ret; + } + + if (data->read_f11_ctrl_regs) { + ret = rmi_write_block(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); + if (ret) + hid_warn(hdev, + "can not write F11 control registers after reset\n"); + } + + if (!device_may_wakeup(hdev->dev.parent)) { + ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL); + if (ret) { + hid_err(hdev, "can not write sleep mode\n"); + return ret; + } + } + + return ret; } static int rmi_post_resume(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + return rmi_reset_attn_mode(hdev); } #endif /* CONFIG_PM */ @@ -595,6 +696,7 @@ static void rmi_register_function(struct rmi_data *data, f->interrupt_count = pdt_entry->interrupt_source_count; f->irq_mask = rmi_gen_mask(f->interrupt_base, f->interrupt_count); + data->interrupt_enable_mask |= f->irq_mask; } } @@ -732,6 +834,35 @@ static int rmi_populate_f01(struct hid_device *hdev) data->firmware_id += info[2] * 65536; } + ret = rmi_read_block(hdev, data->f01.control_base_addr, info, + 2); + + if (ret) { + hid_err(hdev, "can not read f01 ctrl registers\n"); + return ret; + } + + data->f01_ctrl0 = info[0]; + + if (!info[1]) { + /* + * Do to a firmware bug in some touchpads the F01 interrupt + * enable control register will be cleared on reset. + * This will stop the touchpad from reporting data, so + * if F01 CTRL1 is 0 then we need to explicitly enable + * interrupts for the functions we want data for. + */ + data->restore_interrupt_mask = true; + + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write to control reg 1: %d.\n", + ret); + return ret; + } + } + return 0; } @@ -904,24 +1035,23 @@ static int rmi_populate_f11(struct hid_device *hdev) if (has_data40) data->f11.report_size += data->max_fingers * 2; - /* - * retrieve the ctrl registers - * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, - * and there is no way to know if the first 20 bytes are here or not. - * We use only the first 12 bytes, so get only them. - */ - ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12); + ret = rmi_read_block(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); if (ret) { hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret); return ret; } - data->max_x = buf[6] | (buf[7] << 8); - data->max_y = buf[8] | (buf[9] << 8); + /* data->f11_ctrl_regs now contains valid register data */ + data->read_f11_ctrl_regs = true; + + data->max_x = data->f11_ctrl_regs[6] | (data->f11_ctrl_regs[7] << 8); + data->max_y = data->f11_ctrl_regs[8] | (data->f11_ctrl_regs[9] << 8); if (has_dribble) { - buf[0] = buf[0] & ~BIT(6); - ret = rmi_write(hdev, data->f11.control_base_addr, buf); + data->f11_ctrl_regs[0] = data->f11_ctrl_regs[0] & ~BIT(6); + ret = rmi_write(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs); if (ret) { hid_err(hdev, "can not write to control reg 0: %d.\n", ret); @@ -930,9 +1060,9 @@ static int rmi_populate_f11(struct hid_device *hdev) } if (has_palm_detect) { - buf[11] = buf[11] & ~BIT(0); + data->f11_ctrl_regs[11] = data->f11_ctrl_regs[11] & ~BIT(0); ret = rmi_write(hdev, data->f11.control_base_addr + 11, - &buf[11]); + &data->f11_ctrl_regs[11]); if (ret) { hid_err(hdev, "can not write to control reg 11: %d.\n", ret); @@ -1273,6 +1403,7 @@ static struct hid_driver rmi_driver = { .input_mapping = rmi_input_mapping, .input_configured = rmi_input_configured, #ifdef CONFIG_PM + .suspend = rmi_suspend, .resume = rmi_post_resume, .reset_resume = rmi_post_reset, #endif diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 090a1ba0abb6..a76eb2a0a987 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -774,6 +774,9 @@ static const struct hid_device_id sensor_hub_devices[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS, USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA), .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE, + USB_DEVICE_ID_ITE_LENOVO_YOGA), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, { } diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ed2f008f8403..661f94f8ab8b 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -296,7 +296,14 @@ static __u8 navigation_rdesc[] = { 0x09, 0x01, /* Usage (Pointer), */ 0x81, 0x02, /* Input (Variable), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x95, 0x20, /* Report Count (26), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x95, 0x01, /* Report Count (1), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x1E, /* Report Count (24), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x30, /* Report Count (48), */ @@ -1270,6 +1277,17 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, * has to be BYTE_SWAPPED before passing up to joystick interface */ if ((sc->quirks & SIXAXIS_CONTROLLER) && rd[0] == 0x01 && size == 49) { + /* + * When connected via Bluetooth the Sixaxis occasionally sends + * a report with the second byte 0xff and the rest zeroed. + * + * This report does not reflect the actual state of the + * controller must be ignored to avoid generating false input + * events. + */ + if (rd[1] == 0xff) + return -EINVAL; + swap(rd[41], rd[42]); swap(rd[43], rd[44]); swap(rd[45], rd[46]); @@ -1836,7 +1854,7 @@ static void dualshock4_state_worker(struct work_struct *work) } else { memset(buf, 0, DS4_REPORT_0x11_SIZE); buf[0] = 0x11; - buf[1] = 0xB0; + buf[1] = 0x80; buf[3] = 0x0F; offset = 6; } diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index 94167310e15a..b905d501e752 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -858,7 +858,7 @@ static int uclogic_tablet_enable(struct hid_device *hdev) for (p = drvdata->rdesc; p <= drvdata->rdesc + drvdata->rsize - 4;) { if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D && - p[3] < sizeof(params)) { + p[3] < ARRAY_SIZE(params)) { v = params[p[3]]; put_unaligned(cpu_to_le32(v), (s32 *)p); p += 4; diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index f77469d4edfb..2871f3c81a4c 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -149,6 +149,8 @@ struct i2c_hid { int irq; struct i2c_hid_platform_data pdata; + + bool irq_wake_enabled; }; static int __i2c_hid_command(struct i2c_client *client, @@ -1091,14 +1093,21 @@ static int i2c_hid_suspend(struct device *dev) struct i2c_hid *ihid = i2c_get_clientdata(client); struct hid_device *hid = ihid->hid; int ret = 0; - - disable_irq(ihid->irq); - if (device_may_wakeup(&client->dev)) - enable_irq_wake(ihid->irq); + int wake_status; if (hid->driver && hid->driver->suspend) ret = hid->driver->suspend(hid, PMSG_SUSPEND); + disable_irq(ihid->irq); + if (device_may_wakeup(&client->dev)) { + wake_status = enable_irq_wake(ihid->irq); + if (!wake_status) + ihid->irq_wake_enabled = true; + else + hid_warn(hid, "Failed to enable irq wake: %d\n", + wake_status); + } + /* Save some power */ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); @@ -1111,14 +1120,21 @@ static int i2c_hid_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct i2c_hid *ihid = i2c_get_clientdata(client); struct hid_device *hid = ihid->hid; + int wake_status; enable_irq(ihid->irq); ret = i2c_hid_hwreset(client); if (ret) return ret; - if (device_may_wakeup(&client->dev)) - disable_irq_wake(ihid->irq); + if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) { + wake_status = disable_irq_wake(ihid->irq); + if (!wake_status) + ihid->irq_wake_enabled = false; + else + hid_warn(hid, "Failed to disable irq wake: %d\n", + wake_status); + } if (hid->driver && hid->driver->reset_resume) { ret = hid->driver->reset_resume(hid); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 1a23d78fe5e7..36712e9f56c2 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -164,7 +164,7 @@ static void hid_io_error(struct hid_device *hid) if (time_after(jiffies, usbhid->stop_retry)) { /* Retries failed, so do a port reset unless we lack bandwidth*/ - if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) + if (!test_bit(HID_NO_BANDWIDTH, &usbhid->iofl) && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { schedule_work(&usbhid->reset_work); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 53e7de7cb9e2..965432e413c6 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -87,6 +87,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, @@ -114,7 +117,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 5f6e48e55df9..9a4912c1828d 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1447,17 +1447,52 @@ fail_leds: pad_input_dev = NULL; wacom_wac->pad_registered = false; fail_register_pad_input: - input_unregister_device(touch_input_dev); + if (touch_input_dev) + input_unregister_device(touch_input_dev); wacom_wac->touch_input = NULL; wacom_wac->touch_registered = false; fail_register_touch_input: - input_unregister_device(pen_input_dev); + if (pen_input_dev) + input_unregister_device(pen_input_dev); wacom_wac->pen_input = NULL; wacom_wac->pen_registered = false; fail_register_pen_input: return error; } +/* + * Not all devices report physical dimensions from HID. + * Compute the default from hardcoded logical dimension + * and resolution before driver overwrites them. + */ +static void wacom_set_default_phy(struct wacom_features *features) +{ + if (features->x_resolution) { + features->x_phy = (features->x_max * 100) / + features->x_resolution; + features->y_phy = (features->y_max * 100) / + features->y_resolution; + } +} + +static void wacom_calculate_res(struct wacom_features *features) +{ + /* set unit to "100th of a mm" for devices not reported by HID */ + if (!features->unit) { + features->unit = 0x11; + features->unitExpo = -3; + } + + features->x_resolution = wacom_calc_hid_res(features->x_max, + features->x_phy, + features->unit, + features->unitExpo); + features->y_resolution = wacom_calc_hid_res(features->y_max, + features->y_phy, + features->unit, + features->unitExpo); +} + static void wacom_wireless_work(struct work_struct *work) { struct wacom *wacom = container_of(work, struct wacom, work); @@ -1515,6 +1550,8 @@ static void wacom_wireless_work(struct work_struct *work) if (wacom_wac1->features.type != INTUOSHT && wacom_wac1->features.type != BAMBOO_PT) wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD; + wacom_set_default_phy(&wacom_wac1->features); + wacom_calculate_res(&wacom_wac1->features); snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen", wacom_wac1->features.name); snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad", @@ -1533,7 +1570,9 @@ static void wacom_wireless_work(struct work_struct *work) wacom_wac2->features = *((struct wacom_features *)id->driver_data); wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; + wacom_set_default_phy(&wacom_wac2->features); wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; + wacom_calculate_res(&wacom_wac2->features); snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX, "%s (WL) Finger",wacom_wac2->features.name); snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX, @@ -1581,39 +1620,6 @@ void wacom_battery_work(struct work_struct *work) } } -/* - * Not all devices report physical dimensions from HID. - * Compute the default from hardcoded logical dimension - * and resolution before driver overwrites them. - */ -static void wacom_set_default_phy(struct wacom_features *features) -{ - if (features->x_resolution) { - features->x_phy = (features->x_max * 100) / - features->x_resolution; - features->y_phy = (features->y_max * 100) / - features->y_resolution; - } -} - -static void wacom_calculate_res(struct wacom_features *features) -{ - /* set unit to "100th of a mm" for devices not reported by HID */ - if (!features->unit) { - features->unit = 0x11; - features->unitExpo = -3; - } - - features->x_resolution = wacom_calc_hid_res(features->x_max, - features->x_phy, - features->unit, - features->unitExpo); - features->y_resolution = wacom_calc_hid_res(features->y_max, - features->y_phy, - features->unit, - features->unitExpo); -} - static size_t wacom_compute_pktlen(struct hid_device *hdev) { struct hid_report_enum *report_enum; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index c40a6d14c8f2..0215ab62bb93 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2417,6 +2417,9 @@ void wacom_setup_device_quirks(struct wacom *wacom) features->x_max = 4096; features->y_max = 4096; } + else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) { + features->device_type |= WACOM_DEVICETYPE_PAD; + } } /* |