Commit fc8104bc authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'wacom' into next

Merge large update to Wacom driver, converting it from USB to a HID
driver and unifying wired and bluetooth support, from Benjamin
Tissoires.
parents 62238f3a f2e0a7d4
...@@ -748,12 +748,17 @@ config THRUSTMASTER_FF ...@@ -748,12 +748,17 @@ config THRUSTMASTER_FF
Rumble Force or Force Feedback Wheel. Rumble Force or Force Feedback Wheel.
config HID_WACOM config HID_WACOM
tristate "Wacom Bluetooth devices support" tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on HID depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY select POWER_SUPPLY
---help--- select NEW_LEDS
Support for Wacom Graphire Bluetooth and Intuos4 WL tablets. select LEDS_CLASS
help
Say Y here if you want to use the USB or BT version of the Wacom Intuos
or Graphire tablet.
To compile this driver as a module, choose M here: the
module will be called wacom.
config HID_WIIMOTE config HID_WIIMOTE
tristate "Nintendo Wii / Wii U peripherals" tristate "Nintendo Wii / Wii U peripherals"
......
...@@ -115,7 +115,9 @@ obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o ...@@ -115,7 +115,9 @@ obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
obj-$(CONFIG_HID_XINMO) += hid-xinmo.o obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_HID_WACOM) += wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
......
...@@ -787,6 +787,15 @@ static int hid_scan_report(struct hid_device *hid) ...@@ -787,6 +787,15 @@ static int hid_scan_report(struct hid_device *hid)
/* hid-rmi should take care of them, not hid-generic */ /* hid-rmi should take care of them, not hid-generic */
hid->group = HID_GROUP_RMI; hid->group = HID_GROUP_RMI;
/*
* Vendor specific handlings
*/
switch (hid->vendor) {
case USB_VENDOR_ID_WACOM:
hid->group = HID_GROUP_WACOM;
break;
}
vfree(parser); vfree(parser);
return 0; return 0;
} }
...@@ -1933,8 +1942,6 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1933,8 +1942,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
...@@ -2339,7 +2346,6 @@ static const struct hid_device_id hid_ignore_list[] = { ...@@ -2339,7 +2346,6 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
......
/*
* Bluetooth Wacom Tablet support
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
* Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
* Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
* Copyright (c) 2011 Przemysław Firszt <przemo@firszt.eu>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/power_supply.h>
#include "hid-ids.h"
#define PAD_DEVICE_ID 0x0F
#define WAC_CMD_LED_CONTROL 0x20
#define WAC_CMD_ICON_START_STOP 0x21
#define WAC_CMD_ICON_TRANSFER 0x26
struct wacom_data {
__u16 tool;
__u16 butstate;
__u8 whlstate;
__u8 features;
__u32 id;
__u32 serial;
unsigned char high_speed;
__u8 battery_capacity;
__u8 power_raw;
__u8 ps_connected;
__u8 bat_charging;
struct power_supply battery;
struct power_supply ac;
__u8 led_selector;
struct led_classdev *leds[4];
};
/*percent of battery capacity for Graphire
8th value means AC online and show 100% capacity */
static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_STATUS,
};
static enum power_supply_property wacom_ac_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_SCOPE,
};
static void wacom_scramble(__u8 *image)
{
__u16 mask;
__u16 s1;
__u16 s2;
__u16 r1 ;
__u16 r2 ;
__u16 r;
__u8 buf[256];
int i, w, x, y, z;
for (x = 0; x < 32; x++) {
for (y = 0; y < 8; y++)
buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
}
/* Change 76543210 into GECA6420 as required by Intuos4 WL
* HGFEDCBA HFDB7531
*/
for (x = 0; x < 4; x++) {
for (y = 0; y < 4; y++) {
for (z = 0; z < 8; z++) {
mask = 0x0001;
r1 = 0;
r2 = 0;
i = (x << 6) + (y << 4) + z;
s1 = buf[i];
s2 = buf[i+8];
for (w = 0; w < 8; w++) {
r1 |= (s1 & mask);
r2 |= (s2 & mask);
s1 <<= 1;
s2 <<= 1;
mask <<= 2;
}
r = r1 | (r2 << 1);
i = (x << 6) + (y << 4) + (z << 1);
image[i] = 0xFF & r;
image[i+1] = (0xFF00 & r) >> 8;
}
}
}
}
static void wacom_set_image(struct hid_device *hdev, const char *image,
__u8 icon_no)
{
__u8 rep_data[68];
__u8 p[256];
int ret, i, j;
for (i = 0; i < 256; i++)
p[i] = image[i];
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0)
goto err;
rep_data[0] = WAC_CMD_ICON_TRANSFER;
rep_data[1] = icon_no & 0x07;
wacom_scramble(p);
for (i = 0; i < 4; i++) {
for (j = 0; j < 64; j++)
rep_data[j + 3] = p[(i << 6) + j];
rep_data[2] = i;
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
err:
return;
}
static void wacom_leds_set_brightness(struct led_classdev *led_dev,
enum led_brightness value)
{
struct device *dev = led_dev->dev->parent;
struct hid_device *hdev;
struct wacom_data *wdata;
unsigned char *buf;
__u8 led = 0;
int i;
hdev = container_of(dev, struct hid_device, dev);
wdata = hid_get_drvdata(hdev);
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev)
wdata->led_selector = i;
}
led = wdata->led_selector | 0x04;
buf = kzalloc(9, GFP_KERNEL);
if (buf) {
buf[0] = WAC_CMD_LED_CONTROL;
buf[1] = led;
buf[2] = value >> 2;
buf[3] = value;
/* use fixed brightness for OLEDs */
buf[4] = 0x08;
hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
kfree(buf);
}
return;
}
static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
{
struct wacom_data *wdata;
struct device *dev = led_dev->dev->parent;
int value = 0;
int i;
wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev) {
value = wdata->leds[i]->brightness;
break;
}
}
return value;
}
static int wacom_initialize_leds(struct hid_device *hdev)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct led_classdev *led;
struct device *dev = &hdev->dev;
size_t namesz = strlen(dev_name(dev)) + 12;
char *name;
int i, ret;
wdata->led_selector = 0;
for (i = 0; i < 4; i++) {
led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
if (!led) {
hid_warn(hdev,
"can't allocate memory for LED selector\n");
ret = -ENOMEM;
goto err;
}
name = (void *)&led[1];
snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
led->name = name;
led->brightness = 0;
led->max_brightness = 127;
led->brightness_get = wacom_leds_get_brightness;
led->brightness_set = wacom_leds_set_brightness;
wdata->leds[i] = led;
ret = led_classdev_register(dev, wdata->leds[i]);
if (ret) {
wdata->leds[i] = NULL;
kfree(led);
hid_warn(hdev, "can't register LED\n");
goto err;
}
}
err:
return ret;
}
static void wacom_destroy_leds(struct hid_device *hdev)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct led_classdev *led;
int i;
for (i = 0; i < 4; ++i) {
if (wdata->leds[i]) {
led = wdata->leds[i];
wdata->leds[i] = NULL;
led_classdev_unregister(led);
kfree(led);
}
}
}
static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy,
struct wacom_data, battery);
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = wdata->battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
if (wdata->bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
if (wdata->battery_capacity == 100 && wdata->ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int wacom_ac_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* fall through */
case POWER_SUPPLY_PROP_ONLINE:
val->intval = wdata->ps_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static void wacom_set_features(struct hid_device *hdev, u8 speed)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
int limit, ret;
__u8 rep_data[2];
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
if (speed == 0)
rep_data[0] = 0x05;
else
rep_data[0] = 0x06;
rep_data[1] = 0x00;
limit = 3;
do {
ret = hid_hw_raw_request(hdev, rep_data[0],
rep_data, 2, HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
wdata->high_speed = speed;
return;
}
}
/*
* Note that if the raw queries fail, it's not a hard failure
* and it is safe to continue
*/
hid_warn(hdev, "failed to poke device, command %d, err %d\n",
rep_data[0], ret);
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
if (speed == 1)
wdata->features &= ~0x20;
else
wdata->features |= 0x20;
rep_data[0] = 0x03;
rep_data[1] = wdata->features;
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0)
wdata->high_speed = speed;
break;
}
return;
}
static ssize_t wacom_show_speed(struct device *dev,
struct device_attribute
*attr, char *buf)
{
struct wacom_data *wdata = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
}
static ssize_t wacom_store_speed(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
int new_speed;
if (sscanf(buf, "%1d", &new_speed ) != 1)
return -EINVAL;
if (new_speed == 0 || new_speed == 1) {
wacom_set_features(hdev, new_speed);
return strnlen(buf, PAGE_SIZE);
} else
return -EINVAL;
}
static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
wacom_show_speed, wacom_store_speed);
#define WACOM_STORE(OLED_ID) \
static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct hid_device *hdev = container_of(dev, struct hid_device, \
dev); \
\
if (count != 256) \
return -EINVAL; \
\
wacom_set_image(hdev, buf, OLED_ID); \
\
return count; \
} \
\
static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \
wacom_oled##OLED_ID##_store)
WACOM_STORE(0);
WACOM_STORE(1);
WACOM_STORE(2);
WACOM_STORE(3);
WACOM_STORE(4);
WACOM_STORE(5);
WACOM_STORE(6);
WACOM_STORE(7);
static int wacom_gr_parse_report(struct hid_device *hdev,
struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
int tool, x, y, rw;
tool = 0;
/* Get X & Y positions */
x = le16_to_cpu(*(__le16 *) &data[2]);
y = le16_to_cpu(*(__le16 *) &data[4]);
/* Get current tool identifier */
if (data[1] & 0x90) { /* If pen is in the in/active area */
switch ((data[1] >> 5) & 3) {
case 0: /* Pen */
tool = BTN_TOOL_PEN;
break;
case 1: /* Rubber */
tool = BTN_TOOL_RUBBER;
break;
case 2: /* Mouse with wheel */
case 3: /* Mouse without wheel */
tool = BTN_TOOL_MOUSE;
break;
}
/* Reset tool if out of active tablet area */
if (!(data[1] & 0x10))
tool = 0;
}
/* If tool changed, notify input subsystem */
if (wdata->tool != tool) {
if (wdata->tool) {
/* Completely reset old tool state */
if (wdata->tool == BTN_TOOL_MOUSE) {
input_report_key(input, BTN_LEFT, 0);
input_report_key(input, BTN_RIGHT, 0);
input_report_key(input, BTN_MIDDLE, 0);
input_report_abs(input, ABS_DISTANCE,
input_abs_get_max(input, ABS_DISTANCE));
} else {
input_report_key(input, BTN_TOUCH, 0);
input_report_key(input, BTN_STYLUS, 0);
input_report_key(input, BTN_STYLUS2, 0);
input_report_abs(input, ABS_PRESSURE, 0);
}
input_report_key(input, wdata->tool, 0);
input_sync(input);
}
wdata->tool = tool;
if (tool)
input_report_key(input, tool, 1);
}
if (tool) {
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
switch ((data[1] >> 5) & 3) {
case 2: /* Mouse with wheel */
input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
rw = (data[6] & 0x01) ? -1 :
(data[6] & 0x02) ? 1 : 0;
input_report_rel(input, REL_WHEEL, rw);
/* fall through */
case 3: /* Mouse without wheel */
input_report_key(input, BTN_LEFT, data[1] & 0x01);
input_report_key(input, BTN_RIGHT, data[1] & 0x02);
/* Compute distance between mouse and tablet */
rw = 44 - (data[6] >> 2);
if (rw < 0)
rw = 0;
else if (rw > 31)
rw = 31;
input_report_abs(input, ABS_DISTANCE, rw);
break;
default:
input_report_abs(input, ABS_PRESSURE,
data[6] | (((__u16) (data[1] & 0x08)) << 5));
input_report_key(input, BTN_TOUCH, data[1] & 0x01);
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
break;
}
input_sync(input);
}
/* Report the state of the two buttons at the top of the tablet
* as two extra fingerpad keys (buttons 4 & 5). */
rw = data[7] & 0x03;
if (rw != wdata->butstate) {
wdata->butstate = rw;
input_report_key(input, BTN_0, rw & 0x02);
input_report_key(input, BTN_1, rw & 0x01);
input_report_key(input, BTN_TOOL_FINGER, 0xf0);
input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
input_sync(input);
}
/* Store current battery capacity and power supply state*/
rw = (data[7] >> 2 & 0x07);
if (rw != wdata->power_raw) {
wdata->power_raw = rw;
wdata->battery_capacity = batcap_gr[rw];
if (rw == 7)
wdata->ps_connected = 1;
else
wdata->ps_connected = 0;
}
return 1;
}
static void wacom_i4_parse_button_report(struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
__u16 new_butstate;
__u8 new_whlstate;
__u8 sync = 0;
new_whlstate = data[1];
if (new_whlstate != wdata->whlstate) {
wdata->whlstate = new_whlstate;
if (new_whlstate & 0x80) {
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_WHEEL, (new_whlstate & 0x7f));
input_report_key(input, BTN_TOOL_FINGER, 1);
} else {
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_WHEEL, 0);
input_report_key(input, BTN_TOOL_FINGER, 0);
}
sync = 1;
}
new_butstate = (data[3] << 1) | (data[2] & 0x01);
if (new_butstate != wdata->butstate) {
wdata->butstate = new_butstate;
input_report_key(input, BTN_0, new_butstate & 0x001);
input_report_key(input, BTN_1, new_butstate & 0x002);
input_report_key(input, BTN_2, new_butstate & 0x004);
input_report_key(input, BTN_3, new_butstate & 0x008);
input_report_key(input, BTN_4, new_butstate & 0x010);
input_report_key(input, BTN_5, new_butstate & 0x020);
input_report_key(input, BTN_6, new_butstate & 0x040);
input_report_key(input, BTN_7, new_butstate & 0x080);
input_report_key(input, BTN_8, new_butstate & 0x100);
input_report_key(input, BTN_TOOL_FINGER, 1);
sync = 1;
}
if (sync) {
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
input_sync(input);
}
}
static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
__u16 x, y, pressure;
__u8 distance;
__u8 tilt_x, tilt_y;
switch (data[1]) {
case 0x80: /* Out of proximity report */
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_report_key(input, BTN_STYLUS, 0);
input_report_key(input, BTN_STYLUS2, 0);
input_report_key(input, wdata->tool, 0);
input_report_abs(input, ABS_MISC, 0);
input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
wdata->tool = 0;
input_sync(input);
break;
case 0xC2: /* Tool report */
wdata->id = ((data[2] << 4) | (data[3] >> 4) |
((data[7] & 0x0f) << 20) |
((data[8] & 0xf0) << 12));
wdata->serial = ((data[3] & 0x0f) << 28) +
(data[4] << 20) + (data[5] << 12) +
(data[6] << 4) + (data[7] >> 4);
switch (wdata->id) {
case 0x100802:
wdata->tool = BTN_TOOL_PEN;
break;
case 0x10080A:
wdata->tool = BTN_TOOL_RUBBER;
break;
}
break;
default: /* Position/pressure report */
x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1);
y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01);
pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
| (data[1] & 0x01);
distance = (data[9] >> 2) & 0x3f;
tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
tilt_y = data[8] & 0x7f;
input_report_key(input, BTN_TOUCH, pressure > 1);
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
input_report_key(input, wdata->tool, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, pressure);
input_report_abs(input, ABS_DISTANCE, distance);
input_report_abs(input, ABS_TILT_X, tilt_x);
input_report_abs(input, ABS_TILT_Y, tilt_y);
input_report_abs(input, ABS_MISC, wdata->id);
input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
input_report_key(input, wdata->tool, 1);
input_sync(input);
break;
}
return;
}
static void wacom_i4_parse_report(struct hid_device *hdev,
struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
switch (data[0]) {
case 0x00: /* Empty report */
break;
case 0x02: /* Pen report */
wacom_i4_parse_pen_report(wdata, input, data);
break;
case 0x03: /* Features Report */
wdata->features = data[2];
break;
case 0x0C: /* Button report */
wacom_i4_parse_button_report(wdata, input, data);
break;
default:
hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]);
break;
}
}
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *raw_data, int size)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct hid_input *hidinput;
struct input_dev *input;
unsigned char *data = (unsigned char *) raw_data;
int i;
__u8 power_raw;
if (!(hdev->claimed & HID_CLAIMED_INPUT))
return 0;
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
if (data[0] == 0x03) {
return wacom_gr_parse_report(hdev, wdata, input, data);
} else {
hid_err(hdev, "Unknown report: %d,%d size:%d\n",
data[0], data[1], size);
return 0;
}
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
i = 1;
switch (data[0]) {
case 0x04:
wacom_i4_parse_report(hdev, wdata, input, data + i);
i += 10;
/* fall through */
case 0x03:
wacom_i4_parse_report(hdev, wdata, input, data + i);
i += 10;
wacom_i4_parse_report(hdev, wdata, input, data + i);
power_raw = data[i+10];
if (power_raw != wdata->power_raw) {
wdata->power_raw = power_raw;
wdata->battery_capacity = batcap_i4[power_raw & 0x07];
wdata->bat_charging = (power_raw & 0x08) ? 1 : 0;
wdata->ps_connected = (power_raw & 0x10) ? 1 : 0;
}
break;
default:
hid_err(hdev, "Unknown report: %d,%d size:%d\n",
data[0], data[1], size);
return 0;
}
}
return 1;
}
static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
int *max)
{
struct input_dev *input = hi->input;
__set_bit(INPUT_PROP_POINTER, input->propbit);
/* Basics */
input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
__set_bit(REL_WHEEL, input->relbit);
__set_bit(BTN_TOOL_PEN, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_STYLUS, input->keybit);
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
__set_bit(BTN_MIDDLE, input->keybit);
/* Pad */
input_set_capability(input, EV_MSC, MSC_SERIAL);
__set_bit(BTN_0, input->keybit);
__set_bit(BTN_1, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
/* Distance, rubber and mouse */
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_TOOL_MOUSE, input->keybit);
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
__set_bit(ABS_WHEEL, input->absbit);
__set_bit(ABS_MISC, input->absbit);
__set_bit(BTN_2, input->keybit);
__set_bit(BTN_3, input->keybit);
__set_bit(BTN_4, input->keybit);
__set_bit(BTN_5, input->keybit);
__set_bit(BTN_6, input->keybit);
__set_bit(BTN_7, input->keybit);
__set_bit(BTN_8, input->keybit);
input_set_abs_params(input, ABS_WHEEL, 0, 71, 0, 0);
input_set_abs_params(input, ABS_X, 0, 40640, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
break;
}
return 0;
}
static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
struct wacom_data *wdata;
int ret;
wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
if (wdata == NULL) {
hid_err(hdev, "can't alloc wacom descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, wdata);
/* Parse the HID report now */
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_free;
}
ret = device_create_file(&hdev->dev, &dev_attr_speed);
if (ret)
hid_warn(hdev,
"can't create sysfs speed attribute err: %d\n", ret);
#define OLED_INIT(OLED_ID) \
do { \
ret = device_create_file(&hdev->dev, \
&dev_attr_oled##OLED_ID##_img); \
if (ret) \
hid_warn(hdev, \
"can't create sysfs oled attribute, err: %d\n", ret);\
} while (0)
OLED_INIT(0);
OLED_INIT(1);
OLED_INIT(2);
OLED_INIT(3);
OLED_INIT(4);
OLED_INIT(5);
OLED_INIT(6);
OLED_INIT(7);
wdata->features = 0;
wacom_set_features(hdev, 1);
if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
ret = wacom_initialize_leds(hdev);
if (ret)
hid_warn(hdev,
"can't create led attribute, err: %d\n", ret);
}
wdata->battery.properties = wacom_battery_props;
wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
wdata->battery.get_property = wacom_battery_get_property;
wdata->battery.name = "wacom_battery";
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
wdata->battery.use_for_apm = 0;
ret = power_supply_register(&hdev->dev, &wdata->battery);
if (ret) {
hid_err(hdev, "can't create sysfs battery attribute, err: %d\n",
ret);
goto err_battery;
}
power_supply_powers(&wdata->battery, &hdev->dev);
wdata->ac.properties = wacom_ac_props;
wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
wdata->ac.get_property = wacom_ac_get_property;
wdata->ac.name = "wacom_ac";
wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
wdata->ac.use_for_apm = 0;
ret = power_supply_register(&hdev->dev, &wdata->ac);
if (ret) {
hid_err(hdev,
"can't create ac battery attribute, err: %d\n", ret);
goto err_ac;
}
power_supply_powers(&wdata->ac, &hdev->dev);
return 0;
err_ac:
power_supply_unregister(&wdata->battery);
err_battery:
wacom_destroy_leds(hdev);
device_remove_file(&hdev->dev, &dev_attr_oled0_img);
device_remove_file(&hdev->dev, &dev_attr_oled1_img);
device_remove_file(&hdev->dev, &dev_attr_oled2_img);
device_remove_file(&hdev->dev, &dev_attr_oled3_img);
device_remove_file(&hdev->dev, &dev_attr_oled4_img);
device_remove_file(&hdev->dev, &dev_attr_oled5_img);
device_remove_file(&hdev->dev, &dev_attr_oled6_img);
device_remove_file(&hdev->dev, &dev_attr_oled7_img);
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
err_free:
kfree(wdata);
return ret;
}
static void wacom_remove(struct hid_device *hdev)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
wacom_destroy_leds(hdev);
device_remove_file(&hdev->dev, &dev_attr_oled0_img);
device_remove_file(&hdev->dev, &dev_attr_oled1_img);
device_remove_file(&hdev->dev, &dev_attr_oled2_img);
device_remove_file(&hdev->dev, &dev_attr_oled3_img);
device_remove_file(&hdev->dev, &dev_attr_oled4_img);
device_remove_file(&hdev->dev, &dev_attr_oled5_img);
device_remove_file(&hdev->dev, &dev_attr_oled6_img);
device_remove_file(&hdev->dev, &dev_attr_oled7_img);
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
power_supply_unregister(&wdata->battery);
power_supply_unregister(&wdata->ac);
kfree(hid_get_drvdata(hdev));
}
static const struct hid_device_id wacom_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
{ }
};
MODULE_DEVICE_TABLE(hid, wacom_devices);
static struct hid_driver wacom_driver = {
.name = "wacom",
.id_table = wacom_devices,
.probe = wacom_probe,
.remove = wacom_remove,
.raw_event = wacom_raw_event,
.input_mapped = wacom_input_mapped,
};
module_hid_driver(wacom_driver);
MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
MODULE_LICENSE("GPL");
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com> * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be> * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
* Copyright (c) 2002-2011 Ping Cheng <pingc@wacom.com> * Copyright (c) 2002-2011 Ping Cheng <pingc@wacom.com>
* Copyright (c) 2014 Benjamin Tissoires <benjamin.tissoires@redhat.com>
* *
* ChangeLog: * ChangeLog:
* v0.1 (vp) - Initial release * v0.1 (vp) - Initial release
...@@ -72,6 +73,8 @@ ...@@ -72,6 +73,8 @@
* v1.52 (pc) - Query Wacom data upon system resume * v1.52 (pc) - Query Wacom data upon system resume
* - add defines for features->type * - add defines for features->type
* - add new devices (0x9F, 0xE2, and 0XE3) * - add new devices (0x9F, 0xE2, and 0XE3)
* v2.00 (bt) - conversion to a HID driver
* - integration of the Bluetooth devices
*/ */
/* /*
...@@ -93,35 +96,30 @@ ...@@ -93,35 +96,30 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.53" #define DRIVER_VERSION "v2.00"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom tablet driver" #define DRIVER_DESC "USB Wacom tablet driver"
#define DRIVER_LICENSE "GPL" #define DRIVER_LICENSE "GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a #define USB_VENDOR_ID_WACOM 0x056a
#define USB_VENDOR_ID_LENOVO 0x17ef #define USB_VENDOR_ID_LENOVO 0x17ef
struct wacom { struct wacom {
dma_addr_t data_dma;
struct usb_device *usbdev; struct usb_device *usbdev;
struct usb_interface *intf; struct usb_interface *intf;
struct urb *irq;
struct wacom_wac wacom_wac; struct wacom_wac wacom_wac;
struct hid_device *hdev;
struct mutex lock; struct mutex lock;
struct work_struct work; struct work_struct work;
bool open;
char phys[32];
struct wacom_led { struct wacom_led {
u8 select[2]; /* status led selector (0..3) */ u8 select[2]; /* status led selector (0..3) */
u8 llv; /* status led brightness no button (1..127) */ u8 llv; /* status led brightness no button (1..127) */
u8 hlv; /* status led brightness button pressed (1..127) */ u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */ u8 img_lum; /* OLED matrix display brightness */
} led; } led;
bool led_initialized;
struct power_supply battery; struct power_supply battery;
struct power_supply ac;
}; };
static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
...@@ -130,10 +128,19 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) ...@@ -130,10 +128,19 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
schedule_work(&wacom->work); schedule_work(&wacom->work);
} }
extern const struct usb_device_id wacom_ids[]; static inline void wacom_notify_battery(struct wacom_wac *wacom_wac)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
power_supply_changed(&wacom->battery);
}
extern const struct hid_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_device_quirks(struct wacom_features *features); void wacom_setup_device_quirks(struct wacom_features *features);
int wacom_setup_input_capabilities(struct input_dev *input_dev, int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac); struct wacom_wac *wacom_wac);
int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
#endif #endif
...@@ -13,246 +13,106 @@ ...@@ -13,246 +13,106 @@
#include "wacom_wac.h" #include "wacom_wac.h"
#include "wacom.h" #include "wacom.h"
#include <linux/hid.h>
/* defines to get HID report descriptor */
#define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01)
#define HID_DEVICET_REPORT (USB_TYPE_CLASS | 0x02)
#define HID_USAGE_UNDEFINED 0x00
#define HID_USAGE_PAGE 0x05
#define HID_USAGE_PAGE_DIGITIZER 0x0d
#define HID_USAGE_PAGE_DESKTOP 0x01
#define HID_USAGE 0x09
#define HID_USAGE_X ((HID_USAGE_PAGE_DESKTOP << 16) | 0x30)
#define HID_USAGE_Y ((HID_USAGE_PAGE_DESKTOP << 16) | 0x31)
#define HID_USAGE_PRESSURE ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x30)
#define HID_USAGE_X_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3d)
#define HID_USAGE_Y_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3e)
#define HID_USAGE_FINGER ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x22)
#define HID_USAGE_STYLUS ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x20)
#define HID_USAGE_CONTACTMAX ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x55)
#define HID_COLLECTION 0xa1
#define HID_COLLECTION_LOGICAL 0x02
#define HID_COLLECTION_END 0xc0
struct hid_descriptor {
struct usb_descriptor_header header;
__le16 bcdHID;
u8 bCountryCode;
u8 bNumDescriptors;
u8 bDescriptorType;
__le16 wDescriptorLength;
} __attribute__ ((packed));
/* defines to get/set USB message */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define WAC_HID_FEATURE_REPORT 0x03
#define WAC_MSG_RETRIES 5 #define WAC_MSG_RETRIES 5
#define WAC_CMD_LED_CONTROL 0x20 #define WAC_CMD_LED_CONTROL 0x20
#define WAC_CMD_ICON_START 0x21 #define WAC_CMD_ICON_START 0x21
#define WAC_CMD_ICON_XFER 0x23 #define WAC_CMD_ICON_XFER 0x23
#define WAC_CMD_ICON_BT_XFER 0x26
#define WAC_CMD_RETRIES 10 #define WAC_CMD_RETRIES 10
static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id, static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
void *buf, size_t size, unsigned int retries) void *buf, size_t size, unsigned int retries)
{ {
struct usb_device *dev = interface_to_usbdev(intf);
int retval; int retval;
do { do {
retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), retval = hid_hw_raw_request(hdev, id, buf, size, type,
USB_REQ_GET_REPORT, HID_REQ_GET_REPORT);
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 100);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
return retval; return retval;
} }
static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id, static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf,
void *buf, size_t size, unsigned int retries) size_t size, unsigned int retries)
{ {
struct usb_device *dev = interface_to_usbdev(intf);
int retval; int retval;
do { do {
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), retval = hid_hw_raw_request(hdev, buf[0], buf, size, type,
USB_REQ_SET_REPORT, HID_REQ_SET_REPORT);
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 1000);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
return retval; return retval;
} }
static void wacom_sys_irq(struct urb *urb) static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *raw_data, int size)
{ {
struct wacom *wacom = urb->context; struct wacom *wacom = hid_get_drvdata(hdev);
struct device *dev = &wacom->intf->dev;
int retval;
switch (urb->status) { if (size > WACOM_PKGLEN_MAX)
case 0: return 1;
/* success */
break; memcpy(wacom->wacom_wac.data, raw_data, size);
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, urb->status);
return;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, urb->status);
goto exit;
}
wacom_wac_irq(&wacom->wacom_wac, urb->actual_length); wacom_wac_irq(&wacom->wacom_wac, size);
exit: return 0;
usb_mark_last_busy(wacom->usbdev);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
} }
static int wacom_open(struct input_dev *dev) static int wacom_open(struct input_dev *dev)
{ {
struct wacom *wacom = input_get_drvdata(dev); struct wacom *wacom = input_get_drvdata(dev);
int retval = 0; int retval;
if (usb_autopm_get_interface(wacom->intf) < 0)
return -EIO;
mutex_lock(&wacom->lock); mutex_lock(&wacom->lock);
retval = hid_hw_open(wacom->hdev);
if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
retval = -EIO;
goto out;
}
wacom->open = true;
wacom->intf->needs_remote_wakeup = 1;
out:
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
usb_autopm_put_interface(wacom->intf);
return retval; return retval;
} }
static void wacom_close(struct input_dev *dev) static void wacom_close(struct input_dev *dev)
{ {
struct wacom *wacom = input_get_drvdata(dev); struct wacom *wacom = input_get_drvdata(dev);
int autopm_error;
autopm_error = usb_autopm_get_interface(wacom->intf);
mutex_lock(&wacom->lock); mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq); hid_hw_close(wacom->hdev);
wacom->open = false;
wacom->intf->needs_remote_wakeup = 0;
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
if (!autopm_error)
usb_autopm_put_interface(wacom->intf);
} }
/* /*
* Calculate the resolution of the X or Y axis, given appropriate HID data. * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res.
* This function is little more than hidinput_calc_abs_res stripped down.
*/ */
static int wacom_calc_hid_res(int logical_extents, int physical_extents, static int wacom_calc_hid_res(int logical_extents, int physical_extents,
unsigned char unit, unsigned char exponent) unsigned unit, int exponent)
{
int prev, unit_exponent;
/* Check if the extents are sane */
if (logical_extents <= 0 || physical_extents <= 0)
return 0;
/* Get signed value of nybble-sized twos-compliment exponent */
unit_exponent = exponent;
if (unit_exponent > 7)
unit_exponent -= 16;
/* Convert physical_extents to millimeters */
if (unit == 0x11) { /* If centimeters */
unit_exponent += 1;
} else if (unit == 0x13) { /* If inches */
prev = physical_extents;
physical_extents *= 254;
if (physical_extents < prev)
return 0;
unit_exponent -= 1;
} else {
return 0;
}
/* Apply negative unit exponent */
for (; unit_exponent < 0; unit_exponent++) {
prev = logical_extents;
logical_extents *= 10;
if (logical_extents < prev)
return 0;
}
/* Apply positive unit exponent */
for (; unit_exponent > 0; unit_exponent--) {
prev = physical_extents;
physical_extents *= 10;
if (physical_extents < prev)
return 0;
}
/* Calculate resolution */
return logical_extents / physical_extents;
}
static int wacom_parse_logical_collection(unsigned char *report,
struct wacom_features *features)
{ {
int length = 0; struct hid_field field = {
.logical_maximum = logical_extents,
if (features->type == BAMBOO_PT) { .physical_maximum = physical_extents,
.unit = unit,
/* Logical collection is only used by 3rd gen Bamboo Touch */ .unit_exponent = exponent,
features->pktlen = WACOM_PKGLEN_BBTOUCH3; };
features->device_type = BTN_TOOL_FINGER;
return hidinput_calc_abs_res(&field, ABS_X);
features->x_max = features->y_max =
get_unaligned_le16(&report[10]);
length = 11;
}
return length;
} }
static void wacom_retrieve_report_data(struct usb_interface *intf, static void wacom_feature_mapping(struct hid_device *hdev,
struct wacom_features *features) struct hid_field *field, struct hid_usage *usage)
{ {
int result = 0; struct wacom *wacom = hid_get_drvdata(hdev);
unsigned char *rep_data; struct wacom_features *features = &wacom->wacom_wac.features;
rep_data = kmalloc(2, GFP_KERNEL);
if (rep_data) {
rep_data[0] = 12;
result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
rep_data[0], rep_data, 2,
WAC_MSG_RETRIES);
if (result >= 0 && rep_data[1] > 2)
features->touch_max = rep_data[1];
kfree(rep_data); switch (usage->hid) {
case HID_DG_CONTACTMAX:
/* leave touch_max as is if predefined */
if (!features->touch_max)
features->touch_max = field->value[0];
break;
} }
} }
...@@ -285,243 +145,100 @@ static void wacom_retrieve_report_data(struct usb_interface *intf, ...@@ -285,243 +145,100 @@ static void wacom_retrieve_report_data(struct usb_interface *intf,
* interfaces haven't supported pressure or distance, this is enough * interfaces haven't supported pressure or distance, this is enough
* information to override invalid values in the wacom_features table. * information to override invalid values in the wacom_features table.
* *
* 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful
* Collection. Instead they define a Logical Collection with a single * data. We deal with them after returning from this function.
* Logical Maximum for both X and Y.
*
* Intuos5 touch interface does not contain useful data. We deal with
* this after returning from this function.
*/ */
static int wacom_parse_hid(struct usb_interface *intf, static void wacom_usage_mapping(struct hid_device *hdev,
struct hid_descriptor *hid_desc, struct hid_field *field, struct hid_usage *usage)
struct wacom_features *features)
{ {
struct usb_device *dev = interface_to_usbdev(intf); struct wacom *wacom = hid_get_drvdata(hdev);
char limit = 0; struct wacom_features *features = &wacom->wacom_wac.features;
/* result has to be defined as int for some devices */ bool finger = (field->logical == HID_DG_FINGER) ||
int result = 0, touch_max = 0; (field->physical == HID_DG_FINGER);
int i = 0, page = 0, finger = 0, pen = 0; bool pen = (field->logical == HID_DG_STYLUS) ||
unsigned char *report; (field->physical == HID_DG_STYLUS);
report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
if (!report)
return -ENOMEM;
/* retrive report descriptors */
do {
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR,
USB_RECIP_INTERFACE | USB_DIR_IN,
HID_DEVICET_REPORT << 8,
intf->altsetting[0].desc.bInterfaceNumber, /* interface */
report,
hid_desc->wDescriptorLength,
5000); /* 5 secs */
} while (result < 0 && limit++ < WAC_MSG_RETRIES);
/* No need to parse the Descriptor. It isn't an error though */
if (result < 0)
goto out;
for (i = 0; i < hid_desc->wDescriptorLength; i++) {
switch (report[i]) {
case HID_USAGE_PAGE:
page = report[i + 1];
i++;
break;
case HID_USAGE:
switch (page << 16 | report[i + 1]) {
case HID_USAGE_X:
if (finger) {
features->device_type = BTN_TOOL_FINGER;
/* touch device at least supports one touch point */
touch_max = 1;
switch (features->type) {
case TABLETPC2FG:
features->pktlen = WACOM_PKGLEN_TPC2FG;
break;
case MTSCREEN:
case WACOM_24HDT:
features->pktlen = WACOM_PKGLEN_MTOUCH;
break;
case MTTPC:
case MTTPC_B:
features->pktlen = WACOM_PKGLEN_MTTPC;
break;
case BAMBOO_PT:
features->pktlen = WACOM_PKGLEN_BBTOUCH;
break;
default:
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
break;
}
switch (features->type) {
case BAMBOO_PT:
features->x_phy =
get_unaligned_le16(&report[i + 5]);
features->x_max =
get_unaligned_le16(&report[i + 8]);
i += 15;
break;
case WACOM_24HDT:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 8]);
features->unit = report[i - 1];
features->unitExpo = report[i - 3];
i += 12;
break;
case MTTPC_B:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 6]);
features->unit = report[i - 5];
features->unitExpo = report[i - 3];
i += 9;
break;
default:
features->x_max =
get_unaligned_le16(&report[i + 3]);
features->x_phy =
get_unaligned_le16(&report[i + 6]);
features->unit = report[i + 9];
features->unitExpo = report[i + 11];
i += 12;
break;
}
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type >= TABLETPC)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->x_max =
get_unaligned_le16(&report[i + 3]);
i += 4;
}
break;
case HID_USAGE_Y:
if (finger) {
switch (features->type) {
case TABLETPC2FG:
case MTSCREEN:
case MTTPC:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
break;
case WACOM_24HDT:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i - 2]);
i += 7;
break;
case BAMBOO_PT:
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
get_unaligned_le16(&report[i + 6]);
i += 12;
break;
case MTTPC_B:
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 9;
break;
default:
features->y_max =
features->x_max;
features->y_phy =
get_unaligned_le16(&report[i + 3]);
i += 4;
break;
}
} else if (pen) {
features->y_max =
get_unaligned_le16(&report[i + 3]);
i += 4;
}
break;
case HID_USAGE_FINGER:
finger = 1;
i++;
break;
/* /*
* Requiring Stylus Usage will ignore boot mouse * Requiring Stylus Usage will ignore boot mouse
* X/Y values and some cases of invalid Digitizer X/Y * X/Y values and some cases of invalid Digitizer X/Y
* values commonly reported. * values commonly reported.
*/ */
case HID_USAGE_STYLUS: if (!pen && !finger)
pen = 1; return;
i++;
break;
case HID_USAGE_CONTACTMAX: if (finger && !features->touch_max)
/* leave touch_max as is if predefined */ /* touch device at least supports one touch point */
if (!features->touch_max) features->touch_max = 1;
wacom_retrieve_report_data(intf, features);
i++;
break;
case HID_USAGE_PRESSURE: switch (usage->hid) {
if (pen) { case HID_GD_X:
features->pressure_max = features->x_max = field->logical_maximum;
get_unaligned_le16(&report[i + 3]); if (finger) {
i += 4; features->device_type = BTN_TOOL_FINGER;
} features->x_phy = field->physical_maximum;
break; if (features->type != BAMBOO_PT) {
features->unit = field->unit;
features->unitExpo = field->unit_exponent;
} }
break; } else {
features->device_type = BTN_TOOL_PEN;
case HID_COLLECTION_END: }
/* reset UsagePage and Finger */ break;
finger = page = 0; case HID_GD_Y:
break; features->y_max = field->logical_maximum;
if (finger) {
features->y_phy = field->physical_maximum;
if (features->type != BAMBOO_PT) {
features->unit = field->unit;
features->unitExpo = field->unit_exponent;
}
}
break;
case HID_DG_TIPPRESSURE:
if (pen)
features->pressure_max = field->logical_maximum;
break;
}
}
case HID_COLLECTION: static void wacom_parse_hid(struct hid_device *hdev,
i++; struct wacom_features *features)
switch (report[i]) { {
case HID_COLLECTION_LOGICAL: struct hid_report_enum *rep_enum;
i += wacom_parse_logical_collection(&report[i], struct hid_report *hreport;
features); int i, j;
break;
/* check features first */
rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(hreport, &rep_enum->report_list, list) {
for (i = 0; i < hreport->maxfield; i++) {
/* Ignore if report count is out of bounds. */
if (hreport->field[i]->report_count < 1)
continue;
for (j = 0; j < hreport->field[i]->maxusage; j++) {
wacom_feature_mapping(hdev, hreport->field[i],
hreport->field[i]->usage + j);
} }
break;
} }
} }
out: /* now check the input usages */
if (!features->touch_max && touch_max) rep_enum = &hdev->report_enum[HID_INPUT_REPORT];
features->touch_max = touch_max; list_for_each_entry(hreport, &rep_enum->report_list, list) {
result = 0;
kfree(report); if (!hreport->maxfield)
return result; continue;
for (i = 0; i < hreport->maxfield; i++)
for (j = 0; j < hreport->field[i]->maxusage; j++)
wacom_usage_mapping(hdev, hreport->field[i],
hreport->field[i]->usage + j);
}
} }
static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode) static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
int length, int mode)
{ {
unsigned char *rep_data; unsigned char *rep_data;
int error = -ENOMEM, limit = 0; int error = -ENOMEM, limit = 0;
...@@ -534,8 +251,11 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int ...@@ -534,8 +251,11 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
rep_data[0] = report_id; rep_data[0] = report_id;
rep_data[1] = mode; rep_data[1] = mode;
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
report_id, rep_data, length, 1); length, 1);
if (error >= 0)
error = wacom_get_report(hdev, HID_FEATURE_REPORT,
report_id, rep_data, length, 1);
} while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES);
kfree(rep_data); kfree(rep_data);
...@@ -543,6 +263,59 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int ...@@ -543,6 +263,59 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
return error < 0 ? error : 0; return error < 0 ? error : 0;
} }
static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
struct wacom_features *features)
{
struct wacom *wacom = hid_get_drvdata(hdev);
int ret;
u8 rep_data[2];
switch (features->type) {
case GRAPHIRE_BT:
rep_data[0] = 0x03;
rep_data[1] = 0x00;
ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
3);
if (ret >= 0) {
rep_data[0] = speed == 0 ? 0x05 : 0x06;
rep_data[1] = 0x00;
ret = wacom_set_report(hdev, HID_FEATURE_REPORT,
rep_data, 2, 3);
if (ret >= 0) {
wacom->wacom_wac.bt_high_speed = speed;
return 0;
}
}
/*
* Note that if the raw queries fail, it's not a hard failure
* and it is safe to continue
*/
hid_warn(hdev, "failed to poke device, command %d, err %d\n",
rep_data[0], ret);
break;
case INTUOS4WL:
if (speed == 1)
wacom->wacom_wac.bt_features &= ~0x20;
else
wacom->wacom_wac.bt_features |= 0x20;
rep_data[0] = 0x03;
rep_data[1] = wacom->wacom_wac.bt_features;
ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2,
1);
if (ret >= 0)
wacom->wacom_wac.bt_high_speed = speed;
break;
}
return 0;
}
/* /*
* Switch the tablet into its most-capable mode. Wacom tablets are * Switch the tablet into its most-capable mode. Wacom tablets are
* typically configured to power-up in a mode which sends mouse-like * typically configured to power-up in a mode which sends mouse-like
...@@ -550,31 +323,34 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int ...@@ -550,31 +323,34 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
* from the tablet, it is necessary to switch the tablet out of this * from the tablet, it is necessary to switch the tablet out of this
* mode and into one which sends the full range of tablet data. * mode and into one which sends the full range of tablet data.
*/ */
static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_features *features) static int wacom_query_tablet_data(struct hid_device *hdev,
struct wacom_features *features)
{ {
if (hdev->bus == BUS_BLUETOOTH)
return wacom_bt_query_tablet_data(hdev, 1, features);
if (features->device_type == BTN_TOOL_FINGER) { if (features->device_type == BTN_TOOL_FINGER) {
if (features->type > TABLETPC) { if (features->type > TABLETPC) {
/* MT Tablet PC touch */ /* MT Tablet PC touch */
return wacom_set_device_mode(intf, 3, 4, 4); return wacom_set_device_mode(hdev, 3, 4, 4);
} }
else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) { else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
return wacom_set_device_mode(intf, 18, 3, 2); return wacom_set_device_mode(hdev, 18, 3, 2);
} }
} else if (features->device_type == BTN_TOOL_PEN) { } else if (features->device_type == BTN_TOOL_PEN) {
if (features->type <= BAMBOO_PT && features->type != WIRELESS) { if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
return wacom_set_device_mode(intf, 2, 2, 2); return wacom_set_device_mode(hdev, 2, 2, 2);
} }
} }
return 0; return 0;
} }
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, static void wacom_retrieve_hid_descriptor(struct hid_device *hdev,
struct wacom_features *features) struct wacom_features *features)
{ {
int error = 0; struct wacom *wacom = hid_get_drvdata(hdev);
struct usb_host_interface *interface = intf->cur_altsetting; struct usb_interface *intf = wacom->intf;
struct hid_descriptor *hid_desc;
/* default features */ /* default features */
features->device_type = BTN_TOOL_PEN; features->device_type = BTN_TOOL_PEN;
...@@ -599,66 +375,54 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, ...@@ -599,66 +375,54 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
} }
/* only devices that support touch need to retrieve the info */ /* only devices that support touch need to retrieve the info */
if (features->type < BAMBOO_PT) { if (features->type < BAMBOO_PT)
goto out; return;
}
error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc);
if (error) {
error = usb_get_extra_descriptor(&interface->endpoint[0],
HID_DEVICET_REPORT, &hid_desc);
if (error) {
dev_err(&intf->dev,
"can not retrieve extra class descriptor\n");
goto out;
}
}
error = wacom_parse_hid(intf, hid_desc, features);
out: wacom_parse_hid(hdev, features);
return error;
} }
struct wacom_usbdev_data { struct wacom_hdev_data {
struct list_head list; struct list_head list;
struct kref kref; struct kref kref;
struct usb_device *dev; struct hid_device *dev;
struct wacom_shared shared; struct wacom_shared shared;
}; };
static LIST_HEAD(wacom_udev_list); static LIST_HEAD(wacom_udev_list);
static DEFINE_MUTEX(wacom_udev_list_lock); static DEFINE_MUTEX(wacom_udev_list_lock);
static struct usb_device *wacom_get_sibling(struct usb_device *dev, int vendor, int product) static bool wacom_are_sibling(struct hid_device *hdev,
struct hid_device *sibling)
{ {
int port1; struct wacom *wacom = hid_get_drvdata(hdev);
struct usb_device *sibling; struct wacom_features *features = &wacom->wacom_wac.features;
int vid = features->oVid;
if (vendor == 0 && product == 0) int pid = features->oPid;
return dev; int n1,n2;
if (dev->parent == NULL) if (vid == 0 && pid == 0) {
return NULL; vid = hdev->vendor;
pid = hdev->product;
}
usb_hub_for_each_child(dev->parent, port1, sibling) { if (vid != sibling->vendor || pid != sibling->product)
struct usb_device_descriptor *d; return false;
if (sibling == NULL)
continue;
d = &sibling->descriptor; /* Compare the physical path. */
if (d->idVendor == vendor && d->idProduct == product) n1 = strrchr(hdev->phys, '.') - hdev->phys;
return sibling; n2 = strrchr(sibling->phys, '.') - sibling->phys;
} if (n1 != n2 || n1 <= 0 || n2 <= 0)
return false;
return NULL; return !strncmp(hdev->phys, sibling->phys, n1);
} }
static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev) static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
{ {
struct wacom_usbdev_data *data; struct wacom_hdev_data *data;
list_for_each_entry(data, &wacom_udev_list, list) { list_for_each_entry(data, &wacom_udev_list, list) {
if (data->dev == dev) { if (wacom_are_sibling(hdev, data->dev)) {
kref_get(&data->kref); kref_get(&data->kref);
return data; return data;
} }
...@@ -667,28 +431,29 @@ static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev) ...@@ -667,28 +431,29 @@ static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
return NULL; return NULL;
} }
static int wacom_add_shared_data(struct wacom_wac *wacom, static int wacom_add_shared_data(struct hid_device *hdev)
struct usb_device *dev)
{ {
struct wacom_usbdev_data *data; struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_hdev_data *data;
int retval = 0; int retval = 0;
mutex_lock(&wacom_udev_list_lock); mutex_lock(&wacom_udev_list_lock);
data = wacom_get_usbdev_data(dev); data = wacom_get_hdev_data(hdev);
if (!data) { if (!data) {
data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL); data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
if (!data) { if (!data) {
retval = -ENOMEM; retval = -ENOMEM;
goto out; goto out;
} }
kref_init(&data->kref); kref_init(&data->kref);
data->dev = dev; data->dev = hdev;
list_add_tail(&data->list, &wacom_udev_list); list_add_tail(&data->list, &wacom_udev_list);
} }
wacom->shared = &data->shared; wacom_wac->shared = &data->shared;
out: out:
mutex_unlock(&wacom_udev_list_lock); mutex_unlock(&wacom_udev_list_lock);
...@@ -697,8 +462,8 @@ static int wacom_add_shared_data(struct wacom_wac *wacom, ...@@ -697,8 +462,8 @@ static int wacom_add_shared_data(struct wacom_wac *wacom,
static void wacom_release_shared_data(struct kref *kref) static void wacom_release_shared_data(struct kref *kref)
{ {
struct wacom_usbdev_data *data = struct wacom_hdev_data *data =
container_of(kref, struct wacom_usbdev_data, kref); container_of(kref, struct wacom_hdev_data, kref);
mutex_lock(&wacom_udev_list_lock); mutex_lock(&wacom_udev_list_lock);
list_del(&data->list); list_del(&data->list);
...@@ -709,10 +474,10 @@ static void wacom_release_shared_data(struct kref *kref) ...@@ -709,10 +474,10 @@ static void wacom_release_shared_data(struct kref *kref)
static void wacom_remove_shared_data(struct wacom_wac *wacom) static void wacom_remove_shared_data(struct wacom_wac *wacom)
{ {
struct wacom_usbdev_data *data; struct wacom_hdev_data *data;
if (wacom->shared) { if (wacom->shared) {
data = container_of(wacom->shared, struct wacom_usbdev_data, shared); data = container_of(wacom->shared, struct wacom_hdev_data, shared);
kref_put(&data->kref, wacom_release_shared_data); kref_put(&data->kref, wacom_release_shared_data);
wacom->shared = NULL; wacom->shared = NULL;
} }
...@@ -755,38 +520,40 @@ static int wacom_led_control(struct wacom *wacom) ...@@ -755,38 +520,40 @@ static int wacom_led_control(struct wacom *wacom)
buf[4] = wacom->led.img_lum; buf[4] = wacom->led.img_lum;
} }
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL, retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 9,
buf, 9, WAC_CMD_RETRIES); WAC_CMD_RETRIES);
kfree(buf); kfree(buf);
return retval; return retval;
} }
static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img) static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id,
const unsigned len, const void *img)
{ {
unsigned char *buf; unsigned char *buf;
int i, retval; int i, retval;
const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
buf = kzalloc(259, GFP_KERNEL); buf = kzalloc(chunk_len + 3 , GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
/* Send 'start' command */ /* Send 'start' command */
buf[0] = WAC_CMD_ICON_START; buf[0] = WAC_CMD_ICON_START;
buf[1] = 1; buf[1] = 1;
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
buf, 2, WAC_CMD_RETRIES); WAC_CMD_RETRIES);
if (retval < 0) if (retval < 0)
goto out; goto out;
buf[0] = WAC_CMD_ICON_XFER; buf[0] = xfer_id;
buf[1] = button_id & 0x07; buf[1] = button_id & 0x07;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
buf[2] = i; buf[2] = i;
memcpy(buf + 3, img + i * 256, 256); memcpy(buf + 3, img + i * chunk_len, chunk_len);
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER, retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
buf, 259, WAC_CMD_RETRIES); buf, chunk_len + 3, WAC_CMD_RETRIES);
if (retval < 0) if (retval < 0)
break; break;
} }
...@@ -794,8 +561,8 @@ static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *im ...@@ -794,8 +561,8 @@ static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *im
/* Send 'stop' */ /* Send 'stop' */
buf[0] = WAC_CMD_ICON_START; buf[0] = WAC_CMD_ICON_START;
buf[1] = 0; buf[1] = 0;
wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2,
buf, 2, WAC_CMD_RETRIES); WAC_CMD_RETRIES);
out: out:
kfree(buf); kfree(buf);
...@@ -805,7 +572,8 @@ static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *im ...@@ -805,7 +572,8 @@ static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *im
static ssize_t wacom_led_select_store(struct device *dev, int set_id, static ssize_t wacom_led_select_store(struct device *dev, int set_id,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct wacom *wacom = dev_get_drvdata(dev); struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct wacom *wacom = hid_get_drvdata(hdev);
unsigned int id; unsigned int id;
int err; int err;
...@@ -832,7 +600,8 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \ ...@@ -832,7 +600,8 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \ static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct device_attribute *attr, char *buf) \ struct device_attribute *attr, char *buf) \
{ \ { \
struct wacom *wacom = dev_get_drvdata(dev); \ struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \ return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \
} \ } \
static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \ static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \
...@@ -866,7 +635,8 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest, ...@@ -866,7 +635,8 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
static ssize_t wacom_##name##_luminance_store(struct device *dev, \ static ssize_t wacom_##name##_luminance_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \ struct device_attribute *attr, const char *buf, size_t count) \
{ \ { \
struct wacom *wacom = dev_get_drvdata(dev); \ struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
\ \
return wacom_luminance_store(wacom, &wacom->led.field, \ return wacom_luminance_store(wacom, &wacom->led.field, \
buf, count); \ buf, count); \
...@@ -881,15 +651,26 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum); ...@@ -881,15 +651,26 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum);
static ssize_t wacom_button_image_store(struct device *dev, int button_id, static ssize_t wacom_button_image_store(struct device *dev, int button_id,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct wacom *wacom = dev_get_drvdata(dev); struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct wacom *wacom = hid_get_drvdata(hdev);
int err; int err;
unsigned len;
u8 xfer_id;
if (hdev->bus == BUS_BLUETOOTH) {
len = 256;
xfer_id = WAC_CMD_ICON_BT_XFER;
} else {
len = 1024;
xfer_id = WAC_CMD_ICON_XFER;
}
if (count != 1024) if (count != len)
return -EINVAL; return -EINVAL;
mutex_lock(&wacom->lock); mutex_lock(&wacom->lock);
err = wacom_led_putimage(wacom, button_id, buf); err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf);
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
...@@ -965,13 +746,14 @@ static int wacom_initialize_leds(struct wacom *wacom) ...@@ -965,13 +746,14 @@ static int wacom_initialize_leds(struct wacom *wacom)
switch (wacom->wacom_wac.features.type) { switch (wacom->wacom_wac.features.type) {
case INTUOS4S: case INTUOS4S:
case INTUOS4: case INTUOS4:
case INTUOS4WL:
case INTUOS4L: case INTUOS4L:
wacom->led.select[0] = 0; wacom->led.select[0] = 0;
wacom->led.select[1] = 0; wacom->led.select[1] = 0;
wacom->led.llv = 10; wacom->led.llv = 10;
wacom->led.hlv = 20; wacom->led.hlv = 20;
wacom->led.img_lum = 10; wacom->led.img_lum = 10;
error = sysfs_create_group(&wacom->intf->dev.kobj, error = sysfs_create_group(&wacom->hdev->dev.kobj,
&intuos4_led_attr_group); &intuos4_led_attr_group);
break; break;
...@@ -983,7 +765,7 @@ static int wacom_initialize_leds(struct wacom *wacom) ...@@ -983,7 +765,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0; wacom->led.hlv = 0;
wacom->led.img_lum = 0; wacom->led.img_lum = 0;
error = sysfs_create_group(&wacom->intf->dev.kobj, error = sysfs_create_group(&wacom->hdev->dev.kobj,
&cintiq_led_attr_group); &cintiq_led_attr_group);
break; break;
...@@ -1000,7 +782,7 @@ static int wacom_initialize_leds(struct wacom *wacom) ...@@ -1000,7 +782,7 @@ static int wacom_initialize_leds(struct wacom *wacom)
wacom->led.hlv = 0; wacom->led.hlv = 0;
wacom->led.img_lum = 0; wacom->led.img_lum = 0;
error = sysfs_create_group(&wacom->intf->dev.kobj, error = sysfs_create_group(&wacom->hdev->dev.kobj,
&intuos5_led_attr_group); &intuos5_led_attr_group);
} else } else
return 0; return 0;
...@@ -1011,28 +793,35 @@ static int wacom_initialize_leds(struct wacom *wacom) ...@@ -1011,28 +793,35 @@ static int wacom_initialize_leds(struct wacom *wacom)
} }
if (error) { if (error) {
dev_err(&wacom->intf->dev, hid_err(wacom->hdev,
"cannot create sysfs group err: %d\n", error); "cannot create sysfs group err: %d\n", error);
return error; return error;
} }
wacom_led_control(wacom); wacom_led_control(wacom);
wacom->led_initialized = true;
return 0; return 0;
} }
static void wacom_destroy_leds(struct wacom *wacom) static void wacom_destroy_leds(struct wacom *wacom)
{ {
if (!wacom->led_initialized)
return;
wacom->led_initialized = false;
switch (wacom->wacom_wac.features.type) { switch (wacom->wacom_wac.features.type) {
case INTUOS4S: case INTUOS4S:
case INTUOS4: case INTUOS4:
case INTUOS4WL:
case INTUOS4L: case INTUOS4L:
sysfs_remove_group(&wacom->intf->dev.kobj, sysfs_remove_group(&wacom->hdev->dev.kobj,
&intuos4_led_attr_group); &intuos4_led_attr_group);
break; break;
case WACOM_24HD: case WACOM_24HD:
case WACOM_21UX2: case WACOM_21UX2:
sysfs_remove_group(&wacom->intf->dev.kobj, sysfs_remove_group(&wacom->hdev->dev.kobj,
&cintiq_led_attr_group); &cintiq_led_attr_group);
break; break;
...@@ -1043,17 +832,24 @@ static void wacom_destroy_leds(struct wacom *wacom) ...@@ -1043,17 +832,24 @@ static void wacom_destroy_leds(struct wacom *wacom)
case INTUOSPM: case INTUOSPM:
case INTUOSPL: case INTUOSPL:
if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN)
sysfs_remove_group(&wacom->intf->dev.kobj, sysfs_remove_group(&wacom->hdev->dev.kobj,
&intuos5_led_attr_group); &intuos5_led_attr_group);
break; break;
} }
} }
static enum power_supply_property wacom_battery_props[] = { static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_CAPACITY POWER_SUPPLY_PROP_CAPACITY
}; };
static enum power_supply_property wacom_ac_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_SCOPE,
};
static int wacom_battery_get_property(struct power_supply *psy, static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp, enum power_supply_property psp,
union power_supply_propval *val) union power_supply_propval *val)
...@@ -1067,7 +863,16 @@ static int wacom_battery_get_property(struct power_supply *psy, ...@@ -1067,7 +863,16 @@ static int wacom_battery_get_property(struct power_supply *psy,
break; break;
case POWER_SUPPLY_PROP_CAPACITY: case POWER_SUPPLY_PROP_CAPACITY:
val->intval = val->intval =
wacom->wacom_wac.battery_capacity * 100 / 31; wacom->wacom_wac.battery_capacity;
break;
case POWER_SUPPLY_PROP_STATUS:
if (wacom->wacom_wac.bat_charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (wacom->wacom_wac.battery_capacity == 100 &&
wacom->wacom_wac.ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL;
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
...@@ -1077,74 +882,201 @@ static int wacom_battery_get_property(struct power_supply *psy, ...@@ -1077,74 +882,201 @@ static int wacom_battery_get_property(struct power_supply *psy,
return ret; return ret;
} }
static int wacom_ac_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom *wacom = container_of(psy, struct wacom, ac);
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* fall through */
case POWER_SUPPLY_PROP_ONLINE:
val->intval = wacom->wacom_wac.ps_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int wacom_initialize_battery(struct wacom *wacom) static int wacom_initialize_battery(struct wacom *wacom)
{ {
int error = 0; static atomic_t battery_no = ATOMIC_INIT(0);
int error;
unsigned long n;
if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) {
n = atomic_inc_return(&battery_no) - 1;
if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR) {
wacom->battery.properties = wacom_battery_props; wacom->battery.properties = wacom_battery_props;
wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props); wacom->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
wacom->battery.get_property = wacom_battery_get_property; wacom->battery.get_property = wacom_battery_get_property;
wacom->battery.name = "wacom_battery"; sprintf(wacom->wacom_wac.bat_name, "wacom_battery_%ld", n);
wacom->battery.name = wacom->wacom_wac.bat_name;
wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY; wacom->battery.type = POWER_SUPPLY_TYPE_BATTERY;
wacom->battery.use_for_apm = 0; wacom->battery.use_for_apm = 0;
error = power_supply_register(&wacom->usbdev->dev, wacom->ac.properties = wacom_ac_props;
wacom->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
wacom->ac.get_property = wacom_ac_get_property;
sprintf(wacom->wacom_wac.ac_name, "wacom_ac_%ld", n);
wacom->ac.name = wacom->wacom_wac.ac_name;
wacom->ac.type = POWER_SUPPLY_TYPE_MAINS;
wacom->ac.use_for_apm = 0;
error = power_supply_register(&wacom->hdev->dev,
&wacom->battery); &wacom->battery);
if (error)
return error;
power_supply_powers(&wacom->battery, &wacom->hdev->dev);
if (!error) error = power_supply_register(&wacom->hdev->dev, &wacom->ac);
power_supply_powers(&wacom->battery, if (error) {
&wacom->usbdev->dev); power_supply_unregister(&wacom->battery);
return error;
}
power_supply_powers(&wacom->ac, &wacom->hdev->dev);
} }
return error; return 0;
} }
static void wacom_destroy_battery(struct wacom *wacom) static void wacom_destroy_battery(struct wacom *wacom)
{ {
if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_MONITOR && if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
wacom->battery.dev) { wacom->battery.dev) {
power_supply_unregister(&wacom->battery); power_supply_unregister(&wacom->battery);
wacom->battery.dev = NULL; wacom->battery.dev = NULL;
power_supply_unregister(&wacom->ac);
wacom->ac.dev = NULL;
} }
} }
static int wacom_register_input(struct wacom *wacom) static ssize_t wacom_show_speed(struct device *dev,
struct device_attribute
*attr, char *buf)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct wacom *wacom = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed);
}
static ssize_t wacom_store_speed(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct wacom *wacom = hid_get_drvdata(hdev);
u8 new_speed;
if (kstrtou8(buf, 0, &new_speed))
return -EINVAL;
if (new_speed != 0 && new_speed != 1)
return -EINVAL;
wacom_bt_query_tablet_data(hdev, new_speed, &wacom->wacom_wac.features);
return count;
}
static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
wacom_show_speed, wacom_store_speed);
static struct input_dev *wacom_allocate_input(struct wacom *wacom)
{ {
struct input_dev *input_dev; struct input_dev *input_dev;
struct usb_interface *intf = wacom->intf; struct hid_device *hdev = wacom->hdev;
struct usb_device *dev = interface_to_usbdev(intf);
struct wacom_wac *wacom_wac = &(wacom->wacom_wac); struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
int error;
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) { if (!input_dev)
error = -ENOMEM; return NULL;
goto fail1;
}
input_dev->name = wacom_wac->name; input_dev->name = wacom_wac->name;
input_dev->dev.parent = &intf->dev; input_dev->phys = hdev->phys;
input_dev->dev.parent = &hdev->dev;
input_dev->open = wacom_open; input_dev->open = wacom_open;
input_dev->close = wacom_close; input_dev->close = wacom_close;
usb_to_input_id(dev, &input_dev->id); input_dev->uniq = hdev->uniq;
input_dev->id.bustype = hdev->bus;
input_dev->id.vendor = hdev->vendor;
input_dev->id.product = hdev->product;
input_dev->id.version = hdev->version;
input_set_drvdata(input_dev, wacom); input_set_drvdata(input_dev, wacom);
return input_dev;
}
static void wacom_unregister_inputs(struct wacom *wacom)
{
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
if (wacom->wacom_wac.pad_input)
input_unregister_device(wacom->wacom_wac.pad_input);
wacom->wacom_wac.input = NULL;
wacom->wacom_wac.pad_input = NULL;
}
static int wacom_register_inputs(struct wacom *wacom)
{
struct input_dev *input_dev, *pad_input_dev;
struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
int error;
input_dev = wacom_allocate_input(wacom);
pad_input_dev = wacom_allocate_input(wacom);
if (!input_dev || !pad_input_dev) {
error = -ENOMEM;
goto fail1;
}
wacom_wac->input = input_dev; wacom_wac->input = input_dev;
wacom_wac->pad_input = pad_input_dev;
wacom_wac->pad_input->name = wacom_wac->pad_name;
error = wacom_setup_input_capabilities(input_dev, wacom_wac); error = wacom_setup_input_capabilities(input_dev, wacom_wac);
if (error) if (error)
goto fail1; goto fail2;
error = input_register_device(input_dev); error = input_register_device(input_dev);
if (error) if (error)
goto fail2; goto fail2;
error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
if (error) {
/* no pad in use on this interface */
input_free_device(pad_input_dev);
wacom_wac->pad_input = NULL;
pad_input_dev = NULL;
} else {
error = input_register_device(pad_input_dev);
if (error)
goto fail3;
}
return 0; return 0;
fail3:
input_unregister_device(input_dev);
input_dev = NULL;
fail2: fail2:
input_free_device(input_dev);
wacom_wac->input = NULL; wacom_wac->input = NULL;
wacom_wac->pad_input = NULL;
fail1: fail1:
if (input_dev)
input_free_device(input_dev);
if (pad_input_dev)
input_free_device(pad_input_dev);
return error; return error;
} }
...@@ -1153,6 +1085,7 @@ static void wacom_wireless_work(struct work_struct *work) ...@@ -1153,6 +1085,7 @@ static void wacom_wireless_work(struct work_struct *work)
struct wacom *wacom = container_of(work, struct wacom, work); struct wacom *wacom = container_of(work, struct wacom, work);
struct usb_device *usbdev = wacom->usbdev; struct usb_device *usbdev = wacom->usbdev;
struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_device *hdev1, *hdev2;
struct wacom *wacom1, *wacom2; struct wacom *wacom1, *wacom2;
struct wacom_wac *wacom_wac1, *wacom_wac2; struct wacom_wac *wacom_wac1, *wacom_wac2;
int error; int error;
...@@ -1165,50 +1098,49 @@ static void wacom_wireless_work(struct work_struct *work) ...@@ -1165,50 +1098,49 @@ static void wacom_wireless_work(struct work_struct *work)
wacom_destroy_battery(wacom); wacom_destroy_battery(wacom);
/* Stylus interface */ /* Stylus interface */
wacom1 = usb_get_intfdata(usbdev->config->interface[1]); hdev1 = usb_get_intfdata(usbdev->config->interface[1]);
wacom1 = hid_get_drvdata(hdev1);
wacom_wac1 = &(wacom1->wacom_wac); wacom_wac1 = &(wacom1->wacom_wac);
if (wacom_wac1->input) wacom_unregister_inputs(wacom1);
input_unregister_device(wacom_wac1->input);
wacom_wac1->input = NULL;
/* Touch interface */ /* Touch interface */
wacom2 = usb_get_intfdata(usbdev->config->interface[2]); hdev2 = usb_get_intfdata(usbdev->config->interface[2]);
wacom2 = hid_get_drvdata(hdev2);
wacom_wac2 = &(wacom2->wacom_wac); wacom_wac2 = &(wacom2->wacom_wac);
if (wacom_wac2->input) wacom_unregister_inputs(wacom2);
input_unregister_device(wacom_wac2->input);
wacom_wac2->input = NULL;
if (wacom_wac->pid == 0) { if (wacom_wac->pid == 0) {
dev_info(&wacom->intf->dev, "wireless tablet disconnected\n"); hid_info(wacom->hdev, "wireless tablet disconnected\n");
wacom_wac1->shared->type = 0;
} else { } else {
const struct usb_device_id *id = wacom_ids; const struct hid_device_id *id = wacom_ids;
dev_info(&wacom->intf->dev, hid_info(wacom->hdev, "wireless tablet connected with PID %x\n",
"wireless tablet connected with PID %x\n",
wacom_wac->pid); wacom_wac->pid);
while (id->match_flags) { while (id->bus) {
if (id->idVendor == USB_VENDOR_ID_WACOM && if (id->vendor == USB_VENDOR_ID_WACOM &&
id->idProduct == wacom_wac->pid) id->product == wacom_wac->pid)
break; break;
id++; id++;
} }
if (!id->match_flags) { if (!id->bus) {
dev_info(&wacom->intf->dev, hid_info(wacom->hdev, "ignoring unknown PID.\n");
"ignoring unknown PID.\n");
return; return;
} }
/* Stylus interface */ /* Stylus interface */
wacom_wac1->features = wacom_wac1->features =
*((struct wacom_features *)id->driver_info); *((struct wacom_features *)id->driver_data);
wacom_wac1->features.device_type = BTN_TOOL_PEN; wacom_wac1->features.device_type = BTN_TOOL_PEN;
snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen",
wacom_wac1->features.name); wacom_wac1->features.name);
snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
wacom_wac1->features.name);
wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max; wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
wacom_wac1->shared->type = wacom_wac1->features.type; wacom_wac1->shared->type = wacom_wac1->features.type;
error = wacom_register_input(wacom1); error = wacom_register_inputs(wacom1);
if (error) if (error)
goto fail; goto fail;
...@@ -1216,7 +1148,7 @@ static void wacom_wireless_work(struct work_struct *work) ...@@ -1216,7 +1148,7 @@ static void wacom_wireless_work(struct work_struct *work)
if (wacom_wac1->features.touch_max || if (wacom_wac1->features.touch_max ||
wacom_wac1->features.type == INTUOSHT) { wacom_wac1->features.type == INTUOSHT) {
wacom_wac2->features = wacom_wac2->features =
*((struct wacom_features *)id->driver_info); *((struct wacom_features *)id->driver_data);
wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
wacom_wac2->features.device_type = BTN_TOOL_FINGER; wacom_wac2->features.device_type = BTN_TOOL_FINGER;
wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
...@@ -1226,7 +1158,9 @@ static void wacom_wireless_work(struct work_struct *work) ...@@ -1226,7 +1158,9 @@ static void wacom_wireless_work(struct work_struct *work)
else else
snprintf(wacom_wac2->name, WACOM_NAME_MAX, snprintf(wacom_wac2->name, WACOM_NAME_MAX,
"%s (WL) Pad",wacom_wac2->features.name); "%s (WL) Pad",wacom_wac2->features.name);
error = wacom_register_input(wacom2); snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
"%s (WL) Pad", wacom_wac2->features.name);
error = wacom_register_inputs(wacom2);
if (error) if (error)
goto fail; goto fail;
...@@ -1243,15 +1177,8 @@ static void wacom_wireless_work(struct work_struct *work) ...@@ -1243,15 +1177,8 @@ static void wacom_wireless_work(struct work_struct *work)
return; return;
fail: fail:
if (wacom_wac2->input) { wacom_unregister_inputs(wacom1);
input_unregister_device(wacom_wac2->input); wacom_unregister_inputs(wacom2);
wacom_wac2->input = NULL;
}
if (wacom_wac1->input) {
input_unregister_device(wacom_wac1->input);
wacom_wac1->input = NULL;
}
return; return;
} }
...@@ -1282,69 +1209,89 @@ static void wacom_calculate_res(struct wacom_features *features) ...@@ -1282,69 +1209,89 @@ static void wacom_calculate_res(struct wacom_features *features)
features->unitExpo); features->unitExpo);
} }
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) static int wacom_hid_report_len(struct hid_report *report)
{
/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
return ((report->size - 1) >> 3) + 1 + (report->id > 0);
}
static size_t wacom_compute_pktlen(struct hid_device *hdev)
{
struct hid_report_enum *report_enum;
struct hid_report *report;
size_t size = 0;
report_enum = hdev->report_enum + HID_INPUT_REPORT;
list_for_each_entry(report, &report_enum->report_list, list) {
size_t report_size = wacom_hid_report_len(report);
if (report_size > size)
size = report_size;
}
return size;
}
static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = interface_to_usbdev(intf);
struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom; struct wacom *wacom;
struct wacom_wac *wacom_wac; struct wacom_wac *wacom_wac;
struct wacom_features *features; struct wacom_features *features;
int error; int error;
if (!id->driver_info) if (!id->driver_data)
return -EINVAL; return -EINVAL;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
if (!wacom) if (!wacom)
return -ENOMEM; return -ENOMEM;
hid_set_drvdata(hdev, wacom);
wacom->hdev = hdev;
/* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "parse failed\n");
goto fail1;
}
wacom_wac = &wacom->wacom_wac; wacom_wac = &wacom->wacom_wac;
wacom_wac->features = *((struct wacom_features *)id->driver_info); wacom_wac->features = *((struct wacom_features *)id->driver_data);
features = &wacom_wac->features; features = &wacom_wac->features;
features->pktlen = wacom_compute_pktlen(hdev);
if (features->pktlen > WACOM_PKGLEN_MAX) { if (features->pktlen > WACOM_PKGLEN_MAX) {
error = -EINVAL; error = -EINVAL;
goto fail1; goto fail1;
} }
wacom_wac->data = usb_alloc_coherent(dev, WACOM_PKGLEN_MAX, if (features->check_for_hid_type && features->hid_type != hdev->type) {
GFP_KERNEL, &wacom->data_dma); error = -ENODEV;
if (!wacom_wac->data) {
error = -ENOMEM;
goto fail1; goto fail1;
} }
wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!wacom->irq) {
error = -ENOMEM;
goto fail2;
}
wacom->usbdev = dev; wacom->usbdev = dev;
wacom->intf = intf; wacom->intf = intf;
mutex_init(&wacom->lock); mutex_init(&wacom->lock);
INIT_WORK(&wacom->work, wacom_wireless_work); INIT_WORK(&wacom->work, wacom_wireless_work);
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
endpoint = &intf->cur_altsetting->endpoint[0].desc;
/* set the default size in case we do not get them from hid */ /* set the default size in case we do not get them from hid */
wacom_set_default_phy(features); wacom_set_default_phy(features);
/* Retrieve the physical and logical size for touch devices */ /* Retrieve the physical and logical size for touch devices */
error = wacom_retrieve_hid_descriptor(intf, features); wacom_retrieve_hid_descriptor(hdev, features);
if (error)
goto fail3;
/* /*
* Intuos5 has no useful data about its touch interface in its * Intuos5 has no useful data about its touch interface in its
* HID descriptor. If this is the touch interface (wMaxPacketSize * HID descriptor. If this is the touch interface (PacketSize
* of WACOM_PKGLEN_BBTOUCH3), override the table values. * of WACOM_PKGLEN_BBTOUCH3), override the table values.
*/ */
if (features->type >= INTUOS5S && features->type <= INTUOSHT) { if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) { if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
features->device_type = BTN_TOOL_FINGER; features->device_type = BTN_TOOL_FINGER;
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
features->x_max = 4096; features->x_max = 4096;
features->y_max = 4096; features->y_max = 4096;
...@@ -1353,20 +1300,35 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -1353,20 +1300,35 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
} }
} }
/*
* Same thing for Bamboo 3rd gen.
*/
if ((features->type == BAMBOO_PT) &&
(features->pktlen == WACOM_PKGLEN_BBTOUCH3) &&
(features->device_type == BTN_TOOL_PEN)) {
features->device_type = BTN_TOOL_FINGER;
features->x_max = 4096;
features->y_max = 4096;
}
if (hdev->bus == BUS_BLUETOOTH)
features->quirks |= WACOM_QUIRK_BATTERY;
wacom_setup_device_quirks(features); wacom_setup_device_quirks(features);
/* set unit to "100th of a mm" for devices not reported by HID */ /* set unit to "100th of a mm" for devices not reported by HID */
if (!features->unit) { if (!features->unit) {
features->unit = 0x11; features->unit = 0x11;
features->unitExpo = 16 - 3; features->unitExpo = -3;
} }
wacom_calculate_res(features); wacom_calculate_res(features);
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
"%s Pad", features->name);
if (features->quirks & WACOM_QUIRK_MULTI_INPUT) { if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
struct usb_device *other_dev;
/* Append the device type to the name */ /* Append the device type to the name */
if (features->device_type != BTN_TOOL_FINGER) if (features->device_type != BTN_TOOL_FINGER)
strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
...@@ -1375,43 +1337,49 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -1375,43 +1337,49 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
else else
strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
other_dev = wacom_get_sibling(dev, features->oVid, features->oPid); error = wacom_add_shared_data(hdev);
if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
other_dev = dev;
error = wacom_add_shared_data(wacom_wac, other_dev);
if (error) if (error)
goto fail3; goto fail1;
} }
usb_fill_int_urb(wacom->irq, dev,
usb_rcvintpipe(dev, endpoint->bEndpointAddress),
wacom_wac->data, features->pktlen,
wacom_sys_irq, wacom, endpoint->bInterval);
wacom->irq->transfer_dma = wacom->data_dma;
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
error = wacom_initialize_leds(wacom); error = wacom_initialize_leds(wacom);
if (error) if (error)
goto fail4; goto fail2;
if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
(features->quirks & WACOM_QUIRK_BATTERY)) {
error = wacom_initialize_battery(wacom);
if (error)
goto fail3;
}
if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) { if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) {
error = wacom_register_input(wacom); error = wacom_register_inputs(wacom);
if (error) if (error)
goto fail5; goto fail4;
} }
/* Note that if query fails it is not a hard failure */ if (hdev->bus == BUS_BLUETOOTH) {
wacom_query_tablet_data(intf, features); error = device_create_file(&hdev->dev, &dev_attr_speed);
if (error)
hid_warn(hdev,
"can't create sysfs speed attribute err: %d\n",
error);
}
usb_set_intfdata(intf, wacom); /* Note that if query fails it is not a hard failure */
wacom_query_tablet_data(hdev, features);
if (features->quirks & WACOM_QUIRK_MONITOR) { /* Regular HID work starts now */
if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { error = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
error = -EIO; if (error) {
goto fail5; hid_err(hdev, "hw start failed\n");
} goto fail5;
} }
if (features->quirks & WACOM_QUIRK_MONITOR)
error = hid_hw_open(hdev);
if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) { if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) {
if (wacom_wac->features.device_type == BTN_TOOL_FINGER) if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
wacom_wac->shared->touch_input = wacom_wac->input; wacom_wac->shared->touch_input = wacom_wac->input;
...@@ -1419,79 +1387,70 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i ...@@ -1419,79 +1387,70 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
return 0; return 0;
fail5: wacom_destroy_leds(wacom); fail5: if (hdev->bus == BUS_BLUETOOTH)
fail4: wacom_remove_shared_data(wacom_wac); device_remove_file(&hdev->dev, &dev_attr_speed);
fail3: usb_free_urb(wacom->irq); wacom_unregister_inputs(wacom);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); fail4: wacom_destroy_battery(wacom);
fail3: wacom_destroy_leds(wacom);
fail2: wacom_remove_shared_data(wacom_wac);
fail1: kfree(wacom); fail1: kfree(wacom);
hid_set_drvdata(hdev, NULL);
return error; return error;
} }
static void wacom_disconnect(struct usb_interface *intf) static void wacom_remove(struct hid_device *hdev)
{ {
struct wacom *wacom = usb_get_intfdata(intf); struct wacom *wacom = hid_get_drvdata(hdev);
usb_set_intfdata(intf, NULL); hid_hw_stop(hdev);
usb_kill_urb(wacom->irq);
cancel_work_sync(&wacom->work); cancel_work_sync(&wacom->work);
if (wacom->wacom_wac.input) wacom_unregister_inputs(wacom);
input_unregister_device(wacom->wacom_wac.input); if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed);
wacom_destroy_battery(wacom); wacom_destroy_battery(wacom);
wacom_destroy_leds(wacom); wacom_destroy_leds(wacom);
usb_free_urb(wacom->irq);
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
wacom->wacom_wac.data, wacom->data_dma);
wacom_remove_shared_data(&wacom->wacom_wac); wacom_remove_shared_data(&wacom->wacom_wac);
kfree(wacom);
}
static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
{
struct wacom *wacom = usb_get_intfdata(intf);
mutex_lock(&wacom->lock);
usb_kill_urb(wacom->irq);
mutex_unlock(&wacom->lock);
return 0; hid_set_drvdata(hdev, NULL);
kfree(wacom);
} }
static int wacom_resume(struct usb_interface *intf) static int wacom_resume(struct hid_device *hdev)
{ {
struct wacom *wacom = usb_get_intfdata(intf); struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_features *features = &wacom->wacom_wac.features; struct wacom_features *features = &wacom->wacom_wac.features;
int rv = 0;
mutex_lock(&wacom->lock); mutex_lock(&wacom->lock);
/* switch to wacom mode first */ /* switch to wacom mode first */
wacom_query_tablet_data(intf, features); wacom_query_tablet_data(hdev, features);
wacom_led_control(wacom); wacom_led_control(wacom);
if ((wacom->open || (features->quirks & WACOM_QUIRK_MONITOR)) &&
usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
rv = -EIO;
mutex_unlock(&wacom->lock); mutex_unlock(&wacom->lock);
return rv; return 0;
} }
static int wacom_reset_resume(struct usb_interface *intf) static int wacom_reset_resume(struct hid_device *hdev)
{ {
return wacom_resume(intf); return wacom_resume(hdev);
} }
static struct usb_driver wacom_driver = { static struct hid_driver wacom_driver = {
.name = "wacom", .name = "wacom",
.id_table = wacom_ids, .id_table = wacom_ids,
.probe = wacom_probe, .probe = wacom_probe,
.disconnect = wacom_disconnect, .remove = wacom_remove,
.suspend = wacom_suspend, #ifdef CONFIG_PM
.resume = wacom_resume, .resume = wacom_resume,
.reset_resume = wacom_reset_resume, .reset_resume = wacom_reset_resume,
.supports_autosuspend = 1, #endif
.raw_event = wacom_raw_event,
}; };
module_hid_driver(wacom_driver);
module_usb_driver(wacom_driver); MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
...@@ -25,11 +25,23 @@ ...@@ -25,11 +25,23 @@
#define WACOM_INTUOS_RES 100 #define WACOM_INTUOS_RES 100
#define WACOM_INTUOS3_RES 200 #define WACOM_INTUOS3_RES 200
/* Scale factor relating reported contact size to logical contact area. /*
* Scale factor relating reported contact size to logical contact area.
* 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo
*/ */
#define WACOM_CONTACT_AREA_SCALE 2607 #define WACOM_CONTACT_AREA_SCALE 2607
/*
* Percent of battery capacity for Graphire.
* 8th value means AC online and show 100% capacity.
*/
static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
/*
* Percent of battery capacity for Intuos4 WL, AC has a separate bit.
*/
static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
static int wacom_penpartner_irq(struct wacom_wac *wacom) static int wacom_penpartner_irq(struct wacom_wac *wacom)
{ {
unsigned char *data = wacom->data; unsigned char *data = wacom->data;
...@@ -217,17 +229,13 @@ static int wacom_dtus_irq(struct wacom_wac *wacom) ...@@ -217,17 +229,13 @@ static int wacom_dtus_irq(struct wacom_wac *wacom)
"%s: received unknown report #%d", __func__, data[0]); "%s: received unknown report #%d", __func__, data[0]);
return 0; return 0;
} else if (data[0] == WACOM_REPORT_DTUSPAD) { } else if (data[0] == WACOM_REPORT_DTUSPAD) {
input = wacom->pad_input;
input_report_key(input, BTN_0, (data[1] & 0x01)); input_report_key(input, BTN_0, (data[1] & 0x01));
input_report_key(input, BTN_1, (data[1] & 0x02)); input_report_key(input, BTN_1, (data[1] & 0x02));
input_report_key(input, BTN_2, (data[1] & 0x04)); input_report_key(input, BTN_2, (data[1] & 0x04));
input_report_key(input, BTN_3, (data[1] & 0x08)); input_report_key(input, BTN_3, (data[1] & 0x08));
input_report_abs(input, ABS_MISC, input_report_abs(input, ABS_MISC,
data[1] & 0x0f ? PAD_DEVICE_ID : 0); data[1] & 0x0f ? PAD_DEVICE_ID : 0);
/*
* Serial number is required when expresskeys are
* reported through pen interface.
*/
input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
return 1; return 1;
} else { } else {
prox = data[1] & 0x80; prox = data[1] & 0x80;
...@@ -257,7 +265,6 @@ static int wacom_dtus_irq(struct wacom_wac *wacom) ...@@ -257,7 +265,6 @@ static int wacom_dtus_irq(struct wacom_wac *wacom)
wacom->id[0] = 0; wacom->id[0] = 0;
input_report_key(input, wacom->tool[0], prox); input_report_key(input, wacom->tool[0], prox);
input_report_abs(input, ABS_MISC, wacom->id[0]); input_report_abs(input, ABS_MISC, wacom->id[0]);
input_event(input, EV_MSC, MSC_SERIAL, 1);
return 1; return 1;
} }
} }
...@@ -267,11 +274,20 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) ...@@ -267,11 +274,20 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features; struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data; unsigned char *data = wacom->data;
struct input_dev *input = wacom->input; struct input_dev *input = wacom->input;
struct input_dev *pad_input = wacom->pad_input;
int battery_capacity, ps_connected;
int prox; int prox;
int rw = 0; int rw = 0;
int retval = 0; int retval = 0;
if (data[0] != WACOM_REPORT_PENABLED) { if (features->type == GRAPHIRE_BT) {
if (data[0] != WACOM_REPORT_PENABLED_BT) {
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__,
data[0]);
goto exit;
}
} else if (data[0] != WACOM_REPORT_PENABLED) {
dev_dbg(input->dev.parent, dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]); "%s: received unknown report #%d\n", __func__, data[0]);
goto exit; goto exit;
...@@ -305,7 +321,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) ...@@ -305,7 +321,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
if (wacom->tool[0] != BTN_TOOL_MOUSE) { if (wacom->tool[0] != BTN_TOOL_MOUSE) {
input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x03) << 8)); if (features->type == GRAPHIRE_BT)
input_report_abs(input, ABS_PRESSURE, data[6] |
(((__u16) (data[1] & 0x08)) << 5));
else
input_report_abs(input, ABS_PRESSURE, data[6] |
((data[7] & 0x03) << 8));
input_report_key(input, BTN_TOUCH, data[1] & 0x01); input_report_key(input, BTN_TOUCH, data[1] & 0x01);
input_report_key(input, BTN_STYLUS, data[1] & 0x02); input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x04); input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
...@@ -316,6 +337,20 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) ...@@ -316,6 +337,20 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
features->type == WACOM_MO) { features->type == WACOM_MO) {
input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f); input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f);
rw = (data[7] & 0x04) - (data[7] & 0x03); rw = (data[7] & 0x04) - (data[7] & 0x03);
} else if (features->type == GRAPHIRE_BT) {
/* Compute distance between mouse and tablet */
rw = 44 - (data[6] >> 2);
rw = clamp_val(rw, 0, 31);
input_report_abs(input, ABS_DISTANCE, rw);
if (((data[1] >> 5) & 3) == 2) {
/* Mouse with wheel */
input_report_key(input, BTN_MIDDLE,
data[1] & 0x04);
rw = (data[6] & 0x01) ? -1 :
(data[6] & 0x02) ? 1 : 0;
} else {
rw = 0;
}
} else { } else {
input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f); input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f);
rw = -(signed char)data[6]; rw = -(signed char)data[6];
...@@ -327,7 +362,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) ...@@ -327,7 +362,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
wacom->id[0] = 0; wacom->id[0] = 0;
input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
input_report_key(input, wacom->tool[0], prox); input_report_key(input, wacom->tool[0], prox);
input_event(input, EV_MSC, MSC_SERIAL, 1);
input_sync(input); /* sync last event */ input_sync(input); /* sync last event */
} }
...@@ -337,14 +371,13 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) ...@@ -337,14 +371,13 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
prox = data[7] & 0xf8; prox = data[7] & 0xf8;
if (prox || wacom->id[1]) { if (prox || wacom->id[1]) {
wacom->id[1] = PAD_DEVICE_ID; wacom->id[1] = PAD_DEVICE_ID;
input_report_key(input, BTN_BACK, (data[7] & 0x40)); input_report_key(pad_input, BTN_BACK, (data[7] & 0x40));
input_report_key(input, BTN_FORWARD, (data[7] & 0x80)); input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x80));
rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
input_report_rel(input, REL_WHEEL, rw); input_report_rel(pad_input, REL_WHEEL, rw);
if (!prox) if (!prox)
wacom->id[1] = 0; wacom->id[1] = 0;
input_report_abs(input, ABS_MISC, wacom->id[1]); input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
retval = 1; retval = 1;
} }
break; break;
...@@ -353,19 +386,43 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) ...@@ -353,19 +386,43 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
prox = (data[7] & 0xf8) || data[8]; prox = (data[7] & 0xf8) || data[8];
if (prox || wacom->id[1]) { if (prox || wacom->id[1]) {
wacom->id[1] = PAD_DEVICE_ID; wacom->id[1] = PAD_DEVICE_ID;
input_report_key(input, BTN_BACK, (data[7] & 0x08)); input_report_key(pad_input, BTN_BACK, (data[7] & 0x08));
input_report_key(input, BTN_LEFT, (data[7] & 0x20)); input_report_key(pad_input, BTN_LEFT, (data[7] & 0x20));
input_report_key(input, BTN_FORWARD, (data[7] & 0x10)); input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x10));
input_report_key(input, BTN_RIGHT, (data[7] & 0x40)); input_report_key(pad_input, BTN_RIGHT, (data[7] & 0x40));
input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f)); input_report_abs(pad_input, ABS_WHEEL, (data[8] & 0x7f));
if (!prox)
wacom->id[1] = 0;
input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
retval = 1;
}
break;
case GRAPHIRE_BT:
prox = data[7] & 0x03;
if (prox || wacom->id[1]) {
wacom->id[1] = PAD_DEVICE_ID;
input_report_key(pad_input, BTN_0, (data[7] & 0x02));
input_report_key(pad_input, BTN_1, (data[7] & 0x01));
if (!prox) if (!prox)
wacom->id[1] = 0; wacom->id[1] = 0;
input_report_abs(input, ABS_MISC, wacom->id[1]); input_report_abs(pad_input, ABS_MISC, wacom->id[1]);
input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
retval = 1; retval = 1;
} }
break; break;
} }
/* Store current battery capacity and power supply state */
if (features->type == GRAPHIRE_BT) {
rw = (data[7] >> 2 & 0x07);
battery_capacity = batcap_gr[rw];
ps_connected = rw == 7;
if ((wacom->battery_capacity != battery_capacity) ||
(wacom->ps_connected != ps_connected)) {
wacom->battery_capacity = battery_capacity;
wacom->ps_connected = ps_connected;
wacom_notify_battery(wacom);
}
}
exit: exit:
return retval; return retval;
} }
...@@ -584,6 +641,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) ...@@ -584,6 +641,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
/* pad packets. Works as a second tool and is always in prox */ /* pad packets. Works as a second tool and is always in prox */
if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) { if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
input = wacom->pad_input;
if (features->type >= INTUOS4S && features->type <= INTUOS4L) { if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
input_report_key(input, BTN_0, (data[2] & 0x01)); input_report_key(input, BTN_0, (data[2] & 0x01));
input_report_key(input, BTN_1, (data[3] & 0x01)); input_report_key(input, BTN_1, (data[3] & 0x01));
...@@ -773,7 +831,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) ...@@ -773,7 +831,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_abs(input, ABS_MISC, 0); input_report_abs(input, ABS_MISC, 0);
} }
} }
input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
return 1; return 1;
} }
...@@ -901,6 +958,58 @@ static int int_dist(int x1, int y1, int x2, int y2) ...@@ -901,6 +958,58 @@ static int int_dist(int x1, int y1, int x2, int y2)
return int_sqrt(x*x + y*y); return int_sqrt(x*x + y*y);
} }
static void wacom_intuos_bt_process_data(struct wacom_wac *wacom,
unsigned char *data)
{
memcpy(wacom->data, data, 10);
wacom_intuos_irq(wacom);
input_sync(wacom->input);
if (wacom->pad_input)
input_sync(wacom->pad_input);
}
static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
{
unsigned char data[WACOM_PKGLEN_MAX];
int i = 1;
unsigned power_raw, battery_capacity, bat_charging, ps_connected;
memcpy(data, wacom->data, len);
switch (data[0]) {
case 0x04:
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
/* fall through */
case 0x03:
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
wacom_intuos_bt_process_data(wacom, data + i);
i += 10;
power_raw = data[i];
bat_charging = (power_raw & 0x08) ? 1 : 0;
ps_connected = (power_raw & 0x10) ? 1 : 0;
battery_capacity = batcap_i4[power_raw & 0x07];
if ((wacom->battery_capacity != battery_capacity) ||
(wacom->bat_charging != bat_charging) ||
(wacom->ps_connected != ps_connected)) {
wacom->battery_capacity = battery_capacity;
wacom->bat_charging = bat_charging;
wacom->ps_connected = ps_connected;
wacom_notify_battery(wacom);
}
break;
default:
dev_dbg(wacom->input->dev.parent,
"Unknown report: %d,%d size:%zu\n",
data[0], data[1], len);
return 0;
}
return 0;
}
static int wacom_24hdt_irq(struct wacom_wac *wacom) static int wacom_24hdt_irq(struct wacom_wac *wacom)
{ {
struct input_dev *input = wacom->input; struct input_dev *input = wacom->input;
...@@ -1093,7 +1202,7 @@ static int wacom_tpc_pen(struct wacom_wac *wacom) ...@@ -1093,7 +1202,7 @@ static int wacom_tpc_pen(struct wacom_wac *wacom)
input_report_key(input, BTN_STYLUS2, data[1] & 0x10); input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x03) << 8) | data[6]); input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x07) << 8) | data[6]);
input_report_key(input, BTN_TOUCH, data[1] & 0x05); input_report_key(input, BTN_TOUCH, data[1] & 0x05);
input_report_key(input, wacom->tool[0], prox); input_report_key(input, wacom->tool[0], prox);
return 1; return 1;
...@@ -1143,6 +1252,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) ...@@ -1143,6 +1252,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
{ {
struct wacom_features *features = &wacom->features; struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->input; struct input_dev *input = wacom->input;
struct input_dev *pad_input = wacom->pad_input;
unsigned char *data = wacom->data; unsigned char *data = wacom->data;
int i; int i;
...@@ -1177,14 +1287,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) ...@@ -1177,14 +1287,12 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
input_mt_report_pointer_emulation(input, true); input_mt_report_pointer_emulation(input, true);
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0); input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
input_sync(input);
return 0; return 1;
} }
static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
...@@ -1232,7 +1340,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) ...@@ -1232,7 +1340,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data) static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
{ {
struct input_dev *input = wacom->input; struct input_dev *input = wacom->pad_input;
struct wacom_features *features = &wacom->features; struct wacom_features *features = &wacom->features;
if (features->type == INTUOSHT) { if (features->type == INTUOSHT) {
...@@ -1269,9 +1377,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom) ...@@ -1269,9 +1377,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
} }
input_mt_report_pointer_emulation(input, true); input_mt_report_pointer_emulation(input, true);
input_sync(input); return 1;
return 0;
} }
static int wacom_bpt_pen(struct wacom_wac *wacom) static int wacom_bpt_pen(struct wacom_wac *wacom)
...@@ -1375,7 +1481,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len) ...@@ -1375,7 +1481,7 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
connected = data[1] & 0x01; connected = data[1] & 0x01;
if (connected) { if (connected) {
int pid, battery; int pid, battery, ps_connected;
if ((wacom->shared->type == INTUOSHT) && if ((wacom->shared->type == INTUOSHT) &&
wacom->shared->touch_max) { wacom->shared->touch_max) {
...@@ -1385,17 +1491,29 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len) ...@@ -1385,17 +1491,29 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
} }
pid = get_unaligned_be16(&data[6]); pid = get_unaligned_be16(&data[6]);
battery = data[5] & 0x3f; battery = (data[5] & 0x3f) * 100 / 31;
ps_connected = !!(data[5] & 0x80);
if (wacom->pid != pid) { if (wacom->pid != pid) {
wacom->pid = pid; wacom->pid = pid;
wacom_schedule_work(wacom); wacom_schedule_work(wacom);
} }
wacom->battery_capacity = battery;
if (wacom->shared->type &&
(battery != wacom->battery_capacity ||
ps_connected != wacom->ps_connected)) {
wacom->battery_capacity = battery;
wacom->ps_connected = ps_connected;
wacom->bat_charging = ps_connected &&
wacom->battery_capacity < 100;
wacom_notify_battery(wacom);
}
} else if (wacom->pid != 0) { } else if (wacom->pid != 0) {
/* disconnected while previously connected */ /* disconnected while previously connected */
wacom->pid = 0; wacom->pid = 0;
wacom_schedule_work(wacom); wacom_schedule_work(wacom);
wacom->battery_capacity = 0; wacom->battery_capacity = 0;
wacom->bat_charging = 0;
wacom->ps_connected = 0;
} }
return 0; return 0;
...@@ -1416,6 +1534,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) ...@@ -1416,6 +1534,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case WACOM_G4: case WACOM_G4:
case GRAPHIRE: case GRAPHIRE:
case GRAPHIRE_BT:
case WACOM_MO: case WACOM_MO:
sync = wacom_graphire_irq(wacom_wac); sync = wacom_graphire_irq(wacom_wac);
break; break;
...@@ -1450,6 +1569,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) ...@@ -1450,6 +1569,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_intuos_irq(wacom_wac); sync = wacom_intuos_irq(wacom_wac);
break; break;
case INTUOS4WL:
sync = wacom_intuos_bt_irq(wacom_wac, len);
break;
case WACOM_24HDT: case WACOM_24HDT:
sync = wacom_24hdt_irq(wacom_wac); sync = wacom_24hdt_irq(wacom_wac);
break; break;
...@@ -1489,8 +1612,11 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) ...@@ -1489,8 +1612,11 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break; break;
} }
if (sync) if (sync) {
input_sync(wacom_wac->input); input_sync(wacom_wac->input);
if (wacom_wac->pad_input)
input_sync(wacom_wac->pad_input);
}
} }
static void wacom_setup_cintiq(struct wacom_wac *wacom_wac) static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
...@@ -1565,8 +1691,10 @@ void wacom_setup_device_quirks(struct wacom_features *features) ...@@ -1565,8 +1691,10 @@ void wacom_setup_device_quirks(struct wacom_features *features)
features->quirks |= WACOM_QUIRK_NO_INPUT; features->quirks |= WACOM_QUIRK_NO_INPUT;
/* must be monitor interface if no device_type set */ /* must be monitor interface if no device_type set */
if (!features->device_type) if (!features->device_type) {
features->quirks |= WACOM_QUIRK_MONITOR; features->quirks |= WACOM_QUIRK_MONITOR;
features->quirks |= WACOM_QUIRK_BATTERY;
}
} }
} }
...@@ -1615,7 +1743,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1615,7 +1743,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac) struct wacom_wac *wacom_wac)
{ {
struct wacom_features *features = &wacom_wac->features; struct wacom_features *features = &wacom_wac->features;
int i;
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
...@@ -1630,10 +1757,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1630,10 +1757,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
/* fall through */ /* fall through */
case WACOM_G4: case WACOM_G4:
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
__set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
/* fall through */ /* fall through */
case GRAPHIRE: case GRAPHIRE:
...@@ -1652,62 +1775,42 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1652,62 +1775,42 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(INPUT_PROP_POINTER, input_dev->propbit); __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break; break;
case WACOM_24HD: case GRAPHIRE_BT:
__set_bit(BTN_A, input_dev->keybit); __clear_bit(ABS_MISC, input_dev->absbit);
__set_bit(BTN_B, input_dev->keybit); input_set_abs_params(input_dev, ABS_DISTANCE, 0,
__set_bit(BTN_C, input_dev->keybit); features->distance_max,
__set_bit(BTN_X, input_dev->keybit); 0, 0);
__set_bit(BTN_Y, input_dev->keybit);
__set_bit(BTN_Z, input_dev->keybit);
for (i = 6; i < 10; i++) input_set_capability(input_dev, EV_REL, REL_WHEEL);
__set_bit(BTN_0 + i, input_dev->keybit);
__set_bit(KEY_PROG1, input_dev->keybit); __set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit); __set_bit(BTN_RIGHT, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit); __set_bit(BTN_MIDDLE, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
case WACOM_24HD:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
/* fall through */ /* fall through */
case DTK: case DTK:
for (i = 0; i < 6; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac); wacom_setup_cintiq(wacom_wac);
break; break;
case WACOM_22HD: case WACOM_22HD:
__set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
/* fall through */
case WACOM_21UX2: 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: case WACOM_BEE:
__set_bit(BTN_8, input_dev->keybit);
__set_bit(BTN_9, input_dev->keybit);
/* fall through */
case CINTIQ: 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);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
...@@ -1716,9 +1819,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1716,9 +1819,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
break; break;
case WACOM_13HD: case WACOM_13HD:
for (i = 0; i < 9; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac); wacom_setup_cintiq(wacom_wac);
...@@ -1726,21 +1826,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1726,21 +1826,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case INTUOS3: case INTUOS3:
case INTUOS3L: 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: 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);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
/* fall through */ /* fall through */
...@@ -1754,20 +1840,11 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1754,20 +1840,11 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case INTUOS5L: case INTUOS5L:
case INTUOSPM: case INTUOSPM:
case INTUOSPL: case INTUOSPL:
if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_7, input_dev->keybit);
__set_bit(BTN_8, input_dev->keybit);
}
/* fall through */
case INTUOS5S: case INTUOS5S:
case INTUOSPS: case INTUOSPS:
__set_bit(INPUT_PROP_POINTER, input_dev->propbit); __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
if (features->device_type == BTN_TOOL_PEN) { if (features->device_type == BTN_TOOL_PEN) {
for (i = 0; i < 7; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
input_set_abs_params(input_dev, ABS_DISTANCE, 0, input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max, features->distance_max,
0, 0); 0, 0);
...@@ -1787,15 +1864,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1787,15 +1864,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
break; break;
case INTUOS4: case INTUOS4:
case INTUOS4WL:
case INTUOS4L: case INTUOS4L:
__set_bit(BTN_7, input_dev->keybit);
__set_bit(BTN_8, input_dev->keybit);
/* fall through */
case INTUOS4S: case INTUOS4S:
for (i = 0; i < 7; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
wacom_setup_intuos(wacom_wac); wacom_setup_intuos(wacom_wac);
...@@ -1839,11 +1910,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1839,11 +1910,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case DTUS: case DTUS:
case PL: case PL:
case DTU: case DTU:
if (features->type == DTUS) {
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
for (i = 0; i < 4; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
}
__set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit);
...@@ -1877,11 +1943,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1877,11 +1943,6 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
if (features->device_type == BTN_TOOL_FINGER) { if (features->device_type == BTN_TOOL_FINGER) {
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
if (features->touch_max) { if (features->touch_max) {
/* touch interface */ /* touch interface */
unsigned int flags = INPUT_MT_POINTER; unsigned int flags = INPUT_MT_POINTER;
...@@ -1919,449 +1980,629 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1919,449 +1980,629 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
break; break;
case CINTIQ_HYBRID: case CINTIQ_HYBRID:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac);
break;
}
return 0;
}
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;
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
/* kept for making legacy xf86-input-wacom working with the wheels */
__set_bit(ABS_MISC, input_dev->absbit);
/* kept for making legacy xf86-input-wacom accepting the pad */
input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
switch (features->type) {
case GRAPHIRE_BT:
__set_bit(BTN_0, input_dev->keybit);
__set_bit(BTN_1, input_dev->keybit); __set_bit(BTN_1, input_dev->keybit);
__set_bit(BTN_2, input_dev->keybit); break;
__set_bit(BTN_3, input_dev->keybit);
__set_bit(BTN_4, input_dev->keybit); case WACOM_MO:
__set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
break;
case WACOM_G4:
__set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
input_set_capability(input_dev, EV_REL, REL_WHEEL);
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);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
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);
__set_bit(KEY_PROG3, input_dev->keybit);
/* 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_5, input_dev->keybit);
__set_bit(BTN_6, input_dev->keybit); __set_bit(BTN_6, input_dev->keybit);
__set_bit(BTN_7, input_dev->keybit); __set_bit(BTN_7, input_dev->keybit);
__set_bit(BTN_8, 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_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_Z, -900, 899, 0, 0); input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit); break;
case INTUOS5:
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:
/* touch interface does not have the pad device */
if (features->device_type != BTN_TOOL_PEN)
return 1;
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 INTUOS4WL:
/*
* For Bluetooth devices, the udev rule does not work correctly
* for pads unless we add a stylus capability, which forces
* ID_INPUT_TABLET to be set.
*/
__set_bit(BTN_STYLUS, input_dev->keybit);
/* fall through */
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);
wacom_setup_cintiq(wacom_wac);
break; break;
case DTUS:
for (i = 0; i < 4; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
break;
case INTUOSHT:
case BAMBOO_PT:
/* pad device is on the touch interface */
if (features->device_type != BTN_TOOL_FINGER)
return 1;
__clear_bit(ABS_MISC, input_dev->absbit);
__set_bit(BTN_LEFT, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_RIGHT, input_dev->keybit);
break;
default:
/* no pad supported */
return 1;
} }
return 0; return 0;
} }
static const struct wacom_features wacom_features_0x00 = static const struct wacom_features wacom_features_0x00 =
{ "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, { "Wacom Penpartner", 5040, 3780, 255, 0,
0, PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
static const struct wacom_features wacom_features_0x10 = static const struct wacom_features wacom_features_0x10 =
{ "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, { "Wacom Graphire", 10206, 7422, 511, 63,
63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; 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 };
static const struct wacom_features wacom_features_0x11 = static const struct wacom_features wacom_features_0x11 =
{ "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, { "Wacom Graphire2 4x5", 10206, 7422, 511, 63,
63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x12 = static const struct wacom_features wacom_features_0x12 =
{ "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, { "Wacom Graphire2 5x7", 13918, 10206, 511, 63,
63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x13 = static const struct wacom_features wacom_features_0x13 =
{ "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, { "Wacom Graphire3", 10208, 7424, 511, 63,
63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x14 = static const struct wacom_features wacom_features_0x14 =
{ "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, { "Wacom Graphire3 6x8", 16704, 12064, 511, 63,
63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x15 = static const struct wacom_features wacom_features_0x15 =
{ "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, { "Wacom Graphire4 4x5", 10208, 7424, 511, 63,
63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x16 = static const struct wacom_features wacom_features_0x16 =
{ "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, { "Wacom Graphire4 6x8", 16704, 12064, 511, 63,
63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x17 = static const struct wacom_features wacom_features_0x17 =
{ "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, { "Wacom BambooFun 4x5", 14760, 9225, 511, 63,
63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x18 = static const struct wacom_features wacom_features_0x18 =
{ "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, { "Wacom BambooFun 6x8", 21648, 13530, 511, 63,
63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x19 = static const struct wacom_features wacom_features_0x19 =
{ "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, { "Wacom Bamboo1 Medium", 16704, 12064, 511, 63,
63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES };
static const struct wacom_features wacom_features_0x60 = static const struct wacom_features wacom_features_0x60 =
{ "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, { "Wacom Volito", 5104, 3712, 511, 63,
63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
static const struct wacom_features wacom_features_0x61 = static const struct wacom_features wacom_features_0x61 =
{ "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, { "Wacom PenStation2", 3250, 2320, 255, 63,
63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
static const struct wacom_features wacom_features_0x62 = static const struct wacom_features wacom_features_0x62 =
{ "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, { "Wacom Volito2 4x5", 5104, 3712, 511, 63,
63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
static const struct wacom_features wacom_features_0x63 = static const struct wacom_features wacom_features_0x63 =
{ "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, { "Wacom Volito2 2x3", 3248, 2320, 511, 63,
63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
static const struct wacom_features wacom_features_0x64 = static const struct wacom_features wacom_features_0x64 =
{ "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, { "Wacom PenPartner2", 3250, 2320, 511, 63,
63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES };
static const struct wacom_features wacom_features_0x65 = static const struct wacom_features wacom_features_0x65 =
{ "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, { "Wacom Bamboo", 14760, 9225, 511, 63,
63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x69 = static const struct wacom_features wacom_features_0x69 =
{ "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, { "Wacom Bamboo1", 5104, 3712, 511, 63,
63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
static const struct wacom_features wacom_features_0x6A = static const struct wacom_features wacom_features_0x6A =
{ "Wacom Bamboo1 4x6", WACOM_PKGLEN_GRAPHIRE, 14760, 9225, 1023, { "Wacom Bamboo1 4x6", 14760, 9225, 1023, 63,
63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x6B = static const struct wacom_features wacom_features_0x6B =
{ "Wacom Bamboo1 5x8", WACOM_PKGLEN_GRAPHIRE, 21648, 13530, 1023, { "Wacom Bamboo1 5x8", 21648, 13530, 1023, 63,
63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x20 = static const struct wacom_features wacom_features_0x20 =
{ "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, { "Wacom Intuos 4x5", 12700, 10600, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x21 = static const struct wacom_features wacom_features_0x21 =
{ "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, { "Wacom Intuos 6x8", 20320, 16240, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x22 = static const struct wacom_features wacom_features_0x22 =
{ "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, { "Wacom Intuos 9x12", 30480, 24060, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x23 = static const struct wacom_features wacom_features_0x23 =
{ "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, { "Wacom Intuos 12x12", 30480, 31680, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x24 = static const struct wacom_features wacom_features_0x24 =
{ "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, { "Wacom Intuos 12x18", 45720, 31680, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x30 = static const struct wacom_features wacom_features_0x30 =
{ "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, { "Wacom PL400", 5408, 4056, 255, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x31 = static const struct wacom_features wacom_features_0x31 =
{ "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, { "Wacom PL500", 6144, 4608, 255, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x32 = static const struct wacom_features wacom_features_0x32 =
{ "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, { "Wacom PL600", 6126, 4604, 255, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x33 = static const struct wacom_features wacom_features_0x33 =
{ "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, { "Wacom PL600SX", 6260, 5016, 255, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x34 = static const struct wacom_features wacom_features_0x34 =
{ "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, { "Wacom PL550", 6144, 4608, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x35 = static const struct wacom_features wacom_features_0x35 =
{ "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, { "Wacom PL800", 7220, 5780, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x37 = static const struct wacom_features wacom_features_0x37 =
{ "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, { "Wacom PL700", 6758, 5406, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x38 = static const struct wacom_features wacom_features_0x38 =
{ "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, { "Wacom PL510", 6282, 4762, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x39 = static const struct wacom_features wacom_features_0x39 =
{ "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, { "Wacom DTU710", 34080, 27660, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0xC4 = static const struct wacom_features wacom_features_0xC4 =
{ "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, { "Wacom DTF521", 6282, 4762, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0xC0 = static const struct wacom_features wacom_features_0xC0 =
{ "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, { "Wacom DTF720", 6858, 5506, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0xC2 = static const struct wacom_features wacom_features_0xC2 =
{ "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, { "Wacom DTF720a", 6858, 5506, 511, 0,
0, PL, WACOM_PL_RES, WACOM_PL_RES }; PL, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x03 = static const struct wacom_features wacom_features_0x03 =
{ "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, { "Wacom Cintiq Partner", 20480, 15360, 511, 0,
0, PTU, WACOM_PL_RES, WACOM_PL_RES }; PTU, WACOM_PL_RES, WACOM_PL_RES };
static const struct wacom_features wacom_features_0x41 = static const struct wacom_features wacom_features_0x41 =
{ "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, { "Wacom Intuos2 4x5", 12700, 10600, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x42 = static const struct wacom_features wacom_features_0x42 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x43 = static const struct wacom_features wacom_features_0x43 =
{ "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, { "Wacom Intuos2 9x12", 30480, 24060, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x44 = static const struct wacom_features wacom_features_0x44 =
{ "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, { "Wacom Intuos2 12x12", 30480, 31680, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x45 = static const struct wacom_features wacom_features_0x45 =
{ "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, { "Wacom Intuos2 12x18", 45720, 31680, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xB0 = static const struct wacom_features wacom_features_0xB0 =
{ "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, { "Wacom Intuos3 4x5", 25400, 20320, 1023, 63,
63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB1 = static const struct wacom_features wacom_features_0xB1 =
{ "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, { "Wacom Intuos3 6x8", 40640, 30480, 1023, 63,
63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB2 = static const struct wacom_features wacom_features_0xB2 =
{ "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, { "Wacom Intuos3 9x12", 60960, 45720, 1023, 63,
63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB3 = static const struct wacom_features wacom_features_0xB3 =
{ "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, { "Wacom Intuos3 12x12", 60960, 60960, 1023, 63,
63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB4 = static const struct wacom_features wacom_features_0xB4 =
{ "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, { "Wacom Intuos3 12x19", 97536, 60960, 1023, 63,
63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB5 = static const struct wacom_features wacom_features_0xB5 =
{ "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, { "Wacom Intuos3 6x11", 54204, 31750, 1023, 63,
63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB7 = static const struct wacom_features wacom_features_0xB7 =
{ "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, { "Wacom Intuos3 4x6", 31496, 19685, 1023, 63,
63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB8 = static const struct wacom_features wacom_features_0xB8 =
{ "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, { "Wacom Intuos4 4x6", 31496, 19685, 2047, 63,
63, INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xB9 = static const struct wacom_features wacom_features_0xB9 =
{ "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, { "Wacom Intuos4 6x9", 44704, 27940, 2047, 63,
63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xBA = static const struct wacom_features wacom_features_0xBA =
{ "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, { "Wacom Intuos4 8x13", 65024, 40640, 2047, 63,
63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xBB = static const struct wacom_features wacom_features_0xBB =
{ "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, { "Wacom Intuos4 12x19", 97536, 60960, 2047, 63,
63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xBC = static const struct wacom_features wacom_features_0xBC =
{ "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40640, 25400, 2047, { "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xBD =
{ "Wacom Intuos4 WL", 40640, 25400, 2047, 63,
INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x26 = static const struct wacom_features wacom_features_0x26 =
{ "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, { "Wacom Intuos5 touch S", 31496, 19685, 2047, 63,
63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
.touch_max = 16 };
static const struct wacom_features wacom_features_0x27 = static const struct wacom_features wacom_features_0x27 =
{ "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, { "Wacom Intuos5 touch M", 44704, 27940, 2047, 63,
63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
.touch_max = 16 };
static const struct wacom_features wacom_features_0x28 = static const struct wacom_features wacom_features_0x28 =
{ "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, { "Wacom Intuos5 touch L", 65024, 40640, 2047, 63,
63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 };
.touch_max = 16 };
static const struct wacom_features wacom_features_0x29 = static const struct wacom_features wacom_features_0x29 =
{ "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, { "Wacom Intuos5 S", 31496, 19685, 2047, 63,
63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x2A = static const struct wacom_features wacom_features_0x2A =
{ "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, { "Wacom Intuos5 M", 44704, 27940, 2047, 63,
63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x314 = static const struct wacom_features wacom_features_0x314 =
{ "Wacom Intuos Pro S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, { "Wacom Intuos Pro S", 31496, 19685, 2047, 63,
63, INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
.touch_max = 16 }; .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x315 = static const struct wacom_features wacom_features_0x315 =
{ "Wacom Intuos Pro M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, { "Wacom Intuos Pro M", 44704, 27940, 2047, 63,
63, INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
.touch_max = 16 }; .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x317 = static const struct wacom_features wacom_features_0x317 =
{ "Wacom Intuos Pro L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, { "Wacom Intuos Pro L", 65024, 40640, 2047, 63,
63, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
.touch_max = 16 }; .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0xF4 = static const struct wacom_features wacom_features_0xF4 =
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104280, 65400, 2047, { "Wacom Cintiq 24HD", 104280, 65400, 2047, 63,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 }; WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0xF8 = static const struct wacom_features wacom_features_0xF8 =
{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104280, 65400, 2047, /* Pen */ { "Wacom Cintiq 24HD touch", 104280, 65400, 2047, 63, /* Pen */
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
static const struct wacom_features wacom_features_0xF6 = static const struct wacom_features wacom_features_0xF6 =
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */ { "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10 }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x3F = static const struct wacom_features wacom_features_0x3F =
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xC5 = static const struct wacom_features wacom_features_0xC5 =
{ "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, { "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63,
63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xC6 = static const struct wacom_features wacom_features_0xC6 =
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, { "Wacom Cintiq 12WX", 53020, 33440, 1023, 63,
63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x304 = static const struct wacom_features wacom_features_0x304 =
{ "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59352, 33648, 1023, { "Wacom Cintiq 13HD", 59352, 33648, 1023, 63,
63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 }; WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0xC7 = static const struct wacom_features wacom_features_0xC7 =
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, { "Wacom DTU1931", 37832, 30305, 511, 0,
0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xCE = static const struct wacom_features wacom_features_0xCE =
{ "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, { "Wacom DTU2231", 47864, 27011, 511, 0,
0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBMOUSE };
static const struct wacom_features wacom_features_0xF0 = static const struct wacom_features wacom_features_0xF0 =
{ "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, { "Wacom DTU1631", 34623, 19553, 511, 0,
0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xFB = static const struct wacom_features wacom_features_0xFB =
{ "Wacom DTU1031", WACOM_PKGLEN_DTUS, 22096, 13960, 511, { "Wacom DTU1031", 22096, 13960, 511, 0,
0, DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x57 = static const struct wacom_features wacom_features_0x57 =
{ "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047, { "Wacom DTK2241", 95640, 54060, 2047, 63,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 }; DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0x59 = /* Pen */ static const struct wacom_features wacom_features_0x59 = /* Pen */
{ "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047, { "Wacom DTH2242", 95640, 54060, 2047, 63,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
static const struct wacom_features wacom_features_0x5D = /* Touch */ static const struct wacom_features wacom_features_0x5D = /* Touch */
{ "Wacom DTH2242", .type = WACOM_24HDT, { "Wacom DTH2242", .type = WACOM_24HDT,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0xCC = static const struct wacom_features wacom_features_0xCC =
{ "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87000, 65400, 2047, { "Wacom Cintiq 21UX2", 87000, 65400, 2047, 63,
63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 }; WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0xFA = static const struct wacom_features wacom_features_0xFA =
{ "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047, { "Wacom Cintiq 22HD", 95640, 54060, 2047, 63,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 }; WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200 };
static const struct wacom_features wacom_features_0x5B = static const struct wacom_features wacom_features_0x5B =
{ "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95640, 54060, 2047, { "Wacom Cintiq 22HDT", 95640, 54060, 2047, 63,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
static const struct wacom_features wacom_features_0x5E = static const struct wacom_features wacom_features_0x5E =
{ "Wacom Cintiq 22HDT", .type = WACOM_24HDT, { "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10 }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x90 = static const struct wacom_features wacom_features_0x90 =
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 90", 26202, 16325, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x93 = static const struct wacom_features wacom_features_0x93 =
{ "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 93", 26202, 16325, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x97 = static const struct wacom_features wacom_features_0x97 =
{ "Wacom ISDv4 97", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 511, { "Wacom ISDv4 97", 26202, 16325, 511, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x9A = static const struct wacom_features wacom_features_0x9A =
{ "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 9A", 26202, 16325, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x9F = static const struct wacom_features wacom_features_0x9F =
{ "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 9F", 26202, 16325, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE2 = static const struct wacom_features wacom_features_0xE2 =
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, { "Wacom ISDv4 E2", 26202, 16325, 255, 0,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xE3 = static const struct wacom_features wacom_features_0xE3 =
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, { "Wacom ISDv4 E3", 26202, 16325, 255, 0,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xE5 = static const struct wacom_features wacom_features_0xE5 =
{ "Wacom ISDv4 E5", WACOM_PKGLEN_MTOUCH, 26202, 16325, 255, { "Wacom ISDv4 E5", 26202, 16325, 255, 0,
0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE6 = static const struct wacom_features wacom_features_0xE6 =
{ "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, { "Wacom ISDv4 E6", 27760, 15694, 255, 0,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xEC = static const struct wacom_features wacom_features_0xEC =
{ "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255, { "Wacom ISDv4 EC", 25710, 14500, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xED = static const struct wacom_features wacom_features_0xED =
{ "Wacom ISDv4 ED", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 ED", 26202, 16325, 255, 0,
0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xEF = static const struct wacom_features wacom_features_0xEF =
{ "Wacom ISDv4 EF", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 EF", 26202, 16325, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x100 = static const struct wacom_features wacom_features_0x100 =
{ "Wacom ISDv4 100", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, { "Wacom ISDv4 100", 26202, 16325, 255, 0,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x101 = static const struct wacom_features wacom_features_0x101 =
{ "Wacom ISDv4 101", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, { "Wacom ISDv4 101", 26202, 16325, 255, 0,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x10D = static const struct wacom_features wacom_features_0x10D =
{ "Wacom ISDv4 10D", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, { "Wacom ISDv4 10D", 26202, 16325, 255, 0,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x10E = static const struct wacom_features wacom_features_0x10E =
{ "Wacom ISDv4 10E", WACOM_PKGLEN_MTTPC, 27760, 15694, 255, { "Wacom ISDv4 10E", 27760, 15694, 255, 0,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x10F = static const struct wacom_features wacom_features_0x10F =
{ "Wacom ISDv4 10F", WACOM_PKGLEN_MTTPC, 27760, 15694, 255, { "Wacom ISDv4 10F", 27760, 15694, 255, 0,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x116 = static const struct wacom_features wacom_features_0x116 =
{ "Wacom ISDv4 116", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, { "Wacom ISDv4 116", 26202, 16325, 255, 0,
0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x12C =
{ "Wacom ISDv4 12C", 27848, 15752, 2047, 0,
TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x4001 = static const struct wacom_features wacom_features_0x4001 =
{ "Wacom ISDv4 4001", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, { "Wacom ISDv4 4001", 26202, 16325, 255, 0,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x4004 = static const struct wacom_features wacom_features_0x4004 =
{ "Wacom ISDv4 4004", WACOM_PKGLEN_MTTPC, 11060, 6220, 255, { "Wacom ISDv4 4004", 11060, 6220, 255, 0,
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x5000 = static const struct wacom_features wacom_features_0x5000 =
{ "Wacom ISDv4 5000", WACOM_PKGLEN_MTTPC, 27848, 15752, 1023, { "Wacom ISDv4 5000", 27848, 15752, 1023, 0,
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x5002 = static const struct wacom_features wacom_features_0x5002 =
{ "Wacom ISDv4 5002", WACOM_PKGLEN_MTTPC, 29576, 16724, 1023, { "Wacom ISDv4 5002", 29576, 16724, 1023, 0,
0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x47 = static const struct wacom_features wacom_features_0x47 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x84 = static const struct wacom_features wacom_features_0x84 =
{ "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0, { "Wacom Wireless Receiver", 0, 0, 0, 0,
0, WIRELESS, 0, 0, .touch_max = 16 }; WIRELESS, 0, 0, .touch_max = 16 };
static const struct wacom_features wacom_features_0xD0 = static const struct wacom_features wacom_features_0xD0 =
{ "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD1 = static const struct wacom_features wacom_features_0xD1 =
{ "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD2 = static const struct wacom_features wacom_features_0xD2 =
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom Bamboo Craft", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD3 = static const struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, { "Wacom Bamboo 2FG 6x8", 21648, 13700, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD4 = static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD5 = static const struct wacom_features wacom_features_0xD5 =
{ "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, { "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD6 = static const struct wacom_features wacom_features_0xD6 =
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD7 = static const struct wacom_features wacom_features_0xD7 =
{ "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom BambooPT 2FG Small", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD8 = static const struct wacom_features wacom_features_0xD8 =
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, { "Wacom Bamboo Comic 2FG", 21648, 13700, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xDA = static const struct wacom_features wacom_features_0xDA =
{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, { "Wacom Bamboo 2FG 4x5 SE", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xDB = static const struct wacom_features wacom_features_0xDB =
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, { "Wacom Bamboo 2FG 6x8 SE", 21648, 13700, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
.touch_max = 2 };
static const struct wacom_features wacom_features_0xDD = static const struct wacom_features wacom_features_0xDD =
{ "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, { "Wacom Bamboo Connect", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xDE = static const struct wacom_features wacom_features_0xDE =
{ "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, { "Wacom Bamboo 16FG 4x5", 14720, 9200, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
.touch_max = 16 };
static const struct wacom_features wacom_features_0xDF = static const struct wacom_features wacom_features_0xDF =
{ "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 21648, 13700, 1023, { "Wacom Bamboo 16FG 6x8", 21648, 13700, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
.touch_max = 16 };
static const struct wacom_features wacom_features_0x300 = static const struct wacom_features wacom_features_0x300 =
{ "Wacom Bamboo One S", WACOM_PKGLEN_BBPEN, 14720, 9225, 1023, { "Wacom Bamboo One S", 14720, 9225, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x301 = static const struct wacom_features wacom_features_0x301 =
{ "Wacom Bamboo One M", WACOM_PKGLEN_BBPEN, 21648, 13530, 1023, { "Wacom Bamboo One M", 21648, 13530, 1023, 31,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x302 = static const struct wacom_features wacom_features_0x302 =
{ "Wacom Intuos PT S", WACOM_PKGLEN_BBPEN, 15200, 9500, 1023, { "Wacom Intuos PT S", 15200, 9500, 1023, 31,
31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
.touch_max = 16 }; .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x303 = static const struct wacom_features wacom_features_0x303 =
{ "Wacom Intuos PT M", WACOM_PKGLEN_BBPEN, 21600, 13500, 1023, { "Wacom Intuos PT M", 21600, 13500, 1023, 31,
31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
.touch_max = 16 }; .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x30E = static const struct wacom_features wacom_features_0x30E =
{ "Wacom Intuos S", WACOM_PKGLEN_BBPEN, 15200, 9500, 1023, { "Wacom Intuos S", 15200, 9500, 1023, 31,
31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x6004 = static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, { "ISD-V4", 12800, 8000, 255, 0,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x0307 = static const struct wacom_features wacom_features_0x307 =
{ "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 59352, 33648, 2047, { "Wacom ISDv5 307", 59352, 33648, 2047, 63,
63, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200, CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 200, 200,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
static const struct wacom_features wacom_features_0x0309 = static const struct wacom_features wacom_features_0x309 =
{ "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */ { "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10 }; .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
#define USB_DEVICE_WACOM(prod) \ #define USB_DEVICE_WACOM(prod) \
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
.driver_info = (kernel_ulong_t)&wacom_features_##prod .driver_data = (kernel_ulong_t)&wacom_features_##prod
#define USB_DEVICE_DETAILED(prod, class, sub, proto) \ #define BT_DEVICE_WACOM(prod) \
USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_WACOM, prod, class, \ HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\
sub, proto), \ .driver_data = (kernel_ulong_t)&wacom_features_##prod
.driver_info = (kernel_ulong_t)&wacom_features_##prod
#define USB_DEVICE_LENOVO(prod) \ #define USB_DEVICE_LENOVO(prod) \
USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \
.driver_info = (kernel_ulong_t)&wacom_features_##prod .driver_data = (kernel_ulong_t)&wacom_features_##prod
const struct usb_device_id wacom_ids[] = { const struct hid_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x00) }, { USB_DEVICE_WACOM(0x00) },
{ USB_DEVICE_WACOM(0x03) },
{ USB_DEVICE_WACOM(0x10) }, { USB_DEVICE_WACOM(0x10) },
{ USB_DEVICE_WACOM(0x11) }, { USB_DEVICE_WACOM(0x11) },
{ USB_DEVICE_WACOM(0x12) }, { USB_DEVICE_WACOM(0x12) },
...@@ -2372,20 +2613,16 @@ const struct usb_device_id wacom_ids[] = { ...@@ -2372,20 +2613,16 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x17) }, { USB_DEVICE_WACOM(0x17) },
{ USB_DEVICE_WACOM(0x18) }, { USB_DEVICE_WACOM(0x18) },
{ USB_DEVICE_WACOM(0x19) }, { USB_DEVICE_WACOM(0x19) },
{ USB_DEVICE_WACOM(0x60) },
{ USB_DEVICE_WACOM(0x61) },
{ USB_DEVICE_WACOM(0x62) },
{ USB_DEVICE_WACOM(0x63) },
{ USB_DEVICE_WACOM(0x64) },
{ USB_DEVICE_WACOM(0x65) },
{ USB_DEVICE_WACOM(0x69) },
{ USB_DEVICE_WACOM(0x6A) },
{ USB_DEVICE_WACOM(0x6B) },
{ USB_DEVICE_WACOM(0x20) }, { USB_DEVICE_WACOM(0x20) },
{ USB_DEVICE_WACOM(0x21) }, { USB_DEVICE_WACOM(0x21) },
{ USB_DEVICE_WACOM(0x22) }, { USB_DEVICE_WACOM(0x22) },
{ USB_DEVICE_WACOM(0x23) }, { USB_DEVICE_WACOM(0x23) },
{ USB_DEVICE_WACOM(0x24) }, { USB_DEVICE_WACOM(0x24) },
{ USB_DEVICE_WACOM(0x26) },
{ USB_DEVICE_WACOM(0x27) },
{ USB_DEVICE_WACOM(0x28) },
{ USB_DEVICE_WACOM(0x29) },
{ USB_DEVICE_WACOM(0x2A) },
{ USB_DEVICE_WACOM(0x30) }, { USB_DEVICE_WACOM(0x30) },
{ USB_DEVICE_WACOM(0x31) }, { USB_DEVICE_WACOM(0x31) },
{ USB_DEVICE_WACOM(0x32) }, { USB_DEVICE_WACOM(0x32) },
...@@ -2395,20 +2632,34 @@ const struct usb_device_id wacom_ids[] = { ...@@ -2395,20 +2632,34 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x37) }, { USB_DEVICE_WACOM(0x37) },
{ USB_DEVICE_WACOM(0x38) }, { USB_DEVICE_WACOM(0x38) },
{ USB_DEVICE_WACOM(0x39) }, { USB_DEVICE_WACOM(0x39) },
{ USB_DEVICE_WACOM(0xC4) }, { USB_DEVICE_WACOM(0x3F) },
{ USB_DEVICE_WACOM(0xC0) },
{ USB_DEVICE_WACOM(0xC2) },
{ USB_DEVICE_WACOM(0x03) },
{ USB_DEVICE_WACOM(0x41) }, { USB_DEVICE_WACOM(0x41) },
{ USB_DEVICE_WACOM(0x42) }, { USB_DEVICE_WACOM(0x42) },
{ USB_DEVICE_WACOM(0x43) }, { USB_DEVICE_WACOM(0x43) },
{ USB_DEVICE_WACOM(0x44) }, { USB_DEVICE_WACOM(0x44) },
{ USB_DEVICE_WACOM(0x45) }, { USB_DEVICE_WACOM(0x45) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0x57) }, { USB_DEVICE_WACOM(0x57) },
{ USB_DEVICE_WACOM(0x59) }, { USB_DEVICE_WACOM(0x59) },
{ USB_DEVICE_DETAILED(0x5D, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0x5B) }, { USB_DEVICE_WACOM(0x5B) },
{ USB_DEVICE_DETAILED(0x5E, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x5D) },
{ USB_DEVICE_WACOM(0x5E) },
{ USB_DEVICE_WACOM(0x60) },
{ USB_DEVICE_WACOM(0x61) },
{ USB_DEVICE_WACOM(0x62) },
{ USB_DEVICE_WACOM(0x63) },
{ USB_DEVICE_WACOM(0x64) },
{ USB_DEVICE_WACOM(0x65) },
{ USB_DEVICE_WACOM(0x69) },
{ USB_DEVICE_WACOM(0x6A) },
{ USB_DEVICE_WACOM(0x6B) },
{ BT_DEVICE_WACOM(0x81) },
{ USB_DEVICE_WACOM(0x84) },
{ USB_DEVICE_WACOM(0x90) },
{ USB_DEVICE_WACOM(0x93) },
{ USB_DEVICE_WACOM(0x97) },
{ USB_DEVICE_WACOM(0x9A) },
{ USB_DEVICE_WACOM(0x9F) },
{ USB_DEVICE_WACOM(0xB0) }, { USB_DEVICE_WACOM(0xB0) },
{ USB_DEVICE_WACOM(0xB1) }, { USB_DEVICE_WACOM(0xB1) },
{ USB_DEVICE_WACOM(0xB2) }, { USB_DEVICE_WACOM(0xB2) },
...@@ -2421,23 +2672,15 @@ const struct usb_device_id wacom_ids[] = { ...@@ -2421,23 +2672,15 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xBA) }, { USB_DEVICE_WACOM(0xBA) },
{ USB_DEVICE_WACOM(0xBB) }, { USB_DEVICE_WACOM(0xBB) },
{ USB_DEVICE_WACOM(0xBC) }, { USB_DEVICE_WACOM(0xBC) },
{ USB_DEVICE_WACOM(0x26) }, { BT_DEVICE_WACOM(0xBD) },
{ USB_DEVICE_WACOM(0x27) }, { USB_DEVICE_WACOM(0xC0) },
{ USB_DEVICE_WACOM(0x28) }, { USB_DEVICE_WACOM(0xC2) },
{ USB_DEVICE_WACOM(0x29) }, { USB_DEVICE_WACOM(0xC4) },
{ USB_DEVICE_WACOM(0x2A) },
{ USB_DEVICE_WACOM(0x3F) },
{ USB_DEVICE_WACOM(0xC5) }, { USB_DEVICE_WACOM(0xC5) },
{ USB_DEVICE_WACOM(0xC6) }, { USB_DEVICE_WACOM(0xC6) },
{ USB_DEVICE_WACOM(0xC7) }, { USB_DEVICE_WACOM(0xC7) },
/* { USB_DEVICE_WACOM(0xCC) },
* DTU-2231 has two interfaces on the same configuration, { USB_DEVICE_WACOM(0xCE) },
* only one is used.
*/
{ USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ USB_DEVICE_WACOM(0x84) },
{ USB_DEVICE_WACOM(0xD0) }, { USB_DEVICE_WACOM(0xD0) },
{ USB_DEVICE_WACOM(0xD1) }, { USB_DEVICE_WACOM(0xD1) },
{ USB_DEVICE_WACOM(0xD2) }, { USB_DEVICE_WACOM(0xD2) },
...@@ -2452,13 +2695,6 @@ const struct usb_device_id wacom_ids[] = { ...@@ -2452,13 +2695,6 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xDD) }, { USB_DEVICE_WACOM(0xDD) },
{ USB_DEVICE_WACOM(0xDE) }, { USB_DEVICE_WACOM(0xDE) },
{ USB_DEVICE_WACOM(0xDF) }, { USB_DEVICE_WACOM(0xDF) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
{ USB_DEVICE_WACOM(0x93) },
{ USB_DEVICE_WACOM(0x97) },
{ USB_DEVICE_WACOM(0x9A) },
{ USB_DEVICE_WACOM(0x9F) },
{ USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE2) },
{ USB_DEVICE_WACOM(0xE3) }, { USB_DEVICE_WACOM(0xE3) },
{ USB_DEVICE_WACOM(0xE5) }, { USB_DEVICE_WACOM(0xE5) },
...@@ -2466,34 +2702,34 @@ const struct usb_device_id wacom_ids[] = { ...@@ -2466,34 +2702,34 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0xEC) },
{ USB_DEVICE_WACOM(0xED) }, { USB_DEVICE_WACOM(0xED) },
{ USB_DEVICE_WACOM(0xEF) }, { USB_DEVICE_WACOM(0xEF) },
{ USB_DEVICE_WACOM(0xF0) },
{ USB_DEVICE_WACOM(0xF4) },
{ USB_DEVICE_WACOM(0xF6) },
{ USB_DEVICE_WACOM(0xF8) },
{ USB_DEVICE_WACOM(0xFA) },
{ USB_DEVICE_WACOM(0xFB) },
{ USB_DEVICE_WACOM(0x100) }, { USB_DEVICE_WACOM(0x100) },
{ USB_DEVICE_WACOM(0x101) }, { USB_DEVICE_WACOM(0x101) },
{ USB_DEVICE_WACOM(0x10D) }, { USB_DEVICE_WACOM(0x10D) },
{ USB_DEVICE_WACOM(0x10E) }, { USB_DEVICE_WACOM(0x10E) },
{ USB_DEVICE_WACOM(0x10F) }, { USB_DEVICE_WACOM(0x10F) },
{ USB_DEVICE_WACOM(0x116) }, { USB_DEVICE_WACOM(0x116) },
{ USB_DEVICE_WACOM(0x12C) },
{ USB_DEVICE_WACOM(0x300) }, { USB_DEVICE_WACOM(0x300) },
{ USB_DEVICE_WACOM(0x301) }, { USB_DEVICE_WACOM(0x301) },
{ USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x302) },
{ USB_DEVICE_DETAILED(0x303, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x303) },
{ USB_DEVICE_DETAILED(0x30E, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0x304) }, { USB_DEVICE_WACOM(0x304) },
{ USB_DEVICE_DETAILED(0x314, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x307) },
{ USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x309) },
{ USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0x30E) },
{ USB_DEVICE_WACOM(0x314) },
{ USB_DEVICE_WACOM(0x315) },
{ USB_DEVICE_WACOM(0x317) },
{ USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) }, { USB_DEVICE_WACOM(0x5000) },
{ USB_DEVICE_WACOM(0x5002) }, { USB_DEVICE_WACOM(0x5002) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
{ USB_DEVICE_WACOM(0xF8) },
{ USB_DEVICE_DETAILED(0xF6, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0xFA) },
{ USB_DEVICE_WACOM(0xFB) },
{ USB_DEVICE_WACOM(0x0307) },
{ USB_DEVICE_DETAILED(0x0309, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_LENOVO(0x6004) },
{ } { }
}; };
MODULE_DEVICE_TABLE(usb, wacom_ids); MODULE_DEVICE_TABLE(hid, wacom_ids);
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
/* wacom data packet report IDs */ /* wacom data packet report IDs */
#define WACOM_REPORT_PENABLED 2 #define WACOM_REPORT_PENABLED 2
#define WACOM_REPORT_PENABLED_BT 3
#define WACOM_REPORT_INTUOSREAD 5 #define WACOM_REPORT_INTUOSREAD 5
#define WACOM_REPORT_INTUOSWRITE 6 #define WACOM_REPORT_INTUOSWRITE 6
#define WACOM_REPORT_INTUOSPAD 12 #define WACOM_REPORT_INTUOSPAD 12
...@@ -68,10 +69,12 @@ ...@@ -68,10 +69,12 @@
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002 #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
#define WACOM_QUIRK_NO_INPUT 0x0004 #define WACOM_QUIRK_NO_INPUT 0x0004
#define WACOM_QUIRK_MONITOR 0x0008 #define WACOM_QUIRK_MONITOR 0x0008
#define WACOM_QUIRK_BATTERY 0x0010
enum { enum {
PENPARTNER = 0, PENPARTNER = 0,
GRAPHIRE, GRAPHIRE,
GRAPHIRE_BT,
WACOM_G4, WACOM_G4,
PTU, PTU,
PL, PL,
...@@ -83,6 +86,7 @@ enum { ...@@ -83,6 +86,7 @@ enum {
INTUOS3L, INTUOS3L,
INTUOS4S, INTUOS4S,
INTUOS4, INTUOS4,
INTUOS4WL,
INTUOS4L, INTUOS4L,
INTUOS5S, INTUOS5S,
INTUOS5, INTUOS5,
...@@ -114,7 +118,6 @@ enum { ...@@ -114,7 +118,6 @@ enum {
struct wacom_features { struct wacom_features {
const char *name; const char *name;
int pktlen;
int x_max; int x_max;
int y_max; int y_max;
int pressure_max; int pressure_max;
...@@ -127,8 +130,8 @@ struct wacom_features { ...@@ -127,8 +130,8 @@ struct wacom_features {
int device_type; int device_type;
int x_phy; int x_phy;
int y_phy; int y_phy;
unsigned char unit; unsigned unit;
unsigned char unitExpo; int unitExpo;
int x_fuzz; int x_fuzz;
int y_fuzz; int y_fuzz;
int pressure_fuzz; int pressure_fuzz;
...@@ -137,6 +140,9 @@ struct wacom_features { ...@@ -137,6 +140,9 @@ struct wacom_features {
unsigned touch_max; unsigned touch_max;
int oVid; int oVid;
int oPid; int oPid;
int pktlen;
bool check_for_hid_type;
int hid_type;
}; };
struct wacom_shared { struct wacom_shared {
...@@ -150,16 +156,24 @@ struct wacom_shared { ...@@ -150,16 +156,24 @@ struct wacom_shared {
struct wacom_wac { struct wacom_wac {
char name[WACOM_NAME_MAX]; char name[WACOM_NAME_MAX];
unsigned char *data; char pad_name[WACOM_NAME_MAX];
char bat_name[WACOM_NAME_MAX];
char ac_name[WACOM_NAME_MAX];
unsigned char data[WACOM_PKGLEN_MAX];
int tool[2]; int tool[2];
int id[2]; int id[2];
__u32 serial[2]; __u32 serial[2];
struct wacom_features features; struct wacom_features features;
struct wacom_shared *shared; struct wacom_shared *shared;
struct input_dev *input; struct input_dev *input;
struct input_dev *pad_input;
int pid; int pid;
int battery_capacity; int battery_capacity;
int num_contacts_left; int num_contacts_left;
int bat_charging;
int ps_connected;
u8 bt_features;
u8 bt_high_speed;
}; };
#endif #endif
...@@ -73,22 +73,6 @@ config TABLET_USB_KBTAB ...@@ -73,22 +73,6 @@ config TABLET_USB_KBTAB
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called kbtab. module will be called kbtab.
config TABLET_USB_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_ARCH_HAS_HCD
select POWER_SUPPLY
select USB
select NEW_LEDS
select LEDS_CLASS
help
Say Y here if you want to use the USB version of the Wacom Intuos
or Graphire tablet. Make sure to say Y to "Mouse support"
(CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
(CONFIG_INPUT_EVDEV) as well.
To compile this driver as a module, choose M here: the
module will be called wacom.
config TABLET_SERIAL_WACOM4 config TABLET_SERIAL_WACOM4
tristate "Wacom protocol 4 serial tablet support" tristate "Wacom protocol 4 serial tablet support"
select SERIO select SERIO
......
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
# Makefile for the tablet drivers # Makefile for the tablet drivers
# #
# Multipart objects.
wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o
...@@ -310,6 +310,11 @@ struct hid_item { ...@@ -310,6 +310,11 @@ struct hid_item {
*/ */
#define HID_GROUP_RMI 0x0100 #define HID_GROUP_RMI 0x0100
/*
* Vendor specific HID device groups
*/
#define HID_GROUP_WACOM 0x0101
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
* persistent for main-items. The global environment can be saved and * persistent for main-items. The global environment can be saved and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment