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 972 additions and 291 deletions

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;