From: Chris Bagwell <ch...@cnpbagwell.com> This aligns 2.6.30 behavior with 2.6.38 driver except for MT support. Instead of MT events for touch, it sends ABS_X/Y for 1st touch only. This is similar to a synaptics touchpad behavior.
The driver does correctly send DOUBLE/TRIPLE/QUADTAP events so if user maps input to xf86-input-synaptics then they will get working 2-finger gestures for scrolling. This works because Bamboo was also changed from Protocol 4 to Generic Protocol; same as 2.6.36 and 2.6.38 driver. This also means either xf86-input-wacom 0.11 or 0.12 is needed. Tested with CentOS 6.2 (2.6.32 kernel and Xorg 1.10) and xf86-input-wacom 0.12. --- Anybody see a reason not to change from Protocol 4 to Generic so they are all working the same? This basically means remove the report for MSC_SERIAL with a value fixed to "0". 2.6.30/wacom_sys.c | 35 +++++- 2.6.30/wacom_wac.c | 339 +++++++++++++++++++++++++++++++--------------------- 2.6.30/wacom_wac.h | 2 + 3 files changed, 236 insertions(+), 140 deletions(-) diff --git a/2.6.30/wacom_sys.c b/2.6.30/wacom_sys.c index d460d6d..8d616df 100755 --- a/2.6.30/wacom_sys.c +++ b/2.6.30/wacom_sys.c @@ -32,7 +32,10 @@ #define HID_USAGE_Y_TILT 0x3e #define HID_USAGE_FINGER 0x22 #define HID_USAGE_STYLUS 0x20 -#define HID_COLLECTION 0xc0 +#define HID_COLLECTION 0xa1 +#define HID_COLLECTION_LOGICAL 0x02 +#define HID_COLLECTION_END 0xc0 + enum { WCM_UNDEFINED = 0, @@ -143,6 +146,25 @@ static void wacom_close(struct input_dev *dev) mutex_unlock(&wacom->lock); } +static int wacom_parse_logical_collection(unsigned char *report, + struct wacom_features *features) +{ + int length = 0; + + if (features->type == BAMBOO_PT) { + + /* Logical collection is only used by 3rd gen Bamboo Touch */ + features->pktlen = WACOM_PKGLEN_BBTOUCH3; + features->device_type = BTN_TOOL_DOUBLETAP; + + features->x_max = features->y_max = + get_unaligned_le16(&report[10]); + + length = 11; + } + return length; +} + static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc, struct wacom_features *features) { @@ -302,10 +324,19 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi } break; - case HID_COLLECTION: + case HID_COLLECTION_END: /* reset UsagePage and Finger */ finger = usage = 0; break; + case HID_COLLECTION: + i++; + switch (report[i]) { + case HID_COLLECTION_LOGICAL: + i += wacom_parse_logical_collection(&report[i], + features); + break; + } + break; } } diff --git a/2.6.30/wacom_wac.c b/2.6.30/wacom_wac.c index bad56d3..d678a72 100755 --- a/2.6.30/wacom_wac.c +++ b/2.6.30/wacom_wac.c @@ -197,137 +197,152 @@ static int wacom_ptu_irq(struct wacom_wac *wacom) return 1; } -static void wacom_bpt_finger_in(struct wacom_wac *wacom, char *data, int idx) +static int wacom_bpt_touch(struct wacom_wac *wacom) { - int x = 0, y = 0; - int finger = idx + 1; struct input_dev *input = wacom->input; + unsigned char *data = wacom->data; + int i, touch_count = 0; - x = get_unaligned_be16(&data[3 + (idx * 9)]) & 0x7ff; - y = get_unaligned_be16(&data[5 + (idx * 9)]) & 0x7ff; + if (data[0] != 0x02) + return 0; - if (wacom->last_finger != finger) { - if (x == input->abs[ABS_X]) - x++; + for (i = 0; i < 1; i++) { + int offset = (data[1] & 0x80) ? (8 * 0) : (9 * 0); + bool touch = data[offset + 3] & 0x80; - if (y == input->abs[ABS_Y]) - y++; + /* + * Touch events need to be disabled while stylus is + * in proximity because user's hand is resting on touchpad + * and sending unwanted events. User expects tablet buttons + * to continue working though. + */ + touch = touch && !wacom->shared->stylus_in_proximity; + + if (touch) + touch_count++; + + /* Only 1st touch is supported in kernels without MT */ + if (i > 0) + continue; + + if (touch) { + int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff; + int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff; + x <<= 5; + y <<= 5; + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + } } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_MISC, wacom->id[0]); - input_report_key(input, wacom->tool[finger], 1); + input_report_key(input, BTN_TOUCH, touch_count); + input_report_key(input, BTN_TOOL_FINGER, touch_count == 1); + input_report_key(input, BTN_TOOL_DOUBLETAP, touch_count == 2); + + input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); + input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); + input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); + input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0); - if (!idx) - input_report_key(input, BTN_TOUCH, 1); - input_event(input, EV_MSC, MSC_SERIAL, finger); input_sync(input); - wacom->last_finger = finger; + return 0; } -static void wacom_bpt_touch_out(struct wacom_wac *wacom, int idx) +static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) { - int finger = idx + 1; struct input_dev *input = wacom->input; + bool touch = data[1] & 0x80; - input_report_abs(input, ABS_PRESSURE, 0); - input_report_abs(input, ABS_MISC, 0); - input_report_key(input, wacom->tool[finger], 0); + touch = touch && !wacom->shared->stylus_in_proximity; - if (!idx) - input_report_key(input, BTN_TOUCH, 0); - input_event(input, EV_MSC, MSC_SERIAL, finger); - input_sync(input); + if (touch) { + int x = (data[2] << 4) | (data[4] >> 4); + int y = (data[3] << 4) | (data[4] & 0x0f); + int w = data[6]; + + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_TOOL_WIDTH, w); + } } -static void wacom_bpt_touch_in(struct wacom_wac *wacom) +static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data) { - char *data = wacom->data; + struct input_dev *input = wacom->input; - /* First finger down */ - if (data[3] & 0x80) { - wacom->tool[1] = BTN_TOOL_DOUBLETAP; - wacom->id[0] = TOUCH_DEVICE_ID; - wacom_bpt_finger_in(wacom, data, 0); - } else if (wacom->id[2] & 0x01) - wacom_bpt_touch_out(wacom, 0); - - /* Second finger down */ - if (data[12] & 0x80) { - wacom->tool[2] = BTN_TOOL_TRIPLETAP; - wacom_bpt_finger_in(wacom, data, 1); - } else if (wacom->id[2] & 0x02) - wacom_bpt_touch_out(wacom, 1); + input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); + input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); + input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); + input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0); } -static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len) +static int wacom_bpt3_touch(struct wacom_wac *wacom) { - char *data = wacom->data; - int prox = 0, retval = 0; struct input_dev *input = wacom->input; + unsigned char *data = wacom->data; + int count = data[1] & 0x03; + int i, saw_touch = 0, touch_count = 0; + + if (data[0] != 0x02) + return 0; + + /* data has up to 7 fixed sized 8-byte messages starting at data[2] */ + for (i = 0; i < count; i++) { + int offset = (8 * i) + 2; + int msg_id = data[offset]; + + if (msg_id >= 2 && msg_id <= 17) + { + bool touch = data[offset+1] & 0x80 && !wacom->shared->stylus_in_proximity; + if (touch) + touch_count++; + + /* Only 1st touch support on kernels without MT */ + if (msg_id == 2) + wacom_bpt3_touch_msg(wacom, data + offset); + saw_touch++; + } else if (msg_id == 128) + wacom_bpt3_button_msg(wacom, data + offset); - if (data[0] != WACOM_REPORT_PENABLED) { - dbg("wacom_bpt_irq: received unknown report #%d", data[0]); - goto exit; } - /* Touch packet */ - if (len == WACOM_PKGLEN_BBTOUCH) { - - /* Send pad data if there are any - * don't repeat all zeros - */ - prox = data[1] & 0x0f; - if (prox || wacom->id[1]) { - if (!wacom->id[1]) /* in-prox */ - wacom->id[1] = PAD_DEVICE_ID; - - if (!prox) /* out-prox */ - wacom->id[1] = 0; - - input_report_key(input, BTN_0, data[1] & 0x1); - input_report_key(input, BTN_1, data[1] & 0x2); - input_report_key(input, BTN_2, data[1] & 0x4); - input_report_key(input, BTN_3, data[1] & 0x8); - input_report_abs(input, ABS_MISC, wacom->id[1]); - input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - input_sync(input); - } - - if (wacom->shared->stylus_in_proximity) { - if (wacom->id[2] & 0x01) - wacom_bpt_touch_out(wacom, 0); + if (saw_touch) { + input_report_key(input, BTN_TOUCH, touch_count); + input_report_key(input, BTN_TOOL_FINGER, touch_count == 1); + input_report_key(input, BTN_TOOL_DOUBLETAP, touch_count == 2); + input_report_key(input, BTN_TOOL_TRIPLETAP, touch_count == 3); + input_report_key(input, BTN_TOOL_QUADTAP, touch_count >= 4); + } - if (wacom->id[2] & 0x02) - wacom_bpt_touch_out(wacom, 1); - wacom->id[2] = 0; - return 0; - } + input_sync(input); - prox = (data[17] & 0x30 >> 4); - if (prox) { - /* initialize last touched finger */ - if (!wacom->id[1]) - wacom->last_finger = 1; + return 0; +} - wacom_bpt_touch_in(wacom); - } else { - if (wacom->id[2] & 0x01) - wacom_bpt_touch_out(wacom, 0); +static int wacom_bpt_pen(struct wacom_wac *wacom) +{ + struct input_dev *input = wacom->input; + unsigned char *data = wacom->data; + int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0; - if (wacom->id[2] & 0x02) - wacom_bpt_touch_out(wacom, 1); + if (data[0] != 0x02) + return 0; - wacom->id[0] = 0; - } - wacom->id[2] = (((data[3] & 0x80) >> 7) & 0x1) | - (((data[12] & 0x80) >> 6) & 0x2); + prox = (data[1] & 0x20) == 0x20; - } else if (len == WACOM_PKGLEN_BBFUN) { /* Penabled */ - prox = (data[1] & 0x10) && (data[1] & 0x20); - if (!wacom->shared->stylus_in_proximity) { /* in-prox */ + /* + * All reports shared between PEN and RUBBER tool must be + * forced to a known starting value (zero) when transitioning to + * out-of-prox. + * + * If not reset then, to userspace, it will look like lost events + * if new tool comes in-prox with same values as previous tool sent. + * + * Hardware does report zero in most out-of-prox cases but not all. + */ + if (prox) { + if (!wacom->shared->stylus_in_proximity) { if (data[1] & 0x08) { wacom->tool[0] = BTN_TOOL_RUBBER; wacom->id[0] = ERASER_DEVICE_ID; @@ -337,26 +352,53 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len) } wacom->shared->stylus_in_proximity = true; } - input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); - input_report_abs(input, ABS_DISTANCE, data[8]); - input_report_key(input, BTN_TOUCH, data[1] & 0x01); - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x04); - if (!prox) { - wacom->id[0] = 0; - wacom->shared->stylus_in_proximity = false; - input_report_abs(input, ABS_X, 0); - input_report_abs(input, ABS_Y, 0); - } else { - 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_key(input, wacom->tool[0], prox); - input_report_abs(input, ABS_MISC, wacom->id[0]); - retval = 1; + x = le16_to_cpup((__le16 *)&data[2]); + y = le16_to_cpup((__le16 *)&data[4]); + p = le16_to_cpup((__le16 *)&data[6]); + /* + * Convert distance from out prox to distance from tablet. + * distance will be greater than distance_max once + * touching and applying pressure; do not report negative + * distance. + */ + if (data[8] <= wacom->features.distance_max) + d = wacom->features.distance_max - data[8]; + + pen = data[1] & 0x01; + btn1 = data[1] & 0x02; + btn2 = data[1] & 0x04; } -exit: - return retval; + + input_report_key(input, BTN_TOUCH, pen); + input_report_key(input, BTN_STYLUS, btn1); + input_report_key(input, BTN_STYLUS2, btn2); + + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_PRESSURE, p); + input_report_abs(input, ABS_DISTANCE, d); + + if (!prox) { + wacom->id[0] = 0; + wacom->shared->stylus_in_proximity = false; + } + + input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */ + input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */ + + return 1; +} + +static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len) +{ + if (len == WACOM_PKGLEN_BBTOUCH) + return wacom_bpt_touch(wacom); + else if (len == WACOM_PKGLEN_BBTOUCH3) + return wacom_bpt3_touch(wacom); + else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN) + return wacom_bpt_pen(wacom); + + return 0; } static int wacom_graphire_irq(struct wacom_wac *wacom) @@ -1130,23 +1172,35 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, switch (wacom_wac->features.type) { case BAMBOO_PT: - if (features->device_type == BTN_TOOL_TRIPLETAP) { - __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); - __set_bit(BTN_TOOL_TRIPLETAP, 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); + __clear_bit(ABS_MISC, input_dev->absbit); + + if (features->device_type == BTN_TOOL_DOUBLETAP) { + + __set_bit(BTN_LEFT, input_dev->keybit); + __set_bit(BTN_FORWARD, input_dev->keybit); + __set_bit(BTN_RIGHT, input_dev->keybit); + __set_bit(BTN_BACK, input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0); - input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0); + __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { + __set_bit(BTN_TOOL_TRIPLETAP, + input_dev->keybit); + __set_bit(BTN_TOOL_QUADTAP, + input_dev->keybit); + input_set_abs_params(input_dev, ABS_TOOL_WIDTH, + 0, 255, 0, 0); + + } } if (features->device_type == BTN_TOOL_PEN) { __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit); __set_bit(BTN_STYLUS2, input_dev->keybit); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, + wacom_wac->features.distance_max, + 0, 0); } break; case WACOM_MO: @@ -1318,27 +1372,33 @@ static const struct wacom_features wacom_features_0x6A = static const struct wacom_features wacom_features_0x6B = { "Wacom Bamboo1 5x8", WACOM_PKGLEN_GRAPHIRE, 21648, 13530, 1023, 63, GRAPHIRE }; static const struct wacom_features wacom_features_0xD1 = - { "Wacom BambooFun 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooFun 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD4 = - { "Wacom Bamboo Pen 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Pen 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD2 = - { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD3 = - { "Wacom BambooFun 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 63, BAMBOO_PT }; + { "Wacom BambooFun 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD0 = - { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD5 = - { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD6 = - { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD7 = - { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xD8 = - { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xDA = - { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, BAMBOO_PT }; static const struct wacom_features wacom_features_0xDB = - { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, BAMBOO_PT }; +static const struct wacom_features wacom_features_0xDD = + { "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, 31, BAMBOO_PT }; +static const struct wacom_features wacom_features_0xDE = + { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, 31, BAMBOO_PT }; +static const struct wacom_features wacom_features_0xDF = + { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 21648, 13700, 1023, 31, BAMBOO_PT } ; static const struct wacom_features wacom_features_0x20 = { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; static const struct wacom_features wacom_features_0x21 = @@ -1507,6 +1567,9 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xD8) }, { USB_DEVICE_WACOM(0xDA) }, { USB_DEVICE_WACOM(0xDB) }, + { USB_DEVICE_WACOM(0xDD) }, + { USB_DEVICE_WACOM(0xDE) }, + { USB_DEVICE_WACOM(0xDF) }, { USB_DEVICE_WACOM(0x41) }, { USB_DEVICE_WACOM(0x42) }, { USB_DEVICE_WACOM(0x43) }, diff --git a/2.6.30/wacom_wac.h b/2.6.30/wacom_wac.h index aabe67c..6cd51ff 100755 --- a/2.6.30/wacom_wac.h +++ b/2.6.30/wacom_wac.h @@ -22,6 +22,8 @@ #define WACOM_PKGLEN_TPC1FG 5 #define WACOM_PKGLEN_TPC2FG 14 #define WACOM_PKGLEN_BBTOUCH 20 +#define WACOM_PKGLEN_BBTOUCH3 64 +#define WACOM_PKGLEN_BBPEN 10 /* device IDs */ #define STYLUS_DEVICE_ID 0x02 -- 1.7.7.6 ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ _______________________________________________ Linuxwacom-devel mailing list Linuxwacom-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel