aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/alps.c
diff options
context:
space:
mode:
authorMasaki Ota <masaki.ota@jp.alps.com>2015-03-27 23:57:52 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-04-07 11:47:42 -0400
commit3db5b9f782b50a309fe0fb89fb890f6b4f66d9ae (patch)
treefee92348b2bd33e686c54d956efefe286f73f67f /drivers/input/mouse/alps.c
parent8eccd39340adb502ac7131552e8a4a2f35c35e06 (diff)
Input: ALPS - add support for SS4 touchpad devices
This change adds support for SS4 touchpad devices as ALPS_PROTO_V8 protocol. They are real multi-touch devices and can be found in TOSHIBA Tecra C50. Signed-off-by: Masaki Ota <masaki.ota@jp.alps.com> Acked-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r--drivers/input/mouse/alps.c329
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
156static const struct alps_protocol_info alps_v8_protocol_data = {
157 ALPS_PROTO_V8, 0x18, 0x18, 0
158};
159
156static void alps_set_abs_params_st(struct alps_data *priv, 160static void alps_set_abs_params_st(struct alps_data *priv,
157 struct input_dev *dev1); 161 struct input_dev *dev1);
158static void alps_set_abs_params_mt(struct alps_data *priv, 162static void alps_set_abs_params_mt(struct alps_data *priv,
159 struct input_dev *dev1); 163 struct input_dev *dev1);
160static void alps_set_abs_params_v7(struct alps_data *priv, 164static void alps_set_abs_params_v7(struct alps_data *priv,
161 struct input_dev *dev1); 165 struct input_dev *dev1);
166static 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
1096unsigned 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
1114static 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
1205static 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
1257static 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
1090static DEFINE_MUTEX(alps_mutex); 1266static DEFINE_MUTEX(alps_mutex);
1091 1267
1092static void alps_register_bare_ps2_mouse(struct work_struct *work) 1268static 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
2317static 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
2343int 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
2368int 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
2381static 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
2135static int alps_dolphin_get_device_area(struct psmouse *psmouse, 2399static 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
2491static 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, &param[0], PSMOUSE_CMD_SETRATE) ||
2501 ps2_command(ps2dev, &param[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
2515error:
2516 alps_exit_command_mode(psmouse);
2517 return ret;
2518}
2519
2227static int alps_set_protocol(struct psmouse *psmouse, 2520static 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
2790static 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
2479int alps_init(struct psmouse *psmouse) 2802int alps_init(struct psmouse *psmouse)