diff options
Diffstat (limited to 'drivers/input/mouse/elantech.c')
-rw-r--r-- | drivers/input/mouse/elantech.c | 72 |
1 files changed, 55 insertions, 17 deletions
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 04d9bf320a4..32503565faf 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,15 +243,37 @@ 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) |
248 | */ | 270 | */ |
249 | static void elantech_report_absolute_v2(struct psmouse *psmouse) | 271 | static void elantech_report_absolute_v2(struct psmouse *psmouse) |
250 | { | 272 | { |
273 | struct elantech_data *etd = psmouse->private; | ||
251 | struct input_dev *dev = psmouse->dev; | 274 | struct input_dev *dev = psmouse->dev; |
252 | unsigned char *packet = psmouse->packet; | 275 | unsigned char *packet = psmouse->packet; |
253 | int fingers, x1, y1, x2, y2; | 276 | unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0; |
254 | 277 | ||
255 | /* byte 0: n1 n0 . . . . R L */ | 278 | /* byte 0: n1 n0 . . . . R L */ |
256 | fingers = (packet[0] & 0xc0) >> 6; | 279 | fingers = (packet[0] & 0xc0) >> 6; |
@@ -270,14 +293,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) | |||
270 | * byte 1: . . . . . x10 x9 x8 | 293 | * byte 1: . . . . . x10 x9 x8 |
271 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 | 294 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 |
272 | */ | 295 | */ |
273 | input_report_abs(dev, ABS_X, | 296 | x1 = ((packet[1] & 0x07) << 8) | packet[2]; |
274 | ((packet[1] & 0x07) << 8) | packet[2]); | ||
275 | /* | 297 | /* |
276 | * byte 4: . . . . . . y9 y8 | 298 | * byte 4: . . . . . . y9 y8 |
277 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 | 299 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 |
278 | */ | 300 | */ |
279 | input_report_abs(dev, ABS_Y, | 301 | y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]); |
280 | 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 | |||
306 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); | ||
307 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); | ||
281 | break; | 308 | break; |
282 | 309 | ||
283 | case 2: | 310 | case 2: |
@@ -303,23 +330,24 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) | |||
303 | */ | 330 | */ |
304 | input_report_abs(dev, ABS_X, x1 << 2); | 331 | input_report_abs(dev, ABS_X, x1 << 2); |
305 | input_report_abs(dev, ABS_Y, y1 << 2); | 332 | input_report_abs(dev, ABS_Y, y1 << 2); |
306 | /* | 333 | |
307 | * For compatibility with the proprietary X Elantech driver | 334 | /* Unknown so just report sensible values */ |
308 | * report both coordinates as hat coordinates | 335 | pres = 127; |
309 | */ | 336 | width = 7; |
310 | input_report_abs(dev, ABS_HAT0X, x1); | ||
311 | input_report_abs(dev, ABS_HAT0Y, y1); | ||
312 | input_report_abs(dev, ABS_HAT1X, x2); | ||
313 | input_report_abs(dev, ABS_HAT1Y, y2); | ||
314 | break; | 337 | break; |
315 | } | 338 | } |
316 | 339 | ||
340 | elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); | ||
317 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); | 341 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); |
318 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); | 342 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); |
319 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); | 343 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); |
320 | input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); | 344 | input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); |
321 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 345 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); |
322 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 346 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); |
347 | if (etd->reports_pressure) { | ||
348 | input_report_abs(dev, ABS_PRESSURE, pres); | ||
349 | input_report_abs(dev, ABS_TOOL_WIDTH, width); | ||
350 | } | ||
323 | 351 | ||
324 | input_sync(dev); | 352 | input_sync(dev); |
325 | } | 353 | } |
@@ -478,10 +506,16 @@ static void elantech_set_input_params(struct psmouse *psmouse) | |||
478 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); | 506 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); |
479 | input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); | 507 | input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); |
480 | input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); | 508 | input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); |
481 | input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); | 509 | if (etd->reports_pressure) { |
482 | input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); | 510 | input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, |
483 | input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); | 511 | ETP_PMAX_V2, 0, 0); |
484 | input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); | 512 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, |
513 | ETP_WMAX_V2, 0, 0); | ||
514 | } | ||
515 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); | ||
516 | input_mt_init_slots(dev, 2); | ||
517 | input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); | ||
518 | input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); | ||
485 | break; | 519 | break; |
486 | } | 520 | } |
487 | } | 521 | } |
@@ -725,6 +759,10 @@ int elantech_init(struct psmouse *psmouse) | |||
725 | etd->debug = 1; | 759 | etd->debug = 1; |
726 | /* Don't know how to do parity checking for version 2 */ | 760 | /* Don't know how to do parity checking for version 2 */ |
727 | etd->paritycheck = 0; | 761 | etd->paritycheck = 0; |
762 | |||
763 | if (etd->fw_version >= 0x020800) | ||
764 | etd->reports_pressure = true; | ||
765 | |||
728 | } else { | 766 | } else { |
729 | etd->hw_version = 1; | 767 | etd->hw_version = 1; |
730 | etd->paritycheck = 1; | 768 | etd->paritycheck = 1; |