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 | |
| 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>
| -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; |
