diff options
author | Yunkang Tang <tommywill2011@gmail.com> | 2013-12-26 17:54:19 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-12-26 18:44:39 -0500 |
commit | ee65d4b36de8ddf4467f788faa5d8ddd1bfcdaa2 (patch) | |
tree | b83ba964dff094e5d5cf7b0c66c0b334ef8fc900 /drivers | |
parent | 01d08185850c2eb5ce80722df3fdb5d7a291fb79 (diff) |
Input: ALPS - add support for "Dolphin" devices
This adds support for another flavor of ALPS protocol used in newer
"Dolphin" devices.
Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/mouse/alps.c | 214 | ||||
-rw-r--r-- | drivers/input/mouse/alps.h | 7 |
2 files changed, 179 insertions, 42 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 5cf62e315218..fb15c64ffb95 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -277,6 +277,57 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) | |||
277 | } | 277 | } |
278 | 278 | ||
279 | /* | 279 | /* |
280 | * Process bitmap data for V5 protocols. Return value is null. | ||
281 | * | ||
282 | * The bitmaps don't have enough data to track fingers, so this function | ||
283 | * only generates points representing a bounding box of at most two contacts. | ||
284 | * These two points are returned in x1, y1, x2, and y2. | ||
285 | */ | ||
286 | static void alps_process_bitmap_dolphin(struct alps_data *priv, | ||
287 | struct alps_fields *fields, | ||
288 | int *x1, int *y1, int *x2, int *y2) | ||
289 | { | ||
290 | int box_middle_x, box_middle_y; | ||
291 | unsigned int x_map, y_map; | ||
292 | unsigned char start_bit, end_bit; | ||
293 | unsigned char x_msb, x_lsb, y_msb, y_lsb; | ||
294 | |||
295 | x_map = fields->x_map; | ||
296 | y_map = fields->y_map; | ||
297 | |||
298 | if (!x_map || !y_map) | ||
299 | return; | ||
300 | |||
301 | /* Get Most-significant and Least-significant bit */ | ||
302 | x_msb = fls(x_map); | ||
303 | x_lsb = ffs(x_map); | ||
304 | y_msb = fls(y_map); | ||
305 | y_lsb = ffs(y_map); | ||
306 | |||
307 | /* Most-significant bit should never exceed max sensor line number */ | ||
308 | if (x_msb > priv->x_bits || y_msb > priv->y_bits) | ||
309 | return; | ||
310 | |||
311 | *x1 = *y1 = *x2 = *y2 = 0; | ||
312 | |||
313 | if (fields->fingers > 1) { | ||
314 | start_bit = priv->x_bits - x_msb; | ||
315 | end_bit = priv->x_bits - x_lsb; | ||
316 | box_middle_x = (priv->x_max * (start_bit + end_bit)) / | ||
317 | (2 * (priv->x_bits - 1)); | ||
318 | |||
319 | start_bit = y_lsb - 1; | ||
320 | end_bit = y_msb - 1; | ||
321 | box_middle_y = (priv->y_max * (start_bit + end_bit)) / | ||
322 | (2 * (priv->y_bits - 1)); | ||
323 | *x1 = fields->x; | ||
324 | *y1 = fields->y; | ||
325 | *x2 = 2 * box_middle_x - *x1; | ||
326 | *y2 = 2 * box_middle_y - *y1; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | /* | ||
280 | * Process bitmap data from v3 and v4 protocols. Returns the number of | 331 | * Process bitmap data from v3 and v4 protocols. Returns the number of |
281 | * fingers detected. A return value of 0 means at least one of the | 332 | * fingers detected. A return value of 0 means at least one of the |
282 | * bitmaps was empty. | 333 | * bitmaps was empty. |
@@ -481,7 +532,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p) | |||
481 | f->ts_middle = !!(p[3] & 0x40); | 532 | f->ts_middle = !!(p[3] & 0x40); |
482 | } | 533 | } |
483 | 534 | ||
484 | static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) | 535 | static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, |
536 | struct psmouse *psmouse) | ||
485 | { | 537 | { |
486 | f->first_mp = !!(p[4] & 0x40); | 538 | f->first_mp = !!(p[4] & 0x40); |
487 | f->is_mp = !!(p[0] & 0x40); | 539 | f->is_mp = !!(p[0] & 0x40); |
@@ -502,48 +554,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) | |||
502 | alps_decode_buttons_v3(f, p); | 554 | alps_decode_buttons_v3(f, p); |
503 | } | 555 | } |
504 | 556 | ||
505 | static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p) | 557 | static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, |
558 | struct psmouse *psmouse) | ||
506 | { | 559 | { |
507 | alps_decode_pinnacle(f, p); | 560 | alps_decode_pinnacle(f, p, psmouse); |
508 | 561 | ||
509 | f->x_map |= (p[5] & 0x10) << 11; | 562 | f->x_map |= (p[5] & 0x10) << 11; |
510 | f->y_map |= (p[5] & 0x20) << 6; | 563 | f->y_map |= (p[5] & 0x20) << 6; |
511 | } | 564 | } |
512 | 565 | ||
513 | static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p) | 566 | static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, |
567 | struct psmouse *psmouse) | ||
514 | { | 568 | { |
569 | u64 palm_data = 0; | ||
570 | struct alps_data *priv = psmouse->private; | ||
571 | |||
515 | f->first_mp = !!(p[0] & 0x02); | 572 | f->first_mp = !!(p[0] & 0x02); |
516 | f->is_mp = !!(p[0] & 0x20); | 573 | f->is_mp = !!(p[0] & 0x20); |
517 | 574 | ||
518 | f->fingers = ((p[0] & 0x6) >> 1 | | 575 | if (!f->is_mp) { |
576 | f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); | ||
577 | f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); | ||
578 | f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; | ||
579 | alps_decode_buttons_v3(f, p); | ||
580 | } else { | ||
581 | f->fingers = ((p[0] & 0x6) >> 1 | | ||
519 | (p[0] & 0x10) >> 2); | 582 | (p[0] & 0x10) >> 2); |
520 | f->x_map = ((p[2] & 0x60) >> 5) | | ||
521 | ((p[4] & 0x7f) << 2) | | ||
522 | ((p[5] & 0x7f) << 9) | | ||
523 | ((p[3] & 0x07) << 16) | | ||
524 | ((p[3] & 0x70) << 15) | | ||
525 | ((p[0] & 0x01) << 22); | ||
526 | f->y_map = (p[1] & 0x7f) | | ||
527 | ((p[2] & 0x1f) << 7); | ||
528 | |||
529 | f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); | ||
530 | f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); | ||
531 | f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; | ||
532 | 583 | ||
533 | alps_decode_buttons_v3(f, p); | 584 | palm_data = (p[1] & 0x7f) | |
585 | ((p[2] & 0x7f) << 7) | | ||
586 | ((p[4] & 0x7f) << 14) | | ||
587 | ((p[5] & 0x7f) << 21) | | ||
588 | ((p[3] & 0x07) << 28) | | ||
589 | (((u64)p[3] & 0x70) << 27) | | ||
590 | (((u64)p[0] & 0x01) << 34); | ||
591 | |||
592 | /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ | ||
593 | f->y_map = palm_data & (BIT(priv->y_bits) - 1); | ||
594 | |||
595 | /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ | ||
596 | f->x_map = (palm_data >> priv->y_bits) & | ||
597 | (BIT(priv->x_bits) - 1); | ||
598 | } | ||
534 | } | 599 | } |
535 | 600 | ||
536 | static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | 601 | static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) |
537 | { | 602 | { |
538 | struct alps_data *priv = psmouse->private; | 603 | struct alps_data *priv = psmouse->private; |
539 | unsigned char *packet = psmouse->packet; | 604 | unsigned char *packet = psmouse->packet; |
540 | struct input_dev *dev = psmouse->dev; | 605 | struct input_dev *dev = psmouse->dev; |
541 | struct input_dev *dev2 = priv->dev2; | 606 | struct input_dev *dev2 = priv->dev2; |
542 | int x1 = 0, y1 = 0, x2 = 0, y2 = 0; | 607 | int x1 = 0, y1 = 0, x2 = 0, y2 = 0; |
543 | int fingers = 0, bmap_fingers; | 608 | int fingers = 0, bmap_fn; |
544 | struct alps_fields f; | 609 | struct alps_fields f = {0}; |
545 | 610 | ||
546 | priv->decode_fields(&f, packet); | 611 | priv->decode_fields(&f, packet, psmouse); |
547 | 612 | ||
548 | /* | 613 | /* |
549 | * There's no single feature of touchpad position and bitmap packets | 614 | * There's no single feature of touchpad position and bitmap packets |
@@ -560,19 +625,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) | |||
560 | */ | 625 | */ |
561 | if (f.is_mp) { | 626 | if (f.is_mp) { |
562 | fingers = f.fingers; | 627 | fingers = f.fingers; |
563 | bmap_fingers = alps_process_bitmap(priv, | 628 | if (priv->proto_version == ALPS_PROTO_V3) { |
564 | f.x_map, f.y_map, | 629 | bmap_fn = alps_process_bitmap(priv, f.x_map, |
565 | &x1, &y1, &x2, &y2); | 630 | f.y_map, &x1, &y1, |
566 | 631 | &x2, &y2); | |
567 | /* | 632 | |
568 | * We shouldn't report more than one finger if | 633 | /* |
569 | * we don't have two coordinates. | 634 | * We shouldn't report more than one finger if |
570 | */ | 635 | * we don't have two coordinates. |
571 | if (fingers > 1 && bmap_fingers < 2) | 636 | */ |
572 | fingers = bmap_fingers; | 637 | if (fingers > 1 && bmap_fn < 2) |
573 | 638 | fingers = bmap_fn; | |
574 | /* Now process position packet */ | 639 | |
575 | priv->decode_fields(&f, priv->multi_data); | 640 | /* Now process position packet */ |
641 | priv->decode_fields(&f, priv->multi_data, | ||
642 | psmouse); | ||
643 | } else { | ||
644 | /* | ||
645 | * Because Dolphin uses position packet's | ||
646 | * coordinate data as Pt1 and uses it to | ||
647 | * calculate Pt2, so we need to do position | ||
648 | * packet decode first. | ||
649 | */ | ||
650 | priv->decode_fields(&f, priv->multi_data, | ||
651 | psmouse); | ||
652 | |||
653 | /* | ||
654 | * Since Dolphin's finger number is reliable, | ||
655 | * there is no need to compare with bmap_fn. | ||
656 | */ | ||
657 | alps_process_bitmap_dolphin(priv, &f, &x1, &y1, | ||
658 | &x2, &y2); | ||
659 | } | ||
576 | } else { | 660 | } else { |
577 | priv->multi_packet = 0; | 661 | priv->multi_packet = 0; |
578 | } | 662 | } |
@@ -662,7 +746,7 @@ static void alps_process_packet_v3(struct psmouse *psmouse) | |||
662 | return; | 746 | return; |
663 | } | 747 | } |
664 | 748 | ||
665 | alps_process_touchpad_packet_v3(psmouse); | 749 | alps_process_touchpad_packet_v3_v5(psmouse); |
666 | } | 750 | } |
667 | 751 | ||
668 | static void alps_process_packet_v6(struct psmouse *psmouse) | 752 | static void alps_process_packet_v6(struct psmouse *psmouse) |
@@ -1709,6 +1793,52 @@ error: | |||
1709 | return -1; | 1793 | return -1; |
1710 | } | 1794 | } |
1711 | 1795 | ||
1796 | static int alps_dolphin_get_device_area(struct psmouse *psmouse, | ||
1797 | struct alps_data *priv) | ||
1798 | { | ||
1799 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1800 | unsigned char param[4] = {0}; | ||
1801 | int num_x_electrode, num_y_electrode; | ||
1802 | |||
1803 | if (alps_enter_command_mode(psmouse)) | ||
1804 | return -1; | ||
1805 | |||
1806 | param[0] = 0x0a; | ||
1807 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || | ||
1808 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || | ||
1809 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || | ||
1810 | ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || | ||
1811 | ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) | ||
1812 | return -1; | ||
1813 | |||
1814 | if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | ||
1815 | return -1; | ||
1816 | |||
1817 | /* | ||
1818 | * Dolphin's sensor line number is not fixed. It can be calculated | ||
1819 | * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. | ||
1820 | * Further more, we can get device's x_max and y_max by multiplying | ||
1821 | * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. | ||
1822 | * | ||
1823 | * e.g. When we get register's sensor_x = 11 & sensor_y = 8, | ||
1824 | * real sensor line number X = 11 + 8 = 19, and | ||
1825 | * real sensor line number Y = 8 + 1 = 9. | ||
1826 | * So, x_max = (19 - 1) * 64 = 1152, and | ||
1827 | * y_max = (9 - 1) * 64 = 512. | ||
1828 | */ | ||
1829 | num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); | ||
1830 | num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); | ||
1831 | priv->x_bits = num_x_electrode; | ||
1832 | priv->y_bits = num_y_electrode; | ||
1833 | priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; | ||
1834 | priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; | ||
1835 | |||
1836 | if (alps_exit_command_mode(psmouse)) | ||
1837 | return -1; | ||
1838 | |||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1712 | static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) | 1842 | static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) |
1713 | { | 1843 | { |
1714 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 1844 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
@@ -1763,13 +1893,13 @@ static void alps_set_defaults(struct alps_data *priv) | |||
1763 | break; | 1893 | break; |
1764 | case ALPS_PROTO_V5: | 1894 | case ALPS_PROTO_V5: |
1765 | priv->hw_init = alps_hw_init_dolphin_v1; | 1895 | priv->hw_init = alps_hw_init_dolphin_v1; |
1766 | priv->process_packet = alps_process_packet_v3; | 1896 | priv->process_packet = alps_process_touchpad_packet_v3_v5; |
1767 | priv->decode_fields = alps_decode_dolphin; | 1897 | priv->decode_fields = alps_decode_dolphin; |
1768 | priv->set_abs_params = alps_set_abs_params_mt; | 1898 | priv->set_abs_params = alps_set_abs_params_mt; |
1769 | priv->nibble_commands = alps_v3_nibble_commands; | 1899 | priv->nibble_commands = alps_v3_nibble_commands; |
1770 | priv->addr_command = PSMOUSE_CMD_RESET_WRAP; | 1900 | priv->addr_command = PSMOUSE_CMD_RESET_WRAP; |
1771 | priv->byte0 = 0xc8; | 1901 | priv->byte0 = 0xc8; |
1772 | priv->mask0 = 0xc8; | 1902 | priv->mask0 = 0xd8; |
1773 | priv->flags = 0; | 1903 | priv->flags = 0; |
1774 | priv->x_max = 1360; | 1904 | priv->x_max = 1360; |
1775 | priv->y_max = 660; | 1905 | priv->y_max = 660; |
@@ -1845,11 +1975,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) | |||
1845 | if (alps_match_table(psmouse, priv, e7, ec) == 0) { | 1975 | if (alps_match_table(psmouse, priv, e7, ec) == 0) { |
1846 | return 0; | 1976 | return 0; |
1847 | } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && | 1977 | } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && |
1848 | ec[0] == 0x73 && ec[1] == 0x01) { | 1978 | ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { |
1849 | priv->proto_version = ALPS_PROTO_V5; | 1979 | priv->proto_version = ALPS_PROTO_V5; |
1850 | alps_set_defaults(priv); | 1980 | alps_set_defaults(priv); |
1851 | 1981 | if (alps_dolphin_get_device_area(psmouse, priv)) | |
1852 | return 0; | 1982 | return -EIO; |
1983 | else | ||
1984 | return 0; | ||
1853 | } else if (ec[0] == 0x88 && ec[1] == 0x08) { | 1985 | } else if (ec[0] == 0x88 && ec[1] == 0x08) { |
1854 | priv->proto_version = ALPS_PROTO_V3; | 1986 | priv->proto_version = ALPS_PROTO_V3; |
1855 | alps_set_defaults(priv); | 1987 | alps_set_defaults(priv); |
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 704f0f924307..03f88b6940c7 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h | |||
@@ -19,6 +19,10 @@ | |||
19 | #define ALPS_PROTO_V5 5 | 19 | #define ALPS_PROTO_V5 5 |
20 | #define ALPS_PROTO_V6 6 | 20 | #define ALPS_PROTO_V6 6 |
21 | 21 | ||
22 | #define DOLPHIN_COUNT_PER_ELECTRODE 64 | ||
23 | #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ | ||
24 | #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ | ||
25 | |||
22 | /** | 26 | /** |
23 | * struct alps_model_info - touchpad ID table | 27 | * struct alps_model_info - touchpad ID table |
24 | * @signature: E7 response string to match. | 28 | * @signature: E7 response string to match. |
@@ -146,7 +150,8 @@ struct alps_data { | |||
146 | 150 | ||
147 | int (*hw_init)(struct psmouse *psmouse); | 151 | int (*hw_init)(struct psmouse *psmouse); |
148 | void (*process_packet)(struct psmouse *psmouse); | 152 | void (*process_packet)(struct psmouse *psmouse); |
149 | void (*decode_fields)(struct alps_fields *f, unsigned char *p); | 153 | void (*decode_fields)(struct alps_fields *f, unsigned char *p, |
154 | struct psmouse *psmouse); | ||
150 | void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); | 155 | void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); |
151 | 156 | ||
152 | int prev_fin; | 157 | int prev_fin; |