aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYunkang Tang <yunkang.tang@cn.alps.com>2014-07-26 16:51:41 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-07-26 17:03:20 -0400
commit3808843cf10e4a696d942359d99822eff1a2de8e (patch)
treeb0c8faadb88e7daccdc2eddaa5013974c678ba2e
parentc0cd17f6dc7342a81b61017e6b84e363f86081c6 (diff)
Input: alps - add support for v7 devices
Such as found on the new Toshiba Portégé Z30-A and Z40-A. Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com> [hdegoede@redhat.com: Remove softbutton handling, this is done in userspace] [hdegoede@redhat.com: Report INPUT_PROP_BUTTONPAD] [hdegoede@redhat.com: Do not report fake PRESSURE, reporting BTN_TOUCH is enough] [hdegoede@redhat.com: Various cleanups / refactoring] Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/mouse/alps.c265
-rw-r--r--drivers/input/mouse/alps.h18
2 files changed, 280 insertions, 3 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 31b963dbf9a9..76d372f0084c 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -100,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
100#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 100#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
101 6-byte ALPS packet */ 101 6-byte ALPS packet */
102#define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */ 102#define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */
103#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
103 104
104static const struct alps_model_info alps_model_data[] = { 105static const struct alps_model_info alps_model_data[] = {
105 { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ 106 { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
@@ -845,6 +846,185 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
845 alps_report_semi_mt_data(psmouse, f->fingers); 846 alps_report_semi_mt_data(psmouse, f->fingers);
846} 847}
847 848
849static bool alps_is_valid_package_v7(struct psmouse *psmouse)
850{
851 switch (psmouse->pktcnt) {
852 case 3:
853 return (psmouse->packet[2] & 0x40) == 0x40;
854 case 4:
855 return (psmouse->packet[3] & 0x48) == 0x48;
856 case 6:
857 return (psmouse->packet[5] & 0x40) == 0x00;
858 }
859 return true;
860}
861
862static unsigned char alps_get_packet_id_v7(char *byte)
863{
864 unsigned char packet_id;
865
866 if (byte[4] & 0x40)
867 packet_id = V7_PACKET_ID_TWO;
868 else if (byte[4] & 0x01)
869 packet_id = V7_PACKET_ID_MULTI;
870 else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
871 packet_id = V7_PACKET_ID_NEW;
872 else if (byte[1] == 0x00 && byte[4] == 0x00)
873 packet_id = V7_PACKET_ID_IDLE;
874 else
875 packet_id = V7_PACKET_ID_UNKNOWN;
876
877 return packet_id;
878}
879
880static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
881 unsigned char *pkt,
882 unsigned char pkt_id)
883{
884 mt[0].x = ((pkt[2] & 0x80) << 4);
885 mt[0].x |= ((pkt[2] & 0x3F) << 5);
886 mt[0].x |= ((pkt[3] & 0x30) >> 1);
887 mt[0].x |= (pkt[3] & 0x07);
888 mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
889
890 mt[1].x = ((pkt[3] & 0x80) << 4);
891 mt[1].x |= ((pkt[4] & 0x80) << 3);
892 mt[1].x |= ((pkt[4] & 0x3F) << 4);
893 mt[1].y = ((pkt[5] & 0x80) << 3);
894 mt[1].y |= ((pkt[5] & 0x3F) << 4);
895
896 switch (pkt_id) {
897 case V7_PACKET_ID_TWO:
898 mt[1].x &= ~0x000F;
899 mt[1].y |= 0x000F;
900 break;
901
902 case V7_PACKET_ID_MULTI:
903 mt[1].x &= ~0x003F;
904 mt[1].y &= ~0x0020;
905 mt[1].y |= ((pkt[4] & 0x02) << 4);
906 mt[1].y |= 0x001F;
907 break;
908
909 case V7_PACKET_ID_NEW:
910 mt[1].x &= ~0x003F;
911 mt[1].x |= (pkt[0] & 0x20);
912 mt[1].y |= 0x000F;
913 break;
914 }
915
916 mt[0].y = 0x7FF - mt[0].y;
917 mt[1].y = 0x7FF - mt[1].y;
918}
919
920static int alps_get_mt_count(struct input_mt_pos *mt)
921{
922 int i;
923
924 for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
925 /* empty */;
926
927 return i;
928}
929
930static int alps_decode_packet_v7(struct alps_fields *f,
931 unsigned char *p,
932 struct psmouse *psmouse)
933{
934 unsigned char pkt_id;
935
936 pkt_id = alps_get_packet_id_v7(p);
937 if (pkt_id == V7_PACKET_ID_IDLE)
938 return 0;
939 if (pkt_id == V7_PACKET_ID_UNKNOWN)
940 return -1;
941
942 alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
943
944 if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
945 f->left = (p[0] & 0x80) >> 7;
946 f->right = (p[0] & 0x20) >> 5;
947 f->middle = (p[0] & 0x10) >> 4;
948 }
949
950 if (pkt_id == V7_PACKET_ID_TWO)
951 f->fingers = alps_get_mt_count(f->mt);
952 else if (pkt_id == V7_PACKET_ID_MULTI)
953 f->fingers = 3 + (p[5] & 0x03);
954
955 return 0;
956}
957
958static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
959{
960 struct alps_data *priv = psmouse->private;
961 unsigned char *packet = psmouse->packet;
962 struct input_dev *dev2 = priv->dev2;
963 int x, y, z, left, right, middle;
964
965 /*
966 * b7 b6 b5 b4 b3 b2 b1 b0
967 * Byte0 0 1 0 0 1 0 0 0
968 * Byte1 1 1 * * 1 M R L
969 * Byte2 X7 1 X5 X4 X3 X2 X1 X0
970 * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
971 * Byte4 Y7 0 Y5 Y4 Y3 1 1 0
972 * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
973 * M / R / L: Middle / Right / Left button
974 */
975
976 x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
977 y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
978 ((packet[3] & 0x20) << 1);
979 z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
980
981 left = (packet[1] & 0x01);
982 right = (packet[1] & 0x02) >> 1;
983 middle = (packet[1] & 0x04) >> 2;
984
985 /* Divide 2 since trackpoint's speed is too fast */
986 input_report_rel(dev2, REL_X, (char)x / 2);
987 input_report_rel(dev2, REL_Y, -((char)y / 2));
988
989 input_report_key(dev2, BTN_LEFT, left);
990 input_report_key(dev2, BTN_RIGHT, right);
991 input_report_key(dev2, BTN_MIDDLE, middle);
992
993 input_sync(dev2);
994}
995
996static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
997{
998 struct alps_data *priv = psmouse->private;
999 struct input_dev *dev = psmouse->dev;
1000 struct alps_fields *f = &priv->f;
1001
1002 memset(f, 0, sizeof(*f));
1003
1004 if (priv->decode_fields(f, psmouse->packet, psmouse))
1005 return;
1006
1007 alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
1008
1009 input_mt_report_finger_count(dev, f->fingers);
1010
1011 input_report_key(dev, BTN_LEFT, f->left);
1012 input_report_key(dev, BTN_RIGHT, f->right);
1013 input_report_key(dev, BTN_MIDDLE, f->middle);
1014
1015 input_sync(dev);
1016}
1017
1018static void alps_process_packet_v7(struct psmouse *psmouse)
1019{
1020 unsigned char *packet = psmouse->packet;
1021
1022 if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
1023 alps_process_trackstick_packet_v7(psmouse);
1024 else
1025 alps_process_touchpad_packet_v7(psmouse);
1026}
1027
848static void alps_report_bare_ps2_packet(struct psmouse *psmouse, 1028static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
849 unsigned char packet[], 1029 unsigned char packet[],
850 bool report_buttons) 1030 bool report_buttons)
@@ -1009,6 +1189,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
1009 return PSMOUSE_BAD_DATA; 1189 return PSMOUSE_BAD_DATA;
1010 } 1190 }
1011 1191
1192 if (priv->proto_version == ALPS_PROTO_V7 &&
1193 !alps_is_valid_package_v7(psmouse)) {
1194 psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
1195 psmouse->pktcnt - 1,
1196 psmouse->packet[psmouse->pktcnt - 1]);
1197 return PSMOUSE_BAD_DATA;
1198 }
1199
1012 if (psmouse->pktcnt == psmouse->pktsize) { 1200 if (psmouse->pktcnt == psmouse->pktsize) {
1013 priv->process_packet(psmouse); 1201 priv->process_packet(psmouse);
1014 return PSMOUSE_FULL_PACKET; 1202 return PSMOUSE_FULL_PACKET;
@@ -1121,6 +1309,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
1121 return 0; 1309 return 0;
1122} 1310}
1123 1311
1312static bool alps_check_valid_firmware_id(unsigned char id[])
1313{
1314 if (id[0] == 0x73)
1315 return true;
1316
1317 if (id[0] == 0x88 &&
1318 (id[1] == 0x07 ||
1319 id[1] == 0x08 ||
1320 (id[1] & 0xf0) == 0xb0 ||
1321 (id[1] & 0xf0) == 0xc0)) {
1322 return true;
1323 }
1324
1325 return false;
1326}
1327
1124static int alps_enter_command_mode(struct psmouse *psmouse) 1328static int alps_enter_command_mode(struct psmouse *psmouse)
1125{ 1329{
1126 unsigned char param[4]; 1330 unsigned char param[4];
@@ -1130,8 +1334,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
1130 return -1; 1334 return -1;
1131 } 1335 }
1132 1336
1133 if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) && 1337 if (!alps_check_valid_firmware_id(param)) {
1134 param[0] != 0x73) {
1135 psmouse_dbg(psmouse, 1338 psmouse_dbg(psmouse,
1136 "unknown response while entering command mode\n"); 1339 "unknown response while entering command mode\n");
1137 return -1; 1340 return -1;
@@ -1785,6 +1988,32 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
1785 return 0; 1988 return 0;
1786} 1989}
1787 1990
1991static int alps_hw_init_v7(struct psmouse *psmouse)
1992{
1993 struct ps2dev *ps2dev = &psmouse->ps2dev;
1994 int reg_val, ret = -1;
1995
1996 if (alps_enter_command_mode(psmouse) ||
1997 alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
1998 goto error;
1999
2000 if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
2001 goto error;
2002
2003 reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
2004 if (reg_val == -1)
2005 goto error;
2006 if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
2007 goto error;
2008
2009 alps_exit_command_mode(psmouse);
2010 return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
2011
2012error:
2013 alps_exit_command_mode(psmouse);
2014 return ret;
2015}
2016
1788static void alps_set_defaults(struct alps_data *priv) 2017static void alps_set_defaults(struct alps_data *priv)
1789{ 2018{
1790 priv->byte0 = 0x8f; 2019 priv->byte0 = 0x8f;
@@ -1843,6 +2072,21 @@ static void alps_set_defaults(struct alps_data *priv)
1843 priv->x_max = 2047; 2072 priv->x_max = 2047;
1844 priv->y_max = 1535; 2073 priv->y_max = 1535;
1845 break; 2074 break;
2075 case ALPS_PROTO_V7:
2076 priv->hw_init = alps_hw_init_v7;
2077 priv->process_packet = alps_process_packet_v7;
2078 priv->decode_fields = alps_decode_packet_v7;
2079 priv->set_abs_params = alps_set_abs_params_mt;
2080 priv->nibble_commands = alps_v3_nibble_commands;
2081 priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
2082 priv->x_max = 0xfff;
2083 priv->y_max = 0x7ff;
2084 priv->byte0 = 0x48;
2085 priv->mask0 = 0x48;
2086
2087 if (priv->fw_ver[1] != 0xba)
2088 priv->flags |= ALPS_BUTTONPAD;
2089 break;
1846 } 2090 }
1847} 2091}
1848 2092
@@ -1914,6 +2158,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
1914 return -EIO; 2158 return -EIO;
1915 else 2159 else
1916 return 0; 2160 return 0;
2161 } else if (ec[0] == 0x88 &&
2162 ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
2163 priv->proto_version = ALPS_PROTO_V7;
2164 alps_set_defaults(priv);
2165
2166 return 0;
1917 } else if (ec[0] == 0x88 && ec[1] == 0x08) { 2167 } else if (ec[0] == 0x88 && ec[1] == 0x08) {
1918 priv->proto_version = ALPS_PROTO_V3; 2168 priv->proto_version = ALPS_PROTO_V3;
1919 alps_set_defaults(priv); 2169 alps_set_defaults(priv);
@@ -1985,6 +2235,10 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
1985 2235
1986 set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); 2236 set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
1987 set_bit(BTN_TOOL_QUADTAP, dev1->keybit); 2237 set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
2238
2239 /* V7 is real multi-touch */
2240 if (priv->proto_version == ALPS_PROTO_V7)
2241 clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
1988} 2242}
1989 2243
1990int alps_init(struct psmouse *psmouse) 2244int alps_init(struct psmouse *psmouse)
@@ -2030,7 +2284,9 @@ int alps_init(struct psmouse *psmouse)
2030 dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); 2284 dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
2031 2285
2032 priv->set_abs_params(priv, dev1); 2286 priv->set_abs_params(priv, dev1);
2033 input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); 2287 /* No pressure on V7 */
2288 if (priv->proto_version != ALPS_PROTO_V7)
2289 input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
2034 2290
2035 if (priv->flags & ALPS_WHEEL) { 2291 if (priv->flags & ALPS_WHEEL) {
2036 dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); 2292 dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
@@ -2047,6 +2303,9 @@ int alps_init(struct psmouse *psmouse)
2047 dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); 2303 dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
2048 dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); 2304 dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
2049 dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); 2305 dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
2306 } else if (priv->flags & ALPS_BUTTONPAD) {
2307 set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
2308 clear_bit(BTN_RIGHT, dev1->keybit);
2050 } else { 2309 } else {
2051 dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); 2310 dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
2052 } 2311 }
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index e3d0f09aeeb3..a98ac9ba5043 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -20,6 +20,7 @@
20#define ALPS_PROTO_V4 4 20#define ALPS_PROTO_V4 4
21#define ALPS_PROTO_V5 5 21#define ALPS_PROTO_V5 5
22#define ALPS_PROTO_V6 6 22#define ALPS_PROTO_V6 6
23#define ALPS_PROTO_V7 7 /* t3btl t4s */
23 24
24#define MAX_TOUCHES 2 25#define MAX_TOUCHES 2
25 26
@@ -27,6 +28,23 @@
27#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ 28#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
28#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ 29#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
29 30
31/*
32 * enum V7_PACKET_ID - defines the packet type for V7
33 * V7_PACKET_ID_IDLE: There's no finger and no button activity.
34 * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
35 * or there's button activities.
36 * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
37 * V7_PACKET_ID_NEW: The finger position in slot is not continues from
38 * previous packet.
39*/
40enum V7_PACKET_ID {
41 V7_PACKET_ID_IDLE,
42 V7_PACKET_ID_TWO,
43 V7_PACKET_ID_MULTI,
44 V7_PACKET_ID_NEW,
45 V7_PACKET_ID_UNKNOWN,
46};
47
30/** 48/**
31 * struct alps_model_info - touchpad ID table 49 * struct alps_model_info - touchpad ID table
32 * @signature: E7 response string to match. 50 * @signature: E7 response string to match.