diff options
author | Kevin Cernekee <cernekee@gmail.com> | 2013-02-14 01:28:07 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-02-14 12:18:34 -0500 |
commit | cd401204873101245287afc07271b39c79194d9c (patch) | |
tree | 22a7bee493a3c10259e8640fd14da1d952c4310a /drivers/input | |
parent | 1302bac33d9e88cd43e482191a806998f3ed43cc (diff) |
Input: ALPS - enable trackstick on Rushmore touchpads
Separate out the common trackstick probe/setup sequences, then call them
from each of the v3 init functions.
Credits: Emmanual Thome furnished the information on the trackstick init
and how it affected the report format.
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Tested-by: Dave Turvene <dturvene@dahetral.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/mouse/alps.c | 185 |
1 files changed, 115 insertions, 70 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index bf2fa51853e3..7b99fc7c9438 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -29,6 +29,9 @@ | |||
29 | */ | 29 | */ |
30 | #define ALPS_CMD_NIBBLE_10 0x01f2 | 30 | #define ALPS_CMD_NIBBLE_10 0x01f2 |
31 | 31 | ||
32 | #define ALPS_REG_BASE_RUSHMORE 0xc2c0 | ||
33 | #define ALPS_REG_BASE_PINNACLE 0x0000 | ||
34 | |||
32 | static const struct alps_nibble_commands alps_v3_nibble_commands[] = { | 35 | static const struct alps_nibble_commands alps_v3_nibble_commands[] = { |
33 | { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ | 36 | { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ |
34 | { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ | 37 | { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ |
@@ -1166,26 +1169,31 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse) | |||
1166 | } | 1169 | } |
1167 | 1170 | ||
1168 | /* | 1171 | /* |
1169 | * Enable or disable passthrough mode to the trackstick. Must be in | 1172 | * Enable or disable passthrough mode to the trackstick. |
1170 | * command mode when calling this function. | ||
1171 | */ | 1173 | */ |
1172 | static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable) | 1174 | static int alps_passthrough_mode_v3(struct psmouse *psmouse, |
1175 | int reg_base, bool enable) | ||
1173 | { | 1176 | { |
1174 | int reg_val; | 1177 | int reg_val, ret = -1; |
1175 | 1178 | ||
1176 | reg_val = alps_command_mode_read_reg(psmouse, 0x0008); | 1179 | if (alps_enter_command_mode(psmouse, NULL)) |
1177 | if (reg_val == -1) | ||
1178 | return -1; | 1180 | return -1; |
1179 | 1181 | ||
1182 | reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008); | ||
1183 | if (reg_val == -1) | ||
1184 | goto error; | ||
1185 | |||
1180 | if (enable) | 1186 | if (enable) |
1181 | reg_val |= 0x01; | 1187 | reg_val |= 0x01; |
1182 | else | 1188 | else |
1183 | reg_val &= ~0x01; | 1189 | reg_val &= ~0x01; |
1184 | 1190 | ||
1185 | if (__alps_command_mode_write_reg(psmouse, reg_val)) | 1191 | ret = __alps_command_mode_write_reg(psmouse, reg_val); |
1186 | return -1; | ||
1187 | 1192 | ||
1188 | return 0; | 1193 | error: |
1194 | if (alps_exit_command_mode(psmouse)) | ||
1195 | ret = -1; | ||
1196 | return ret; | ||
1189 | } | 1197 | } |
1190 | 1198 | ||
1191 | /* Must be in command mode when calling this function */ | 1199 | /* Must be in command mode when calling this function */ |
@@ -1204,69 +1212,102 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse) | |||
1204 | return 0; | 1212 | return 0; |
1205 | } | 1213 | } |
1206 | 1214 | ||
1207 | static int alps_hw_init_v3(struct psmouse *psmouse) | 1215 | static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base) |
1208 | { | 1216 | { |
1209 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 1217 | int ret = -EIO, reg_val; |
1210 | int reg_val; | ||
1211 | unsigned char param[4]; | ||
1212 | 1218 | ||
1213 | if (alps_enter_command_mode(psmouse, NULL)) | 1219 | if (alps_enter_command_mode(psmouse, NULL)) |
1214 | goto error; | 1220 | goto error; |
1215 | 1221 | ||
1216 | /* Check for trackstick */ | 1222 | reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08); |
1217 | reg_val = alps_command_mode_read_reg(psmouse, 0x0008); | ||
1218 | if (reg_val == -1) | 1223 | if (reg_val == -1) |
1219 | goto error; | 1224 | goto error; |
1220 | if (reg_val & 0x80) { | 1225 | |
1221 | if (alps_passthrough_mode_v3(psmouse, true)) | 1226 | /* bit 7: trackstick is present */ |
1222 | goto error; | 1227 | ret = reg_val & 0x80 ? 0 : -ENODEV; |
1223 | if (alps_exit_command_mode(psmouse)) | 1228 | |
1224 | goto error; | 1229 | error: |
1230 | alps_exit_command_mode(psmouse); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | |||
1234 | static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) | ||
1235 | { | ||
1236 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1237 | int ret = 0; | ||
1238 | unsigned char param[4]; | ||
1239 | |||
1240 | if (alps_passthrough_mode_v3(psmouse, reg_base, true)) | ||
1241 | return -EIO; | ||
1242 | |||
1243 | /* | ||
1244 | * E7 report for the trackstick | ||
1245 | * | ||
1246 | * There have been reports of failures to seem to trace back | ||
1247 | * to the above trackstick check failing. When these occur | ||
1248 | * this E7 report fails, so when that happens we continue | ||
1249 | * with the assumption that there isn't a trackstick after | ||
1250 | * all. | ||
1251 | */ | ||
1252 | if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) { | ||
1253 | psmouse_warn(psmouse, "trackstick E7 report failed\n"); | ||
1254 | ret = -ENODEV; | ||
1255 | } else { | ||
1256 | psmouse_dbg(psmouse, | ||
1257 | "trackstick E7 report: %2.2x %2.2x %2.2x\n", | ||
1258 | param[0], param[1], param[2]); | ||
1225 | 1259 | ||
1226 | /* | 1260 | /* |
1227 | * E7 report for the trackstick | 1261 | * Not sure what this does, but it is absolutely |
1228 | * | 1262 | * essential. Without it, the touchpad does not |
1229 | * There have been reports of failures to seem to trace back | 1263 | * work at all and the trackstick just emits normal |
1230 | * to the above trackstick check failing. When these occur | 1264 | * PS/2 packets. |
1231 | * this E7 report fails, so when that happens we continue | ||
1232 | * with the assumption that there isn't a trackstick after | ||
1233 | * all. | ||
1234 | */ | 1265 | */ |
1235 | param[0] = 0x64; | 1266 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1236 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | 1267 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1237 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | 1268 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1238 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || | 1269 | alps_command_mode_send_nibble(psmouse, 0x9) || |
1239 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 1270 | alps_command_mode_send_nibble(psmouse, 0x4)) { |
1240 | psmouse_warn(psmouse, "trackstick E7 report failed\n"); | 1271 | psmouse_err(psmouse, |
1241 | } else { | 1272 | "Error sending magic E6 sequence\n"); |
1242 | psmouse_dbg(psmouse, | 1273 | ret = -EIO; |
1243 | "trackstick E7 report: %2.2x %2.2x %2.2x\n", | 1274 | goto error; |
1244 | param[0], param[1], param[2]); | ||
1245 | |||
1246 | /* | ||
1247 | * Not sure what this does, but it is absolutely | ||
1248 | * essential. Without it, the touchpad does not | ||
1249 | * work at all and the trackstick just emits normal | ||
1250 | * PS/2 packets. | ||
1251 | */ | ||
1252 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1253 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1254 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | ||
1255 | alps_command_mode_send_nibble(psmouse, 0x9) || | ||
1256 | alps_command_mode_send_nibble(psmouse, 0x4)) { | ||
1257 | psmouse_err(psmouse, | ||
1258 | "Error sending magic E6 sequence\n"); | ||
1259 | goto error_passthrough; | ||
1260 | } | ||
1261 | } | 1275 | } |
1262 | 1276 | ||
1263 | if (alps_enter_command_mode(psmouse, NULL)) | 1277 | /* |
1264 | goto error_passthrough; | 1278 | * This ensures the trackstick packets are in the format |
1265 | if (alps_passthrough_mode_v3(psmouse, false)) | 1279 | * supported by this driver. If bit 1 isn't set the packet |
1266 | goto error; | 1280 | * format is different. |
1281 | */ | ||
1282 | if (alps_enter_command_mode(psmouse, NULL) || | ||
1283 | alps_command_mode_write_reg(psmouse, | ||
1284 | reg_base + 0x08, 0x82) || | ||
1285 | alps_exit_command_mode(psmouse)) | ||
1286 | ret = -EIO; | ||
1267 | } | 1287 | } |
1268 | 1288 | ||
1269 | if (alps_absolute_mode_v3(psmouse)) { | 1289 | error: |
1290 | if (alps_passthrough_mode_v3(psmouse, reg_base, false)) | ||
1291 | ret = -EIO; | ||
1292 | |||
1293 | return ret; | ||
1294 | } | ||
1295 | |||
1296 | static int alps_hw_init_v3(struct psmouse *psmouse) | ||
1297 | { | ||
1298 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
1299 | int reg_val; | ||
1300 | unsigned char param[4]; | ||
1301 | |||
1302 | reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE); | ||
1303 | if (reg_val == -EIO) | ||
1304 | goto error; | ||
1305 | if (reg_val == 0 && | ||
1306 | alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) | ||
1307 | goto error; | ||
1308 | |||
1309 | if (alps_enter_command_mode(psmouse, NULL) || | ||
1310 | alps_absolute_mode_v3(psmouse)) { | ||
1270 | psmouse_err(psmouse, "Failed to enter absolute mode\n"); | 1311 | psmouse_err(psmouse, "Failed to enter absolute mode\n"); |
1271 | goto error; | 1312 | goto error; |
1272 | } | 1313 | } |
@@ -1303,14 +1344,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse) | |||
1303 | if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) | 1344 | if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) |
1304 | goto error; | 1345 | goto error; |
1305 | 1346 | ||
1306 | /* | ||
1307 | * This ensures the trackstick packets are in the format | ||
1308 | * supported by this driver. If bit 1 isn't set the packet | ||
1309 | * format is different. | ||
1310 | */ | ||
1311 | if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82)) | ||
1312 | goto error; | ||
1313 | |||
1314 | alps_exit_command_mode(psmouse); | 1347 | alps_exit_command_mode(psmouse); |
1315 | 1348 | ||
1316 | /* Set rate and enable data reporting */ | 1349 | /* Set rate and enable data reporting */ |
@@ -1323,10 +1356,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse) | |||
1323 | 1356 | ||
1324 | return 0; | 1357 | return 0; |
1325 | 1358 | ||
1326 | error_passthrough: | ||
1327 | /* Something failed while in passthrough mode, so try to get out */ | ||
1328 | if (!alps_enter_command_mode(psmouse, NULL)) | ||
1329 | alps_passthrough_mode_v3(psmouse, false); | ||
1330 | error: | 1359 | error: |
1331 | /* | 1360 | /* |
1332 | * Leaving the touchpad in command mode will essentially render | 1361 | * Leaving the touchpad in command mode will essentially render |
@@ -1339,9 +1368,19 @@ error: | |||
1339 | 1368 | ||
1340 | static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) | 1369 | static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) |
1341 | { | 1370 | { |
1371 | struct alps_data *priv = psmouse->private; | ||
1342 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 1372 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
1343 | int reg_val, ret = -1; | 1373 | int reg_val, ret = -1; |
1344 | 1374 | ||
1375 | if (priv->flags & ALPS_DUALPOINT) { | ||
1376 | reg_val = alps_setup_trackstick_v3(psmouse, | ||
1377 | ALPS_REG_BASE_RUSHMORE); | ||
1378 | if (reg_val == -EIO) | ||
1379 | goto error; | ||
1380 | if (reg_val == -ENODEV) | ||
1381 | priv->flags &= ~ALPS_DUALPOINT; | ||
1382 | } | ||
1383 | |||
1345 | if (alps_enter_command_mode(psmouse, NULL) || | 1384 | if (alps_enter_command_mode(psmouse, NULL) || |
1346 | alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 || | 1385 | alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 || |
1347 | alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00)) | 1386 | alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00)) |
@@ -1562,6 +1601,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) | |||
1562 | priv->x_bits = 16; | 1601 | priv->x_bits = 16; |
1563 | priv->y_bits = 12; | 1602 | priv->y_bits = 12; |
1564 | 1603 | ||
1604 | /* hack to make addr_command, nibble_command available */ | ||
1605 | psmouse->private = priv; | ||
1606 | |||
1607 | if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE)) | ||
1608 | priv->flags &= ~ALPS_DUALPOINT; | ||
1609 | |||
1565 | return 0; | 1610 | return 0; |
1566 | } else if (ec[0] == 0x88 && ec[1] == 0x07 && | 1611 | } else if (ec[0] == 0x88 && ec[1] == 0x07 && |
1567 | ec[2] >= 0x90 && ec[2] <= 0x9d) { | 1612 | ec[2] >= 0x90 && ec[2] <= 0x9d) { |