diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2010-08-29 01:00:47 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-29 01:46:14 -0400 |
commit | 5e8b9140f306ce30e7c56c568198720514efc872 (patch) | |
tree | ff2389c6ac6c049d5bd51d00c439326cd86f6103 /drivers/input/touchscreen | |
parent | aaba933eeb8d7f804508bc74baa58656240107f8 (diff) |
Input: wacom_w8001 - add multitouch slot support
Some serial wacom devices support two-finger touch. Test for this during
init and parse the touch packets accordingly. Touch packets are
processed using Protocol B (MT Slots).
Note: there are several wacom versions that do touch but not two-finger
touch. These are not catered for here, touch events for these are simply
discarded.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/wacom_w8001.c | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 89abda06db74..9ae4c7b16ba7 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c | |||
@@ -48,6 +48,8 @@ MODULE_LICENSE("GPL"); | |||
48 | #define W8001_PKTLEN_TPCCTL 11 /* control packet */ | 48 | #define W8001_PKTLEN_TPCCTL 11 /* control packet */ |
49 | #define W8001_PKTLEN_TOUCH2FG 13 | 49 | #define W8001_PKTLEN_TOUCH2FG 13 |
50 | 50 | ||
51 | #define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */ | ||
52 | |||
51 | struct w8001_coord { | 53 | struct w8001_coord { |
52 | u8 rdy; | 54 | u8 rdy; |
53 | u8 tsw; | 55 | u8 tsw; |
@@ -85,6 +87,7 @@ struct w8001 { | |||
85 | char phys[32]; | 87 | char phys[32]; |
86 | int type; | 88 | int type; |
87 | unsigned int pktlen; | 89 | unsigned int pktlen; |
90 | int trkid[2]; | ||
88 | }; | 91 | }; |
89 | 92 | ||
90 | static void parse_data(u8 *data, struct w8001_coord *coord) | 93 | static void parse_data(u8 *data, struct w8001_coord *coord) |
@@ -111,6 +114,35 @@ static void parse_data(u8 *data, struct w8001_coord *coord) | |||
111 | coord->tilt_y = data[8] & 0x7F; | 114 | coord->tilt_y = data[8] & 0x7F; |
112 | } | 115 | } |
113 | 116 | ||
117 | static void parse_touch(struct w8001 *w8001) | ||
118 | { | ||
119 | static int trkid; | ||
120 | struct input_dev *dev = w8001->dev; | ||
121 | unsigned char *data = w8001->data; | ||
122 | int i; | ||
123 | |||
124 | for (i = 0; i < 2; i++) { | ||
125 | input_mt_slot(dev, i); | ||
126 | |||
127 | if (data[0] & (1 << i)) { | ||
128 | int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]); | ||
129 | int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]); | ||
130 | /* data[5,6] and [11,12] is finger capacity */ | ||
131 | |||
132 | input_report_abs(dev, ABS_MT_POSITION_X, x); | ||
133 | input_report_abs(dev, ABS_MT_POSITION_Y, y); | ||
134 | input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER); | ||
135 | if (w8001->trkid[i] < 0) | ||
136 | w8001->trkid[i] = trkid++ & MAX_TRACKING_ID; | ||
137 | } else { | ||
138 | w8001->trkid[i] = -1; | ||
139 | } | ||
140 | input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]); | ||
141 | } | ||
142 | |||
143 | input_sync(dev); | ||
144 | } | ||
145 | |||
114 | static void parse_touchquery(u8 *data, struct w8001_touch_query *query) | 146 | static void parse_touchquery(u8 *data, struct w8001_touch_query *query) |
115 | { | 147 | { |
116 | memset(query, 0, sizeof(*query)); | 148 | memset(query, 0, sizeof(*query)); |
@@ -220,10 +252,10 @@ static irqreturn_t w8001_interrupt(struct serio *serio, | |||
220 | complete(&w8001->cmd_done); | 252 | complete(&w8001->cmd_done); |
221 | break; | 253 | break; |
222 | 254 | ||
255 | /* 2 finger touch packet */ | ||
223 | case W8001_PKTLEN_TOUCH2FG - 1: | 256 | case W8001_PKTLEN_TOUCH2FG - 1: |
224 | /* ignore two-finger touch packet. */ | 257 | w8001->idx = 0; |
225 | if (w8001->pktlen == w8001->idx) | 258 | parse_touch(w8001); |
226 | w8001->idx = 0; | ||
227 | break; | 259 | break; |
228 | } | 260 | } |
229 | 261 | ||
@@ -285,6 +317,16 @@ static int w8001_setup(struct w8001 *w8001) | |||
285 | break; | 317 | break; |
286 | case 5: | 318 | case 5: |
287 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; | 319 | w8001->pktlen = W8001_PKTLEN_TOUCH2FG; |
320 | |||
321 | input_mt_create_slots(dev, 2); | ||
322 | input_set_abs_params(dev, ABS_MT_TRACKING_ID, | ||
323 | 0, MAX_TRACKING_ID, 0, 0); | ||
324 | input_set_abs_params(dev, ABS_MT_POSITION_X, | ||
325 | 0, touch.x, 0, 0); | ||
326 | input_set_abs_params(dev, ABS_MT_POSITION_Y, | ||
327 | 0, touch.y, 0, 0); | ||
328 | input_set_abs_params(dev, ABS_MT_TOOL_TYPE, | ||
329 | 0, 0, 0, 0); | ||
288 | break; | 330 | break; |
289 | } | 331 | } |
290 | } | 332 | } |
@@ -330,6 +372,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) | |||
330 | w8001->serio = serio; | 372 | w8001->serio = serio; |
331 | w8001->id = serio->id.id; | 373 | w8001->id = serio->id.id; |
332 | w8001->dev = input_dev; | 374 | w8001->dev = input_dev; |
375 | w8001->trkid[0] = w8001->trkid[1] = -1; | ||
333 | init_completion(&w8001->cmd_done); | 376 | init_completion(&w8001->cmd_done); |
334 | snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); | 377 | snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); |
335 | 378 | ||