aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorÉric Piel <E.A.B.Piel@tudelft.nl>2011-05-17 01:45:54 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-05-17 01:48:39 -0400
commit89eec4d71e0a4e47a2f12a08992ada7500ea78a0 (patch)
treef20c42679ecca9939454ca95427918282e9ada6e
parentf941c705f68fa62f694678bf2efde64dfb9962bb (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.c39
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
246static 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 */
258static 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);