Commit 1963518b authored by Ping Cheng's avatar Ping Cheng Committed by Dmitry Torokhov

Input: wacom - add 0xE5 (MT device) support

Main part of patch is adding support for a new Wacom MT touch
packet and labels these devices using MTSCREEN type.

Other items of interest:

Delete some duplicate code in HID parsing for Y info since
its already done in X path.

In wacom_query_tablet_data(), only invoke the set report
that requests tablets to send Wacom Touch packets for
Finger interfaces.  Mostly, this is to make code intent clear.
Tested-by: default avatarJason Gerecke <killertofu@gmail.com>
Signed-off-by: default avatarChris Bagwell <chris@cnpbagwell.com>
Signed-off-by: default avatarPing Cheng <pingc@wacom.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent f393ee2b
...@@ -135,6 +135,6 @@ extern const struct usb_device_id wacom_ids[]; ...@@ -135,6 +135,6 @@ extern const struct usb_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);
void 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);
#endif #endif
...@@ -317,6 +317,10 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -317,6 +317,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
/* need to reset back */ /* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG; features->pktlen = WACOM_PKGLEN_TPC2FG;
} }
if (features->type == MTSCREEN)
features->pktlen = WACOM_PKGLEN_MTOUCH;
if (features->type == BAMBOO_PT) { if (features->type == BAMBOO_PT) {
/* need to reset back */ /* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH; features->pktlen = WACOM_PKGLEN_BBTOUCH;
...@@ -349,18 +353,15 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -349,18 +353,15 @@ static int wacom_parse_hid(struct usb_interface *intf,
case HID_USAGE_Y: case HID_USAGE_Y:
if (usage == WCM_DESKTOP) { if (usage == WCM_DESKTOP) {
if (finger) { if (finger) {
features->device_type = BTN_TOOL_FINGER; int type = features->type;
if (features->type == TABLETPC2FG) {
/* need to reset back */ if (type == TABLETPC2FG || type == MTSCREEN) {
features->pktlen = WACOM_PKGLEN_TPC2FG;
features->y_max = features->y_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
features->y_phy = features->y_phy =
get_unaligned_le16(&report[i + 6]); get_unaligned_le16(&report[i + 6]);
i += 7; i += 7;
} else if (features->type == BAMBOO_PT) { } else if (type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
features->y_phy = features->y_phy =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
features->y_max = features->y_max =
...@@ -374,10 +375,6 @@ static int wacom_parse_hid(struct usb_interface *intf, ...@@ -374,10 +375,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 4; i += 4;
} }
} else if (pen) { } else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->y_max = features->y_max =
get_unaligned_le16(&report[i + 3]); get_unaligned_le16(&report[i + 3]);
i += 4; i += 4;
...@@ -440,22 +437,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat ...@@ -440,22 +437,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
if (!rep_data) if (!rep_data)
return error; return error;
/* ask to report tablet data if it is MT Tablet PC or /* ask to report Wacom data */
* not a Tablet PC */ if (features->device_type == BTN_TOOL_FINGER) {
if (features->type == TABLETPC2FG) { /* if it is an MT Tablet PC touch */
do { if (features->type == TABLETPC2FG ||
rep_data[0] = 3; features->type == MTSCREEN) {
rep_data[1] = 4; do {
rep_data[2] = 0; rep_data[0] = 3;
rep_data[3] = 0; rep_data[1] = 4;
report_id = 3; rep_data[2] = 0;
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, rep_data[3] = 0;
report_id, rep_data, 4, 1); report_id = 3;
if (error >= 0) error = wacom_set_report(intf,
error = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
WAC_HID_FEATURE_REPORT, report_id,
report_id, rep_data, 4, 1); rep_data, 4, 1);
} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES); if (error >= 0)
error = wacom_get_report(intf,
WAC_HID_FEATURE_REPORT,
report_id,
rep_data, 4, 1);
} while ((error < 0 || rep_data[1] != 4) &&
limit++ < WAC_MSG_RETRIES);
}
} else if (features->type != TABLETPC && } else if (features->type != TABLETPC &&
features->type != WIRELESS && features->type != WIRELESS &&
features->device_type == BTN_TOOL_PEN) { features->device_type == BTN_TOOL_PEN) {
...@@ -477,7 +481,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat ...@@ -477,7 +481,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
} }
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
struct wacom_features *features) struct wacom_features *features)
{ {
int error = 0; int error = 0;
struct usb_host_interface *interface = intf->cur_altsetting; struct usb_host_interface *interface = intf->cur_altsetting;
...@@ -505,10 +509,13 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, ...@@ -505,10 +509,13 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
} }
} }
/* only Tablet PCs and Bamboo P&T need to retrieve the info */ /* only devices that support touch need to retrieve the info */
if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) && if (features->type != TABLETPC &&
(features->type != BAMBOO_PT)) features->type != TABLETPC2FG &&
features->type != BAMBOO_PT &&
features->type != MTSCREEN) {
goto out; goto out;
}
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
if (usb_get_extra_descriptor(&interface->endpoint[0], if (usb_get_extra_descriptor(&interface->endpoint[0],
...@@ -978,8 +985,10 @@ static int wacom_register_input(struct wacom *wacom) ...@@ -978,8 +985,10 @@ static int wacom_register_input(struct wacom *wacom)
int error; int error;
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) if (!input_dev) {
return -ENOMEM; error = -ENOMEM;
goto fail1;
}
input_dev->name = wacom_wac->name; input_dev->name = wacom_wac->name;
input_dev->dev.parent = &intf->dev; input_dev->dev.parent = &intf->dev;
...@@ -989,14 +998,20 @@ static int wacom_register_input(struct wacom *wacom) ...@@ -989,14 +998,20 @@ static int wacom_register_input(struct wacom *wacom)
input_set_drvdata(input_dev, wacom); input_set_drvdata(input_dev, wacom);
wacom_wac->input = input_dev; wacom_wac->input = input_dev;
wacom_setup_input_capabilities(input_dev, wacom_wac); error = wacom_setup_input_capabilities(input_dev, wacom_wac);
if (error)
goto fail1;
error = input_register_device(input_dev); error = input_register_device(input_dev);
if (error) { if (error)
input_free_device(input_dev); goto fail2;
wacom_wac->input = NULL;
} return 0;
fail2:
input_free_device(input_dev);
wacom_wac->input = NULL;
fail1:
return error; return error;
} }
......
...@@ -768,6 +768,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) ...@@ -768,6 +768,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 1; return 1;
} }
static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
{
int touch_max = wacom->features.touch_max;
int i;
if (!wacom->slots)
return -1;
for (i = 0; i < touch_max; ++i) {
if (wacom->slots[i] == contactid)
return i;
}
for (i = 0; i < touch_max; ++i) {
if (wacom->slots[i] == -1)
return i;
}
return -1;
}
static int wacom_mt_touch(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
char *data = wacom->data;
int i;
int current_num_contacts = data[2];
int contacts_to_send = 0;
/*
* First packet resets the counter since only the first
* packet in series will have non-zero current_num_contacts.
*/
if (current_num_contacts)
wacom->num_contacts_left = current_num_contacts;
/* There are at most 5 contacts per packet */
contacts_to_send = min(5, wacom->num_contacts_left);
for (i = 0; i < contacts_to_send; i++) {
int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
bool touch = data[offset] & 0x1;
int id = le16_to_cpup((__le16 *)&data[offset + 1]);
int slot = find_slot_from_contactid(wacom, id);
if (slot < 0)
continue;
input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
int x = le16_to_cpup((__le16 *)&data[offset + 7]);
int y = le16_to_cpup((__le16 *)&data[offset + 9]);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
wacom->slots[slot] = touch ? id : -1;
}
input_mt_report_pointer_emulation(input, true);
wacom->num_contacts_left -= contacts_to_send;
if (wacom->num_contacts_left < 0)
wacom->num_contacts_left = 0;
return 1;
}
static int wacom_tpc_mt_touch(struct wacom_wac *wacom) static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
{ {
struct input_dev *input = wacom->input; struct input_dev *input = wacom->input;
...@@ -806,6 +872,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) ...@@ -806,6 +872,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
bool prox; bool prox;
int x = 0, y = 0; int x = 0, y = 0;
if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
return 0;
if (!wacom->shared->stylus_in_proximity) { if (!wacom->shared->stylus_in_proximity) {
if (len == WACOM_PKGLEN_TPC1FG) { if (len == WACOM_PKGLEN_TPC1FG) {
prox = data[0] & 0x01; prox = data[0] & 0x01;
...@@ -873,10 +942,10 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) ...@@ -873,10 +942,10 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
switch (len) { switch (len) {
case WACOM_PKGLEN_TPC1FG: case WACOM_PKGLEN_TPC1FG:
return wacom_tpc_single_touch(wacom, len); return wacom_tpc_single_touch(wacom, len);
case WACOM_PKGLEN_TPC2FG: case WACOM_PKGLEN_TPC2FG:
return wacom_tpc_mt_touch(wacom); return wacom_tpc_mt_touch(wacom);
default: default:
switch (data[0]) { switch (data[0]) {
...@@ -885,6 +954,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) ...@@ -885,6 +954,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
case WACOM_REPORT_TPCST: case WACOM_REPORT_TPCST:
return wacom_tpc_single_touch(wacom, len); return wacom_tpc_single_touch(wacom, len);
case WACOM_REPORT_TPCMT:
return wacom_mt_touch(wacom);
case WACOM_REPORT_PENABLED: case WACOM_REPORT_PENABLED:
return wacom_tpc_pen(wacom); return wacom_tpc_pen(wacom);
} }
...@@ -1164,6 +1236,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) ...@@ -1164,6 +1236,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case TABLETPC: case TABLETPC:
case TABLETPC2FG: case TABLETPC2FG:
case MTSCREEN:
sync = wacom_tpc_irq(wacom_wac, len); sync = wacom_tpc_irq(wacom_wac, len);
break; break;
...@@ -1237,7 +1310,8 @@ void wacom_setup_device_quirks(struct wacom_features *features) ...@@ -1237,7 +1310,8 @@ void wacom_setup_device_quirks(struct wacom_features *features)
/* these device have multiple inputs */ /* these device have multiple inputs */
if (features->type == TABLETPC || features->type == TABLETPC2FG || if (features->type == TABLETPC || features->type == TABLETPC2FG ||
features->type == BAMBOO_PT || features->type == WIRELESS || features->type == BAMBOO_PT || features->type == WIRELESS ||
(features->type >= INTUOS5S && features->type <= INTUOS5L)) (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
features->type == MTSCREEN)
features->quirks |= WACOM_QUIRK_MULTI_INPUT; features->quirks |= WACOM_QUIRK_MULTI_INPUT;
/* quirk for bamboo touch with 2 low res touches */ /* quirk for bamboo touch with 2 low res touches */
...@@ -1268,8 +1342,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max, ...@@ -1268,8 +1342,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
return (logical_max * 100) / physical_max; return (logical_max * 100) / physical_max;
} }
void 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)
{ {
struct wacom_features *features = &wacom_wac->features; struct wacom_features *features = &wacom_wac->features;
int i; int i;
...@@ -1465,8 +1539,18 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1465,8 +1539,18 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
break; break;
case TABLETPC2FG: case TABLETPC2FG:
case MTSCREEN:
if (features->device_type == BTN_TOOL_FINGER) { if (features->device_type == BTN_TOOL_FINGER) {
wacom_wac->slots = kmalloc(features->touch_max *
sizeof(int),
GFP_KERNEL);
if (!wacom_wac->slots)
return -ENOMEM;
for (i = 0; i < features->touch_max; i++)
wacom_wac->slots[i] = -1;
input_mt_init_slots(input_dev, features->touch_max); input_mt_init_slots(input_dev, features->touch_max);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0); 0, MT_TOOL_MAX, 0, 0);
...@@ -1552,6 +1636,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1552,6 +1636,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
} }
break; break;
} }
return 0;
} }
static const struct wacom_features wacom_features_0x00 = static const struct wacom_features wacom_features_0x00 =
...@@ -1784,6 +1869,9 @@ static const struct wacom_features wacom_features_0xE3 = ...@@ -1784,6 +1869,9 @@ static const struct wacom_features wacom_features_0xE3 =
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 }; .touch_max = 2 };
static const struct wacom_features wacom_features_0xE5 =
{ "Wacom ISDv4 E5", WACOM_PKGLEN_MTOUCH, 26202, 16325, 255,
0, 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", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
...@@ -1962,6 +2050,7 @@ const struct usb_device_id wacom_ids[] = { ...@@ -1962,6 +2050,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x9F) }, { 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(0xE6) }, { USB_DEVICE_WACOM(0xE6) },
{ USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0xEC) },
{ USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_WACOM(0x47) },
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
#define WACOM_PKGLEN_BBTOUCH3 64 #define WACOM_PKGLEN_BBTOUCH3 64
#define WACOM_PKGLEN_BBPEN 10 #define WACOM_PKGLEN_BBPEN 10
#define WACOM_PKGLEN_WIRELESS 32 #define WACOM_PKGLEN_WIRELESS 32
#define WACOM_PKGLEN_MTOUCH 62
/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11
/* device IDs */ /* device IDs */
#define STYLUS_DEVICE_ID 0x02 #define STYLUS_DEVICE_ID 0x02
...@@ -41,6 +45,7 @@ ...@@ -41,6 +45,7 @@
#define WACOM_REPORT_INTUOS5PAD 3 #define WACOM_REPORT_INTUOS5PAD 3
#define WACOM_REPORT_TPC1FG 6 #define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13 #define WACOM_REPORT_TPC2FG 13
#define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCHID 15 #define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16 #define WACOM_REPORT_TPCST 16
...@@ -76,6 +81,7 @@ enum { ...@@ -76,6 +81,7 @@ enum {
WACOM_MO, WACOM_MO,
TABLETPC, TABLETPC,
TABLETPC2FG, TABLETPC2FG,
MTSCREEN,
MAX_TYPE MAX_TYPE
}; };
...@@ -118,6 +124,8 @@ struct wacom_wac { ...@@ -118,6 +124,8 @@ struct wacom_wac {
struct input_dev *input; struct input_dev *input;
int pid; int pid;
int battery_capacity; int battery_capacity;
int num_contacts_left;
int *slots;
}; };
#endif #endif
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