diff options
author | Daniel Kurtz <djkurtz@chromium.org> | 2011-08-24 02:02:40 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-08-24 02:08:24 -0400 |
commit | 4dc772d274abdedcccbcebab42d4bf0016ec2e80 (patch) | |
tree | 2b7837ecf69f7590371f6cca0428ff6b8e9aec56 /drivers/input/mouse | |
parent | a93bd154d8571f1be84b04d7451ec72a490636d8 (diff) |
Input: synaptics - process finger (<=3) transitions
Synaptics image sensor touchpads track 5 fingers, but only report 2.
This patch attempts to deal with some idiosyncrasies of these touchpads:
* When there are 3 or more fingers, only two are reported.
* The touchpad tracks the 5 fingers in slot[0] through slot[4].
* It always reports the lowest and highest valid slots in SGM and AGM
packets, respectively.
* The number of fingers is only reported in the SGM packet. However,
the number of fingers can change either before or after an AGM
packet.
* Thus, if an SGM reports a different number of fingers than the last
SGM, it is impossible to tell whether the intervening AGM corresponds
to the old number of fingers or the new number of fingers.
* For example, when going from 2->3 fingers, it is not possible to tell
whether tell AGM contains slot[1] (old 2nd finger) or slot[2] (new
3rd finger).
* When fingers are added one at at time, from 1->2->3, it is possible to
track which slots are contained in the SGM and AGM packets:
1 finger: SGM = slot[0], no AGM
2 fingers: SGM = slot[0], AGM = slot[1]
3 fingers: SGM = slot[0], AGM = slot[2]
* It is also possible to track which slot is contained in the SGM when 1
of 2 fingers is removed. This is because the touchpad sends a special
(0,0,0) AGM packet whenever all fingers are removed except slot[0]:
Last AGM == (0,0,0): SGM contains slot[1]
Else: SGM contains slot[0]
* However, once there are 3 fingers, if exactly 1 finger is removed, it
is impossible to tell which 2 slots are contained in SGM and AGM.
The (SGM,AGM) could be (0,1), (0,2), or (1,2). There is no way to know.
* Similarly, if two fingers are simultaneously removed (3->1), then it
is only possible to know if SGM still contains slot[0].
* Since it is not possible to reliably track which slot is being
reported, we invalidate the tracking_id every time the number of
fingers changes until this ambiguity is resolved when:
a) All fingers are removed.
b) 4 or 5 fingers are touched, generates an AGM-CONTACT packet.
c) All fingers are removed except slot[0]. In this special case, the
ambiguity is resolved since by the (0,0,0) AGM packet.
Behavior of the driver:
When 2 or more fingers are present on the touchpad, the kernel reports
up to two MT-B slots containing the position data for two of the fingers
reported by the touchpad. If the identity of a finger cannot be tracked
when the number-of-fingers changes, the corresponding MT-B slot will be
invalidated (track_id set to -1), and a new track_id will be assigned in
a subsequent input event report.
The driver always reports the total number of fingers using one of the
EV_KEY/BTN_TOOL_*TAP events. This could differ from the number of valid
MT-B slots for two reasons:
a) There are more than 2 fingers on the pad.
b) During ambiguous number-of-fingers transitions, the correct track_id
for one or both of the slots cannot be determined, so the slots are
invalidated.
Thus, this is a hybrid singletouch/MT-B scheme. Userspace can detect
this behavior by noting that the driver supports more EV_KEY/BTN_TOOL_*TAP
events than its maximum EV_ABS/ABS_MT_SLOT.
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.c | 290 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.h | 4 |
2 files changed, 278 insertions, 16 deletions
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index a7af8565e2de..aec9cf7124f8 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -453,6 +453,9 @@ static void synaptics_parse_agm(const unsigned char buf[], | |||
453 | default: | 453 | default: |
454 | break; | 454 | break; |
455 | } | 455 | } |
456 | |||
457 | /* Record that at least one AGM has been received since last SGM */ | ||
458 | priv->agm_pending = true; | ||
456 | } | 459 | } |
457 | 460 | ||
458 | static int synaptics_parse_hw_state(const unsigned char buf[], | 461 | static int synaptics_parse_hw_state(const unsigned char buf[], |
@@ -606,26 +609,53 @@ static void synaptics_report_slot(struct input_dev *dev, int slot, | |||
606 | } | 609 | } |
607 | 610 | ||
608 | static void synaptics_report_mt_data(struct psmouse *psmouse, | 611 | static void synaptics_report_mt_data(struct psmouse *psmouse, |
609 | int count, | 612 | struct synaptics_mt_state *mt_state, |
610 | const struct synaptics_hw_state *sgm) | 613 | const struct synaptics_hw_state *sgm) |
611 | { | 614 | { |
612 | struct input_dev *dev = psmouse->dev; | 615 | struct input_dev *dev = psmouse->dev; |
613 | struct synaptics_data *priv = psmouse->private; | 616 | struct synaptics_data *priv = psmouse->private; |
614 | struct synaptics_hw_state *agm = &priv->agm; | 617 | struct synaptics_hw_state *agm = &priv->agm; |
618 | struct synaptics_mt_state *old = &priv->mt_state; | ||
615 | 619 | ||
616 | switch (count) { | 620 | switch (mt_state->count) { |
617 | case 0: | 621 | case 0: |
618 | synaptics_report_slot(dev, 0, NULL); | 622 | synaptics_report_slot(dev, 0, NULL); |
619 | synaptics_report_slot(dev, 1, NULL); | 623 | synaptics_report_slot(dev, 1, NULL); |
620 | break; | 624 | break; |
621 | case 1: | 625 | case 1: |
622 | synaptics_report_slot(dev, 0, sgm); | 626 | if (mt_state->sgm == -1) { |
623 | synaptics_report_slot(dev, 1, NULL); | 627 | synaptics_report_slot(dev, 0, NULL); |
628 | synaptics_report_slot(dev, 1, NULL); | ||
629 | } else if (mt_state->sgm == 0) { | ||
630 | synaptics_report_slot(dev, 0, sgm); | ||
631 | synaptics_report_slot(dev, 1, NULL); | ||
632 | } else { | ||
633 | synaptics_report_slot(dev, 0, NULL); | ||
634 | synaptics_report_slot(dev, 1, sgm); | ||
635 | } | ||
624 | break; | 636 | break; |
625 | case 2: | 637 | default: |
626 | case 3: /* Fall-through case */ | 638 | /* |
627 | synaptics_report_slot(dev, 0, sgm); | 639 | * If the finger slot contained in SGM is valid, and either |
628 | synaptics_report_slot(dev, 1, agm); | 640 | * hasn't changed, or is new, then report SGM in MTB slot 0. |
641 | * Otherwise, empty MTB slot 0. | ||
642 | */ | ||
643 | if (mt_state->sgm != -1 && | ||
644 | (mt_state->sgm == old->sgm || old->sgm == -1)) | ||
645 | synaptics_report_slot(dev, 0, sgm); | ||
646 | else | ||
647 | synaptics_report_slot(dev, 0, NULL); | ||
648 | |||
649 | /* | ||
650 | * If the finger slot contained in AGM is valid, and either | ||
651 | * hasn't changed, or is new, then report AGM in MTB slot 1. | ||
652 | * Otherwise, empty MTB slot 1. | ||
653 | */ | ||
654 | if (mt_state->agm != -1 && | ||
655 | (mt_state->agm == old->agm || old->agm == -1)) | ||
656 | synaptics_report_slot(dev, 1, agm); | ||
657 | else | ||
658 | synaptics_report_slot(dev, 1, NULL); | ||
629 | break; | 659 | break; |
630 | } | 660 | } |
631 | 661 | ||
@@ -633,29 +663,257 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, | |||
633 | input_mt_report_pointer_emulation(dev, false); | 663 | input_mt_report_pointer_emulation(dev, false); |
634 | 664 | ||
635 | /* Send the number of fingers reported by touchpad itself. */ | 665 | /* Send the number of fingers reported by touchpad itself. */ |
636 | input_mt_report_finger_count(dev, count); | 666 | input_mt_report_finger_count(dev, mt_state->count); |
637 | 667 | ||
638 | synaptics_report_buttons(psmouse, sgm); | 668 | synaptics_report_buttons(psmouse, sgm); |
639 | 669 | ||
640 | input_sync(dev); | 670 | input_sync(dev); |
641 | } | 671 | } |
642 | 672 | ||
673 | /* Handle case where mt_state->count = 0 */ | ||
674 | static void synaptics_image_sensor_0f(struct synaptics_data *priv, | ||
675 | struct synaptics_mt_state *mt_state) | ||
676 | { | ||
677 | synaptics_mt_state_set(mt_state, 0, -1, -1); | ||
678 | priv->mt_state_lost = false; | ||
679 | } | ||
680 | |||
681 | /* Handle case where mt_state->count = 1 */ | ||
682 | static void synaptics_image_sensor_1f(struct synaptics_data *priv, | ||
683 | struct synaptics_mt_state *mt_state) | ||
684 | { | ||
685 | struct synaptics_hw_state *agm = &priv->agm; | ||
686 | struct synaptics_mt_state *old = &priv->mt_state; | ||
687 | |||
688 | /* | ||
689 | * If the last AGM was (0,0,0), and there is only one finger left, | ||
690 | * then we absolutely know that SGM contains slot 0, and all other | ||
691 | * fingers have been removed. | ||
692 | */ | ||
693 | if (priv->agm_pending && agm->z == 0) { | ||
694 | synaptics_mt_state_set(mt_state, 1, 0, -1); | ||
695 | priv->mt_state_lost = false; | ||
696 | return; | ||
697 | } | ||
698 | |||
699 | switch (old->count) { | ||
700 | case 0: | ||
701 | synaptics_mt_state_set(mt_state, 1, 0, -1); | ||
702 | break; | ||
703 | case 1: | ||
704 | /* | ||
705 | * If mt_state_lost, then the previous transition was 3->1, | ||
706 | * and SGM now contains either slot 0 or 1, but we don't know | ||
707 | * which. So, we just assume that the SGM now contains slot 1. | ||
708 | * | ||
709 | * If pending AGM and either: | ||
710 | * (a) the previous SGM slot contains slot 0, or | ||
711 | * (b) there was no SGM slot | ||
712 | * then, the SGM now contains slot 1 | ||
713 | * | ||
714 | * Case (a) happens with very rapid "drum roll" gestures, where | ||
715 | * slot 0 finger is lifted and a new slot 1 finger touches | ||
716 | * within one reporting interval. | ||
717 | * | ||
718 | * Case (b) happens if initially two or more fingers tap | ||
719 | * briefly, and all but one lift before the end of the first | ||
720 | * reporting interval. | ||
721 | * | ||
722 | * (In both these cases, slot 0 will becomes empty, so SGM | ||
723 | * contains slot 1 with the new finger) | ||
724 | * | ||
725 | * Else, if there was no previous SGM, it now contains slot 0. | ||
726 | * | ||
727 | * Otherwise, SGM still contains the same slot. | ||
728 | */ | ||
729 | if (priv->mt_state_lost || | ||
730 | (priv->agm_pending && old->sgm <= 0)) | ||
731 | synaptics_mt_state_set(mt_state, 1, 1, -1); | ||
732 | else if (old->sgm == -1) | ||
733 | synaptics_mt_state_set(mt_state, 1, 0, -1); | ||
734 | break; | ||
735 | case 2: | ||
736 | /* | ||
737 | * If mt_state_lost, we don't know which finger SGM contains. | ||
738 | * | ||
739 | * So, report 1 finger, but with both slots empty. | ||
740 | * We will use slot 1 on subsequent 1->1 | ||
741 | */ | ||
742 | if (priv->mt_state_lost) { | ||
743 | synaptics_mt_state_set(mt_state, 1, -1, -1); | ||
744 | break; | ||
745 | } | ||
746 | /* | ||
747 | * Since the last AGM was NOT (0,0,0), it was the finger in | ||
748 | * slot 0 that has been removed. | ||
749 | * So, SGM now contains previous AGM's slot, and AGM is now | ||
750 | * empty. | ||
751 | */ | ||
752 | synaptics_mt_state_set(mt_state, 1, old->agm, -1); | ||
753 | break; | ||
754 | case 3: | ||
755 | /* | ||
756 | * Since last AGM was not (0,0,0), we don't know which finger | ||
757 | * is left. | ||
758 | * | ||
759 | * So, report 1 finger, but with both slots empty. | ||
760 | * We will use slot 1 on subsequent 1->1 | ||
761 | */ | ||
762 | synaptics_mt_state_set(mt_state, 1, -1, -1); | ||
763 | priv->mt_state_lost = true; | ||
764 | break; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | /* Handle case where mt_state->count = 2 */ | ||
769 | static void synaptics_image_sensor_2f(struct synaptics_data *priv, | ||
770 | struct synaptics_mt_state *mt_state) | ||
771 | { | ||
772 | struct synaptics_mt_state *old = &priv->mt_state; | ||
773 | |||
774 | switch (old->count) { | ||
775 | case 0: | ||
776 | synaptics_mt_state_set(mt_state, 2, 0, 1); | ||
777 | break; | ||
778 | case 1: | ||
779 | /* | ||
780 | * If previous SGM contained slot 1 or higher, SGM now contains | ||
781 | * slot 0 (the newly touching finger) and AGM contains SGM's | ||
782 | * previous slot. | ||
783 | * | ||
784 | * Otherwise, SGM still contains slot 0 and AGM now contains | ||
785 | * slot 1. | ||
786 | */ | ||
787 | if (old->sgm >= 1) | ||
788 | synaptics_mt_state_set(mt_state, 2, 0, old->sgm); | ||
789 | else | ||
790 | synaptics_mt_state_set(mt_state, 2, 0, 1); | ||
791 | break; | ||
792 | case 2: | ||
793 | /* | ||
794 | * If mt_state_lost, SGM now contains either finger 1 or 2, but | ||
795 | * we don't know which. | ||
796 | * So, we just assume that the SGM contains slot 0 and AGM 1. | ||
797 | */ | ||
798 | if (priv->mt_state_lost) | ||
799 | synaptics_mt_state_set(mt_state, 2, 0, 1); | ||
800 | /* | ||
801 | * Otherwise, use the same mt_state, since it either hasn't | ||
802 | * changed, or was updated by a recently received AGM-CONTACT | ||
803 | * packet. | ||
804 | */ | ||
805 | break; | ||
806 | case 3: | ||
807 | /* | ||
808 | * 3->2 transitions have two unsolvable problems: | ||
809 | * 1) no indication is given which finger was removed | ||
810 | * 2) no way to tell if agm packet was for finger 3 | ||
811 | * before 3->2, or finger 2 after 3->2. | ||
812 | * | ||
813 | * So, report 2 fingers, but empty all slots. | ||
814 | * We will guess slots [0,1] on subsequent 2->2. | ||
815 | */ | ||
816 | synaptics_mt_state_set(mt_state, 2, -1, -1); | ||
817 | priv->mt_state_lost = true; | ||
818 | break; | ||
819 | } | ||
820 | } | ||
821 | |||
822 | /* Handle case where mt_state->count = 3 */ | ||
823 | static void synaptics_image_sensor_3f(struct synaptics_data *priv, | ||
824 | struct synaptics_mt_state *mt_state) | ||
825 | { | ||
826 | struct synaptics_mt_state *old = &priv->mt_state; | ||
827 | |||
828 | switch (old->count) { | ||
829 | case 0: | ||
830 | synaptics_mt_state_set(mt_state, 3, 0, 2); | ||
831 | break; | ||
832 | case 1: | ||
833 | /* | ||
834 | * If previous SGM contained slot 2 or higher, SGM now contains | ||
835 | * slot 0 (one of the newly touching fingers) and AGM contains | ||
836 | * SGM's previous slot. | ||
837 | * | ||
838 | * Otherwise, SGM now contains slot 0 and AGM contains slot 2. | ||
839 | */ | ||
840 | if (old->sgm >= 2) | ||
841 | synaptics_mt_state_set(mt_state, 3, 0, old->sgm); | ||
842 | else | ||
843 | synaptics_mt_state_set(mt_state, 3, 0, 2); | ||
844 | break; | ||
845 | case 2: | ||
846 | /* | ||
847 | * After some 3->1 and all 3->2 transitions, we lose track | ||
848 | * of which slot is reported by SGM and AGM. | ||
849 | * | ||
850 | * For 2->3 in this state, report 3 fingers, but empty all | ||
851 | * slots, and we will guess (0,2) on a subsequent 0->3. | ||
852 | * | ||
853 | * To userspace, the resulting transition will look like: | ||
854 | * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2] | ||
855 | */ | ||
856 | if (priv->mt_state_lost) { | ||
857 | synaptics_mt_state_set(mt_state, 3, -1, -1); | ||
858 | break; | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | * If the (SGM,AGM) really previously contained slots (0, 1), | ||
863 | * then we cannot know what slot was just reported by the AGM, | ||
864 | * because the 2->3 transition can occur either before or after | ||
865 | * the AGM packet. Thus, this most recent AGM could contain | ||
866 | * either the same old slot 1 or the new slot 2. | ||
867 | * Subsequent AGMs will be reporting slot 2. | ||
868 | * | ||
869 | * To userspace, the resulting transition will look like: | ||
870 | * 2:[0,1] -> 3:[0,-1] -> 3:[0,2] | ||
871 | */ | ||
872 | synaptics_mt_state_set(mt_state, 3, 0, -1); | ||
873 | break; | ||
874 | case 3: | ||
875 | /* | ||
876 | * If, for whatever reason, the previous agm was invalid, | ||
877 | * Assume SGM now contains slot 0, AGM now contains slot 2. | ||
878 | */ | ||
879 | if (old->agm <= 2) | ||
880 | synaptics_mt_state_set(mt_state, 3, 0, 2); | ||
881 | /* | ||
882 | * mt_state either hasn't changed, or was updated by a recently | ||
883 | * received AGM-CONTACT packet. | ||
884 | */ | ||
885 | break; | ||
886 | } | ||
887 | } | ||
888 | |||
643 | static void synaptics_image_sensor_process(struct psmouse *psmouse, | 889 | static void synaptics_image_sensor_process(struct psmouse *psmouse, |
644 | struct synaptics_hw_state *sgm) | 890 | struct synaptics_hw_state *sgm) |
645 | { | 891 | { |
646 | int count; | 892 | struct synaptics_data *priv = psmouse->private; |
893 | struct synaptics_hw_state *agm = &priv->agm; | ||
894 | struct synaptics_mt_state mt_state; | ||
647 | 895 | ||
896 | /* Initialize using current mt_state (as updated by last agm) */ | ||
897 | mt_state = agm->mt_state; | ||
898 | |||
899 | /* | ||
900 | * Update mt_state using the new finger count and current mt_state. | ||
901 | */ | ||
648 | if (sgm->z == 0) | 902 | if (sgm->z == 0) |
649 | count = 0; | 903 | synaptics_image_sensor_0f(priv, &mt_state); |
650 | else if (sgm->w >= 4) | 904 | else if (sgm->w >= 4) |
651 | count = 1; | 905 | synaptics_image_sensor_1f(priv, &mt_state); |
652 | else if (sgm->w == 0) | 906 | else if (sgm->w == 0) |
653 | count = 2; | 907 | synaptics_image_sensor_2f(priv, &mt_state); |
654 | else | 908 | else if (sgm->w == 1) |
655 | count = 3; | 909 | synaptics_image_sensor_3f(priv, &mt_state); |
656 | 910 | ||
657 | /* Send resulting input events to user space */ | 911 | /* Send resulting input events to user space */ |
658 | synaptics_report_mt_data(psmouse, count, sgm); | 912 | synaptics_report_mt_data(psmouse, &mt_state, sgm); |
913 | |||
914 | /* Store updated mt_state */ | ||
915 | priv->mt_state = agm->mt_state = mt_state; | ||
916 | priv->agm_pending = false; | ||
659 | } | 917 | } |
660 | 918 | ||
661 | /* | 919 | /* |
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 20f57dfebed1..622aea8dd7e0 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h | |||
@@ -161,11 +161,15 @@ struct synaptics_data { | |||
161 | 161 | ||
162 | struct serio *pt_port; /* Pass-through serio port */ | 162 | struct serio *pt_port; /* Pass-through serio port */ |
163 | 163 | ||
164 | struct synaptics_mt_state mt_state; /* Current mt finger state */ | ||
165 | bool mt_state_lost; /* mt_state may be incorrect */ | ||
166 | |||
164 | /* | 167 | /* |
165 | * Last received Advanced Gesture Mode (AGM) packet. An AGM packet | 168 | * Last received Advanced Gesture Mode (AGM) packet. An AGM packet |
166 | * contains position data for a second contact, at half resolution. | 169 | * contains position data for a second contact, at half resolution. |
167 | */ | 170 | */ |
168 | struct synaptics_hw_state agm; | 171 | struct synaptics_hw_state agm; |
172 | bool agm_pending; /* new AGM packet received */ | ||
169 | }; | 173 | }; |
170 | 174 | ||
171 | void synaptics_module_init(void); | 175 | void synaptics_module_init(void); |