From: Ping Cheng Date: Sun, 29 Apr 2012 21:09:18 -0700 Subject: Input: wacom - add 0xE5 (MT device) support commit 1963518b9b1b8019d33b4b08deee6f873ffa2730 upstream. 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: Jason Gerecke Signed-off-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov Signed-off-by: Jonathan Nieder --- drivers/input/tablet/wacom.h | 4 +- drivers/input/tablet/wacom_sys.c | 91 ++++++++++++++++++++--------------- drivers/input/tablet/wacom_wac.c | 99 ++++++++++++++++++++++++++++++++++++-- drivers/input/tablet/wacom_wac.h | 8 +++ 4 files changed, 157 insertions(+), 45 deletions(-) diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index b4842d0e61dd..b79d45198d82 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -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_setup_device_quirks(struct wacom_features *features); -void wacom_setup_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac); +int wacom_setup_input_capabilities(struct input_dev *input_dev, + struct wacom_wac *wacom_wac); #endif diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index 53598c2065cf..734671aeb572 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -317,6 +317,10 @@ static int wacom_parse_hid(struct usb_interface *intf, /* need to reset back */ features->pktlen = WACOM_PKGLEN_TPC2FG; } + + if (features->type == MTSCREEN) + features->pktlen = WACOM_PKGLEN_MTOUCH; + if (features->type == BAMBOO_PT) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_BBTOUCH; @@ -349,18 +353,15 @@ static int wacom_parse_hid(struct usb_interface *intf, case HID_USAGE_Y: if (usage == WCM_DESKTOP) { if (finger) { - features->device_type = BTN_TOOL_FINGER; - if (features->type == TABLETPC2FG) { - /* need to reset back */ - features->pktlen = WACOM_PKGLEN_TPC2FG; + int type = features->type; + + if (type == TABLETPC2FG || type == MTSCREEN) { features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = get_unaligned_le16(&report[i + 6]); i += 7; - } else if (features->type == BAMBOO_PT) { - /* need to reset back */ - features->pktlen = WACOM_PKGLEN_BBTOUCH; + } else if (type == BAMBOO_PT) { features->y_phy = get_unaligned_le16(&report[i + 3]); features->y_max = @@ -374,10 +375,6 @@ static int wacom_parse_hid(struct usb_interface *intf, i += 4; } } 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 = get_unaligned_le16(&report[i + 3]); i += 4; @@ -440,22 +437,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat if (!rep_data) return error; - /* ask to report tablet data if it is MT Tablet PC or - * not a Tablet PC */ - if (features->type == TABLETPC2FG) { - do { - rep_data[0] = 3; - rep_data[1] = 4; - rep_data[2] = 0; - rep_data[3] = 0; - report_id = 3; - error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, - report_id, rep_data, 4, 1); - 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); + /* ask to report Wacom data */ + if (features->device_type == BTN_TOOL_FINGER) { + /* if it is an MT Tablet PC touch */ + if (features->type == TABLETPC2FG || + features->type == MTSCREEN) { + do { + rep_data[0] = 3; + rep_data[1] = 4; + rep_data[2] = 0; + rep_data[3] = 0; + report_id = 3; + error = wacom_set_report(intf, + WAC_HID_FEATURE_REPORT, + report_id, + rep_data, 4, 1); + 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 && features->type != WIRELESS && features->device_type == BTN_TOOL_PEN) { @@ -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, - struct wacom_features *features) + struct wacom_features *features) { int error = 0; struct usb_host_interface *interface = intf->cur_altsetting; @@ -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 */ - if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) && - (features->type != BAMBOO_PT)) + /* only devices that support touch need to retrieve the info */ + if (features->type != TABLETPC && + features->type != TABLETPC2FG && + features->type != BAMBOO_PT && + features->type != MTSCREEN) { goto out; + } if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) { if (usb_get_extra_descriptor(&interface->endpoint[0], @@ -978,8 +985,10 @@ static int wacom_register_input(struct wacom *wacom) int error; input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; + if (!input_dev) { + error = -ENOMEM; + goto fail1; + } input_dev->name = wacom_wac->name; input_dev->dev.parent = &intf->dev; @@ -989,14 +998,20 @@ static int wacom_register_input(struct wacom *wacom) input_set_drvdata(input_dev, wacom); 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); - if (error) { - input_free_device(input_dev); - wacom_wac->input = NULL; - } + if (error) + goto fail2; + return 0; + +fail2: + input_free_device(input_dev); + wacom_wac->input = NULL; +fail1: return error; } diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index e5cd0e57d178..10e5cf870359 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -768,6 +768,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) 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) { struct input_dev *input = wacom->input; @@ -806,6 +872,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) bool prox; int x = 0, y = 0; + if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG) + return 0; + if (!wacom->shared->stylus_in_proximity) { if (len == WACOM_PKGLEN_TPC1FG) { prox = data[0] & 0x01; @@ -873,10 +942,10 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) switch (len) { case WACOM_PKGLEN_TPC1FG: - return wacom_tpc_single_touch(wacom, len); + return wacom_tpc_single_touch(wacom, len); case WACOM_PKGLEN_TPC2FG: - return wacom_tpc_mt_touch(wacom); + return wacom_tpc_mt_touch(wacom); default: switch (data[0]) { @@ -885,6 +954,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) case WACOM_REPORT_TPCST: return wacom_tpc_single_touch(wacom, len); + case WACOM_REPORT_TPCMT: + return wacom_mt_touch(wacom); + case WACOM_REPORT_PENABLED: return wacom_tpc_pen(wacom); } @@ -1164,6 +1236,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) case TABLETPC: case TABLETPC2FG: + case MTSCREEN: sync = wacom_tpc_irq(wacom_wac, len); break; @@ -1237,7 +1310,8 @@ void wacom_setup_device_quirks(struct wacom_features *features) /* these device have multiple inputs */ if (features->type == TABLETPC || features->type == TABLETPC2FG || 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; /* quirk for bamboo touch with 2 low res touches */ @@ -1268,8 +1342,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max, return (logical_max * 100) / physical_max; } -void wacom_setup_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) +int wacom_setup_input_capabilities(struct input_dev *input_dev, + struct wacom_wac *wacom_wac) { struct wacom_features *features = &wacom_wac->features; int i; @@ -1465,8 +1539,18 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, break; case TABLETPC2FG: + case MTSCREEN: 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_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); @@ -1552,6 +1636,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, } break; } + return 0; } static const struct wacom_features wacom_features_0x00 = @@ -1784,6 +1869,9 @@ static const struct wacom_features wacom_features_0xE3 = { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .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 = { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, @@ -1962,6 +2050,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x9F) }, { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, + { USB_DEVICE_WACOM(0xE5) }, { USB_DEVICE_WACOM(0xE6) }, { USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0x47) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 321269c1ac4c..78fbd3f42009 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -25,6 +25,10 @@ #define WACOM_PKGLEN_BBTOUCH3 64 #define WACOM_PKGLEN_BBPEN 10 #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 */ #define STYLUS_DEVICE_ID 0x02 @@ -41,6 +45,7 @@ #define WACOM_REPORT_INTUOS5PAD 3 #define WACOM_REPORT_TPC1FG 6 #define WACOM_REPORT_TPC2FG 13 +#define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCHID 15 #define WACOM_REPORT_TPCST 16 @@ -76,6 +81,7 @@ enum { WACOM_MO, TABLETPC, TABLETPC2FG, + MTSCREEN, MAX_TYPE }; @@ -118,6 +124,8 @@ struct wacom_wac { struct input_dev *input; int pid; int battery_capacity; + int num_contacts_left; + int *slots; }; #endif -- 1.7.10.1