diff options
author | Éric Piel <E.A.B.Piel@tudelft.nl> | 2011-05-17 01:45:54 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-05-17 01:48:39 -0400 |
commit | 89eec4d71e0a4e47a2f12a08992ada7500ea78a0 (patch) | |
tree | f20c42679ecca9939454ca95427918282e9ada6e | |
parent | f941c705f68fa62f694678bf2efde64dfb9962bb (diff) |
Input: elantech - report multitouch with proper ABS_MT messages
Multitouch info was reported only via a old protocol used by the
proprietary X driver from elantech. Let's report the multitouch info
also following the official MT protocol. It's semi-mt because the device
only reports the lowest/highest coordinates.
This was done following the multi-touch-protocol.txt documentation, and
inspired by the bcm5974 and elantech implementations. Testing was light
as there is not many applications using this protocol yet, but the X
synaptics driver didn't complain and the X multitouch driver behaved
correctly.
Signed-off-by: Éric Piel <eric.piel@tremplin-utc.net>
Reviewed-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/mouse/elantech.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 5cde11f4ef5e..32648b34b115 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/input.h> | 18 | #include <linux/input.h> |
19 | #include <linux/input/mt.h> | ||
19 | #include <linux/serio.h> | 20 | #include <linux/serio.h> |
20 | #include <linux/libps2.h> | 21 | #include <linux/libps2.h> |
21 | #include "psmouse.h" | 22 | #include "psmouse.h" |
@@ -242,6 +243,27 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) | |||
242 | input_sync(dev); | 243 | input_sync(dev); |
243 | } | 244 | } |
244 | 245 | ||
246 | static void elantech_set_slot(struct input_dev *dev, int slot, bool active, | ||
247 | unsigned int x, unsigned int y) | ||
248 | { | ||
249 | input_mt_slot(dev, slot); | ||
250 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); | ||
251 | if (active) { | ||
252 | input_report_abs(dev, ABS_MT_POSITION_X, x); | ||
253 | input_report_abs(dev, ABS_MT_POSITION_Y, y); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */ | ||
258 | static void elantech_report_semi_mt_data(struct input_dev *dev, | ||
259 | unsigned int num_fingers, | ||
260 | unsigned int x1, unsigned int y1, | ||
261 | unsigned int x2, unsigned int y2) | ||
262 | { | ||
263 | elantech_set_slot(dev, 0, num_fingers != 0, x1, y1); | ||
264 | elantech_set_slot(dev, 1, num_fingers == 2, x2, y2); | ||
265 | } | ||
266 | |||
245 | /* | 267 | /* |
246 | * Interpret complete data packets and report absolute mode input events for | 268 | * Interpret complete data packets and report absolute mode input events for |
247 | * hardware version 2. (6 byte packets) | 269 | * hardware version 2. (6 byte packets) |
@@ -251,7 +273,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) | |||
251 | struct elantech_data *etd = psmouse->private; | 273 | struct elantech_data *etd = psmouse->private; |
252 | struct input_dev *dev = psmouse->dev; | 274 | struct input_dev *dev = psmouse->dev; |
253 | unsigned char *packet = psmouse->packet; | 275 | unsigned char *packet = psmouse->packet; |
254 | int fingers, x1, y1, x2, y2, width = 0, pres = 0; | 276 | unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0; |
255 | 277 | ||
256 | /* byte 0: n1 n0 . . . . R L */ | 278 | /* byte 0: n1 n0 . . . . R L */ |
257 | fingers = (packet[0] & 0xc0) >> 6; | 279 | fingers = (packet[0] & 0xc0) >> 6; |
@@ -271,14 +293,16 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) | |||
271 | * byte 1: . . . . . x10 x9 x8 | 293 | * byte 1: . . . . . x10 x9 x8 |
272 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 | 294 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 |
273 | */ | 295 | */ |
274 | input_report_abs(dev, ABS_X, | 296 | x1 = ((packet[1] & 0x07) << 8) | packet[2]; |
275 | ((packet[1] & 0x07) << 8) | packet[2]); | ||
276 | /* | 297 | /* |
277 | * byte 4: . . . . . . y9 y8 | 298 | * byte 4: . . . . . . y9 y8 |
278 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 | 299 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 |
279 | */ | 300 | */ |
280 | input_report_abs(dev, ABS_Y, | 301 | y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]); |
281 | ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5])); | 302 | |
303 | input_report_abs(dev, ABS_X, x1); | ||
304 | input_report_abs(dev, ABS_Y, y1); | ||
305 | |||
282 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); | 306 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); |
283 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); | 307 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); |
284 | break; | 308 | break; |
@@ -321,6 +345,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) | |||
321 | break; | 345 | break; |
322 | } | 346 | } |
323 | 347 | ||
348 | elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); | ||
324 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); | 349 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); |
325 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); | 350 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); |
326 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); | 351 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); |
@@ -495,6 +520,10 @@ static void elantech_set_input_params(struct psmouse *psmouse) | |||
495 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, | 520 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, |
496 | ETP_WMAX_V2, 0, 0); | 521 | ETP_WMAX_V2, 0, 0); |
497 | } | 522 | } |
523 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); | ||
524 | input_mt_init_slots(dev, 2); | ||
525 | input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); | ||
526 | input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); | ||
498 | input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); | 527 | input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); |
499 | input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); | 528 | input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); |
500 | input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); | 529 | input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); |