summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/tablet/wacom_wac.c148
-rw-r--r--drivers/input/tablet/wacom_wac.h5
2 files changed, 80 insertions, 73 deletions
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 950a81d7a67c..847fd0135bcf 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -236,13 +236,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
input_report_rel(input, REL_WHEEL, rw);
input_report_key(input, BTN_TOOL_FINGER, 0xf0);
- input_report_abs(input, ABS_MISC, wacom->id[1]);
if (!prox)
wacom->id[1] = 0;
input_report_abs(input, ABS_MISC, wacom->id[1]);
input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+ retval = 1;
}
- retval = 1;
break;
case WACOM_MO:
@@ -616,43 +615,59 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx)
{
struct input_dev *input = wacom->input;
+ int finger = idx + 1;
+ int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff;
+ int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff;
+
+ /*
+ * Work around input core suppressing "duplicate" events since
+ * we are abusing ABS_X/ABS_Y to transmit multi-finger data.
+ * This should go away once we switch to true multitouch
+ * protocol.
+ */
+ if (wacom->last_finger != finger) {
+ if (x == input->abs[ABS_X])
+ x++;
+
+ if (y == input->abs[ABS_Y])
+ y++;
+ }
- input_report_abs(input, ABS_X,
- data[2 + idx * 2] | ((data[3 + idx * 2] & 0x7f) << 8));
- input_report_abs(input, ABS_Y,
- data[6 + idx * 2] | ((data[7 + idx * 2] & 0x7f) << 8));
+ 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[idx], 1);
- if (idx)
- input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
- else
+ input_report_key(input, wacom->tool[finger], 1);
+ if (!idx)
input_report_key(input, BTN_TOUCH, 1);
+ input_event(input, EV_MSC, MSC_SERIAL, finger);
+ input_sync(wacom->input);
+
+ wacom->last_finger = finger;
}
static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx)
{
struct input_dev *input = wacom->input;
+ int finger = idx + 1;
input_report_abs(input, ABS_X, 0);
input_report_abs(input, ABS_Y, 0);
input_report_abs(input, ABS_MISC, 0);
- input_report_key(input, wacom->tool[idx], 0);
- if (idx)
- input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
- else
+ input_report_key(input, wacom->tool[finger], 0);
+ if (!idx)
input_report_key(input, BTN_TOUCH, 0);
+ input_event(input, EV_MSC, MSC_SERIAL, finger);
+ input_sync(input);
}
static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len)
{
char *data = wacom->data;
struct input_dev *input = wacom->input;
- static int firstFinger = 0;
- static int secondFinger = 0;
- wacom->tool[0] = BTN_TOOL_DOUBLETAP;
+ wacom->tool[1] = BTN_TOOL_DOUBLETAP;
wacom->id[0] = TOUCH_DEVICE_ID;
- wacom->tool[1] = BTN_TOOL_TRIPLETAP;
+ wacom->tool[2] = BTN_TOOL_TRIPLETAP;
if (len != WACOM_PKGLEN_TPC1FG) {
@@ -664,45 +679,29 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len)
input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6]));
input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6]));
input_report_abs(input, ABS_MISC, wacom->id[0]);
- input_report_key(input, wacom->tool[0], 1);
+ input_report_key(input, wacom->tool[1], 1);
+ input_sync(input);
break;
case WACOM_REPORT_TPC2FG:
- /* keep this byte to send proper out-prox event */
- wacom->id[1] = data[1] & 0x03;
-
- if (data[1] & 0x01) {
+ if (data[1] & 0x01)
wacom_tpc_finger_in(wacom, data, 0);
- firstFinger = 1;
- } else if (firstFinger) {
+ else if (wacom->id[1] & 0x01)
wacom_tpc_touch_out(wacom, 0);
- }
-
- if (data[1] & 0x02) {
- /* sync first finger data */
- if (firstFinger)
- input_sync(input);
+ if (data[1] & 0x02)
wacom_tpc_finger_in(wacom, data, 1);
- secondFinger = 1;
- } else if (secondFinger) {
- /* sync first finger data */
- if (firstFinger)
- input_sync(input);
-
+ else if (wacom->id[1] & 0x02)
wacom_tpc_touch_out(wacom, 1);
- secondFinger = 0;
- }
- if (!(data[1] & 0x01))
- firstFinger = 0;
break;
}
} else {
input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
input_report_key(input, BTN_TOUCH, 1);
- input_report_abs(input, ABS_MISC, wacom->id[0]);
- input_report_key(input, wacom->tool[0], 1);
+ input_report_abs(input, ABS_MISC, wacom->id[1]);
+ input_report_key(input, wacom->tool[1], 1);
+ input_sync(input);
}
}
@@ -711,13 +710,26 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
struct wacom_features *features = &wacom->features;
char *data = wacom->data;
struct input_dev *input = wacom->input;
- int prox = 0, pressure, idx = -1;
+ int prox = 0, pressure;
+ int retval = 0;
dbg("wacom_tpc_irq: received report #%d", data[0]);
if (len == WACOM_PKGLEN_TPC1FG || /* single touch */
data[0] == WACOM_REPORT_TPC1FG || /* single touch */
data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */
+
+ if (wacom->shared->stylus_in_proximity) {
+ if (wacom->id[1] & 0x01)
+ wacom_tpc_touch_out(wacom, 0);
+
+ if (wacom->id[1] & 0x02)
+ wacom_tpc_touch_out(wacom, 1);
+
+ wacom->id[1] = 0;
+ return 0;
+ }
+
if (len == WACOM_PKGLEN_TPC1FG) { /* with touch */
prox = data[0] & 0x01;
} else { /* with capacity */
@@ -729,36 +741,30 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
prox = data[1] & 0x03;
}
- if (!wacom->shared->stylus_in_proximity) {
- if (prox) {
- wacom_tpc_touch_in(wacom, len);
- } else {
- if (data[0] == WACOM_REPORT_TPC2FG) {
- /* 2FGT out-prox */
- idx = (wacom->id[1] & 0x01) - 1;
- if (idx == 0) {
- wacom_tpc_touch_out(wacom, idx);
- /* sync first finger event */
- if (wacom->id[1] & 0x02)
- input_sync(input);
- }
- idx = (wacom->id[1] & 0x02) - 1;
- if (idx == 1)
- wacom_tpc_touch_out(wacom, idx);
- } else {
- /* one finger touch */
+ if (prox) {
+ if (!wacom->id[1])
+ wacom->last_finger = 1;
+ wacom_tpc_touch_in(wacom, len);
+ } else {
+ if (data[0] == WACOM_REPORT_TPC2FG) {
+ /* 2FGT out-prox */
+ if (wacom->id[1] & 0x01)
wacom_tpc_touch_out(wacom, 0);
- }
- wacom->id[0] = 0;
- }
- } else if (wacom->id[0]) { /* force touch out-prox */
- wacom_tpc_touch_out(wacom, 0);
+
+ if (wacom->id[1] & 0x02)
+ wacom_tpc_touch_out(wacom, 1);
+ } else
+ /* one finger touch */
+ wacom_tpc_touch_out(wacom, 0);
+
+ wacom->id[0] = 0;
}
- return 1;
+ /* keep prox bit to send proper out-prox event */
+ wacom->id[1] = prox;
} else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */
prox = data[1] & 0x20;
- if (!wacom->id[0]) { /* first in prox */
+ if (!wacom->shared->stylus_in_proximity) { /* first in prox */
/* Going into proximity select tool */
wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
if (wacom->tool[0] == BTN_TOOL_PEN)
@@ -783,9 +789,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
}
input_report_key(input, wacom->tool[0], prox);
input_report_abs(input, ABS_MISC, wacom->id[0]);
- return 1;
+ retval = 1;
}
- return 0;
+ return retval;
}
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 69098a2aa690..063f1af3204f 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -80,9 +80,10 @@ struct wacom_shared {
struct wacom_wac {
char name[64];
unsigned char *data;
- int tool[2];
- int id[2];
+ int tool[3];
+ int id[3];
__u32 serial[2];
+ int last_finger;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;