Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: ALPS - add semi-MT support for v4 protocol

This patch adds semi-MT support for ALPS v4 protocol touchpads.
It is based on the work by Seth Forshee for ALPS v3 and v4 protocol
support. Three packets are required to assemble and process the MT
data. ST events are reported at once to avoid latency. If there
were two contacts or more, report MT data instead of ST events.

Thanks to Seth Forshee for providing most of the code, guidance
and insight for producing this patch.

Signed-off-by: George Pantalos <gpantalos@gmail.com>
Acked-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

George Pantalos and committed by
Dmitry Torokhov
3b7e09fa ae99ea56

+75 -6
+73 -6
drivers/input/mouse/alps.c
··· 604 604 605 605 static void alps_process_packet_v4(struct psmouse *psmouse) 606 606 { 607 + struct alps_data *priv = psmouse->private; 607 608 unsigned char *packet = psmouse->packet; 608 609 struct input_dev *dev = psmouse->dev; 610 + int offset; 609 611 int x, y, z; 610 612 int left, right; 613 + int x1, y1, x2, y2; 614 + int fingers = 0; 615 + unsigned int x_bitmap, y_bitmap; 616 + 617 + /* 618 + * v4 has a 6-byte encoding for bitmap data, but this data is 619 + * broken up between 3 normal packets. Use priv->multi_packet to 620 + * track our position in the bitmap packet. 621 + */ 622 + if (packet[6] & 0x40) { 623 + /* sync, reset position */ 624 + priv->multi_packet = 0; 625 + } 626 + 627 + if (WARN_ON_ONCE(priv->multi_packet > 2)) 628 + return; 629 + 630 + offset = 2 * priv->multi_packet; 631 + priv->multi_data[offset] = packet[6]; 632 + priv->multi_data[offset + 1] = packet[7]; 633 + 634 + if (++priv->multi_packet > 2) { 635 + priv->multi_packet = 0; 636 + 637 + x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) | 638 + ((priv->multi_data[3] & 0x60) << 3) | 639 + ((priv->multi_data[0] & 0x3f) << 2) | 640 + ((priv->multi_data[1] & 0x60) >> 5); 641 + y_bitmap = ((priv->multi_data[5] & 0x01) << 10) | 642 + ((priv->multi_data[3] & 0x1f) << 5) | 643 + (priv->multi_data[1] & 0x1f); 644 + 645 + fingers = alps_process_bitmap(x_bitmap, y_bitmap, 646 + &x1, &y1, &x2, &y2); 647 + 648 + /* Store MT data.*/ 649 + priv->fingers = fingers; 650 + priv->x1 = x1; 651 + priv->x2 = x2; 652 + priv->y1 = y1; 653 + priv->y2 = y2; 654 + } 611 655 612 656 left = packet[4] & 0x01; 613 657 right = packet[4] & 0x02; ··· 661 617 y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); 662 618 z = packet[5] & 0x7f; 663 619 620 + /* 621 + * If there were no contacts in the bitmap, use ST 622 + * points in MT reports. 623 + * If there were two contacts or more, report MT data. 624 + */ 625 + if (priv->fingers < 2) { 626 + x1 = x; 627 + y1 = y; 628 + fingers = z > 0 ? 1 : 0; 629 + } else { 630 + fingers = priv->fingers; 631 + x1 = priv->x1; 632 + x2 = priv->x2; 633 + y1 = priv->y1; 634 + y2 = priv->y2; 635 + } 636 + 664 637 if (z >= 64) 665 638 input_report_key(dev, BTN_TOUCH, 1); 666 639 else 667 640 input_report_key(dev, BTN_TOUCH, 0); 641 + 642 + alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); 643 + 644 + input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); 645 + input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); 646 + input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); 647 + input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); 648 + 649 + input_report_key(dev, BTN_LEFT, left); 650 + input_report_key(dev, BTN_RIGHT, right); 668 651 669 652 if (z > 0) { 670 653 input_report_abs(dev, ABS_X, x); 671 654 input_report_abs(dev, ABS_Y, y); 672 655 } 673 656 input_report_abs(dev, ABS_PRESSURE, z); 674 - 675 - input_report_key(dev, BTN_TOOL_FINGER, z > 0); 676 - input_report_key(dev, BTN_LEFT, left); 677 - input_report_key(dev, BTN_RIGHT, right); 678 657 679 658 input_sync(dev); 680 659 } ··· 1624 1557 input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); 1625 1558 break; 1626 1559 case ALPS_PROTO_V3: 1560 + case ALPS_PROTO_V4: 1627 1561 set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); 1628 1562 input_mt_init_slots(dev1, 2); 1629 1563 input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); ··· 1633 1565 set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); 1634 1566 set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); 1635 1567 set_bit(BTN_TOOL_QUADTAP, dev1->keybit); 1636 - /* fall through */ 1637 - case ALPS_PROTO_V4: 1568 + 1638 1569 input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0); 1639 1570 input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0); 1640 1571 break;
+2
drivers/input/mouse/alps.h
··· 39 39 int prev_fin; /* Finger bit from previous packet */ 40 40 int multi_packet; /* Multi-packet data in progress */ 41 41 unsigned char multi_data[6]; /* Saved multi-packet data */ 42 + int x1, x2, y1, y2; /* Coordinates from last MT report */ 43 + int fingers; /* Number of fingers from MT report */ 42 44 u8 quirks; 43 45 struct timer_list timer; 44 46 };