diff options
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r-- | drivers/input/mouse/alps.c | 329 |
1 files changed, 326 insertions, 3 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index c7924b6f7d4b..ad741c04936d 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -153,12 +153,18 @@ static const struct alps_protocol_info alps_v7_protocol_data = { | |||
153 | ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT | 153 | ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT |
154 | }; | 154 | }; |
155 | 155 | ||
156 | static const struct alps_protocol_info alps_v8_protocol_data = { | ||
157 | ALPS_PROTO_V8, 0x18, 0x18, 0 | ||
158 | }; | ||
159 | |||
156 | static void alps_set_abs_params_st(struct alps_data *priv, | 160 | static void alps_set_abs_params_st(struct alps_data *priv, |
157 | struct input_dev *dev1); | 161 | struct input_dev *dev1); |
158 | static void alps_set_abs_params_mt(struct alps_data *priv, | 162 | static void alps_set_abs_params_mt(struct alps_data *priv, |
159 | struct input_dev *dev1); | 163 | struct input_dev *dev1); |
160 | static void alps_set_abs_params_v7(struct alps_data *priv, | 164 | static void alps_set_abs_params_v7(struct alps_data *priv, |
161 | struct input_dev *dev1); | 165 | struct input_dev *dev1); |
166 | static void alps_set_abs_params_ss4_v2(struct alps_data *priv, | ||
167 | struct input_dev *dev1); | ||
162 | 168 | ||
163 | /* Packet formats are described in Documentation/input/alps.txt */ | 169 | /* Packet formats are described in Documentation/input/alps.txt */ |
164 | 170 | ||
@@ -1087,6 +1093,176 @@ static void alps_process_packet_v7(struct psmouse *psmouse) | |||
1087 | alps_process_touchpad_packet_v7(psmouse); | 1093 | alps_process_touchpad_packet_v7(psmouse); |
1088 | } | 1094 | } |
1089 | 1095 | ||
1096 | unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte) | ||
1097 | { | ||
1098 | unsigned char pkt_id = SS4_PACKET_ID_IDLE; | ||
1099 | |||
1100 | if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && | ||
1101 | (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) { | ||
1102 | pkt_id = SS4_PACKET_ID_IDLE; | ||
1103 | } else if (!(byte[3] & 0x10)) { | ||
1104 | pkt_id = SS4_PACKET_ID_ONE; | ||
1105 | } else if (!(byte[3] & 0x20)) { | ||
1106 | pkt_id = SS4_PACKET_ID_TWO; | ||
1107 | } else { | ||
1108 | pkt_id = SS4_PACKET_ID_MULTI; | ||
1109 | } | ||
1110 | |||
1111 | return pkt_id; | ||
1112 | } | ||
1113 | |||
1114 | static int alps_decode_ss4_v2(struct alps_fields *f, | ||
1115 | unsigned char *p, struct psmouse *psmouse) | ||
1116 | { | ||
1117 | struct alps_data *priv = psmouse->private; | ||
1118 | unsigned char pkt_id; | ||
1119 | unsigned int no_data_x, no_data_y; | ||
1120 | |||
1121 | pkt_id = alps_get_pkt_id_ss4_v2(p); | ||
1122 | |||
1123 | /* Current packet is 1Finger coordinate packet */ | ||
1124 | switch (pkt_id) { | ||
1125 | case SS4_PACKET_ID_ONE: | ||
1126 | f->mt[0].x = SS4_1F_X_V2(p); | ||
1127 | f->mt[0].y = SS4_1F_Y_V2(p); | ||
1128 | f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; | ||
1129 | f->fingers = 1; | ||
1130 | f->first_mp = 0; | ||
1131 | f->is_mp = 0; | ||
1132 | break; | ||
1133 | |||
1134 | case SS4_PACKET_ID_TWO: | ||
1135 | if (priv->flags & ALPS_BUTTONPAD) { | ||
1136 | f->mt[0].x = SS4_BTL_MF_X_V2(p, 0); | ||
1137 | f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0); | ||
1138 | f->mt[1].x = SS4_BTL_MF_X_V2(p, 1); | ||
1139 | f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1); | ||
1140 | } else { | ||
1141 | f->mt[0].x = SS4_STD_MF_X_V2(p, 0); | ||
1142 | f->mt[0].y = SS4_STD_MF_Y_V2(p, 0); | ||
1143 | f->mt[1].x = SS4_STD_MF_X_V2(p, 1); | ||
1144 | f->mt[1].y = SS4_STD_MF_Y_V2(p, 1); | ||
1145 | } | ||
1146 | f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0; | ||
1147 | |||
1148 | if (SS4_IS_MF_CONTINUE(p)) { | ||
1149 | f->first_mp = 1; | ||
1150 | } else { | ||
1151 | f->fingers = 2; | ||
1152 | f->first_mp = 0; | ||
1153 | } | ||
1154 | f->is_mp = 0; | ||
1155 | |||
1156 | break; | ||
1157 | |||
1158 | case SS4_PACKET_ID_MULTI: | ||
1159 | if (priv->flags & ALPS_BUTTONPAD) { | ||
1160 | f->mt[2].x = SS4_BTL_MF_X_V2(p, 0); | ||
1161 | f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0); | ||
1162 | f->mt[3].x = SS4_BTL_MF_X_V2(p, 1); | ||
1163 | f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1); | ||
1164 | no_data_x = SS4_MFPACKET_NO_AX_BL; | ||
1165 | no_data_y = SS4_MFPACKET_NO_AY_BL; | ||
1166 | } else { | ||
1167 | f->mt[2].x = SS4_STD_MF_X_V2(p, 0); | ||
1168 | f->mt[2].y = SS4_STD_MF_Y_V2(p, 0); | ||
1169 | f->mt[3].x = SS4_STD_MF_X_V2(p, 1); | ||
1170 | f->mt[3].y = SS4_STD_MF_Y_V2(p, 1); | ||
1171 | no_data_x = SS4_MFPACKET_NO_AX; | ||
1172 | no_data_y = SS4_MFPACKET_NO_AY; | ||
1173 | } | ||
1174 | |||
1175 | f->first_mp = 0; | ||
1176 | f->is_mp = 1; | ||
1177 | |||
1178 | if (SS4_IS_5F_DETECTED(p)) { | ||
1179 | f->fingers = 5; | ||
1180 | } else if (f->mt[3].x == no_data_x && | ||
1181 | f->mt[3].y == no_data_y) { | ||
1182 | f->mt[3].x = 0; | ||
1183 | f->mt[3].y = 0; | ||
1184 | f->fingers = 3; | ||
1185 | } else { | ||
1186 | f->fingers = 4; | ||
1187 | } | ||
1188 | break; | ||
1189 | |||
1190 | case SS4_PACKET_ID_IDLE: | ||
1191 | default: | ||
1192 | memset(f, 0, sizeof(struct alps_fields)); | ||
1193 | break; | ||
1194 | } | ||
1195 | |||
1196 | f->left = !!(SS4_BTN_V2(p) & 0x01); | ||
1197 | if (!(priv->flags & ALPS_BUTTONPAD)) { | ||
1198 | f->right = !!(SS4_BTN_V2(p) & 0x02); | ||
1199 | f->middle = !!(SS4_BTN_V2(p) & 0x04); | ||
1200 | } | ||
1201 | |||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1205 | static void alps_process_packet_ss4_v2(struct psmouse *psmouse) | ||
1206 | { | ||
1207 | struct alps_data *priv = psmouse->private; | ||
1208 | unsigned char *packet = psmouse->packet; | ||
1209 | struct input_dev *dev = psmouse->dev; | ||
1210 | struct alps_fields *f = &priv->f; | ||
1211 | |||
1212 | memset(f, 0, sizeof(struct alps_fields)); | ||
1213 | priv->decode_fields(f, packet, psmouse); | ||
1214 | if (priv->multi_packet) { | ||
1215 | /* | ||
1216 | * Sometimes the first packet will indicate a multi-packet | ||
1217 | * sequence, but sometimes the next multi-packet would not | ||
1218 | * come. Check for this, and when it happens process the | ||
1219 | * position packet as usual. | ||
1220 | */ | ||
1221 | if (f->is_mp) { | ||
1222 | /* Now process the 1st packet */ | ||
1223 | priv->decode_fields(f, priv->multi_data, psmouse); | ||
1224 | } else { | ||
1225 | priv->multi_packet = 0; | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | /* | ||
1230 | * "f.is_mp" would always be '0' after merging the 1st and 2nd packet. | ||
1231 | * When it is set, it means 2nd packet comes without 1st packet come. | ||
1232 | */ | ||
1233 | if (f->is_mp) | ||
1234 | return; | ||
1235 | |||
1236 | /* Save the first packet */ | ||
1237 | if (!priv->multi_packet && f->first_mp) { | ||
1238 | priv->multi_packet = 1; | ||
1239 | memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); | ||
1240 | return; | ||
1241 | } | ||
1242 | |||
1243 | priv->multi_packet = 0; | ||
1244 | |||
1245 | alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4); | ||
1246 | |||
1247 | input_mt_report_finger_count(dev, f->fingers); | ||
1248 | |||
1249 | input_report_key(dev, BTN_LEFT, f->left); | ||
1250 | input_report_key(dev, BTN_RIGHT, f->right); | ||
1251 | input_report_key(dev, BTN_MIDDLE, f->middle); | ||
1252 | |||
1253 | input_report_abs(dev, ABS_PRESSURE, f->pressure); | ||
1254 | input_sync(dev); | ||
1255 | } | ||
1256 | |||
1257 | static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) | ||
1258 | { | ||
1259 | if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08)) | ||
1260 | return false; | ||
1261 | if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0)) | ||
1262 | return false; | ||
1263 | return true; | ||
1264 | } | ||
1265 | |||
1090 | static DEFINE_MUTEX(alps_mutex); | 1266 | static DEFINE_MUTEX(alps_mutex); |
1091 | 1267 | ||
1092 | static void alps_register_bare_ps2_mouse(struct work_struct *work) | 1268 | static void alps_register_bare_ps2_mouse(struct work_struct *work) |
@@ -1307,8 +1483,12 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | |||
1307 | * a device connected to the external PS/2 port. Because bare PS/2 | 1483 | * a device connected to the external PS/2 port. Because bare PS/2 |
1308 | * protocol does not have enough constant bits to self-synchronize | 1484 | * protocol does not have enough constant bits to self-synchronize |
1309 | * properly we only do this if the device is fully synchronized. | 1485 | * properly we only do this if the device is fully synchronized. |
1486 | * Can not distinguish V8's first byte from PS/2 packet's | ||
1310 | */ | 1487 | */ |
1311 | if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) { | 1488 | if (priv->proto_version != ALPS_PROTO_V8 && |
1489 | !psmouse->out_of_sync_cnt && | ||
1490 | (psmouse->packet[0] & 0xc8) == 0x08) { | ||
1491 | |||
1312 | if (psmouse->pktcnt == 3) { | 1492 | if (psmouse->pktcnt == 3) { |
1313 | alps_report_bare_ps2_packet(psmouse, psmouse->packet, | 1493 | alps_report_bare_ps2_packet(psmouse, psmouse->packet, |
1314 | true); | 1494 | true); |
@@ -1356,8 +1536,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | |||
1356 | return PSMOUSE_BAD_DATA; | 1536 | return PSMOUSE_BAD_DATA; |
1357 | } | 1537 | } |
1358 | 1538 | ||
1359 | if (priv->proto_version == ALPS_PROTO_V7 && | 1539 | if ((priv->proto_version == ALPS_PROTO_V7 && |
1360 | !alps_is_valid_package_v7(psmouse)) { | 1540 | !alps_is_valid_package_v7(psmouse)) || |
1541 | (priv->proto_version == ALPS_PROTO_V8 && | ||
1542 | !alps_is_valid_package_ss4_v2(psmouse))) { | ||
1361 | psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", | 1543 | psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", |
1362 | psmouse->pktcnt - 1, | 1544 | psmouse->pktcnt - 1, |
1363 | psmouse->packet[psmouse->pktcnt - 1]); | 1545 | psmouse->packet[psmouse->pktcnt - 1]); |
@@ -2132,6 +2314,88 @@ error: | |||
2132 | return -1; | 2314 | return -1; |
2133 | } | 2315 | } |
2134 | 2316 | ||
2317 | static int alps_get_otp_values_ss4_v2(struct psmouse *psmouse, | ||
2318 | unsigned char index, unsigned char otp[]) | ||
2319 | { | ||
2320 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
2321 | |||
2322 | switch (index) { | ||
2323 | case 0: | ||
2324 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || | ||
2325 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || | ||
2326 | ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO)) | ||
2327 | return -1; | ||
2328 | |||
2329 | break; | ||
2330 | |||
2331 | case 1: | ||
2332 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || | ||
2333 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || | ||
2334 | ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO)) | ||
2335 | return -1; | ||
2336 | |||
2337 | break; | ||
2338 | } | ||
2339 | |||
2340 | return 0; | ||
2341 | } | ||
2342 | |||
2343 | int alps_update_device_area_ss4_v2(unsigned char otp[][4], | ||
2344 | struct alps_data *priv) | ||
2345 | { | ||
2346 | int num_x_electrode; | ||
2347 | int num_y_electrode; | ||
2348 | int x_pitch, y_pitch, x_phys, y_phys; | ||
2349 | |||
2350 | num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F); | ||
2351 | num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F); | ||
2352 | |||
2353 | priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE; | ||
2354 | priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE; | ||
2355 | |||
2356 | x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM; | ||
2357 | y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM; | ||
2358 | |||
2359 | x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */ | ||
2360 | y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */ | ||
2361 | |||
2362 | priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */ | ||
2363 | priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */ | ||
2364 | |||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | int alps_update_btn_info_ss4_v2(unsigned char otp[][4], struct alps_data *priv) | ||
2369 | { | ||
2370 | |||
2371 | unsigned char is_btnless; | ||
2372 | |||
2373 | is_btnless = (otp[1][1] >> 3) & 0x01; | ||
2374 | |||
2375 | if (is_btnless) | ||
2376 | priv->flags |= ALPS_BUTTONPAD; | ||
2377 | |||
2378 | return 0; | ||
2379 | } | ||
2380 | |||
2381 | static int alps_set_defaults_ss4_v2(struct psmouse *psmouse, | ||
2382 | struct alps_data *priv) | ||
2383 | { | ||
2384 | unsigned char otp[2][4]; | ||
2385 | |||
2386 | memset(otp, 0, sizeof(otp)); | ||
2387 | |||
2388 | if (alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]) || | ||
2389 | alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0])) | ||
2390 | return -1; | ||
2391 | |||
2392 | alps_update_device_area_ss4_v2(otp, priv); | ||
2393 | |||
2394 | alps_update_btn_info_ss4_v2(otp, priv); | ||
2395 | |||
2396 | return 0; | ||
2397 | } | ||
2398 | |||
2135 | static int alps_dolphin_get_device_area(struct psmouse *psmouse, | 2399 | static int alps_dolphin_get_device_area(struct psmouse *psmouse, |
2136 | struct alps_data *priv) | 2400 | struct alps_data *priv) |
2137 | { | 2401 | { |
@@ -2224,6 +2488,35 @@ error: | |||
2224 | return ret; | 2488 | return ret; |
2225 | } | 2489 | } |
2226 | 2490 | ||
2491 | static int alps_hw_init_ss4_v2(struct psmouse *psmouse) | ||
2492 | { | ||
2493 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
2494 | char param[2] = {0x64, 0x28}; | ||
2495 | int ret = -1; | ||
2496 | |||
2497 | /* enter absolute mode */ | ||
2498 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || | ||
2499 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || | ||
2500 | ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || | ||
2501 | ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) { | ||
2502 | goto error; | ||
2503 | } | ||
2504 | |||
2505 | /* T.B.D. Decread noise packet number, delete in the future */ | ||
2506 | if (alps_exit_command_mode(psmouse) || | ||
2507 | alps_enter_command_mode(psmouse) || | ||
2508 | alps_command_mode_write_reg(psmouse, 0x001D, 0x20)) { | ||
2509 | goto error; | ||
2510 | } | ||
2511 | alps_exit_command_mode(psmouse); | ||
2512 | |||
2513 | return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); | ||
2514 | |||
2515 | error: | ||
2516 | alps_exit_command_mode(psmouse); | ||
2517 | return ret; | ||
2518 | } | ||
2519 | |||
2227 | static int alps_set_protocol(struct psmouse *psmouse, | 2520 | static int alps_set_protocol(struct psmouse *psmouse, |
2228 | struct alps_data *priv, | 2521 | struct alps_data *priv, |
2229 | const struct alps_protocol_info *protocol) | 2522 | const struct alps_protocol_info *protocol) |
@@ -2323,6 +2616,19 @@ static int alps_set_protocol(struct psmouse *psmouse, | |||
2323 | priv->flags |= ALPS_BUTTONPAD; | 2616 | priv->flags |= ALPS_BUTTONPAD; |
2324 | 2617 | ||
2325 | break; | 2618 | break; |
2619 | |||
2620 | case ALPS_PROTO_V8: | ||
2621 | priv->hw_init = alps_hw_init_ss4_v2; | ||
2622 | priv->process_packet = alps_process_packet_ss4_v2; | ||
2623 | priv->decode_fields = alps_decode_ss4_v2; | ||
2624 | priv->set_abs_params = alps_set_abs_params_ss4_v2; | ||
2625 | priv->nibble_commands = alps_v3_nibble_commands; | ||
2626 | priv->addr_command = PSMOUSE_CMD_RESET_WRAP; | ||
2627 | |||
2628 | if (alps_set_defaults_ss4_v2(psmouse, priv)) | ||
2629 | return -EIO; | ||
2630 | |||
2631 | break; | ||
2326 | } | 2632 | } |
2327 | 2633 | ||
2328 | return 0; | 2634 | return 0; |
@@ -2391,6 +2697,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) | |||
2391 | } else if (ec[0] == 0x88 && ec[1] == 0x07 && | 2697 | } else if (ec[0] == 0x88 && ec[1] == 0x07 && |
2392 | ec[2] >= 0x90 && ec[2] <= 0x9d) { | 2698 | ec[2] >= 0x90 && ec[2] <= 0x9d) { |
2393 | protocol = &alps_v3_protocol_data; | 2699 | protocol = &alps_v3_protocol_data; |
2700 | } else if (e7[0] == 0x73 && e7[1] == 0x03 && | ||
2701 | e7[2] == 0x14 && ec[1] == 0x02) { | ||
2702 | protocol = &alps_v8_protocol_data; | ||
2394 | } else { | 2703 | } else { |
2395 | psmouse_dbg(psmouse, | 2704 | psmouse_dbg(psmouse, |
2396 | "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); | 2705 | "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); |
@@ -2474,6 +2783,20 @@ static void alps_set_abs_params_v7(struct alps_data *priv, | |||
2474 | input_mt_init_slots(dev1, MAX_TOUCHES, | 2783 | input_mt_init_slots(dev1, MAX_TOUCHES, |
2475 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | | 2784 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | |
2476 | INPUT_MT_TRACK); | 2785 | INPUT_MT_TRACK); |
2786 | |||
2787 | set_bit(BTN_TOOL_QUINTTAP, dev1->keybit); | ||
2788 | } | ||
2789 | |||
2790 | static void alps_set_abs_params_ss4_v2(struct alps_data *priv, | ||
2791 | struct input_dev *dev1) | ||
2792 | { | ||
2793 | alps_set_abs_params_mt_common(priv, dev1); | ||
2794 | input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); | ||
2795 | set_bit(BTN_TOOL_QUINTTAP, dev1->keybit); | ||
2796 | |||
2797 | input_mt_init_slots(dev1, MAX_TOUCHES, | ||
2798 | INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | | ||
2799 | INPUT_MT_TRACK); | ||
2477 | } | 2800 | } |
2478 | 2801 | ||
2479 | int alps_init(struct psmouse *psmouse) | 2802 | int alps_init(struct psmouse *psmouse) |