aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/alps.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r--drivers/input/mouse/alps.c87
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
107static const struct alps_model_info alps_model_data[] = { 108static 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
1316static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) 1368static 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);