#include "wacom_wac.h"
#include "wacom.h"
-static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
+static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
unsigned char *data = wacom->data;
struct input_dev *input = wacom->input;
wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
input_report_key(input, wacom->tool[0], 1);
input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
- input_report_abs(input, ABS_X, wacom_le16_to_cpu(&data[1]));
- input_report_abs(input, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
+ input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127));
input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
case 2:
input_report_key(input, BTN_TOOL_PEN, 1);
input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
- input_report_abs(input, ABS_X, wacom_le16_to_cpu(&data[1]));
- input_report_abs(input, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
+ input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127);
input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
input_report_key(input, BTN_STYLUS, (data[5] & 0x40));
return 1;
}
-static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
+static int wacom_pl_irq(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
return 1;
}
-static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
+static int wacom_ptu_irq(struct wacom_wac *wacom)
{
unsigned char *data = wacom->data;
struct input_dev *input = wacom->input;
wacom->id[0] = STYLUS_DEVICE_ID;
}
input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
- input_report_abs(input, ABS_X, wacom_le16_to_cpu(&data[2]));
- input_report_abs(input, ABS_Y, wacom_le16_to_cpu(&data[4]));
- input_report_abs(input, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
+ 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_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6]));
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
return 1;
}
-static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
+static int wacom_graphire_irq(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->input;
- int x, y, prox;
+ int prox;
int rw = 0;
int retval = 0;
break;
}
}
- x = wacom_le16_to_cpu(&data[2]);
- y = wacom_le16_to_cpu(&data[4]);
- input_report_abs(input, ABS_X, x);
- input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
+ input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
if (wacom->tool[0] != BTN_TOOL_MOUSE) {
input_report_abs(input, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
input_report_key(input, BTN_TOUCH, data[1] & 0x01);
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:
return retval;
}
-static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
+static int wacom_intuos_inout(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
return 0;
}
-static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
+static void wacom_intuos_general(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
}
}
-static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
+static int wacom_intuos_irq(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
}
/* process in/out prox events */
- result = wacom_intuos_inout(wacom, wcombo);
+ result = wacom_intuos_inout(wacom);
if (result)
return result - 1;
input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
} else {
- input_report_abs(input, ABS_X, wacom_be16_to_cpu(&data[2]));
- input_report_abs(input, ABS_Y, wacom_be16_to_cpu(&data[4]));
+ input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
+ input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
}
/* process general packets */
- wacom_intuos_general(wacom, wcombo);
+ wacom_intuos_general(wacom);
/* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
}
-static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx)
+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, void *wcombo, int idx)
+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, void *wcombo)
+static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len)
{
char *data = wacom->data;
struct input_dev *input = wacom->input;
- struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
- 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 (urb->actual_length != WACOM_PKGLEN_TPC1FG) {
+ if (len != WACOM_PKGLEN_TPC1FG) {
switch (data[0]) {
case WACOM_REPORT_TPC1FG:
- input_report_abs(input, ABS_X, wacom_le16_to_cpu(&data[2]));
- input_report_abs(input, ABS_Y, wacom_le16_to_cpu(&data[4]));
- input_report_abs(input, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
- input_report_key(input, BTN_TOUCH, wacom_le16_to_cpu(&data[6]));
+ 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_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) {
- 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)
- input_sync(input);
-
- wacom_tpc_finger_in(wacom, wcombo, data, 1);
- secondFinger = 1;
- } else if (secondFinger) {
- /* sync first finger data */
- if (firstFinger)
- input_sync(input);
-
- wacom_tpc_touch_out(wacom, wcombo, 1);
- secondFinger = 0;
- }
- if (!(data[1] & 0x01))
- firstFinger = 0;
+ if (data[1] & 0x01)
+ wacom_tpc_finger_in(wacom, data, 0);
+ else if (wacom->id[1] & 0x01)
+ wacom_tpc_touch_out(wacom, 0);
+
+ if (data[1] & 0x02)
+ wacom_tpc_finger_in(wacom, data, 1);
+ else if (wacom->id[1] & 0x02)
+ wacom_tpc_touch_out(wacom, 1);
break;
}
} else {
- input_report_abs(input, ABS_X, wacom_le16_to_cpu(&data[1]));
- input_report_abs(input, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ 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);
}
}
-static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
+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;
- struct urb *urb = ((struct wacom_combo *)wcombo)->urb;
+ int prox = 0, pressure;
+ int retval = 0;
dbg("wacom_tpc_irq: received report #%d", data[0]);
- if (urb->actual_length == WACOM_PKGLEN_TPC1FG || /* single touch */
+ if (len == WACOM_PKGLEN_TPC1FG || /* single touch */
data[0] == WACOM_REPORT_TPC1FG || /* single touch */
data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */
- if (urb->actual_length == WACOM_PKGLEN_TPC1FG) { /* with 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 */
if (data[0] == WACOM_REPORT_TPC1FG)
prox = data[1] & 0x03;
}
- if (!wacom->shared->stylus_in_proximity) {
- if (prox) {
- wacom_tpc_touch_in(wacom, wcombo);
- } else {
- if (data[0] == WACOM_REPORT_TPC2FG) {
- /* 2FGT out-prox */
- 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)
- input_sync(input);
- }
- 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->id[0] = 0;
- }
- } else if (wacom->id[0]) { /* force touch out-prox */
- wacom_tpc_touch_out(wacom, wcombo, 0);
+ 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);
+
+ 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)
}
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
- input_report_abs(input, ABS_X, wacom_le16_to_cpu(&data[2]));
- input_report_abs(input, ABS_Y, wacom_le16_to_cpu(&data[4]));
+ input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
+ input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
pressure = ((data[7] & 0x01) << 8) | data[6];
if (pressure < 0)
pressure = features->pressure_max + pressure + 1;
}
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;
}
-int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
+void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
{
+ bool sync;
+
switch (wacom_wac->features.type) {
case PENPARTNER:
- return wacom_penpartner_irq(wacom_wac, wcombo);
+ sync = wacom_penpartner_irq(wacom_wac);
+ break;
case PL:
- return wacom_pl_irq(wacom_wac, wcombo);
+ sync = wacom_pl_irq(wacom_wac);
+ break;
case WACOM_G4:
case GRAPHIRE:
case WACOM_MO:
- return wacom_graphire_irq(wacom_wac, wcombo);
+ sync = wacom_graphire_irq(wacom_wac);
+ break;
case PTU:
- return wacom_ptu_irq(wacom_wac, wcombo);
+ sync = wacom_ptu_irq(wacom_wac);
+ break;
case INTUOS:
case INTUOS3S:
case INTUOS4L:
case CINTIQ:
case WACOM_BEE:
- return wacom_intuos_irq(wacom_wac, wcombo);
+ sync = wacom_intuos_irq(wacom_wac);
+ break;
case TABLETPC:
case TABLETPC2FG:
- return wacom_tpc_irq(wacom_wac, wcombo);
+ sync = wacom_tpc_irq(wacom_wac, len);
+ break;
default:
- return 0;
+ sync = false;
+ break;
}
- return 0;
+
+ if (sync)
+ input_sync(wacom_wac->input);
}
static void wacom_setup_intuos(struct wacom_wac *wacom_wac)