diff options
author | Seth Forshee <seth.forshee@canonical.com> | 2011-11-07 22:54:13 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-11-08 01:22:11 -0500 |
commit | 01ce661fc83005947dc958a5739c153843af8a73 (patch) | |
tree | b3c3d2c3a671a4d8796c1d99dd648d8fb4c54b73 | |
parent | 25bded7cd60fa460e520e9f819bd06f4c5cb53f0 (diff) |
Input: ALPS - add semi-MT support for v3 protocol
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Chase Douglas <chase.douglas@canonical.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/mouse/alps.c | 233 | ||||
-rw-r--r-- | drivers/input/mouse/alps.h | 1 |
2 files changed, 215 insertions, 19 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index a0248fd62ef8..bd87380bd879 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/input.h> | 19 | #include <linux/input.h> |
20 | #include <linux/input/mt.h> | ||
20 | #include <linux/serio.h> | 21 | #include <linux/serio.h> |
21 | #include <linux/libps2.h> | 22 | #include <linux/libps2.h> |
22 | 23 | ||
@@ -26,6 +27,12 @@ | |||
26 | /* | 27 | /* |
27 | * Definitions for ALPS version 3 and 4 command mode protocol | 28 | * Definitions for ALPS version 3 and 4 command mode protocol |
28 | */ | 29 | */ |
30 | #define ALPS_V3_X_MAX 2000 | ||
31 | #define ALPS_V3_Y_MAX 1400 | ||
32 | |||
33 | #define ALPS_BITMAP_X_BITS 15 | ||
34 | #define ALPS_BITMAP_Y_BITS 11 | ||
35 | |||
29 | #define ALPS_CMD_NIBBLE_10 0x01f2 | 36 | #define ALPS_CMD_NIBBLE_10 0x01f2 |
30 | 37 | ||
31 | static const struct alps_nibble_commands alps_v3_nibble_commands[] = { | 38 | static const struct alps_nibble_commands alps_v3_nibble_commands[] = { |
@@ -250,6 +257,137 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) | |||
250 | input_sync(dev); | 257 | input_sync(dev); |
251 | } | 258 | } |
252 | 259 | ||
260 | /* | ||
261 | * Process bitmap data from v3 and v4 protocols. Returns the number of | ||
262 | * fingers detected. A return value of 0 means at least one of the | ||
263 | * bitmaps was empty. | ||
264 | * | ||
265 | * The bitmaps don't have enough data to track fingers, so this function | ||
266 | * only generates points representing a bounding box of all contacts. | ||
267 | * These points are returned in x1, y1, x2, and y2 when the return value | ||
268 | * is greater than 0. | ||
269 | */ | ||
270 | static int alps_process_bitmap(unsigned int x_map, unsigned int y_map, | ||
271 | int *x1, int *y1, int *x2, int *y2) | ||
272 | { | ||
273 | struct alps_bitmap_point { | ||
274 | int start_bit; | ||
275 | int num_bits; | ||
276 | }; | ||
277 | |||
278 | int fingers_x = 0, fingers_y = 0, fingers; | ||
279 | int i, bit, prev_bit; | ||
280 | struct alps_bitmap_point x_low = {0,}, x_high = {0,}; | ||
281 | struct alps_bitmap_point y_low = {0,}, y_high = {0,}; | ||
282 | struct alps_bitmap_point *point; | ||
283 | |||
284 | if (!x_map || !y_map) | ||
285 | return 0; | ||
286 | |||
287 | *x1 = *y1 = *x2 = *y2 = 0; | ||
288 | |||
289 | prev_bit = 0; | ||
290 | point = &x_low; | ||
291 | for (i = 0; x_map != 0; i++, x_map >>= 1) { | ||
292 | bit = x_map & 1; | ||
293 | if (bit) { | ||
294 | if (!prev_bit) { | ||
295 | point->start_bit = i; | ||
296 | fingers_x++; | ||
297 | } | ||
298 | point->num_bits++; | ||
299 | } else { | ||
300 | if (prev_bit) | ||
301 | point = &x_high; | ||
302 | else | ||
303 | point->num_bits = 0; | ||
304 | } | ||
305 | prev_bit = bit; | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * y bitmap is reversed for what we need (lower positions are in | ||
310 | * higher bits), so we process from the top end. | ||
311 | */ | ||
312 | y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS); | ||
313 | prev_bit = 0; | ||
314 | point = &y_low; | ||
315 | for (i = 0; y_map != 0; i++, y_map <<= 1) { | ||
316 | bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1)); | ||
317 | if (bit) { | ||
318 | if (!prev_bit) { | ||
319 | point->start_bit = i; | ||
320 | fingers_y++; | ||
321 | } | ||
322 | point->num_bits++; | ||
323 | } else { | ||
324 | if (prev_bit) | ||
325 | point = &y_high; | ||
326 | else | ||
327 | point->num_bits = 0; | ||
328 | } | ||
329 | prev_bit = bit; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Fingers can overlap, so we use the maximum count of fingers | ||
334 | * on either axis as the finger count. | ||
335 | */ | ||
336 | fingers = max(fingers_x, fingers_y); | ||
337 | |||
338 | /* | ||
339 | * If total fingers is > 1 but either axis reports only a single | ||
340 | * contact, we have overlapping or adjacent fingers. For the | ||
341 | * purposes of creating a bounding box, divide the single contact | ||
342 | * (roughly) equally between the two points. | ||
343 | */ | ||
344 | if (fingers > 1) { | ||
345 | if (fingers_x == 1) { | ||
346 | i = x_low.num_bits / 2; | ||
347 | x_low.num_bits = x_low.num_bits - i; | ||
348 | x_high.start_bit = x_low.start_bit + i; | ||
349 | x_high.num_bits = max(i, 1); | ||
350 | } else if (fingers_y == 1) { | ||
351 | i = y_low.num_bits / 2; | ||
352 | y_low.num_bits = y_low.num_bits - i; | ||
353 | y_high.start_bit = y_low.start_bit + i; | ||
354 | y_high.num_bits = max(i, 1); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) / | ||
359 | (2 * (ALPS_BITMAP_X_BITS - 1)); | ||
360 | *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) / | ||
361 | (2 * (ALPS_BITMAP_Y_BITS - 1)); | ||
362 | |||
363 | if (fingers > 1) { | ||
364 | *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) / | ||
365 | (2 * (ALPS_BITMAP_X_BITS - 1)); | ||
366 | *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) / | ||
367 | (2 * (ALPS_BITMAP_Y_BITS - 1)); | ||
368 | } | ||
369 | |||
370 | return fingers; | ||
371 | } | ||
372 | |||
373 | static void alps_set_slot(struct input_dev *dev, int slot, bool active, | ||
374 | int x, int y) | ||
375 | { | ||
376 | input_mt_slot(dev, slot); | ||
377 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); | ||
378 | if (active) { | ||
379 | input_report_abs(dev, ABS_MT_POSITION_X, x); | ||
380 | input_report_abs(dev, ABS_MT_POSITION_Y, y); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers, | ||
385 | int x1, int y1, int x2, int y2) | ||
386 | { | ||
387 | alps_set_slot(dev, 0, num_fingers != 0, x1, y1); | ||
388 | alps_set_slot(dev, 1, num_fingers == 2, x2, y2); | ||
389 | } | ||
390 | |||
253 | static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) | 391 | static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) |
254 | { | 392 | { |
255 | struct alps_data *priv = psmouse->private; | 393 | struct alps_data *priv = psmouse->private; |
@@ -318,16 +456,17 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
318 | struct input_dev *dev2 = priv->dev2; | 456 | struct input_dev *dev2 = priv->dev2; |
319 | int x, y, z; | 457 | int x, y, z; |
320 | int left, right, middle; | 458 | int left, right, middle; |
459 | int x1 = 0, y1 = 0, x2 = 0, y2 = 0; | ||
460 | int fingers = 0, bmap_fingers; | ||
461 | unsigned int x_bitmap, y_bitmap; | ||
321 | 462 | ||
322 | /* | 463 | /* |
323 | * There's no single feature of touchpad position and bitmap | 464 | * There's no single feature of touchpad position and bitmap packets |
324 | * packets that can be used to distinguish between them. We | 465 | * that can be used to distinguish between them. We rely on the fact |
325 | * rely on the fact that a bitmap packet should always follow | 466 | * that a bitmap packet should always follow a position packet with |
326 | * a position packet with bit 6 of packet[4] set. | 467 | * bit 6 of packet[4] set. |
327 | */ | 468 | */ |
328 | if (priv->multi_packet) { | 469 | if (priv->multi_packet) { |
329 | priv->multi_packet = 0; | ||
330 | |||
331 | /* | 470 | /* |
332 | * Sometimes a position packet will indicate a multi-packet | 471 | * Sometimes a position packet will indicate a multi-packet |
333 | * sequence, but then what follows is another position | 472 | * sequence, but then what follows is another position |
@@ -335,18 +474,49 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
335 | * position packet as usual. | 474 | * position packet as usual. |
336 | */ | 475 | */ |
337 | if (packet[0] & 0x40) { | 476 | if (packet[0] & 0x40) { |
477 | fingers = (packet[5] & 0x3) + 1; | ||
478 | x_bitmap = ((packet[4] & 0x7e) << 8) | | ||
479 | ((packet[1] & 0x7f) << 2) | | ||
480 | ((packet[0] & 0x30) >> 4); | ||
481 | y_bitmap = ((packet[3] & 0x70) << 4) | | ||
482 | ((packet[2] & 0x7f) << 1) | | ||
483 | (packet[4] & 0x01); | ||
484 | |||
485 | bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap, | ||
486 | &x1, &y1, &x2, &y2); | ||
487 | |||
338 | /* | 488 | /* |
339 | * Bitmap packets are not yet supported, so for now | 489 | * We shouldn't report more than one finger if |
340 | * just ignore them. | 490 | * we don't have two coordinates. |
341 | */ | 491 | */ |
342 | return; | 492 | if (fingers > 1 && bmap_fingers < 2) |
493 | fingers = bmap_fingers; | ||
494 | |||
495 | /* Now process position packet */ | ||
496 | packet = priv->multi_data; | ||
497 | } else { | ||
498 | priv->multi_packet = 0; | ||
343 | } | 499 | } |
344 | } | 500 | } |
345 | 501 | ||
346 | if (!priv->multi_packet && (packet[4] & 0x40)) | 502 | /* |
503 | * Bit 6 of byte 0 is not usually set in position packets. The only | ||
504 | * times it seems to be set is in situations where the data is | ||
505 | * suspect anyway, e.g. a palm resting flat on the touchpad. Given | ||
506 | * this combined with the fact that this bit is useful for filtering | ||
507 | * out misidentified bitmap packets, we reject anything with this | ||
508 | * bit set. | ||
509 | */ | ||
510 | if (packet[0] & 0x40) | ||
511 | return; | ||
512 | |||
513 | if (!priv->multi_packet && (packet[4] & 0x40)) { | ||
347 | priv->multi_packet = 1; | 514 | priv->multi_packet = 1; |
348 | else | 515 | memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); |
349 | priv->multi_packet = 0; | 516 | return; |
517 | } | ||
518 | |||
519 | priv->multi_packet = 0; | ||
350 | 520 | ||
351 | left = packet[3] & 0x01; | 521 | left = packet[3] & 0x01; |
352 | right = packet[3] & 0x02; | 522 | right = packet[3] & 0x02; |
@@ -366,22 +536,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
366 | if (x && y && !z) | 536 | if (x && y && !z) |
367 | return; | 537 | return; |
368 | 538 | ||
539 | /* | ||
540 | * If we don't have MT data or the bitmaps were empty, we have | ||
541 | * to rely on ST data. | ||
542 | */ | ||
543 | if (!fingers) { | ||
544 | x1 = x; | ||
545 | y1 = y; | ||
546 | fingers = z > 0 ? 1 : 0; | ||
547 | } | ||
548 | |||
369 | if (z >= 64) | 549 | if (z >= 64) |
370 | input_report_key(dev, BTN_TOUCH, 1); | 550 | input_report_key(dev, BTN_TOUCH, 1); |
371 | else | 551 | else |
372 | input_report_key(dev, BTN_TOUCH, 0); | 552 | input_report_key(dev, BTN_TOUCH, 0); |
373 | 553 | ||
554 | alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); | ||
555 | |||
556 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); | ||
557 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); | ||
558 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); | ||
559 | input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); | ||
560 | |||
561 | input_report_key(dev, BTN_LEFT, left); | ||
562 | input_report_key(dev, BTN_RIGHT, right); | ||
563 | input_report_key(dev, BTN_MIDDLE, middle); | ||
564 | |||
374 | if (z > 0) { | 565 | if (z > 0) { |
375 | input_report_abs(dev, ABS_X, x); | 566 | input_report_abs(dev, ABS_X, x); |
376 | input_report_abs(dev, ABS_Y, y); | 567 | input_report_abs(dev, ABS_Y, y); |
377 | } | 568 | } |
378 | input_report_abs(dev, ABS_PRESSURE, z); | 569 | input_report_abs(dev, ABS_PRESSURE, z); |
379 | 570 | ||
380 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); | ||
381 | input_report_key(dev, BTN_LEFT, left); | ||
382 | input_report_key(dev, BTN_RIGHT, right); | ||
383 | input_report_key(dev, BTN_MIDDLE, middle); | ||
384 | |||
385 | input_sync(dev); | 571 | input_sync(dev); |
386 | 572 | ||
387 | if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { | 573 | if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { |
@@ -1368,9 +1554,18 @@ int alps_init(struct psmouse *psmouse) | |||
1368 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); | 1554 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); |
1369 | break; | 1555 | break; |
1370 | case ALPS_PROTO_V3: | 1556 | case ALPS_PROTO_V3: |
1557 | set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); | ||
1558 | input_mt_init_slots(dev1, 2); | ||
1559 | input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); | ||
1560 | input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); | ||
1561 | |||
1562 | set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); | ||
1563 | set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); | ||
1564 | set_bit(BTN_TOOL_QUADTAP, dev1->keybit); | ||
1565 | /* fall through */ | ||
1371 | case ALPS_PROTO_V4: | 1566 | case ALPS_PROTO_V4: |
1372 | input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0); | 1567 | input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0); |
1373 | input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0); | 1568 | input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0); |
1374 | break; | 1569 | break; |
1375 | } | 1570 | } |
1376 | 1571 | ||
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 62db7f489a59..a00a4ab92a0f 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h | |||
@@ -38,6 +38,7 @@ struct alps_data { | |||
38 | int addr_command; /* Command to set register address */ | 38 | int addr_command; /* Command to set register address */ |
39 | int prev_fin; /* Finger bit from previous packet */ | 39 | int prev_fin; /* Finger bit from previous packet */ |
40 | int multi_packet; /* Multi-packet data in progress */ | 40 | int multi_packet; /* Multi-packet data in progress */ |
41 | unsigned char multi_data[6]; /* Saved multi-packet data */ | ||
41 | u8 quirks; | 42 | u8 quirks; |
42 | struct timer_list timer; | 43 | struct timer_list timer; |
43 | }; | 44 | }; |