aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/alps.c
diff options
context:
space:
mode:
authorGeorge Pantalos <gpantalos@gmail.com>2012-05-11 01:31:59 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-05-11 01:32:20 -0400
commit3b7e09fad9582df27fd72edd018a9c59d085f896 (patch)
tree6693b0ca5499dbd6f79d62e5ab69b952bb66e231 /drivers/input/mouse/alps.c
parentae99ea562be0a788ccb583aff21f3d2147de531f (diff)
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>
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r--drivers/input/mouse/alps.c79
1 files changed, 73 insertions, 6 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4c6a72d3d48c..ecd93894c806 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -604,10 +604,54 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
604 604
605static void alps_process_packet_v4(struct psmouse *psmouse) 605static void alps_process_packet_v4(struct psmouse *psmouse)
606{ 606{
607 struct alps_data *priv = psmouse->private;
607 unsigned char *packet = psmouse->packet; 608 unsigned char *packet = psmouse->packet;
608 struct input_dev *dev = psmouse->dev; 609 struct input_dev *dev = psmouse->dev;
610 int offset;
609 int x, y, z; 611 int x, y, z;
610 int left, right; 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 left = packet[4] & 0x01; 656 left = packet[4] & 0x01;
613 right = packet[4] & 0x02; 657 right = packet[4] & 0x02;
@@ -617,21 +661,44 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
617 y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); 661 y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
618 z = packet[5] & 0x7f; 662 z = packet[5] & 0x7f;
619 663
664 /*
665 * If there were no contacts in the bitmap, use ST
666 * points in MT reports.
667 * If there were two contacts or more, report MT data.
668 */
669 if (priv->fingers < 2) {
670 x1 = x;
671 y1 = y;
672 fingers = z > 0 ? 1 : 0;
673 } else {
674 fingers = priv->fingers;
675 x1 = priv->x1;
676 x2 = priv->x2;
677 y1 = priv->y1;
678 y2 = priv->y2;
679 }
680
620 if (z >= 64) 681 if (z >= 64)
621 input_report_key(dev, BTN_TOUCH, 1); 682 input_report_key(dev, BTN_TOUCH, 1);
622 else 683 else
623 input_report_key(dev, BTN_TOUCH, 0); 684 input_report_key(dev, BTN_TOUCH, 0);
624 685
686 alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
687
688 input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
689 input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
690 input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
691 input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
692
693 input_report_key(dev, BTN_LEFT, left);
694 input_report_key(dev, BTN_RIGHT, right);
695
625 if (z > 0) { 696 if (z > 0) {
626 input_report_abs(dev, ABS_X, x); 697 input_report_abs(dev, ABS_X, x);
627 input_report_abs(dev, ABS_Y, y); 698 input_report_abs(dev, ABS_Y, y);
628 } 699 }
629 input_report_abs(dev, ABS_PRESSURE, z); 700 input_report_abs(dev, ABS_PRESSURE, z);
630 701
631 input_report_key(dev, BTN_TOOL_FINGER, z > 0);
632 input_report_key(dev, BTN_LEFT, left);
633 input_report_key(dev, BTN_RIGHT, right);
634
635 input_sync(dev); 702 input_sync(dev);
636} 703}
637 704
@@ -1557,6 +1624,7 @@ int alps_init(struct psmouse *psmouse)
1557 input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); 1624 input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
1558 break; 1625 break;
1559 case ALPS_PROTO_V3: 1626 case ALPS_PROTO_V3:
1627 case ALPS_PROTO_V4:
1560 set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); 1628 set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
1561 input_mt_init_slots(dev1, 2); 1629 input_mt_init_slots(dev1, 2);
1562 input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); 1630 input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
@@ -1565,8 +1633,7 @@ int alps_init(struct psmouse *psmouse)
1565 set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); 1633 set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
1566 set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); 1634 set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
1567 set_bit(BTN_TOOL_QUADTAP, dev1->keybit); 1635 set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
1568 /* fall through */ 1636
1569 case ALPS_PROTO_V4:
1570 input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0); 1637 input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
1571 input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0); 1638 input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
1572 break; 1639 break;