diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-11-03 23:45:16 +0100 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-11-03 23:45:16 +0100 |
commit | 84a73014d86fd660822a20c032625e3afe99ca58 (patch) | |
tree | 9e42a2d3c40730947ae18363d00e8a0ee2743792 /drivers/hid | |
parent | Input: alps - only the Dell Latitude D420/430/620/630 have separate stick but... (diff) | |
parent | Input: evdev - fix bug in checking duplicate clock change request (diff) | |
download | linux-84a73014d86fd660822a20c032625e3afe99ca58.tar.xz linux-84a73014d86fd660822a20c032625e3afe99ca58.zip |
Merge branch 'next' into for-linus
Prepare first round of input updates for 4.3 merge window.
Diffstat (limited to 'drivers/hid')
27 files changed, 1352 insertions, 346 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cc4c6649d195..7245b7f8767f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -251,6 +251,18 @@ 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_GFRM + tristate "Google Fiber TV Box remote control support" + depends on HID + ---help--- + Support for Google Fiber TV Box remote controls + config HID_HOLTEK tristate "Holtek HID devices" depends on USB_HID @@ -480,6 +492,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..571d176d22df 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -36,6 +36,8 @@ 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_GFRM) += hid-gfrm.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-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 1d19ce220755..70a11ac38119 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"); @@ -705,8 +724,9 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP || + (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -1807,6 +1827,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) }, @@ -1823,6 +1844,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) }, @@ -1905,8 +1927,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, 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-gfrm.c b/drivers/hid/hid-gfrm.c new file mode 100644 index 000000000000..4d7b7e7f0792 --- /dev/null +++ b/drivers/hid/hid-gfrm.c @@ -0,0 +1,158 @@ +/* + * HID driver for Google Fiber TV Box remote controls + * + * Copyright (c) 2014-2015 Google Inc. + * + * Author: Petri Gynther <pgynther@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/device.h> +#include <linux/hid.h> +#include <linux/input.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GFRM100 1 /* Google Fiber GFRM100 (Bluetooth classic) */ +#define GFRM200 2 /* Google Fiber GFRM200 (Bluetooth LE) */ + +#define GFRM100_SEARCH_KEY_REPORT_ID 0xF7 +#define GFRM100_SEARCH_KEY_DOWN 0x0 +#define GFRM100_SEARCH_KEY_AUDIO_DATA 0x1 +#define GFRM100_SEARCH_KEY_UP 0x2 + +static u8 search_key_dn[3] = {0x40, 0x21, 0x02}; +static u8 search_key_up[3] = {0x40, 0x00, 0x00}; + +static int gfrm_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev); + + if (hdev_type == GFRM100) { + if (usage->hid == (HID_UP_CONSUMER | 0x4)) { + /* Consumer.0004 -> KEY_INFO */ + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_INFO); + return 1; + } + + if (usage->hid == (HID_UP_CONSUMER | 0x41)) { + /* Consumer.0041 -> KEY_OK */ + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_OK); + return 1; + } + } + + return 0; +} + +static int gfrm_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + unsigned long hdev_type = (unsigned long) hid_get_drvdata(hdev); + int ret = 0; + + if (hdev_type != GFRM100) + return 0; + + if (size < 2 || data[0] != GFRM100_SEARCH_KEY_REPORT_ID) + return 0; + + /* + * Convert GFRM100 Search key reports into Consumer.0221 (Key.Search) + * reports. Ignore audio data. + */ + switch (data[1]) { + case GFRM100_SEARCH_KEY_DOWN: + ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_dn, + sizeof(search_key_dn), 1); + break; + + case GFRM100_SEARCH_KEY_AUDIO_DATA: + break; + + case GFRM100_SEARCH_KEY_UP: + ret = hid_report_raw_event(hdev, HID_INPUT_REPORT, search_key_up, + sizeof(search_key_up), 1); + break; + + default: + break; + } + + return (ret < 0) ? ret : -1; +} + +static void gfrm_input_configured(struct hid_device *hid, struct hid_input *hidinput) +{ + /* + * Enable software autorepeat with: + * - repeat delay: 400 msec + * - repeat period: 100 msec + */ + input_enable_softrepeat(hidinput->input, 400, 100); +} + +static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + hid_set_drvdata(hdev, (void *) id->driver_data); + + ret = hid_parse(hdev); + if (ret) + goto done; + + if (id->driver_data == GFRM100) { + /* + * GFRM100 HID Report Descriptor does not describe the Search + * key reports. Thus, we need to add it manually here, so that + * those reports reach gfrm_raw_event() from hid_input_report(). + */ + if (!hid_register_report(hdev, HID_INPUT_REPORT, + GFRM100_SEARCH_KEY_REPORT_ID)) { + ret = -ENOMEM; + goto done; + } + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +done: + return ret; +} + +static void gfrm_remove(struct hid_device *hdev) +{ + hid_hw_stop(hdev); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id gfrm_devices[] = { + { HID_BLUETOOTH_DEVICE(0x58, 0x2000), + .driver_data = GFRM100 }, + { HID_BLUETOOTH_DEVICE(0x471, 0x2210), + .driver_data = GFRM200 }, + { } +}; +MODULE_DEVICE_TABLE(hid, gfrm_devices); + +static struct hid_driver gfrm_driver = { + .name = "gfrm", + .id_table = gfrm_devices, + .probe = gfrm_probe, + .remove = gfrm_remove, + .input_mapping = gfrm_input_mapping, + .raw_event = gfrm_raw_event, + .input_configured = gfrm_input_configured, +}; + +module_hid_driver(gfrm_driver); + +MODULE_AUTHOR("Petri Gynther <pgynther@google.com>"); +MODULE_DESCRIPTION("Google Fiber TV Box remote control driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b3b225b75d0a..f769208276ae 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -233,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 @@ -358,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 @@ -500,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 @@ -602,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 @@ -666,8 +678,9 @@ #define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 -#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc -#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd +#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc +#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd +#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de #define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 @@ -925,7 +938,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 3511bbaba505..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 */ @@ -1163,8 +1166,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct input_event(input, usage->type, usage->code, value); - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && + usage->type == EV_KEY && value) { + input_sync(input); input_event(input, usage->type, usage->code, 0); + } } void hidinput_report_event(struct hid_device *hid, struct hid_report *report) 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-microsoft.c b/drivers/hid/hid-microsoft.c index 32a596f554af..9aa3515090a7 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -276,9 +276,11 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), .driver_data = MS_HIDINPUT }, 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 bfbe1bedda7f..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); @@ -710,7 +710,8 @@ int usbhid_open(struct hid_device *hid) * Wait 50 msec for the queue to empty before allowing events * to go through hid. */ - msleep(50); + if (res == 0 && !(hid->quirks & HID_QUIRK_ALWAYS_POLL)) + msleep(50); clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); } done: diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 53e7de7cb9e2..1dff8f0015ba 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -87,8 +87,12 @@ 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_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, 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 }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, @@ -114,7 +118,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.h b/drivers/hid/wacom.h index a533787a6d85..4681a65a4579 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -113,7 +113,7 @@ struct wacom { struct mutex lock; struct work_struct work; struct wacom_led { - u8 select[2]; /* status led selector (0..3) */ + u8 select[5]; /* status led selector (0..3) */ u8 llv; /* status led brightness no button (1..127) */ u8 hlv; /* status led brightness button pressed (1..127) */ u8 img_lum; /* OLED matrix display brightness */ @@ -123,6 +123,8 @@ struct wacom { struct power_supply *ac; struct power_supply_desc battery_desc; struct power_supply_desc ac_desc; + struct kobject *remote_dir; + struct attribute_group remote_group[5]; }; static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) @@ -147,4 +149,7 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value); void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); void wacom_battery_work(struct work_struct *work); +int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, + int index); +void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 4c0ffca97bef..9a4912c1828d 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -23,9 +23,13 @@ #define WAC_CMD_ICON_XFER 0x23 #define WAC_CMD_ICON_BT_XFER 0x26 #define WAC_CMD_RETRIES 10 +#define WAC_CMD_DELETE_PAIRING 0x20 +#define WAC_CMD_UNPAIR_ALL 0xFF +#define WAC_REMOTE_SERIAL_MAX_STRLEN 9 #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP) #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP) +#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP) static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, size_t size, unsigned int retries) @@ -335,7 +339,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, int report_id, if (error >= 0) error = wacom_get_report(hdev, HID_FEATURE_REPORT, rep_data, length, 1); - } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); + } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); kfree(rep_data); @@ -453,12 +457,11 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, * interface number. */ if (features->type == WIRELESS) { - if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { + if (intf->cur_altsetting->desc.bInterfaceNumber == 0) + features->device_type = WACOM_DEVICETYPE_WL_MONITOR; + else features->device_type = WACOM_DEVICETYPE_NONE; - } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) { - features->device_type |= WACOM_DEVICETYPE_TOUCH; - features->pktlen = WACOM_PKGLEN_BBTOUCH3; - } + return; } wacom_parse_hid(hdev, features); @@ -1120,6 +1123,189 @@ static ssize_t wacom_store_speed(struct device *dev, static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM, wacom_show_speed, wacom_store_speed); + +static ssize_t wacom_show_remote_mode(struct kobject *kobj, + struct kobj_attribute *kattr, + char *buf, int index) +{ + struct device *dev = container_of(kobj->parent, struct device, kobj); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct wacom *wacom = hid_get_drvdata(hdev); + u8 mode; + + mode = wacom->led.select[index]; + if (mode >= 0 && mode < 3) + return snprintf(buf, PAGE_SIZE, "%d\n", mode); + else + return snprintf(buf, PAGE_SIZE, "%d\n", -1); +} + +#define DEVICE_EKR_ATTR_GROUP(SET_ID) \ +static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj, \ + struct kobj_attribute *kattr, char *buf) \ +{ \ + return wacom_show_remote_mode(kobj, kattr, buf, SET_ID); \ +} \ +static struct kobj_attribute remote##SET_ID##_mode_attr = { \ + .attr = {.name = "remote_mode", \ + .mode = DEV_ATTR_RO_PERM}, \ + .show = wacom_show_remote##SET_ID##_mode, \ +}; \ +static struct attribute *remote##SET_ID##_serial_attrs[] = { \ + &remote##SET_ID##_mode_attr.attr, \ + NULL \ +}; \ +static struct attribute_group remote##SET_ID##_serial_group = { \ + .name = NULL, \ + .attrs = remote##SET_ID##_serial_attrs, \ +} + +DEVICE_EKR_ATTR_GROUP(0); +DEVICE_EKR_ATTR_GROUP(1); +DEVICE_EKR_ATTR_GROUP(2); +DEVICE_EKR_ATTR_GROUP(3); +DEVICE_EKR_ATTR_GROUP(4); + +int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index) +{ + int error = 0; + char *buf; + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + + wacom_wac->serial[index] = serial; + + buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; + snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial); + wacom->remote_group[index].name = buf; + + error = sysfs_create_group(wacom->remote_dir, + &wacom->remote_group[index]); + if (error) { + hid_err(wacom->hdev, + "cannot create sysfs group err: %d\n", error); + kobject_put(wacom->remote_dir); + return error; + } + + return 0; +} + +void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial) +{ + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + int i; + + if (!serial) + return; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + if (wacom_wac->serial[i] == serial) { + wacom_wac->serial[i] = 0; + wacom->led.select[i] = WACOM_STATUS_UNKNOWN; + if (wacom->remote_group[i].name) { + sysfs_remove_group(wacom->remote_dir, + &wacom->remote_group[i]); + kfree(wacom->remote_group[i].name); + wacom->remote_group[i].name = NULL; + } + } + } +} + +static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector) +{ + const size_t buf_size = 2; + unsigned char *buf; + int retval; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = WAC_CMD_DELETE_PAIRING; + buf[1] = selector; + + retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf, + buf_size, WAC_CMD_RETRIES); + kfree(buf); + + return retval; +} + +static ssize_t wacom_store_unpair_remote(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned char selector = 0; + struct device *dev = container_of(kobj->parent, struct device, kobj); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct wacom *wacom = hid_get_drvdata(hdev); + int err; + + if (!strncmp(buf, "*\n", 2)) { + selector = WAC_CMD_UNPAIR_ALL; + } else { + hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n", + buf); + return -1; + } + + mutex_lock(&wacom->lock); + + err = wacom_cmd_unpair_remote(wacom, selector); + mutex_unlock(&wacom->lock); + + return err < 0 ? err : count; +} + +static struct kobj_attribute unpair_remote_attr = { + .attr = {.name = "unpair_remote", .mode = 0200}, + .store = wacom_store_unpair_remote, +}; + +static const struct attribute *remote_unpair_attrs[] = { + &unpair_remote_attr.attr, + NULL +}; + +static int wacom_initialize_remote(struct wacom *wacom) +{ + int error = 0; + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + int i; + + if (wacom->wacom_wac.features.type != REMOTE) + return 0; + + wacom->remote_group[0] = remote0_serial_group; + wacom->remote_group[1] = remote1_serial_group; + wacom->remote_group[2] = remote2_serial_group; + wacom->remote_group[3] = remote3_serial_group; + wacom->remote_group[4] = remote4_serial_group; + + wacom->remote_dir = kobject_create_and_add("wacom_remote", + &wacom->hdev->dev.kobj); + if (!wacom->remote_dir) + return -ENOMEM; + + error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs); + + if (error) { + hid_err(wacom->hdev, + "cannot create sysfs group err: %d\n", error); + return error; + } + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + wacom->led.select[i] = WACOM_STATUS_UNKNOWN; + wacom_wac->serial[i] = 0; + } + + return 0; +} + static struct input_dev *wacom_allocate_input(struct wacom *wacom) { struct input_dev *input_dev; @@ -1130,7 +1316,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) if (!input_dev) return NULL; - input_dev->name = wacom_wac->pen_name; + input_dev->name = wacom_wac->features.name; input_dev->phys = hdev->phys; input_dev->dev.parent = &hdev->dev; input_dev->open = wacom_open; @@ -1145,43 +1331,6 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) return input_dev; } -static void wacom_free_inputs(struct wacom *wacom) -{ - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - if (wacom_wac->pen_input) - input_free_device(wacom_wac->pen_input); - if (wacom_wac->touch_input) - input_free_device(wacom_wac->touch_input); - if (wacom_wac->pad_input) - input_free_device(wacom_wac->pad_input); - wacom_wac->pen_input = NULL; - wacom_wac->touch_input = NULL; - wacom_wac->pad_input = NULL; -} - -static int wacom_allocate_inputs(struct wacom *wacom) -{ - struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - pen_input_dev = wacom_allocate_input(wacom); - touch_input_dev = wacom_allocate_input(wacom); - pad_input_dev = wacom_allocate_input(wacom); - if (!pen_input_dev || !touch_input_dev || !pad_input_dev) { - wacom_free_inputs(wacom); - return -ENOMEM; - } - - wacom_wac->pen_input = pen_input_dev; - wacom_wac->touch_input = touch_input_dev; - wacom_wac->touch_input->name = wacom_wac->touch_name; - wacom_wac->pad_input = pad_input_dev; - wacom_wac->pad_input->name = wacom_wac->pad_name; - - return 0; -} - static void wacom_clean_inputs(struct wacom *wacom) { if (wacom->wacom_wac.pen_input) { @@ -1202,12 +1351,33 @@ static void wacom_clean_inputs(struct wacom *wacom) else input_free_device(wacom->wacom_wac.pad_input); } + if (wacom->remote_dir) + kobject_put(wacom->remote_dir); wacom->wacom_wac.pen_input = NULL; wacom->wacom_wac.touch_input = NULL; wacom->wacom_wac.pad_input = NULL; wacom_destroy_leds(wacom); } +static int wacom_allocate_inputs(struct wacom *wacom) +{ + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + + wacom_wac->pen_input = wacom_allocate_input(wacom); + wacom_wac->touch_input = wacom_allocate_input(wacom); + wacom_wac->pad_input = wacom_allocate_input(wacom); + if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) { + wacom_clean_inputs(wacom); + return -ENOMEM; + } + + wacom_wac->pen_input->name = wacom_wac->pen_name; + wacom_wac->touch_input->name = wacom_wac->touch_name; + wacom_wac->pad_input->name = wacom_wac->pad_name; + + return 0; +} + static int wacom_register_inputs(struct wacom *wacom) { struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; @@ -1262,26 +1432,67 @@ static int wacom_register_inputs(struct wacom *wacom) error = wacom_initialize_leds(wacom); if (error) goto fail_leds; + + error = wacom_initialize_remote(wacom); + if (error) + goto fail_remote; } return 0; +fail_remote: + wacom_destroy_leds(wacom); fail_leds: input_unregister_device(pad_input_dev); 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); @@ -1339,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", @@ -1357,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, @@ -1405,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; @@ -1550,11 +1732,9 @@ static int wacom_probe(struct hid_device *hdev, mutex_init(&wacom->lock); INIT_WORK(&wacom->work, wacom_wireless_work); - if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) { - error = wacom_allocate_inputs(wacom); - if (error) - goto fail_allocate_inputs; - } + error = wacom_allocate_inputs(wacom); + if (error) + goto fail_allocate_inputs; /* * Bamboo Pad has a generic hid handling for the Pen, and we switch it @@ -1600,18 +1780,16 @@ static int wacom_probe(struct hid_device *hdev, if (error) goto fail_shared_data; - if (!(features->quirks & WACOM_QUIRK_MONITOR) && + if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) && (features->quirks & WACOM_QUIRK_BATTERY)) { error = wacom_initialize_battery(wacom); if (error) goto fail_battery; } - if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) { - error = wacom_register_inputs(wacom); - if (error) - goto fail_register_inputs; - } + error = wacom_register_inputs(wacom); + if (error) + goto fail_register_inputs; if (hdev->bus == BUS_BLUETOOTH) { error = device_create_file(&hdev->dev, &dev_attr_speed); @@ -1634,7 +1812,7 @@ static int wacom_probe(struct hid_device *hdev, /* Note that if query fails it is not a hard failure */ wacom_query_tablet_data(hdev, features); - if (features->quirks & WACOM_QUIRK_MONITOR) + if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) error = hid_hw_open(hdev); if (wacom_wac->features.type == INTUOSHT && @@ -1708,7 +1886,6 @@ static struct hid_driver wacom_driver = { .id_table = wacom_ids, .probe = wacom_probe, .remove = wacom_remove, - .event = wacom_wac_event, .report = wacom_wac_report, #ifdef CONFIG_PM .resume = wacom_resume, diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 232da89f4e88..0215ab62bb93 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -125,61 +125,47 @@ static int wacom_pl_irq(struct wacom_wac *wacom) prox = data[1] & 0x40; - if (prox) { - wacom->id[0] = ERASER_DEVICE_ID; - pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); - if (features->pressure_max > 255) - pressure = (pressure << 1) | ((data[4] >> 6) & 1); - pressure += (features->pressure_max + 1) / 2; - - /* - * if going from out of proximity into proximity select between the eraser - * and the pen based on the state of the stylus2 button, choose eraser if - * pressed else choose pen. if not a proximity change from out to in, send - * an out of proximity for previous tool then a in for new tool. - */ - if (!wacom->tool[0]) { - /* Eraser bit set for DTF */ - if (data[1] & 0x10) - wacom->tool[1] = BTN_TOOL_RUBBER; - else - /* Going into proximity select tool */ - wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - } else { - /* was entered with stylus2 pressed */ - if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { - /* report out proximity for previous tool */ - input_report_key(input, wacom->tool[1], 0); - input_sync(input); - wacom->tool[1] = BTN_TOOL_PEN; - return 0; - } + if (!wacom->id[0]) { + if ((data[0] & 0x10) || (data[4] & 0x20)) { + wacom->tool[0] = BTN_TOOL_RUBBER; + wacom->id[0] = ERASER_DEVICE_ID; } - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; + else { + wacom->tool[0] = BTN_TOOL_PEN; wacom->id[0] = STYLUS_DEVICE_ID; } - input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */ - input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ - input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); - input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); - input_report_abs(input, ABS_PRESSURE, pressure); + } - input_report_key(input, BTN_TOUCH, data[4] & 0x08); - input_report_key(input, BTN_STYLUS, data[4] & 0x10); - /* Only allow the stylus2 button to be reported for the pen tool. */ - input_report_key(input, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); - } else { - /* report proximity-out of a (valid) tool */ - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; - } - input_report_key(input, wacom->tool[1], prox); + /* If the eraser is in prox, STYLUS2 is always set. If we + * mis-detected the type and notice that STYLUS2 isn't set + * then force the eraser out of prox and let the pen in. + */ + if (wacom->tool[0] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { + input_report_key(input, BTN_TOOL_RUBBER, 0); + input_report_abs(input, ABS_MISC, 0); + input_sync(input); + wacom->tool[0] = BTN_TOOL_PEN; + wacom->id[0] = STYLUS_DEVICE_ID; } - wacom->tool[0] = prox; /* Save proximity state */ + pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); + if (features->pressure_max > 255) + pressure = (pressure << 1) | ((data[4] >> 6) & 1); + pressure += (features->pressure_max + 1) / 2; + + input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); + input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); + input_report_abs(input, ABS_PRESSURE, pressure); + + input_report_key(input, BTN_TOUCH, data[4] & 0x08); + input_report_key(input, BTN_STYLUS, data[4] & 0x10); + /* Only allow the stylus2 button to be reported for the pen tool. */ + input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20)); + + if (!prox) + wacom->id[0] = 0; + input_report_key(input, wacom->tool[0], prox); + input_report_abs(input, ABS_MISC, wacom->id[0]); return 1; } @@ -645,6 +631,130 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 0; } +static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len) +{ + unsigned char *data = wacom_wac->data; + struct input_dev *input = wacom_wac->pad_input; + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); + struct wacom_features *features = &wacom_wac->features; + int bat_charging, bat_percent, touch_ring_mode; + __u32 serial; + int i; + + if (data[0] != WACOM_REPORT_REMOTE) { + dev_dbg(input->dev.parent, + "%s: received unknown report #%d", __func__, data[0]); + return 0; + } + + serial = data[3] + (data[4] << 8) + (data[5] << 16); + wacom_wac->id[0] = PAD_DEVICE_ID; + + input_report_key(input, BTN_0, (data[9] & 0x01)); + input_report_key(input, BTN_1, (data[9] & 0x02)); + input_report_key(input, BTN_2, (data[9] & 0x04)); + input_report_key(input, BTN_3, (data[9] & 0x08)); + input_report_key(input, BTN_4, (data[9] & 0x10)); + input_report_key(input, BTN_5, (data[9] & 0x20)); + input_report_key(input, BTN_6, (data[9] & 0x40)); + input_report_key(input, BTN_7, (data[9] & 0x80)); + + input_report_key(input, BTN_8, (data[10] & 0x01)); + input_report_key(input, BTN_9, (data[10] & 0x02)); + input_report_key(input, BTN_A, (data[10] & 0x04)); + input_report_key(input, BTN_B, (data[10] & 0x08)); + input_report_key(input, BTN_C, (data[10] & 0x10)); + input_report_key(input, BTN_X, (data[10] & 0x20)); + input_report_key(input, BTN_Y, (data[10] & 0x40)); + input_report_key(input, BTN_Z, (data[10] & 0x80)); + + input_report_key(input, BTN_BASE, (data[11] & 0x01)); + input_report_key(input, BTN_BASE2, (data[11] & 0x02)); + + if (data[12] & 0x80) + input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f)); + else + input_report_abs(input, ABS_WHEEL, 0); + + bat_percent = data[7] & 0x7f; + bat_charging = !!(data[7] & 0x80); + + if (data[9] | data[10] | (data[11] & 0x03) | data[12]) + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + else + input_report_abs(input, ABS_MISC, 0); + + input_event(input, EV_MSC, MSC_SERIAL, serial); + + /*Which mode select (LED light) is currently on?*/ + touch_ring_mode = (data[11] & 0xC0) >> 6; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + if (wacom_wac->serial[i] == serial) + wacom->led.select[i] = touch_ring_mode; + } + + if (!wacom->battery && + !(features->quirks & WACOM_QUIRK_BATTERY)) { + features->quirks |= WACOM_QUIRK_BATTERY; + INIT_WORK(&wacom->work, wacom_battery_work); + wacom_schedule_work(wacom_wac); + } + + wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1, + bat_charging); + + return 1; +} + +static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len) +{ + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); + unsigned char *data = wacom_wac->data; + int i; + + if (data[0] != WACOM_REPORT_DEVICE_LIST) + return 0; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + int j = i * 6; + int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4]; + bool connected = data[j+2]; + + if (connected) { + int k; + + if (wacom_wac->serial[i] == serial) + continue; + + if (wacom_wac->serial[i]) { + wacom_remote_destroy_attr_group(wacom, + wacom_wac->serial[i]); + } + + /* A remote can pair more than once with an EKR, + * check to make sure this serial isn't already paired. + */ + for (k = 0; k < WACOM_MAX_REMOTES; k++) { + if (wacom_wac->serial[k] == serial) + break; + } + + if (k < WACOM_MAX_REMOTES) { + wacom_wac->serial[i] = serial; + continue; + } + wacom_remote_create_attr_group(wacom, serial, i); + + } else if (wacom_wac->serial[i]) { + wacom_remote_destroy_attr_group(wacom, + wacom_wac->serial[i]); + } + } + + return 0; +} + static void wacom_intuos_general(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; @@ -1437,6 +1547,12 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void wacom_wac_pen_pre_report(struct hid_device *hdev, + struct hid_report *report) +{ + return; +} + static void wacom_wac_pen_report(struct hid_device *hdev, struct hid_report *report) { @@ -1491,6 +1607,13 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_POSITION_Y, 4); break; + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + features->last_slot_field = usage->hid; + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + break; case HID_DG_CONTACTID: features->last_slot_field = usage->hid; break; @@ -1504,6 +1627,10 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, features->last_slot_field = usage->hid; wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); break; + case HID_DG_CONTACTCOUNT: + wacom_wac->hid_data.cc_index = field->index; + wacom_wac->hid_data.cc_value_index = usage->usage_index; + break; } } @@ -1515,6 +1642,10 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, bool prox = hid_data->tipswitch && !wacom_wac->shared->stylus_in_proximity; + wacom_wac->hid_data.num_received++; + if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected) + return; + if (mt) { int slot; @@ -1531,6 +1662,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, hid_data->x); input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y, hid_data->y); + + if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) { + input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height)); + input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height)); + if (hid_data->width != hid_data->height) + input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1); + } } } @@ -1547,6 +1685,12 @@ static int wacom_wac_finger_event(struct hid_device *hdev, case HID_GD_Y: wacom_wac->hid_data.y = value; break; + case HID_DG_WIDTH: + wacom_wac->hid_data.width = value; + break; + case HID_DG_HEIGHT: + wacom_wac->hid_data.height = value; + break; case HID_DG_CONTACTID: wacom_wac->hid_data.id = value; break; @@ -1564,6 +1708,24 @@ static int wacom_wac_finger_event(struct hid_device *hdev, return 0; } +static void wacom_wac_finger_pre_report(struct hid_device *hdev, + struct hid_report *report) +{ + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct hid_data* hid_data = &wacom_wac->hid_data; + + if (hid_data->cc_index >= 0) { + struct hid_field *field = report->field[hid_data->cc_index]; + int value = field->value[hid_data->cc_value_index]; + if (value) + hid_data->num_expected = value; + } + else { + hid_data->num_expected = wacom_wac->features.touch_max; + } +} + static void wacom_wac_finger_report(struct hid_device *hdev, struct hid_report *report) { @@ -1572,10 +1734,18 @@ static void wacom_wac_finger_report(struct hid_device *hdev, struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; + /* If more packets of data are expected, give us a chance to + * process them rather than immediately syncing a partial + * update. + */ + if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected) + return; + if (touch_max > 1) input_mt_sync_frame(input); input_sync(input); + wacom_wac->hid_data.num_received = 0; /* keep touch state for pen event */ wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac); @@ -1615,6 +1785,25 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void wacom_report_events(struct hid_device *hdev, struct hid_report *report) +{ + int r; + + for (r = 0; r < report->maxfield; r++) { + struct hid_field *field; + unsigned count, n; + + field = report->field[r]; + count = field->report_count; + + if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) + continue; + + for (n = 0; n < count; n++) + wacom_wac_event(hdev, field, &field->usage[n], field->value[n]); + } +} + void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) { struct wacom *wacom = hid_get_drvdata(hdev); @@ -1625,6 +1814,14 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) return; if (WACOM_PEN_FIELD(field)) + wacom_wac_pen_pre_report(hdev, report); + + if (WACOM_FINGER_FIELD(field)) + wacom_wac_finger_pre_report(hdev, report); + + wacom_report_events(hdev, report); + + if (WACOM_PEN_FIELD(field)) return wacom_wac_pen_report(hdev, report); if (WACOM_FINGER_FIELD(field)) @@ -1699,7 +1896,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) int y = (data[3] << 4) | (data[4] & 0x0f); int width, height; - if (features->type >= INTUOSPS && features->type <= INTUOSPL) { + if (features->type >= INTUOSPS && features->type <= INTUOSHT) { width = data[5] * 100; height = data[6] * 100; } else { @@ -2118,6 +2315,13 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) sync = wacom_wireless_irq(wacom_wac, len); break; + case REMOTE: + if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST) + sync = wacom_remote_status_irq(wacom_wac, len); + else + sync = wacom_remote_irq(wacom_wac, len); + break; + default: sync = false; break; @@ -2213,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; + } } /* @@ -2220,10 +2427,13 @@ void wacom_setup_device_quirks(struct wacom *wacom) * 0, whose HID descriptor has an application usage of 0xFF0D * (i.e., WACOM_VENDORDEFINED_PEN). We route pen packets back * out through the HID_GENERIC device created for interface 1, - * so rewrite this one to be of type BTN_TOOL_FINGER. + * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH. */ if (features->type == BAMBOO_PAD) - features->device_type |= WACOM_DEVICETYPE_TOUCH; + features->device_type = WACOM_DEVICETYPE_TOUCH; + + if (features->type == REMOTE) + features->device_type = WACOM_DEVICETYPE_PAD; if (wacom->hdev->bus == BUS_BLUETOOTH) features->quirks |= WACOM_QUIRK_BATTERY; @@ -2239,13 +2449,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) } if (features->type == WIRELESS) { - - /* monitor never has input and pen/touch have delayed create */ - features->quirks |= WACOM_QUIRK_NO_INPUT; - - /* must be monitor interface if no device_type set */ - if (features->device_type == WACOM_DEVICETYPE_NONE) { - features->quirks |= WACOM_QUIRK_MONITOR; + if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) { features->quirks |= WACOM_QUIRK_BATTERY; } } @@ -2510,11 +2714,23 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, return 0; } +static void wacom_setup_numbered_buttons(struct input_dev *input_dev, + int button_count) +{ + int i; + + for (i = 0; i < button_count && i < 10; i++) + __set_bit(BTN_0 + i, input_dev->keybit); + for (i = 10; i < button_count && i < 16; i++) + __set_bit(BTN_A + (i-10), input_dev->keybit); + for (i = 16; i < button_count && i < 18; i++) + __set_bit(BTN_BASE + (i-16), input_dev->keybit); +} + int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { struct wacom_features *features = &wacom_wac->features; - int i; if (!(features->device_type & WACOM_DEVICETYPE_PAD)) return -ENODEV; @@ -2531,10 +2747,14 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, /* kept for making udev and libwacom accepting the pad */ __set_bit(BTN_STYLUS, input_dev->keybit); + wacom_setup_numbered_buttons(input_dev, features->numbered_buttons); + switch (features->type) { + + case CINTIQ_HYBRID: + case DTK: + case DTUS: case GRAPHIRE_BT: - __set_bit(BTN_0, input_dev->keybit); - __set_bit(BTN_1, input_dev->keybit); break; case WACOM_MO: @@ -2552,16 +2772,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, break; case WACOM_24HD: - __set_bit(BTN_A, input_dev->keybit); - __set_bit(BTN_B, input_dev->keybit); - __set_bit(BTN_C, input_dev->keybit); - __set_bit(BTN_X, input_dev->keybit); - __set_bit(BTN_Y, input_dev->keybit); - __set_bit(BTN_Z, input_dev->keybit); - - for (i = 0; i < 10; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - __set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit); __set_bit(KEY_PROG3, input_dev->keybit); @@ -2583,12 +2793,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); break; - case DTK: - for (i = 0; i < 6; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - - break; - case WACOM_22HD: __set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit); @@ -2596,52 +2800,22 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, /* fall through */ case WACOM_21UX2: - __set_bit(BTN_A, input_dev->keybit); - __set_bit(BTN_B, input_dev->keybit); - __set_bit(BTN_C, input_dev->keybit); - __set_bit(BTN_X, input_dev->keybit); - __set_bit(BTN_Y, input_dev->keybit); - __set_bit(BTN_Z, input_dev->keybit); - __set_bit(BTN_BASE, input_dev->keybit); - __set_bit(BTN_BASE2, input_dev->keybit); - /* fall through */ - case WACOM_BEE: - __set_bit(BTN_8, input_dev->keybit); - __set_bit(BTN_9, input_dev->keybit); - /* fall through */ - case CINTIQ: - for (i = 0; i < 8; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); break; case WACOM_13HD: - for (i = 0; i < 9; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; case INTUOS3: case INTUOS3L: - __set_bit(BTN_4, input_dev->keybit); - __set_bit(BTN_5, input_dev->keybit); - __set_bit(BTN_6, input_dev->keybit); - __set_bit(BTN_7, input_dev->keybit); - input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); /* fall through */ case INTUOS3S: - __set_bit(BTN_0, input_dev->keybit); - __set_bit(BTN_1, input_dev->keybit); - __set_bit(BTN_2, input_dev->keybit); - __set_bit(BTN_3, input_dev->keybit); - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); break; @@ -2649,15 +2823,8 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS5L: case INTUOSPM: case INTUOSPL: - __set_bit(BTN_7, input_dev->keybit); - __set_bit(BTN_8, input_dev->keybit); - /* fall through */ - case INTUOS5S: case INTUOSPS: - for (i = 0; i < 7; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; @@ -2672,28 +2839,10 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS4: case INTUOS4L: - __set_bit(BTN_7, input_dev->keybit); - __set_bit(BTN_8, input_dev->keybit); - /* fall through */ - case INTUOS4S: - for (i = 0; i < 7; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; - case CINTIQ_HYBRID: - for (i = 0; i < 9; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - - break; - - case DTUS: - for (i = 0; i < 4; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - break; - case INTUOSHT: case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); @@ -2705,6 +2854,11 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, break; + case REMOTE: + input_set_capability(input_dev, EV_MSC, MSC_SERIAL); + input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); + break; + default: /* no pad supported */ return -ENODEV; @@ -2720,7 +2874,7 @@ static const struct wacom_features wacom_features_0x10 = GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x81 = { "Wacom Graphire BT", 16704, 12064, 511, 32, - GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; + GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES, 2 }; static const struct wacom_features wacom_features_0x11 = { "Wacom Graphire2 4x5", 10206, 7422, 511, 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; @@ -2846,77 +3000,77 @@ static const struct wacom_features wacom_features_0x45 = INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xB0 = { "Wacom Intuos3 4x5", 25400, 20320, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; static const struct wacom_features wacom_features_0xB1 = { "Wacom Intuos3 6x8", 40640, 30480, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB2 = { "Wacom Intuos3 9x12", 60960, 45720, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB3 = { "Wacom Intuos3 12x12", 60960, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB4 = { "Wacom Intuos3 12x19", 97536, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB5 = { "Wacom Intuos3 6x11", 54204, 31750, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB7 = { "Wacom Intuos3 4x6", 31496, 19685, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; static const struct wacom_features wacom_features_0xB8 = { "Wacom Intuos4 4x6", 31496, 19685, 2047, 63, - INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; static const struct wacom_features wacom_features_0xB9 = { "Wacom Intuos4 6x9", 44704, 27940, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBA = { "Wacom Intuos4 8x13", 65024, 40640, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBB = { "Wacom Intuos4 12x19", 97536, 60960, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBC = { "Wacom Intuos4 WL", 40640, 25400, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBD = { "Wacom Intuos4 WL", 40640, 25400, 2047, 63, - INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0x26 = { "Wacom Intuos5 touch S", 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; + INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 }; static const struct wacom_features wacom_features_0x27 = { "Wacom Intuos5 touch M", 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; + INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; static const struct wacom_features wacom_features_0x28 = { "Wacom Intuos5 touch L", 65024, 40640, 2047, 63, - INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; + INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; static const struct wacom_features wacom_features_0x29 = { "Wacom Intuos5 S", 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; static const struct wacom_features wacom_features_0x2A = { "Wacom Intuos5 M", 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0x314 = { "Wacom Intuos Pro S", 31496, 19685, 2047, 63, - INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16, + INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x315 = { "Wacom Intuos Pro M", 44704, 27940, 2047, 63, - INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16, + INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x317 = { "Wacom Intuos Pro L", 65024, 40640, 2047, 63, - INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16, + INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0xF4 = { "Wacom Cintiq 24HD", 104080, 65200, 2047, 63, - WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0xF8 = { "Wacom Cintiq 24HD touch", 104080, 65200, 2047, 63, /* Pen */ - WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; static const struct wacom_features wacom_features_0xF6 = @@ -2925,11 +3079,11 @@ static const struct wacom_features wacom_features_0xF6 = .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x32A = { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63, - WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x32B = { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63, - WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C }; static const struct wacom_features wacom_features_0x32C = @@ -2937,20 +3091,20 @@ static const struct wacom_features wacom_features_0x32C = .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 }; static const struct wacom_features wacom_features_0x3F = { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63, - CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xC5 = { "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; static const struct wacom_features wacom_features_0xC6 = { "Wacom Cintiq 12WX", 53020, 33440, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; static const struct wacom_features wacom_features_0x304 = { "Wacom Cintiq 13HD", 59152, 33448, 1023, 63, - WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x333 = { "Wacom Cintiq 13HD touch", 59152, 33448, 2047, 63, - WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 }; static const struct wacom_features wacom_features_0x335 = @@ -2969,22 +3123,22 @@ static const struct wacom_features wacom_features_0xF0 = DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xFB = { "Wacom DTU1031", 21896, 13760, 511, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_0x32F = { "Wacom DTU1031X", 22472, 12728, 511, 0, - DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_0x336 = { "Wacom DTU1141", 23472, 13203, 1023, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; static const struct wacom_features wacom_features_0x57 = { "Wacom DTK2241", 95640, 54060, 2047, 63, - DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x59 = /* Pen */ { "Wacom DTH2242", 95640, 54060, 2047, 63, - DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D }; static const struct wacom_features wacom_features_0x5D = /* Touch */ @@ -2993,15 +3147,15 @@ static const struct wacom_features wacom_features_0x5D = /* Touch */ .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0xCC = { "Wacom Cintiq 21UX2", 86800, 65200, 2047, 63, - WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0xFA = { "Wacom Cintiq 22HD", 95440, 53860, 2047, 63, - WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x5B = { "Wacom Cintiq 22HDT", 95440, 53860, 2047, 63, - WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e }; static const struct wacom_features wacom_features_0x5E = @@ -3148,7 +3302,7 @@ static const struct wacom_features wacom_features_0x6004 = TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x307 = { "Wacom ISDv5 307", 59152, 33448, 2047, 63, - CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 }; static const struct wacom_features wacom_features_0x309 = @@ -3157,7 +3311,7 @@ static const struct wacom_features wacom_features_0x309 = .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x30A = { "Wacom ISDv5 30A", 59152, 33448, 2047, 63, - CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C }; static const struct wacom_features wacom_features_0x30C = @@ -3174,6 +3328,10 @@ static const struct wacom_features wacom_features_0x323 = { "Wacom Intuos P M", 21600, 13500, 1023, 31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; +static const struct wacom_features wacom_features_0x331 = + { "Wacom Express Key Remote", 0, 0, 0, 0, + REMOTE, 0, 0, 18, .check_for_hid_type = true, + .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC }; @@ -3329,6 +3487,7 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x32B) }, { USB_DEVICE_WACOM(0x32C) }, { USB_DEVICE_WACOM(0x32F) }, + { USB_DEVICE_WACOM(0x331) }, { USB_DEVICE_WACOM(0x333) }, { USB_DEVICE_WACOM(0x335) }, { USB_DEVICE_WACOM(0x336) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 2978c303909d..1e270d401e18 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -16,6 +16,8 @@ #define WACOM_PKGLEN_MAX 192 #define WACOM_NAME_MAX 64 +#define WACOM_MAX_REMOTES 5 +#define WACOM_STATUS_UNKNOWN 255 /* packet length for individual models */ #define WACOM_PKGLEN_BBFUN 9 @@ -65,11 +67,11 @@ #define WACOM_REPORT_USB 192 #define WACOM_REPORT_BPAD_PEN 3 #define WACOM_REPORT_BPAD_TOUCH 16 +#define WACOM_REPORT_DEVICE_LIST 16 +#define WACOM_REPORT_REMOTE 17 /* device quirks */ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 -#define WACOM_QUIRK_NO_INPUT 0x0002 -#define WACOM_QUIRK_MONITOR 0x0004 #define WACOM_QUIRK_BATTERY 0x0008 /* device types */ @@ -77,6 +79,7 @@ #define WACOM_DEVICETYPE_PEN 0x0001 #define WACOM_DEVICETYPE_TOUCH 0x0002 #define WACOM_DEVICETYPE_PAD 0x0004 +#define WACOM_DEVICETYPE_WL_MONITOR 0x0008 #define WACOM_VENDORDEFINED_PEN 0xff0d0001 @@ -130,6 +133,7 @@ enum { WACOM_24HDT, WACOM_27QHDT, BAMBOO_PAD, + REMOTE, TABLETPC, /* add new TPC below */ TABLETPCE, TABLETPC2FG, @@ -149,6 +153,7 @@ struct wacom_features { int type; int x_resolution; int y_resolution; + int numbered_buttons; int x_min; int y_min; int device_type; @@ -193,6 +198,10 @@ struct hid_data { int width; int height; int id; + int cc_index; + int cc_value_index; + int num_expected; + int num_received; }; struct wacom_wac { @@ -204,7 +213,7 @@ struct wacom_wac { unsigned char data[WACOM_PKGLEN_MAX]; int tool[2]; int id[2]; - __u32 serial[2]; + __u32 serial[5]; bool reporting_data; struct wacom_features features; struct wacom_shared *shared; |