diff options
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r-- | drivers/input/mouse/alps.c | 87 |
1 files changed, 75 insertions, 12 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 936f07a4e35f..6d7de9bfed9a 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -103,6 +103,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { | |||
103 | 6-byte ALPS packet */ | 103 | 6-byte ALPS packet */ |
104 | #define ALPS_STICK_BITS 0x100 /* separate stick button bits */ | 104 | #define ALPS_STICK_BITS 0x100 /* separate stick button bits */ |
105 | #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ | 105 | #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ |
106 | #define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ | ||
106 | 107 | ||
107 | static const struct alps_model_info alps_model_data[] = { | 108 | static const struct alps_model_info alps_model_data[] = { |
108 | { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ | 109 | { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ |
@@ -1156,15 +1157,28 @@ static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte) | |||
1156 | { | 1157 | { |
1157 | unsigned char pkt_id = SS4_PACKET_ID_IDLE; | 1158 | unsigned char pkt_id = SS4_PACKET_ID_IDLE; |
1158 | 1159 | ||
1159 | if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && | 1160 | switch (byte[3] & 0x30) { |
1160 | (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) { | 1161 | case 0x00: |
1161 | pkt_id = SS4_PACKET_ID_IDLE; | 1162 | if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && |
1162 | } else if (!(byte[3] & 0x10)) { | 1163 | (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && |
1163 | pkt_id = SS4_PACKET_ID_ONE; | 1164 | byte[5] == 0x00) { |
1164 | } else if (!(byte[3] & 0x20)) { | 1165 | pkt_id = SS4_PACKET_ID_IDLE; |
1166 | } else { | ||
1167 | pkt_id = SS4_PACKET_ID_ONE; | ||
1168 | } | ||
1169 | break; | ||
1170 | case 0x10: | ||
1171 | /* two-finger finger positions */ | ||
1165 | pkt_id = SS4_PACKET_ID_TWO; | 1172 | pkt_id = SS4_PACKET_ID_TWO; |
1166 | } else { | 1173 | break; |
1174 | case 0x20: | ||
1175 | /* stick pointer */ | ||
1176 | pkt_id = SS4_PACKET_ID_STICK; | ||
1177 | break; | ||
1178 | case 0x30: | ||
1179 | /* third and fourth finger positions */ | ||
1167 | pkt_id = SS4_PACKET_ID_MULTI; | 1180 | pkt_id = SS4_PACKET_ID_MULTI; |
1181 | break; | ||
1168 | } | 1182 | } |
1169 | 1183 | ||
1170 | return pkt_id; | 1184 | return pkt_id; |
@@ -1185,7 +1199,13 @@ static int alps_decode_ss4_v2(struct alps_fields *f, | |||
1185 | f->mt[0].x = SS4_1F_X_V2(p); | 1199 | f->mt[0].x = SS4_1F_X_V2(p); |
1186 | f->mt[0].y = SS4_1F_Y_V2(p); | 1200 | f->mt[0].y = SS4_1F_Y_V2(p); |
1187 | f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; | 1201 | f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; |
1188 | f->fingers = 1; | 1202 | /* |
1203 | * When a button is held the device will give us events | ||
1204 | * with x, y, and pressure of 0. This causes annoying jumps | ||
1205 | * if a touch is released while the button is held. | ||
1206 | * Handle this by claiming zero contacts. | ||
1207 | */ | ||
1208 | f->fingers = f->pressure > 0 ? 1 : 0; | ||
1189 | f->first_mp = 0; | 1209 | f->first_mp = 0; |
1190 | f->is_mp = 0; | 1210 | f->is_mp = 0; |
1191 | break; | 1211 | break; |
@@ -1246,16 +1266,40 @@ static int alps_decode_ss4_v2(struct alps_fields *f, | |||
1246 | } | 1266 | } |
1247 | break; | 1267 | break; |
1248 | 1268 | ||
1269 | case SS4_PACKET_ID_STICK: | ||
1270 | if (!(priv->flags & ALPS_DUALPOINT)) { | ||
1271 | psmouse_warn(psmouse, | ||
1272 | "Rejected trackstick packet from non DualPoint device"); | ||
1273 | } else { | ||
1274 | int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f)); | ||
1275 | int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f)); | ||
1276 | int pressure = (s8)(p[4] & 0x7f); | ||
1277 | |||
1278 | input_report_rel(priv->dev2, REL_X, x); | ||
1279 | input_report_rel(priv->dev2, REL_Y, -y); | ||
1280 | input_report_abs(priv->dev2, ABS_PRESSURE, pressure); | ||
1281 | } | ||
1282 | break; | ||
1283 | |||
1249 | case SS4_PACKET_ID_IDLE: | 1284 | case SS4_PACKET_ID_IDLE: |
1250 | default: | 1285 | default: |
1251 | memset(f, 0, sizeof(struct alps_fields)); | 1286 | memset(f, 0, sizeof(struct alps_fields)); |
1252 | break; | 1287 | break; |
1253 | } | 1288 | } |
1254 | 1289 | ||
1255 | f->left = !!(SS4_BTN_V2(p) & 0x01); | 1290 | /* handle buttons */ |
1256 | if (!(priv->flags & ALPS_BUTTONPAD)) { | 1291 | if (pkt_id == SS4_PACKET_ID_STICK) { |
1257 | f->right = !!(SS4_BTN_V2(p) & 0x02); | 1292 | f->ts_left = !!(SS4_BTN_V2(p) & 0x01); |
1258 | f->middle = !!(SS4_BTN_V2(p) & 0x04); | 1293 | if (!(priv->flags & ALPS_BUTTONPAD)) { |
1294 | f->ts_right = !!(SS4_BTN_V2(p) & 0x02); | ||
1295 | f->ts_middle = !!(SS4_BTN_V2(p) & 0x04); | ||
1296 | } | ||
1297 | } else { | ||
1298 | f->left = !!(SS4_BTN_V2(p) & 0x01); | ||
1299 | if (!(priv->flags & ALPS_BUTTONPAD)) { | ||
1300 | f->right = !!(SS4_BTN_V2(p) & 0x02); | ||
1301 | f->middle = !!(SS4_BTN_V2(p) & 0x04); | ||
1302 | } | ||
1259 | } | 1303 | } |
1260 | 1304 | ||
1261 | return 0; | 1305 | return 0; |
@@ -1266,6 +1310,7 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) | |||
1266 | struct alps_data *priv = psmouse->private; | 1310 | struct alps_data *priv = psmouse->private; |
1267 | unsigned char *packet = psmouse->packet; | 1311 | unsigned char *packet = psmouse->packet; |
1268 | struct input_dev *dev = psmouse->dev; | 1312 | struct input_dev *dev = psmouse->dev; |
1313 | struct input_dev *dev2 = priv->dev2; | ||
1269 | struct alps_fields *f = &priv->f; | 1314 | struct alps_fields *f = &priv->f; |
1270 | 1315 | ||
1271 | memset(f, 0, sizeof(struct alps_fields)); | 1316 | memset(f, 0, sizeof(struct alps_fields)); |
@@ -1311,6 +1356,13 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) | |||
1311 | 1356 | ||
1312 | input_report_abs(dev, ABS_PRESSURE, f->pressure); | 1357 | input_report_abs(dev, ABS_PRESSURE, f->pressure); |
1313 | input_sync(dev); | 1358 | input_sync(dev); |
1359 | |||
1360 | if (priv->flags & ALPS_DUALPOINT) { | ||
1361 | input_report_key(dev2, BTN_LEFT, f->ts_left); | ||
1362 | input_report_key(dev2, BTN_RIGHT, f->ts_right); | ||
1363 | input_report_key(dev2, BTN_MIDDLE, f->ts_middle); | ||
1364 | input_sync(dev2); | ||
1365 | } | ||
1314 | } | 1366 | } |
1315 | 1367 | ||
1316 | static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) | 1368 | static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) |
@@ -2695,6 +2747,10 @@ static int alps_set_protocol(struct psmouse *psmouse, | |||
2695 | if (alps_set_defaults_ss4_v2(psmouse, priv)) | 2747 | if (alps_set_defaults_ss4_v2(psmouse, priv)) |
2696 | return -EIO; | 2748 | return -EIO; |
2697 | 2749 | ||
2750 | if (priv->fw_ver[1] == 0x1) | ||
2751 | priv->flags |= ALPS_DUALPOINT | | ||
2752 | ALPS_DUALPOINT_WITH_PRESSURE; | ||
2753 | |||
2698 | break; | 2754 | break; |
2699 | } | 2755 | } |
2700 | 2756 | ||
@@ -2767,6 +2823,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) | |||
2767 | } else if (e7[0] == 0x73 && e7[1] == 0x03 && | 2823 | } else if (e7[0] == 0x73 && e7[1] == 0x03 && |
2768 | e7[2] == 0x14 && ec[1] == 0x02) { | 2824 | e7[2] == 0x14 && ec[1] == 0x02) { |
2769 | protocol = &alps_v8_protocol_data; | 2825 | protocol = &alps_v8_protocol_data; |
2826 | } else if (e7[0] == 0x73 && e7[1] == 0x03 && | ||
2827 | e7[2] == 0x28 && ec[1] == 0x01) { | ||
2828 | protocol = &alps_v8_protocol_data; | ||
2770 | } else { | 2829 | } else { |
2771 | psmouse_dbg(psmouse, | 2830 | psmouse_dbg(psmouse, |
2772 | "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); | 2831 | "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); |
@@ -2949,6 +3008,10 @@ int alps_init(struct psmouse *psmouse) | |||
2949 | 3008 | ||
2950 | input_set_capability(dev2, EV_REL, REL_X); | 3009 | input_set_capability(dev2, EV_REL, REL_X); |
2951 | input_set_capability(dev2, EV_REL, REL_Y); | 3010 | input_set_capability(dev2, EV_REL, REL_Y); |
3011 | if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) { | ||
3012 | input_set_capability(dev2, EV_ABS, ABS_PRESSURE); | ||
3013 | input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0); | ||
3014 | } | ||
2952 | input_set_capability(dev2, EV_KEY, BTN_LEFT); | 3015 | input_set_capability(dev2, EV_KEY, BTN_LEFT); |
2953 | input_set_capability(dev2, EV_KEY, BTN_RIGHT); | 3016 | input_set_capability(dev2, EV_KEY, BTN_RIGHT); |
2954 | input_set_capability(dev2, EV_KEY, BTN_MIDDLE); | 3017 | input_set_capability(dev2, EV_KEY, BTN_MIDDLE); |