From: Chris Bagwell <ch...@cnpbagwell.com> Bamboo P&T/Tablet PC code supports multi-touch but is using the standard input driver's ABS_X/Y/PRESSURE which filters duplicate events since it does not know they are unrelated. Its also using Wacom-specific "serial channels" concept to inform X driver which finger is currently being sent.
Starting with kernel 2.6.30, a multi-touch interface was added to the kernel input layer to address this issue for all modern multi-touch input devices. This patch converts the 2 finger touch events over to this multi-touch interface. It is backwards compatible in that pre-existing wacom X drivers will still see the first finger's events using standard ABS_X/Y/PRESSURE interface. Additional updates are needed to xdrv to support processing these new MT events. Signed-off-by: Chris Bagwell <ch...@cnpbagwell.com> --- src/2.6.27/wacom.h | 1 + src/2.6.27/wacom_sys.c | 34 +++++- src/2.6.27/wacom_wac.c | 287 ++++++++++++++++++----------------------------- 3 files changed, 141 insertions(+), 181 deletions(-) diff --git a/src/2.6.27/wacom.h b/src/2.6.27/wacom.h index 5ec8abf..60a5fa2 100755 --- a/src/2.6.27/wacom.h +++ b/src/2.6.27/wacom.h @@ -134,6 +134,7 @@ extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data); extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data); extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value); extern void wacom_input_sync(void *wcombo); +extern void wacom_input_mt_sync(void *wcombo); extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/src/2.6.27/wacom_sys.c b/src/2.6.27/wacom_sys.c index 93947b0..8f299f9 100755 --- a/src/2.6.27/wacom_sys.c +++ b/src/2.6.27/wacom_sys.c @@ -160,6 +160,12 @@ void wacom_input_sync(void *wcombo) input_sync(get_input_dev((struct wacom_combo *)wcombo)); } +void wacom_input_mt_sync(void *wcombo) +{ + input_mt_sync(get_input_dev((struct wacom_combo *)wcombo)); +} + + static int wacom_open(struct input_dev *dev) { struct wacom *wacom = input_get_drvdata(dev); @@ -201,12 +207,20 @@ void input_dev_bpt(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { /* 2FGT */ if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) { - input_set_abs_params(input_dev, ABS_RX, 0, - wacom_wac->features->x_phy, 0, 0); + input_set_abs_params(input_dev, ABS_RX, 0, + wacom_wac->features->x_phy, 0, 0); input_set_abs_params(input_dev, ABS_RY, 0, - wacom_wac->features->y_phy, 0, 0); + wacom_wac->features->y_phy, 0, 0); + + /* finger position */ + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, + wacom_wac->features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, + wacom_wac->features->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, + wacom_wac->features->pressure_max, 0, 0); + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP); - input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); @@ -323,6 +337,18 @@ void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0); input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0); input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP); + + if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) { + /* finger position */ + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, + wacom_wac->features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, + wacom_wac->features->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, + wacom_wac->features->pressure_max, + 0, 0); + } + } } diff --git a/src/2.6.27/wacom_wac.c b/src/2.6.27/wacom_wac.c index 13d441b..7e6f25b 100755 --- a/src/2.6.27/wacom_wac.c +++ b/src/2.6.27/wacom_wac.c @@ -150,80 +150,55 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo) return 1; } -static void wacom_bpt_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx) +static void wacom_bpt_touch(struct wacom_wac *wacom, void *wcombo, + int force_out) { - int x = 0, y = 0, pressure; - int finger = idx + 1; + char *data = wacom->data; + int pressure1 = 0, x1 = 0, y1 = 0, pressure2 = 0, x2 = 0, y2 = 0; + int prox1 = 0, prox2 = 0; + + if (!force_out) + { + prox1 = data[3] & 0x80; + if (prox1) + { + pressure1 = (data[2] & 0xff); + x1 = wacom_be16_to_cpu ((unsigned char *)&data[3]) & 0x7ff; + y1 = wacom_be16_to_cpu ((unsigned char *)&data[5]) & 0x7ff; + } + + prox2 = data[12] & 0x80; + if (prox2) + { + pressure2 = (data[11] & 0xff); + x2 = wacom_be16_to_cpu ((unsigned char *)&data[12]) & 0x7ff; + y2 = wacom_be16_to_cpu ((unsigned char *)&data[14]) & 0x7ff; + } + } - pressure = (data[2 + (idx * 9)] & 0xff); - x = wacom_be16_to_cpu ((unsigned char *)&data[3 + (idx * 9)]) & 0x7ff; - y = wacom_be16_to_cpu ((unsigned char *)&data[5 + (idx * 9)]) & 0x7ff; + wacom_report_abs(wcombo, ABS_MT_TOUCH_MAJOR, prox1 != 0); + wacom_report_abs(wcombo, ABS_MT_POSITION_X, x1); + wacom_report_abs(wcombo, ABS_MT_POSITION_Y, y1); - wacom_report_abs(wcombo, ABS_X, x + idx); - wacom_report_abs(wcombo, ABS_Y, y + idx); - wacom_report_abs(wcombo, ABS_PRESSURE, pressure + idx); - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[idx], 1); + wacom_input_mt_sync(wcombo); - if (!idx) - wacom_report_key(wcombo, BTN_TOUCH, 1); - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, finger); -} + wacom_report_abs(wcombo, ABS_MT_TOUCH_MAJOR, prox2 != 0); + wacom_report_abs(wcombo, ABS_MT_POSITION_X, x2); + wacom_report_abs(wcombo, ABS_MT_POSITION_Y, y2); -static void wacom_bpt_touch_out(struct wacom_wac *wacom, void *wcombo, int idx) -{ - int finger = idx + 1; + wacom_input_mt_sync(wcombo); - wacom_report_abs(wcombo, ABS_X, 0); - wacom_report_abs(wcombo, ABS_Y, 0); - wacom_report_abs(wcombo, ABS_PRESSURE, 0); - wacom_report_abs(wcombo, ABS_MISC, 0); - wacom_report_key(wcombo, wacom->tool[idx], 0); + wacom_report_key(wcombo, BTN_TOUCH, prox1); + wacom_report_key(wcombo, BTN_TOOL_DOUBLETAP, prox1 && prox2); - if (!idx) - wacom_report_key(wcombo, BTN_TOUCH, 0); - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, finger); -} + wacom_report_abs(wcombo, ABS_PRESSURE, pressure1); + wacom_report_abs(wcombo, ABS_X, x1); + wacom_report_abs(wcombo, ABS_Y, y1); -static void wacom_bpt_touch_in(struct wacom_wac *wacom, void *wcombo) -{ - char *data = wacom->data; - static int firstFinger = 0; - static int secondFinger = 0; - - wacom->tool[0] = BTN_TOOL_DOUBLETAP; - wacom->id[0] = TOUCH_DEVICE_ID; - wacom->tool[1] = BTN_TOOL_TRIPLETAP; - wacom->id[1] = (((data[3] & 0x80) >> 7) & 0x1) | - (((data[12] & 0x80) >> 6) & 0x2); - - /* First finger down */ - if (data[3] & 0x80) { - wacom_bpt_finger_in(wacom, wcombo, data, 0); - firstFinger = 1; - } else if (firstFinger) { - wacom_bpt_touch_out(wacom, wcombo, 0); - } - - /* Second finger down */ - if (data[12] & 0x80) { - /* sync first finger data */ - if (firstFinger) - wacom_input_sync(wcombo); - - wacom_bpt_finger_in(wacom, wcombo, data, 1); - secondFinger = 1; - } else if (secondFinger) { - /* sync first finger data */ - if (firstFinger) - wacom_input_sync(wcombo); + wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID); + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 1); + wacom_input_sync(wcombo); - wacom_bpt_touch_out(wacom, wcombo, 1); - secondFinger = 0; - } - - if (!(data[3] & 0x80)) - firstFinger = 0; } static int wacom_bpt_irq(struct wacom_wac *wacom, void *wcombo) @@ -265,28 +240,18 @@ static int wacom_bpt_irq(struct wacom_wac *wacom, void *wcombo) if (!stylusInProx) { if (prox) { if (touchInProx) { - wacom_bpt_touch_in(wacom, wcombo); + wacom_bpt_touch(wacom, wcombo, 0); touchOut = 1; retval = 1; } } else { - if (wacom->id[1] & 0x1) { - wacom_bpt_touch_out(wacom, wcombo, 0); - /* sync first finger event */ - if (wacom->id[1] & 0x2) { - wacom_input_sync(wcombo); - } - } - if (wacom->id[1] & 0x2) { - wacom_bpt_touch_out(wacom, wcombo, 1); - } + wacom_bpt_touch(wacom, wcombo, 1); touchOut = 0; touchInProx = 1; retval = 1; } } else if (touchOut || !prox) { /* force touch out-prox */ - wacom_bpt_touch_out(wacom, wcombo, 0); - wacom_bpt_touch_out(wacom, wcombo, 1); + wacom_bpt_touch(wacom, wcombo, 1); touchOut = 0; touchInProx = 1; @@ -785,96 +750,82 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) return 1; } -static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx) -{ - wacom_report_abs(wcombo, ABS_X, - (data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8)); - wacom_report_abs(wcombo, ABS_Y, - (data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8)); - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[idx], 1); - if (!idx) - wacom_report_key(wcombo, BTN_TOUCH, 1); - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, idx + 1); -} - -static void wacom_tpc_touch_out(struct wacom_wac *wacom, void *wcombo, int idx) -{ - wacom_report_abs(wcombo, ABS_X, 0); - wacom_report_abs(wcombo, ABS_Y, 0); - wacom_report_abs(wcombo, ABS_MISC, 0); - wacom_report_key(wcombo, wacom->tool[idx], 0); - if (!idx) - wacom_report_key(wcombo, BTN_TOUCH, 0); - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, idx + 1); - return; -} - -static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo) +static void wacom_tpc_touch(struct wacom_wac *wacom, void *wcombo, + int force_out) { char *data = wacom->data; struct urb *urb = ((struct wacom_combo *)wcombo)->urb; - static int firstFinger = 0; - static int secondFinger = 0; - - wacom->tool[0] = BTN_TOOL_DOUBLETAP; - wacom->id[0] = TOUCH_DEVICE_ID; - wacom->tool[1] = BTN_TOOL_TRIPLETAP; - - if (urb->actual_length != WACOM_PKGLEN_TPC1FG) { - switch (data[0]) { - case WACOM_REPORT_TPC1FG: - wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2])); - wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4])); - wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6])); - wacom_report_key(wcombo, BTN_TOUCH, wacom_le16_to_cpu(&data[6])); - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[0], 1); - break; - case WACOM_REPORT_TPC2FG: - /* keep this byte to send proper out-prox event */ - wacom->id[1] = data[1] & 0x03; - - if (data[1] & 0x01) { - wacom_tpc_finger_in(wacom, wcombo, data, 0); - firstFinger = 1; - } else if (firstFinger) { - wacom_tpc_touch_out(wacom, wcombo, 0); - } - - if (data[1] & 0x02) { - /* sync first finger data */ - if (firstFinger) - wacom_input_sync(wcombo); - - wacom_tpc_finger_in(wacom, wcombo, data, 1); - secondFinger = 1; - } else if (secondFinger) { - /* sync first finger data */ - if (firstFinger) - wacom_input_sync(wcombo); + int pressure1 = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; + int prox1 = 0, prox2 = 0; + int send_multi = 0, send_pressure = 0; + + if (!force_out && urb->actual_length != WACOM_PKGLEN_TPC1FG) { + if (data[0] == WACOM_REPORT_TPC1FG) { + prox1 = data[1] & 0x01; + if (prox1) + { + x1 = wacom_le16_to_cpu(&data[2]); + y1 = wacom_le16_to_cpu(&data[4]); + pressure1 = wacom_le16_to_cpu(&data[6]); + } + send_pressure = 1; + } else if (data[0] == WACOM_REPORT_TPC2FG) { + prox1 = data[1] & 0x01; + if (prox1) + { + x1 = (data[2] & 0xff) | ((data[3] & 0x7f) << 8); + y1 = (data[6] & 0xff) | ((data[7] & 0x7f) << 8); + } - wacom_tpc_touch_out(wacom, wcombo, 1); - secondFinger = 0; - } - if (!(data[1] & 0x01)) - firstFinger = 0; - break; + prox2 = data[1] & 0x01; + if (prox2) + { + x2 = (data[4] & 0xff) | ((data[5] & 0x7f) << 8); + y2 = (data[8] & 0xff) | ((data[9] & 0x7f) << 8); } - } else { - wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1])); - wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3])); - wacom_report_key(wcombo, BTN_TOUCH, 1); - wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); - wacom_report_key(wcombo, wacom->tool[0], 1); + + send_multi = 1; + } + } else if (!force_out) { + prox1 = data[0] & 0x01; + if (prox1) + { + x1 = wacom_le16_to_cpu(&data[1]); + y1 = wacom_le16_to_cpu(&data[3]); + } } + + wacom_report_abs(wcombo, ABS_MT_TOUCH_MAJOR, prox1 != 0); + wacom_report_abs(wcombo, ABS_MT_POSITION_X, x1); + wacom_report_abs(wcombo, ABS_MT_POSITION_Y, y1); + + wacom_input_mt_sync(wcombo); + + wacom_report_abs(wcombo, ABS_MT_TOUCH_MAJOR, prox2 != 0); + wacom_report_abs(wcombo, ABS_MT_POSITION_X, x2); + wacom_report_abs(wcombo, ABS_MT_POSITION_Y, y2); + + wacom_input_mt_sync(wcombo); + + wacom_report_key(wcombo, BTN_TOUCH, prox1); + wacom_report_key(wcombo, BTN_TOOL_DOUBLETAP, prox1 && prox2); + + if (send_pressure) + wacom_report_abs(wcombo, ABS_PRESSURE, pressure1); + wacom_report_abs(wcombo, ABS_X, x1); + wacom_report_abs(wcombo, ABS_Y, y1); + + wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID); + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 1); + wacom_input_sync(wcombo); + return; } static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) { char *data = wacom->data; - int prox = 0, pressure, idx = -1; + int prox = 0, pressure; static int stylusInProx, touchInProx = 1, touchOut; struct urb *urb = ((struct wacom_combo *)wcombo)->urb; @@ -897,36 +848,18 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) if (!stylusInProx) { /* stylus not in prox */ if (prox) { if (touchInProx) { - wacom_tpc_touch_in(wacom, wcombo); + wacom_tpc_touch(wacom, wcombo, 0); touchOut = 1; return 1; } } else { - /* 2FGT out-prox */ - if (data[0] == WACOM_REPORT_TPC2FG) { - idx = (wacom->id[1] & 0x01) - 1; - if (idx == 0) { - wacom_tpc_touch_out(wacom, wcombo, idx); - /* sync first finger event */ - if (wacom->id[1] & 0x02) - wacom_input_sync(wcombo); - } - idx = (wacom->id[1] & 0x02) - 1; - if (idx == 1) - wacom_tpc_touch_out(wacom, wcombo, idx); - } else /* one finger touch */ - wacom_tpc_touch_out(wacom, wcombo, 0); + wacom_tpc_touch(wacom, wcombo, 1); touchOut = 0; touchInProx = 1; return 1; } } else if (touchOut || !prox) { /* force touch out-prox */ - wacom_tpc_touch_out(wacom, wcombo, 0); - if (data[0] == WACOM_REPORT_TPC2FG) { - idx = (wacom->id[1] & 0x02) - 1; - if (idx == 1) - wacom_tpc_touch_out(wacom, wcombo, idx); - } + wacom_tpc_touch(wacom, wcombo, 1); touchOut = 0; touchInProx = 1; return 1; -- 1.6.6.1 ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev _______________________________________________ Linuxwacom-devel mailing list Linuxwacom-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel