diff options
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r-- | drivers/input/mouse/alps.c | 206 |
1 files changed, 203 insertions, 3 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index ca7a26f1dce8..5cf62e315218 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -70,6 +70,25 @@ static const struct alps_nibble_commands alps_v4_nibble_commands[] = { | |||
70 | { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ | 70 | { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static const struct alps_nibble_commands alps_v6_nibble_commands[] = { | ||
74 | { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ | ||
75 | { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */ | ||
76 | { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */ | ||
77 | { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */ | ||
78 | { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */ | ||
79 | { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */ | ||
80 | { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */ | ||
81 | { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */ | ||
82 | { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */ | ||
83 | { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */ | ||
84 | { PSMOUSE_CMD_SETRES, 0x00 }, /* a */ | ||
85 | { PSMOUSE_CMD_SETRES, 0x01 }, /* b */ | ||
86 | { PSMOUSE_CMD_SETRES, 0x02 }, /* c */ | ||
87 | { PSMOUSE_CMD_SETRES, 0x03 }, /* d */ | ||
88 | { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */ | ||
89 | { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ | ||
90 | }; | ||
91 | |||
73 | 92 | ||
74 | #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ | 93 | #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ |
75 | #define ALPS_PASS 0x04 /* device has a pass-through port */ | 94 | #define ALPS_PASS 0x04 /* device has a pass-through port */ |
@@ -103,6 +122,7 @@ static const struct alps_model_info alps_model_data[] = { | |||
103 | /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ | 122 | /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ |
104 | { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, | 123 | { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, |
105 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, | 124 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, |
125 | { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */ | ||
106 | { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ | 126 | { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ |
107 | { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, | 127 | { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, |
108 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ | 128 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ |
@@ -645,6 +665,76 @@ static void alps_process_packet_v3(struct psmouse *psmouse) | |||
645 | alps_process_touchpad_packet_v3(psmouse); | 665 | alps_process_touchpad_packet_v3(psmouse); |
646 | } | 666 | } |
647 | 667 | ||
668 | static void alps_process_packet_v6(struct psmouse *psmouse) | ||
669 | { | ||
670 | struct alps_data *priv = psmouse->private; | ||
671 | unsigned char *packet = psmouse->packet; | ||
672 | struct input_dev *dev = psmouse->dev; | ||
673 | struct input_dev *dev2 = priv->dev2; | ||
674 | int x, y, z, left, right, middle; | ||
675 | |||
676 | /* | ||
677 | * We can use Byte5 to distinguish if the packet is from Touchpad | ||
678 | * or Trackpoint. | ||
679 | * Touchpad: 0 - 0x7E | ||
680 | * Trackpoint: 0x7F | ||
681 | */ | ||
682 | if (packet[5] == 0x7F) { | ||
683 | /* It should be a DualPoint when received Trackpoint packet */ | ||
684 | if (!(priv->flags & ALPS_DUALPOINT)) | ||
685 | return; | ||
686 | |||
687 | /* Trackpoint packet */ | ||
688 | x = packet[1] | ((packet[3] & 0x20) << 2); | ||
689 | y = packet[2] | ((packet[3] & 0x40) << 1); | ||
690 | z = packet[4]; | ||
691 | left = packet[3] & 0x01; | ||
692 | right = packet[3] & 0x02; | ||
693 | middle = packet[3] & 0x04; | ||
694 | |||
695 | /* To prevent the cursor jump when finger lifted */ | ||
696 | if (x == 0x7F && y == 0x7F && z == 0x7F) | ||
697 | x = y = z = 0; | ||
698 | |||
699 | /* Divide 4 since trackpoint's speed is too fast */ | ||
700 | input_report_rel(dev2, REL_X, (char)x / 4); | ||
701 | input_report_rel(dev2, REL_Y, -((char)y / 4)); | ||
702 | |||
703 | input_report_key(dev2, BTN_LEFT, left); | ||
704 | input_report_key(dev2, BTN_RIGHT, right); | ||
705 | input_report_key(dev2, BTN_MIDDLE, middle); | ||
706 | |||
707 | input_sync(dev2); | ||
708 | return; | ||
709 | } | ||
710 | |||
711 | /* Touchpad packet */ | ||
712 | x = packet[1] | ((packet[3] & 0x78) << 4); | ||
713 | y = packet[2] | ((packet[4] & 0x78) << 4); | ||
714 | z = packet[5]; | ||
715 | left = packet[3] & 0x01; | ||
716 | right = packet[3] & 0x02; | ||
717 | |||
718 | if (z > 30) | ||
719 | input_report_key(dev, BTN_TOUCH, 1); | ||
720 | if (z < 25) | ||
721 | input_report_key(dev, BTN_TOUCH, 0); | ||
722 | |||
723 | if (z > 0) { | ||
724 | input_report_abs(dev, ABS_X, x); | ||
725 | input_report_abs(dev, ABS_Y, y); | ||
726 | } | ||
727 | |||
728 | input_report_abs(dev, ABS_PRESSURE, z); | ||
729 | input_report_key(dev, BTN_TOOL_FINGER, z > 0); | ||
730 | |||
731 | /* v6 touchpad does not have middle button */ | ||
732 | input_report_key(dev, BTN_LEFT, left); | ||
733 | input_report_key(dev, BTN_RIGHT, right); | ||
734 | |||
735 | input_sync(dev); | ||
736 | } | ||
737 | |||
648 | static void alps_process_packet_v4(struct psmouse *psmouse) | 738 | static void alps_process_packet_v4(struct psmouse *psmouse) |
649 | { | 739 | { |
650 | struct alps_data *priv = psmouse->private; | 740 | struct alps_data *priv = psmouse->private; |
@@ -897,7 +987,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | |||
897 | } | 987 | } |
898 | 988 | ||
899 | /* Bytes 2 - pktsize should have 0 in the highest bit */ | 989 | /* Bytes 2 - pktsize should have 0 in the highest bit */ |
900 | if (priv->proto_version != ALPS_PROTO_V5 && | 990 | if ((priv->proto_version < ALPS_PROTO_V5) && |
901 | psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && | 991 | psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && |
902 | (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { | 992 | (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { |
903 | psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", | 993 | psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", |
@@ -1085,6 +1175,80 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse) | |||
1085 | return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); | 1175 | return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); |
1086 | } | 1176 | } |
1087 | 1177 | ||
1178 | static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word) | ||
1179 | { | ||
1180 | int i, nibble; | ||
1181 | |||
1182 | /* | ||
1183 | * b0-b11 are valid bits, send sequence is inverse. | ||
1184 | * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 | ||
1185 | */ | ||
1186 | for (i = 0; i <= 8; i += 4) { | ||
1187 | nibble = (word >> i) & 0xf; | ||
1188 | if (alps_command_mode_send_nibble(psmouse, nibble)) | ||
1189 | return -1; | ||
1190 | } | ||
1191 | |||
1192 | return 0; | ||
1193 | } | ||
1194 | |||
1195 | static int alps_monitor_mode_write_reg(struct psmouse *psmouse, | ||
1196 | u16 addr, u16 value) | ||
1197 | { | ||
1198 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1199 | |||
1200 | /* 0x0A0 is the command to write the word */ | ||
1201 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) || | ||
1202 | alps_monitor_mode_send_word(psmouse, 0x0A0) || | ||
1203 | alps_monitor_mode_send_word(psmouse, addr) || | ||
1204 | alps_monitor_mode_send_word(psmouse, value) || | ||
1205 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) | ||
1206 | return -1; | ||
1207 | |||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | static int alps_monitor_mode(struct psmouse *psmouse, bool enable) | ||
1212 | { | ||
1213 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1214 | |||
1215 | if (enable) { | ||
1216 | /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ | ||
1217 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || | ||
1218 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) || | ||
1219 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
1220 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | ||
1221 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | ||
1222 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1223 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | ||
1224 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO)) | ||
1225 | return -1; | ||
1226 | } else { | ||
1227 | /* EC to exit monitor mode */ | ||
1228 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP)) | ||
1229 | return -1; | ||
1230 | } | ||
1231 | |||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1235 | static int alps_absolute_mode_v6(struct psmouse *psmouse) | ||
1236 | { | ||
1237 | u16 reg_val = 0x181; | ||
1238 | int ret = -1; | ||
1239 | |||
1240 | /* enter monitor mode, to write the register */ | ||
1241 | if (alps_monitor_mode(psmouse, true)) | ||
1242 | return -1; | ||
1243 | |||
1244 | ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val); | ||
1245 | |||
1246 | if (alps_monitor_mode(psmouse, false)) | ||
1247 | ret = -1; | ||
1248 | |||
1249 | return ret; | ||
1250 | } | ||
1251 | |||
1088 | static int alps_get_status(struct psmouse *psmouse, char *param) | 1252 | static int alps_get_status(struct psmouse *psmouse, char *param) |
1089 | { | 1253 | { |
1090 | /* Get status: 0xF5 0xF5 0xF5 0xE9 */ | 1254 | /* Get status: 0xF5 0xF5 0xF5 0xE9 */ |
@@ -1189,6 +1353,32 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse) | |||
1189 | return 0; | 1353 | return 0; |
1190 | } | 1354 | } |
1191 | 1355 | ||
1356 | static int alps_hw_init_v6(struct psmouse *psmouse) | ||
1357 | { | ||
1358 | unsigned char param[2] = {0xC8, 0x14}; | ||
1359 | |||
1360 | /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ | ||
1361 | if (alps_passthrough_mode_v2(psmouse, true)) | ||
1362 | return -1; | ||
1363 | |||
1364 | if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1365 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1366 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1367 | ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || | ||
1368 | ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) | ||
1369 | return -1; | ||
1370 | |||
1371 | if (alps_passthrough_mode_v2(psmouse, false)) | ||
1372 | return -1; | ||
1373 | |||
1374 | if (alps_absolute_mode_v6(psmouse)) { | ||
1375 | psmouse_err(psmouse, "Failed to enable absolute mode\n"); | ||
1376 | return -1; | ||
1377 | } | ||
1378 | |||
1379 | return 0; | ||
1380 | } | ||
1381 | |||
1192 | /* | 1382 | /* |
1193 | * Enable or disable passthrough mode to the trackstick. | 1383 | * Enable or disable passthrough mode to the trackstick. |
1194 | */ | 1384 | */ |
@@ -1553,6 +1743,8 @@ static void alps_set_defaults(struct alps_data *priv) | |||
1553 | priv->hw_init = alps_hw_init_v1_v2; | 1743 | priv->hw_init = alps_hw_init_v1_v2; |
1554 | priv->process_packet = alps_process_packet_v1_v2; | 1744 | priv->process_packet = alps_process_packet_v1_v2; |
1555 | priv->set_abs_params = alps_set_abs_params_st; | 1745 | priv->set_abs_params = alps_set_abs_params_st; |
1746 | priv->x_max = 1023; | ||
1747 | priv->y_max = 767; | ||
1556 | break; | 1748 | break; |
1557 | case ALPS_PROTO_V3: | 1749 | case ALPS_PROTO_V3: |
1558 | priv->hw_init = alps_hw_init_v3; | 1750 | priv->hw_init = alps_hw_init_v3; |
@@ -1584,6 +1776,14 @@ static void alps_set_defaults(struct alps_data *priv) | |||
1584 | priv->x_bits = 23; | 1776 | priv->x_bits = 23; |
1585 | priv->y_bits = 12; | 1777 | priv->y_bits = 12; |
1586 | break; | 1778 | break; |
1779 | case ALPS_PROTO_V6: | ||
1780 | priv->hw_init = alps_hw_init_v6; | ||
1781 | priv->process_packet = alps_process_packet_v6; | ||
1782 | priv->set_abs_params = alps_set_abs_params_st; | ||
1783 | priv->nibble_commands = alps_v6_nibble_commands; | ||
1784 | priv->x_max = 2047; | ||
1785 | priv->y_max = 1535; | ||
1786 | break; | ||
1587 | } | 1787 | } |
1588 | } | 1788 | } |
1589 | 1789 | ||
@@ -1705,8 +1905,8 @@ static void alps_disconnect(struct psmouse *psmouse) | |||
1705 | static void alps_set_abs_params_st(struct alps_data *priv, | 1905 | static void alps_set_abs_params_st(struct alps_data *priv, |
1706 | struct input_dev *dev1) | 1906 | struct input_dev *dev1) |
1707 | { | 1907 | { |
1708 | input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); | 1908 | input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); |
1709 | input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); | 1909 | input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); |
1710 | } | 1910 | } |
1711 | 1911 | ||
1712 | static void alps_set_abs_params_mt(struct alps_data *priv, | 1912 | static void alps_set_abs_params_mt(struct alps_data *priv, |