Merge branches 'for-4.3/chicony', 'for-4.3/cp2112', 'for-4.3/i2c-hid', 'for-4.3/lenovo', 'for-4.3/logitech', 'for-4.3/multitouch', 'for-4.3/picolcd', 'for-4.3/rmi', 'for-4.3/sensor-hub', 'for-4.3/sony' and 'for-4.3/wacom' into for-linus

This commit is contained in:
20 changed files with 973 additions and 292 deletions

View file

@ -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.

View file

@ -486,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

View file

@ -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);

View file

@ -1826,6 +1826,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },

View file

@ -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;
@ -446,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)
{
@ -453,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);
@ -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);
@ -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;
@ -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:
@ -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,
@ -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);
@ -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) {
@ -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);

View file

@ -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
@ -503,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
@ -605,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

View file

@ -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);

View file

@ -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),

View file

@ -1145,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,

View file

@ -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)

View file

@ -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);
}

View file

@ -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)

View file

@ -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

View file

@ -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) },
{ }

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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)
@ -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,40 +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);
input_free_device(wacom_wac->pen_input);
input_free_device(wacom_wac->touch_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) {
@ -1199,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;
@ -1259,10 +1432,16 @@ 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;
@ -1553,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
@ -1603,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);
@ -1637,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 &&
@ -1711,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,

View file

@ -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);
}
wacom->tool[0] = prox; /* Save proximity state */
/* 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;
}
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);
@ -1624,6 +1813,14 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
if (wacom_wac->features.type != HID_GENERIC)
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);
@ -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;
@ -2223,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;
@ -2242,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;
}
}
@ -2513,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;
@ -2534,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:
@ -2555,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);
@ -2586,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);
@ -2599,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;
@ -2652,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;
@ -2675,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);
@ -2708,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;
@ -2723,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 };
@ -2849,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 =
@ -2928,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 =
@ -2940,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 =
@ -2972,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 */
@ -2996,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 =
@ -3151,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 =
@ -3160,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 =
@ -3177,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 };
@ -3332,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) },

View file

@ -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;