diff options
author | Yunkang Tang <yunkang.tang@cn.alps.com> | 2014-07-26 16:51:41 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-07-26 17:03:20 -0400 |
commit | 3808843cf10e4a696d942359d99822eff1a2de8e (patch) | |
tree | b0c8faadb88e7daccdc2eddaa5013974c678ba2e | |
parent | c0cd17f6dc7342a81b61017e6b84e363f86081c6 (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.c | 265 | ||||
-rw-r--r-- | drivers/input/mouse/alps.h | 18 |
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 | ||
104 | static const struct alps_model_info alps_model_data[] = { | 105 | static 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 | ||
849 | static 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 | |||
862 | static 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 | |||
880 | static 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 | |||
920 | static 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 | |||
930 | static 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 | |||
958 | static 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 | |||
996 | static 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 | |||
1018 | static 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 | |||
848 | static void alps_report_bare_ps2_packet(struct psmouse *psmouse, | 1028 | static 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 | ||
1312 | static 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 | |||
1124 | static int alps_enter_command_mode(struct psmouse *psmouse) | 1328 | static 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 | ||
1991 | static 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 | |||
2012 | error: | ||
2013 | alps_exit_command_mode(psmouse); | ||
2014 | return ret; | ||
2015 | } | ||
2016 | |||
1788 | static void alps_set_defaults(struct alps_data *priv) | 2017 | static 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 | ||
1990 | int alps_init(struct psmouse *psmouse) | 2244 | int 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 | */ | ||
40 | enum 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. |