diff options
Diffstat (limited to 'drivers/input/tablet/wacom_wac.c')
-rw-r--r-- | drivers/input/tablet/wacom_wac.c | 247 |
1 files changed, 90 insertions, 157 deletions
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 367fa82a607e..5597637cfd41 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c | |||
@@ -675,169 +675,87 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) | |||
675 | return 1; | 675 | return 1; |
676 | } | 676 | } |
677 | 677 | ||
678 | 678 | static int wacom_tpc_mt_touch(struct wacom_wac *wacom) | |
679 | static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx) | ||
680 | { | 679 | { |
681 | struct input_dev *input = wacom->input; | 680 | struct input_dev *input = wacom->input; |
682 | int finger = idx + 1; | 681 | unsigned char *data = wacom->data; |
683 | int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff; | 682 | int contact_with_no_pen_down_count = 0; |
684 | int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff; | 683 | int i; |
685 | 684 | ||
686 | /* | 685 | for (i = 0; i < 2; i++) { |
687 | * Work around input core suppressing "duplicate" events since | 686 | int p = data[1] & (1 << i); |
688 | * we are abusing ABS_X/ABS_Y to transmit multi-finger data. | 687 | bool touch = p && !wacom->shared->stylus_in_proximity; |
689 | * This should go away once we switch to true multitouch | 688 | |
690 | * protocol. | 689 | input_mt_slot(input, i); |
691 | */ | 690 | input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); |
692 | if (wacom->last_finger != finger) { | 691 | if (touch) { |
693 | if (x == input_abs_get_val(input, ABS_X)) | 692 | int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff; |
694 | x++; | 693 | int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff; |
695 | 694 | ||
696 | if (y == input_abs_get_val(input, ABS_Y)) | 695 | input_report_abs(input, ABS_MT_POSITION_X, x); |
697 | y++; | 696 | input_report_abs(input, ABS_MT_POSITION_Y, y); |
697 | contact_with_no_pen_down_count++; | ||
698 | } | ||
698 | } | 699 | } |
699 | 700 | ||
700 | input_report_abs(input, ABS_X, x); | 701 | /* keep touch state for pen event */ |
701 | input_report_abs(input, ABS_Y, y); | 702 | wacom->shared->touch_down = (contact_with_no_pen_down_count > 0); |
702 | input_report_abs(input, ABS_MISC, wacom->id[0]); | ||
703 | input_report_key(input, wacom->tool[finger], 1); | ||
704 | if (!idx) | ||
705 | input_report_key(input, BTN_TOUCH, 1); | ||
706 | input_event(input, EV_MSC, MSC_SERIAL, finger); | ||
707 | input_sync(input); | ||
708 | 703 | ||
709 | wacom->last_finger = finger; | 704 | input_mt_report_pointer_emulation(input, true); |
710 | } | ||
711 | 705 | ||
712 | static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx) | 706 | return 1; |
713 | { | ||
714 | struct input_dev *input = wacom->input; | ||
715 | int finger = idx + 1; | ||
716 | |||
717 | input_report_abs(input, ABS_X, 0); | ||
718 | input_report_abs(input, ABS_Y, 0); | ||
719 | input_report_abs(input, ABS_MISC, 0); | ||
720 | input_report_key(input, wacom->tool[finger], 0); | ||
721 | if (!idx) | ||
722 | input_report_key(input, BTN_TOUCH, 0); | ||
723 | input_event(input, EV_MSC, MSC_SERIAL, finger); | ||
724 | input_sync(input); | ||
725 | } | 707 | } |
726 | 708 | ||
727 | static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) | 709 | static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) |
728 | { | 710 | { |
729 | char *data = wacom->data; | 711 | char *data = wacom->data; |
730 | struct input_dev *input = wacom->input; | 712 | struct input_dev *input = wacom->input; |
713 | bool prox; | ||
714 | int x = 0, y = 0; | ||
731 | 715 | ||
732 | wacom->tool[1] = BTN_TOOL_DOUBLETAP; | 716 | if (!wacom->shared->stylus_in_proximity) { |
733 | wacom->id[0] = TOUCH_DEVICE_ID; | 717 | if (len == WACOM_PKGLEN_TPC1FG) { |
734 | wacom->tool[2] = BTN_TOOL_TRIPLETAP; | 718 | prox = data[0] & 0x01; |
735 | 719 | x = get_unaligned_le16(&data[1]); | |
736 | if (len != WACOM_PKGLEN_TPC1FG) { | 720 | y = get_unaligned_le16(&data[3]); |
737 | 721 | } else { /* with capacity */ | |
738 | switch (data[0]) { | 722 | prox = data[1] & 0x01; |
723 | x = le16_to_cpup((__le16 *)&data[2]); | ||
724 | y = le16_to_cpup((__le16 *)&data[4]); | ||
725 | } | ||
726 | } else | ||
727 | /* force touch out when pen is in prox */ | ||
728 | prox = 0; | ||
739 | 729 | ||
740 | case WACOM_REPORT_TPC1FG: | 730 | if (prox) { |
741 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); | 731 | input_report_abs(input, ABS_X, x); |
742 | input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); | 732 | input_report_abs(input, ABS_Y, y); |
743 | input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); | 733 | } |
744 | input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6])); | 734 | input_report_key(input, BTN_TOUCH, prox); |
745 | input_report_abs(input, ABS_MISC, wacom->id[0]); | ||
746 | input_report_key(input, wacom->tool[1], 1); | ||
747 | input_sync(input); | ||
748 | break; | ||
749 | 735 | ||
750 | case WACOM_REPORT_TPC2FG: | 736 | /* keep touch state for pen events */ |
751 | if (data[1] & 0x01) | 737 | wacom->shared->touch_down = prox; |
752 | wacom_tpc_finger_in(wacom, data, 0); | ||
753 | else if (wacom->id[1] & 0x01) | ||
754 | wacom_tpc_touch_out(wacom, 0); | ||
755 | 738 | ||
756 | if (data[1] & 0x02) | 739 | return 1; |
757 | wacom_tpc_finger_in(wacom, data, 1); | ||
758 | else if (wacom->id[1] & 0x02) | ||
759 | wacom_tpc_touch_out(wacom, 1); | ||
760 | break; | ||
761 | } | ||
762 | } else { | ||
763 | input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); | ||
764 | input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); | ||
765 | input_report_key(input, BTN_TOUCH, 1); | ||
766 | input_report_abs(input, ABS_MISC, wacom->id[1]); | ||
767 | input_report_key(input, wacom->tool[1], 1); | ||
768 | input_sync(input); | ||
769 | } | ||
770 | } | 740 | } |
771 | 741 | ||
772 | static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) | 742 | static int wacom_tpc_pen(struct wacom_wac *wacom) |
773 | { | 743 | { |
774 | struct wacom_features *features = &wacom->features; | 744 | struct wacom_features *features = &wacom->features; |
775 | char *data = wacom->data; | 745 | char *data = wacom->data; |
776 | struct input_dev *input = wacom->input; | 746 | struct input_dev *input = wacom->input; |
777 | int prox = 0, pressure; | 747 | int pressure; |
778 | int retval = 0; | 748 | bool prox = data[1] & 0x20; |
779 | 749 | ||
780 | dbg("wacom_tpc_irq: received report #%d", data[0]); | 750 | if (!wacom->shared->stylus_in_proximity) /* first in prox */ |
781 | 751 | /* Going into proximity select tool */ | |
782 | if (len == WACOM_PKGLEN_TPC1FG || /* single touch */ | 752 | wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; |
783 | data[0] == WACOM_REPORT_TPC1FG || /* single touch */ | ||
784 | data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */ | ||
785 | |||
786 | if (wacom->shared->stylus_in_proximity) { | ||
787 | if (wacom->id[1] & 0x01) | ||
788 | wacom_tpc_touch_out(wacom, 0); | ||
789 | |||
790 | if (wacom->id[1] & 0x02) | ||
791 | wacom_tpc_touch_out(wacom, 1); | ||
792 | |||
793 | wacom->id[1] = 0; | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | if (len == WACOM_PKGLEN_TPC1FG) { /* with touch */ | ||
798 | prox = data[0] & 0x01; | ||
799 | } else { /* with capacity */ | ||
800 | if (data[0] == WACOM_REPORT_TPC1FG) | ||
801 | /* single touch */ | ||
802 | prox = data[1] & 0x01; | ||
803 | else | ||
804 | /* 2FG touch data */ | ||
805 | prox = data[1] & 0x03; | ||
806 | } | ||
807 | |||
808 | if (prox) { | ||
809 | if (!wacom->id[1]) | ||
810 | wacom->last_finger = 1; | ||
811 | wacom_tpc_touch_in(wacom, len); | ||
812 | } else { | ||
813 | if (data[0] == WACOM_REPORT_TPC2FG) { | ||
814 | /* 2FGT out-prox */ | ||
815 | if (wacom->id[1] & 0x01) | ||
816 | wacom_tpc_touch_out(wacom, 0); | ||
817 | 753 | ||
818 | if (wacom->id[1] & 0x02) | 754 | /* keep pen state for touch events */ |
819 | wacom_tpc_touch_out(wacom, 1); | 755 | wacom->shared->stylus_in_proximity = prox; |
820 | } else | ||
821 | /* one finger touch */ | ||
822 | wacom_tpc_touch_out(wacom, 0); | ||
823 | 756 | ||
824 | wacom->id[0] = 0; | 757 | /* send pen events only when touch is up or forced out */ |
825 | } | 758 | if (!wacom->shared->touch_down) { |
826 | /* keep prox bit to send proper out-prox event */ | ||
827 | wacom->id[1] = prox; | ||
828 | } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ | ||
829 | prox = data[1] & 0x20; | ||
830 | |||
831 | if (!wacom->shared->stylus_in_proximity) { /* first in prox */ | ||
832 | /* Going into proximity select tool */ | ||
833 | wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
834 | if (wacom->tool[0] == BTN_TOOL_PEN) | ||
835 | wacom->id[0] = STYLUS_DEVICE_ID; | ||
836 | else | ||
837 | wacom->id[0] = ERASER_DEVICE_ID; | ||
838 | |||
839 | wacom->shared->stylus_in_proximity = true; | ||
840 | } | ||
841 | input_report_key(input, BTN_STYLUS, data[1] & 0x02); | 759 | input_report_key(input, BTN_STYLUS, data[1] & 0x02); |
842 | input_report_key(input, BTN_STYLUS2, data[1] & 0x10); | 760 | input_report_key(input, BTN_STYLUS2, data[1] & 0x10); |
843 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); | 761 | input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); |
@@ -847,15 +765,27 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) | |||
847 | pressure = features->pressure_max + pressure + 1; | 765 | pressure = features->pressure_max + pressure + 1; |
848 | input_report_abs(input, ABS_PRESSURE, pressure); | 766 | input_report_abs(input, ABS_PRESSURE, pressure); |
849 | input_report_key(input, BTN_TOUCH, data[1] & 0x05); | 767 | input_report_key(input, BTN_TOUCH, data[1] & 0x05); |
850 | if (!prox) { /* out-prox */ | ||
851 | wacom->id[0] = 0; | ||
852 | wacom->shared->stylus_in_proximity = false; | ||
853 | } | ||
854 | input_report_key(input, wacom->tool[0], prox); | 768 | input_report_key(input, wacom->tool[0], prox); |
855 | input_report_abs(input, ABS_MISC, wacom->id[0]); | 769 | return 1; |
856 | retval = 1; | ||
857 | } | 770 | } |
858 | return retval; | 771 | |
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) | ||
776 | { | ||
777 | char *data = wacom->data; | ||
778 | |||
779 | dbg("wacom_tpc_irq: received report #%d", data[0]); | ||
780 | |||
781 | if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG) | ||
782 | return wacom_tpc_single_touch(wacom, len); | ||
783 | else if (data[0] == WACOM_REPORT_TPC2FG) | ||
784 | return wacom_tpc_mt_touch(wacom); | ||
785 | else if (data[0] == WACOM_REPORT_PENABLED) | ||
786 | return wacom_tpc_pen(wacom); | ||
787 | |||
788 | return 0; | ||
859 | } | 789 | } |
860 | 790 | ||
861 | static int wacom_bpt_touch(struct wacom_wac *wacom) | 791 | static int wacom_bpt_touch(struct wacom_wac *wacom) |
@@ -1078,7 +1008,7 @@ void wacom_setup_device_quirks(struct wacom_features *features) | |||
1078 | { | 1008 | { |
1079 | 1009 | ||
1080 | /* touch device found but size is not defined. use default */ | 1010 | /* touch device found but size is not defined. use default */ |
1081 | if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) { | 1011 | if (features->device_type == BTN_TOOL_FINGER && !features->x_max) { |
1082 | features->x_max = 1023; | 1012 | features->x_max = 1023; |
1083 | features->y_max = 1023; | 1013 | features->y_max = 1023; |
1084 | } | 1014 | } |
@@ -1090,7 +1020,7 @@ void wacom_setup_device_quirks(struct wacom_features *features) | |||
1090 | 1020 | ||
1091 | /* quirks for bamboo touch */ | 1021 | /* quirks for bamboo touch */ |
1092 | if (features->type == BAMBOO_PT && | 1022 | if (features->type == BAMBOO_PT && |
1093 | features->device_type == BTN_TOOL_TRIPLETAP) { | 1023 | features->device_type == BTN_TOOL_DOUBLETAP) { |
1094 | features->x_max <<= 5; | 1024 | features->x_max <<= 5; |
1095 | features->y_max <<= 5; | 1025 | features->y_max <<= 5; |
1096 | features->x_fuzz <<= 5; | 1026 | features->x_fuzz <<= 5; |
@@ -1226,27 +1156,30 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
1226 | break; | 1156 | break; |
1227 | 1157 | ||
1228 | case TABLETPC2FG: | 1158 | case TABLETPC2FG: |
1229 | if (features->device_type == BTN_TOOL_TRIPLETAP) { | 1159 | if (features->device_type == BTN_TOOL_DOUBLETAP) { |
1230 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | 1160 | |
1231 | input_set_capability(input_dev, EV_MSC, MSC_SERIAL); | 1161 | input_mt_init_slots(input_dev, 2); |
1162 | input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, | ||
1163 | 0, MT_TOOL_MAX, 0, 0); | ||
1164 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, | ||
1165 | 0, features->x_max, 0, 0); | ||
1166 | input_set_abs_params(input_dev, ABS_MT_POSITION_Y, | ||
1167 | 0, features->y_max, 0, 0); | ||
1232 | } | 1168 | } |
1233 | /* fall through */ | 1169 | /* fall through */ |
1234 | 1170 | ||
1235 | case TABLETPC: | 1171 | case TABLETPC: |
1236 | if (features->device_type == BTN_TOOL_DOUBLETAP || | 1172 | __clear_bit(ABS_MISC, input_dev->absbit); |
1237 | features->device_type == BTN_TOOL_TRIPLETAP) { | 1173 | |
1174 | if (features->device_type != BTN_TOOL_PEN) { | ||
1238 | input_abs_set_res(input_dev, ABS_X, | 1175 | input_abs_set_res(input_dev, ABS_X, |
1239 | wacom_calculate_touch_res(features->x_max, | 1176 | wacom_calculate_touch_res(features->x_max, |
1240 | features->x_phy)); | 1177 | features->x_phy)); |
1241 | input_abs_set_res(input_dev, ABS_Y, | 1178 | input_abs_set_res(input_dev, ABS_Y, |
1242 | wacom_calculate_touch_res(features->y_max, | 1179 | wacom_calculate_touch_res(features->y_max, |
1243 | features->y_phy)); | 1180 | features->y_phy)); |
1244 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | ||
1245 | } | ||
1246 | |||
1247 | if (features->device_type != BTN_TOOL_PEN) | ||
1248 | break; /* no need to process stylus stuff */ | 1181 | break; /* no need to process stylus stuff */ |
1249 | 1182 | } | |
1250 | /* fall through */ | 1183 | /* fall through */ |
1251 | 1184 | ||
1252 | case PL: | 1185 | case PL: |
@@ -1264,7 +1197,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
1264 | case BAMBOO_PT: | 1197 | case BAMBOO_PT: |
1265 | __clear_bit(ABS_MISC, input_dev->absbit); | 1198 | __clear_bit(ABS_MISC, input_dev->absbit); |
1266 | 1199 | ||
1267 | if (features->device_type == BTN_TOOL_TRIPLETAP) { | 1200 | if (features->device_type == BTN_TOOL_DOUBLETAP) { |
1268 | __set_bit(BTN_LEFT, input_dev->keybit); | 1201 | __set_bit(BTN_LEFT, input_dev->keybit); |
1269 | __set_bit(BTN_FORWARD, input_dev->keybit); | 1202 | __set_bit(BTN_FORWARD, input_dev->keybit); |
1270 | __set_bit(BTN_BACK, input_dev->keybit); | 1203 | __set_bit(BTN_BACK, input_dev->keybit); |