Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/jikos/hid

Pull HID updates from Jiri Kosina:
 "to receive patches queued for 4.3 merge window in HID tree. Highlights:

   - a lot of improvements (regarding supported features and devices) to
     Wacom driver, from Aaron Skomra and Jason Gerecke
   - a lot of functional fixes and support for large I2C transfer to
     cp2112 driver, from Ellen Wang
   - HW support improvements to RMI driver, from Andrew Duggan
   - quite some small fixes and device ID additions all over the place"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (44 commits)
  HID: wacom: wacom_setup_numbered_buttons is local to wacom_wac
  HID: wacom: Add support for Express Key Remote.
  HID: wacom: Set button bits based on a new numbered_buttons
  HID: quirks: add QUIRK_NOGET for an other TPV touchscreen
  HID: usbhid: Fix the check for HID_RESET_PENDING in hid_io_error
  HID: i2c-hid: Only disable irq wake if it was successfully enabled during suspend
  HID: wacom: Use tablet-provided touch height/width values for INTUOSHT
  HID: gembird: add new driver to fix Gembird JPD-DualForce 2
  HID: lenovo: Hide middle-button press until release
  HID: lenovo: Add missing return-value check
  HID: lenovo: Use constants for axes names
  HID: wacom: Simplify 'wacom_pl_irq'
  HID: wacom: Do not repeatedly attempt to set device mode on error
  HID: wacom: Do not repeatedly attempt to set device mode on error
  HID: wacom: Remove WACOM_QUIRK_NO_INPUT
  HID: wacom: Replace WACOM_QUIRK_MONITOR with WACOM_DEVICETYPE_WL_MONITOR
  HID: wacom: Use calculated pkglen for wireless touch interface
  HID: sony: Fix DS4 controller reporting rate issues
  HID: chicony: Add support for Acer Aspire Switch 12
  HID: hid-lg: Add USBID for Logitech G29 Wheel
  ...
  • Loading branch information
Linus Torvalds committed Sep 2, 2015
2 parents 2d678b6 + f212bd9 commit 851328f
Show file tree
Hide file tree
Showing 26 changed files with 1,144 additions and 308 deletions.
19 changes: 19 additions & 0 deletions Documentation/ABI/testing/sysfs-driver-wacom
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,22 @@ Description:
The format is also scrambled, like in the USB mode, and it can
be summarized by converting 76543210 into GECA6420.
HGFEDCBA HFDB7531

What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/unpair_remote
Date: July 2015
Contact: linux-input@vger.kernel.org
Description:
Writing the character sequence '*' followed by a newline to
this file will delete all of the current pairings on the
device. Other character sequences are reserved. This file is
write only.

What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/<serial_number>/remote_mode
Date: July 2015
Contact: linux-input@vger.kernel.org
Description:
Reading from this file reports the mode status of the
remote as indicated by the LED lights on the device. If no
reports have been received from the paired device, reading
from this file will report '-1'. The mode is read-only
and cannot be set through the driver.
7 changes: 7 additions & 0 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ config HID_EZKEY
---help---
Support for Ezkey BTC 8193 keyboard.

config HID_GEMBIRD
tristate "Gembird Joypad"
depends on HID
---help---
Support for Gembird JPD-DualForce 2.

config HID_HOLTEK
tristate "Holtek HID devices"
depends on USB_HID
Expand Down Expand Up @@ -480,6 +486,7 @@ config HID_MULTITOUCH
- Atmel panels
- Cando dual touch panels
- Chunghwa panels
- CJTouch panels
- CVTouch panels
- Cypress TrueTouch panels
- Elan Microelectronics touch panels
Expand Down
1 change: 1 addition & 0 deletions drivers/hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_ELO) += hid-elo.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o
obj-$(CONFIG_HID_GT683R) += hid-gt683r.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
Expand Down
26 changes: 26 additions & 0 deletions drivers/hid/hid-chicony.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/input.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>

#include "hid-ids.h"

Expand Down Expand Up @@ -57,17 +58,42 @@ 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);

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);
Expand Down
29 changes: 26 additions & 3 deletions drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) },
Expand All @@ -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) },
Expand Down Expand Up @@ -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) },
Expand Down
107 changes: 80 additions & 27 deletions drivers/hid/hid-cp2112.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -446,33 +447,71 @@ 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)
{
struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
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);
Expand Down Expand Up @@ -508,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);
Expand All @@ -537,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;
Expand All @@ -554,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:
Expand All @@ -569,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,
Expand All @@ -582,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);
Expand Down Expand Up @@ -675,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) {
Expand Down Expand Up @@ -1030,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);
Expand Down
Loading

0 comments on commit 851328f

Please sign in to comment.