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/mouse | |
| 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/mouse')
| -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) { |
