aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse
diff options
context:
space:
mode:
authorDaniel Kurtz <djkurtz@chromium.org>2011-08-24 02:02:25 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-08-24 02:08:12 -0400
commit3cdfee9ea7e98eb6e8c3d4d66f2dfcfffe6afc4d (patch)
treea545a98c243d9eb4d9254651587ddfade4fb32f5 /drivers/input/mouse
parent85615476e2039d2567075d7949a30f0c204f8103 (diff)
Input: synaptics - add image sensor support
Synaptics makes (at least) two kinds of touchpad sensors: * Older pads use a profile sensor that could only infer the location of individual fingers based on the projection of their profiles onto row and column sensors. * Newer pads use an image sensor that can track true finger position using a two-dimensional sensor grid. Both sensor types support an "Advanced Gesture Mode": When multiple fingers are detected, the touchpad sends alternating "Advanced Gesture Mode" (AGM) and "Simple Gesture Mode" (SGM) packets. The AGM packets have w=2, and contain reduced resolution finger data The SGM packets have w={0,1} and contain full resolution finger data Profile sensors try to report the "upper" (larger y value) finger in the SGM packet, and the lower (smaller y value) in the AGM packet. However, due to the nature of the profile sensor, they easily get confused when fingers cross, and can start reporting the x-coordinate of one with the y-coordinate of the other. Thus, for profile sensors, "semi-mt" was created, which reports a "bounding box" created by pairing min and max coordinates of the two pairs of reported fingers. Image sensors can report the actual coordinates of two of the fingers present. This patch detects if the touchpad is an image sensor and reports finger data using the MT-B protocol. NOTE: This patch only adds partial support for 2-finger gestures. The proper interpretation of the slot contents when more than two fingers are present is left to later patches. Also, handling of 'number of fingers' transitions is incomplete. Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Acked-by: Chase Douglas <chase.douglas@canonical.com> Acked-by: Henrik Rydberg <rydberg@euromail.se> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/synaptics.c124
-rw-r--r--drivers/input/mouse/synaptics.h3
2 files changed, 110 insertions, 17 deletions
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 8e9360ab4ec4..e6e59c59391d 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -304,7 +304,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
304 static unsigned char param = 0xc8; 304 static unsigned char param = 0xc8;
305 struct synaptics_data *priv = psmouse->private; 305 struct synaptics_data *priv = psmouse->private;
306 306
307 if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) 307 if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
308 SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
308 return 0; 309 return 0;
309 310
310 if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) 311 if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
@@ -463,7 +464,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
463 hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; 464 hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
464 } 465 }
465 466
466 if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { 467 if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
468 SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
469 hw->w == 2) {
467 synaptics_parse_agm(buf, priv); 470 synaptics_parse_agm(buf, priv);
468 return 1; 471 return 1;
469 } 472 }
@@ -543,6 +546,94 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
543 } 546 }
544} 547}
545 548
549static void synaptics_report_buttons(struct psmouse *psmouse,
550 const struct synaptics_hw_state *hw)
551{
552 struct input_dev *dev = psmouse->dev;
553 struct synaptics_data *priv = psmouse->private;
554 int i;
555
556 input_report_key(dev, BTN_LEFT, hw->left);
557 input_report_key(dev, BTN_RIGHT, hw->right);
558
559 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
560 input_report_key(dev, BTN_MIDDLE, hw->middle);
561
562 if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
563 input_report_key(dev, BTN_FORWARD, hw->up);
564 input_report_key(dev, BTN_BACK, hw->down);
565 }
566
567 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
568 input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
569}
570
571static void synaptics_report_slot(struct input_dev *dev, int slot,
572 const struct synaptics_hw_state *hw)
573{
574 input_mt_slot(dev, slot);
575 input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL));
576 if (!hw)
577 return;
578
579 input_report_abs(dev, ABS_MT_POSITION_X, hw->x);
580 input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y));
581 input_report_abs(dev, ABS_MT_PRESSURE, hw->z);
582}
583
584static void synaptics_report_mt_data(struct psmouse *psmouse,
585 int count,
586 const struct synaptics_hw_state *sgm)
587{
588 struct input_dev *dev = psmouse->dev;
589 struct synaptics_data *priv = psmouse->private;
590 struct synaptics_hw_state *agm = &priv->agm;
591
592 switch (count) {
593 case 0:
594 synaptics_report_slot(dev, 0, NULL);
595 synaptics_report_slot(dev, 1, NULL);
596 break;
597 case 1:
598 synaptics_report_slot(dev, 0, sgm);
599 synaptics_report_slot(dev, 1, NULL);
600 break;
601 case 2:
602 case 3: /* Fall-through case */
603 synaptics_report_slot(dev, 0, sgm);
604 synaptics_report_slot(dev, 1, agm);
605 break;
606 }
607
608 /* Don't use active slot count to generate BTN_TOOL events. */
609 input_mt_report_pointer_emulation(dev, false);
610
611 /* Send the number of fingers reported by touchpad itself. */
612 input_mt_report_finger_count(dev, count);
613
614 synaptics_report_buttons(psmouse, sgm);
615
616 input_sync(dev);
617}
618
619static void synaptics_image_sensor_process(struct psmouse *psmouse,
620 struct synaptics_hw_state *sgm)
621{
622 int count;
623
624 if (sgm->z == 0)
625 count = 0;
626 else if (sgm->w >= 4)
627 count = 1;
628 else if (sgm->w == 0)
629 count = 2;
630 else
631 count = 3;
632
633 /* Send resulting input events to user space */
634 synaptics_report_mt_data(psmouse, count, sgm);
635}
636
546/* 637/*
547 * called for each full received packet from the touchpad 638 * called for each full received packet from the touchpad
548 */ 639 */
@@ -553,11 +644,15 @@ static void synaptics_process_packet(struct psmouse *psmouse)
553 struct synaptics_hw_state hw; 644 struct synaptics_hw_state hw;
554 int num_fingers; 645 int num_fingers;
555 int finger_width; 646 int finger_width;
556 int i;
557 647
558 if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) 648 if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
559 return; 649 return;
560 650
651 if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
652 synaptics_image_sensor_process(psmouse, &hw);
653 return;
654 }
655
561 if (hw.scroll) { 656 if (hw.scroll) {
562 priv->scroll += hw.scroll; 657 priv->scroll += hw.scroll;
563 658
@@ -623,24 +718,12 @@ static void synaptics_process_packet(struct psmouse *psmouse)
623 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); 718 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
624 719
625 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); 720 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
626 input_report_key(dev, BTN_LEFT, hw.left);
627 input_report_key(dev, BTN_RIGHT, hw.right);
628
629 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 721 if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
630 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); 722 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
631 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); 723 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
632 } 724 }
633 725
634 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) 726 synaptics_report_buttons(psmouse, &hw);
635 input_report_key(dev, BTN_MIDDLE, hw.middle);
636
637 if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
638 input_report_key(dev, BTN_FORWARD, hw.up);
639 input_report_key(dev, BTN_BACK, hw.down);
640 }
641
642 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
643 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
644 727
645 input_sync(dev); 728 input_sync(dev);
646} 729}
@@ -739,7 +822,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
739 set_abs_position_params(dev, priv, ABS_X, ABS_Y); 822 set_abs_position_params(dev, priv, ABS_X, ABS_Y);
740 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); 823 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
741 824
742 if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { 825 if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
826 input_mt_init_slots(dev, 2);
827 set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
828 ABS_MT_POSITION_Y);
829 /* Image sensors can report per-contact pressure */
830 input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
831 } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
832 /* Non-image sensors with AGM use semi-mt */
743 __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); 833 __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
744 input_mt_init_slots(dev, 2); 834 input_mt_init_slots(dev, 2);
745 set_abs_position_params(dev, priv, ABS_MT_POSITION_X, 835 set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index a9efbf3e3ea1..0ea7616e8fe1 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -74,6 +74,8 @@
74 * 2 0x04 reduced filtering firmware does less filtering on 74 * 2 0x04 reduced filtering firmware does less filtering on
75 * position data, driver should watch 75 * position data, driver should watch
76 * for noise. 76 * for noise.
77 * 2 0x08 image sensor image sensor tracks 5 fingers, but only
78 * reports 2.
77 * 2 0x20 report min query 0x0f gives min coord reported 79 * 2 0x20 report min query 0x0f gives min coord reported
78 */ 80 */
79#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ 81#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
@@ -82,6 +84,7 @@
82#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) 84#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000)
83#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) 85#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
84#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) 86#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
87#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
85 88
86/* synaptics modes query bits */ 89/* synaptics modes query bits */
87#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) 90#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))