diff options
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r-- | drivers/input/mouse/alps.c | 254 |
1 files changed, 227 insertions, 27 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index b03e7e0b4099..f93c2c0daf1f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> | 5 | * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> |
6 | * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> | 6 | * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> |
7 | * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> | 7 | * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> |
8 | * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net> | ||
8 | * | 9 | * |
9 | * ALPS detection, tap switching and status querying info is taken from | 10 | * ALPS detection, tap switching and status querying info is taken from |
10 | * tpconfig utility (by C. Scott Ananian and Bruce Kall). | 11 | * tpconfig utility (by C. Scott Ananian and Bruce Kall). |
@@ -28,7 +29,6 @@ | |||
28 | #define dbg(format, arg...) do {} while (0) | 29 | #define dbg(format, arg...) do {} while (0) |
29 | #endif | 30 | #endif |
30 | 31 | ||
31 | |||
32 | #define ALPS_OLDPROTO 0x01 /* old style input */ | 32 | #define ALPS_OLDPROTO 0x01 /* old style input */ |
33 | #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ | 33 | #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ |
34 | #define ALPS_PASS 0x04 /* device has a pass-through port */ | 34 | #define ALPS_PASS 0x04 /* device has a pass-through port */ |
@@ -37,7 +37,8 @@ | |||
37 | #define ALPS_FW_BK_1 0x10 /* front & back buttons present */ | 37 | #define ALPS_FW_BK_1 0x10 /* front & back buttons present */ |
38 | #define ALPS_FW_BK_2 0x20 /* front & back buttons present */ | 38 | #define ALPS_FW_BK_2 0x20 /* front & back buttons present */ |
39 | #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ | 39 | #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ |
40 | 40 | #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with | |
41 | 6-byte ALPS packet */ | ||
41 | 42 | ||
42 | static const struct alps_model_info alps_model_data[] = { | 43 | static const struct alps_model_info alps_model_data[] = { |
43 | { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ | 44 | { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ |
@@ -58,7 +59,9 @@ static const struct alps_model_info alps_model_data[] = { | |||
58 | { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ | 59 | { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ |
59 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, | 60 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, |
60 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ | 61 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ |
61 | { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ | 62 | /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ |
63 | { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, | ||
64 | ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, | ||
62 | { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ | 65 | { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ |
63 | }; | 66 | }; |
64 | 67 | ||
@@ -69,20 +72,88 @@ static const struct alps_model_info alps_model_data[] = { | |||
69 | */ | 72 | */ |
70 | 73 | ||
71 | /* | 74 | /* |
72 | * ALPS abolute Mode - new format | 75 | * PS/2 packet format |
76 | * | ||
77 | * byte 0: 0 0 YSGN XSGN 1 M R L | ||
78 | * byte 1: X7 X6 X5 X4 X3 X2 X1 X0 | ||
79 | * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 | ||
80 | * | ||
81 | * Note that the device never signals overflow condition. | ||
82 | * | ||
83 | * ALPS absolute Mode - new format | ||
73 | * | 84 | * |
74 | * byte 0: 1 ? ? ? 1 ? ? ? | 85 | * byte 0: 1 ? ? ? 1 ? ? ? |
75 | * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 | 86 | * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 |
76 | * byte 2: 0 x10 x9 x8 x7 ? fin ges | 87 | * byte 2: 0 x10 x9 x8 x7 ? fin ges |
77 | * byte 3: 0 y9 y8 y7 1 M R L | 88 | * byte 3: 0 y9 y8 y7 1 M R L |
78 | * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 | 89 | * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 |
79 | * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 | 90 | * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 |
80 | * | 91 | * |
92 | * Dualpoint device -- interleaved packet format | ||
93 | * | ||
94 | * byte 0: 1 1 0 0 1 1 1 1 | ||
95 | * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 | ||
96 | * byte 2: 0 x10 x9 x8 x7 0 fin ges | ||
97 | * byte 3: 0 0 YSGN XSGN 1 1 1 1 | ||
98 | * byte 4: X7 X6 X5 X4 X3 X2 X1 X0 | ||
99 | * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 | ||
100 | * byte 6: 0 y9 y8 y7 1 m r l | ||
101 | * byte 7: 0 y6 y5 y4 y3 y2 y1 y0 | ||
102 | * byte 8: 0 z6 z5 z4 z3 z2 z1 z0 | ||
103 | * | ||
104 | * CAPITALS = stick, miniscules = touchpad | ||
105 | * | ||
81 | * ?'s can have different meanings on different models, | 106 | * ?'s can have different meanings on different models, |
82 | * such as wheel rotation, extra buttons, stick buttons | 107 | * such as wheel rotation, extra buttons, stick buttons |
83 | * on a dualpoint, etc. | 108 | * on a dualpoint, etc. |
84 | */ | 109 | */ |
85 | 110 | ||
111 | static bool alps_is_valid_first_byte(const struct alps_model_info *model, | ||
112 | unsigned char data) | ||
113 | { | ||
114 | return (data & model->mask0) == model->byte0; | ||
115 | } | ||
116 | |||
117 | static void alps_report_buttons(struct psmouse *psmouse, | ||
118 | struct input_dev *dev1, struct input_dev *dev2, | ||
119 | int left, int right, int middle) | ||
120 | { | ||
121 | struct alps_data *priv = psmouse->private; | ||
122 | const struct alps_model_info *model = priv->i; | ||
123 | |||
124 | if (model->flags & ALPS_PS2_INTERLEAVED) { | ||
125 | struct input_dev *dev; | ||
126 | |||
127 | /* | ||
128 | * If shared button has already been reported on the | ||
129 | * other device (dev2) then this event should be also | ||
130 | * sent through that device. | ||
131 | */ | ||
132 | dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; | ||
133 | input_report_key(dev, BTN_LEFT, left); | ||
134 | |||
135 | dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; | ||
136 | input_report_key(dev, BTN_RIGHT, right); | ||
137 | |||
138 | dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; | ||
139 | input_report_key(dev, BTN_MIDDLE, middle); | ||
140 | |||
141 | /* | ||
142 | * Sync the _other_ device now, we'll do the first | ||
143 | * device later once we report the rest of the events. | ||
144 | */ | ||
145 | input_sync(dev2); | ||
146 | } else { | ||
147 | /* | ||
148 | * For devices with non-interleaved packets we know what | ||
149 | * device buttons belong to so we can simply report them. | ||
150 | */ | ||
151 | input_report_key(dev1, BTN_LEFT, left); | ||
152 | input_report_key(dev1, BTN_RIGHT, right); | ||
153 | input_report_key(dev1, BTN_MIDDLE, middle); | ||
154 | } | ||
155 | } | ||
156 | |||
86 | static void alps_process_packet(struct psmouse *psmouse) | 157 | static void alps_process_packet(struct psmouse *psmouse) |
87 | { | 158 | { |
88 | struct alps_data *priv = psmouse->private; | 159 | struct alps_data *priv = psmouse->private; |
@@ -93,18 +164,6 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
93 | int x, y, z, ges, fin, left, right, middle; | 164 | int x, y, z, ges, fin, left, right, middle; |
94 | int back = 0, forward = 0; | 165 | int back = 0, forward = 0; |
95 | 166 | ||
96 | if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ | ||
97 | input_report_key(dev2, BTN_LEFT, packet[0] & 1); | ||
98 | input_report_key(dev2, BTN_RIGHT, packet[0] & 2); | ||
99 | input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); | ||
100 | input_report_rel(dev2, REL_X, | ||
101 | packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); | ||
102 | input_report_rel(dev2, REL_Y, | ||
103 | packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); | ||
104 | input_sync(dev2); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | if (model->flags & ALPS_OLDPROTO) { | 167 | if (model->flags & ALPS_OLDPROTO) { |
109 | left = packet[2] & 0x10; | 168 | left = packet[2] & 0x10; |
110 | right = packet[2] & 0x08; | 169 | right = packet[2] & 0x08; |
@@ -140,18 +199,13 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
140 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); | 199 | input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); |
141 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); | 200 | input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); |
142 | 201 | ||
143 | input_report_key(dev2, BTN_LEFT, left); | 202 | alps_report_buttons(psmouse, dev2, dev, left, right, middle); |
144 | input_report_key(dev2, BTN_RIGHT, right); | ||
145 | input_report_key(dev2, BTN_MIDDLE, middle); | ||
146 | 203 | ||
147 | input_sync(dev); | ||
148 | input_sync(dev2); | 204 | input_sync(dev2); |
149 | return; | 205 | return; |
150 | } | 206 | } |
151 | 207 | ||
152 | input_report_key(dev, BTN_LEFT, left); | 208 | alps_report_buttons(psmouse, dev, dev2, left, right, middle); |
153 | input_report_key(dev, BTN_RIGHT, right); | ||
154 | input_report_key(dev, BTN_MIDDLE, middle); | ||
155 | 209 | ||
156 | /* Convert hardware tap to a reasonable Z value */ | 210 | /* Convert hardware tap to a reasonable Z value */ |
157 | if (ges && !fin) | 211 | if (ges && !fin) |
@@ -202,25 +256,168 @@ static void alps_process_packet(struct psmouse *psmouse) | |||
202 | input_sync(dev); | 256 | input_sync(dev); |
203 | } | 257 | } |
204 | 258 | ||
259 | static void alps_report_bare_ps2_packet(struct psmouse *psmouse, | ||
260 | unsigned char packet[], | ||
261 | bool report_buttons) | ||
262 | { | ||
263 | struct alps_data *priv = psmouse->private; | ||
264 | struct input_dev *dev2 = priv->dev2; | ||
265 | |||
266 | if (report_buttons) | ||
267 | alps_report_buttons(psmouse, dev2, psmouse->dev, | ||
268 | packet[0] & 1, packet[0] & 2, packet[0] & 4); | ||
269 | |||
270 | input_report_rel(dev2, REL_X, | ||
271 | packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); | ||
272 | input_report_rel(dev2, REL_Y, | ||
273 | packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); | ||
274 | |||
275 | input_sync(dev2); | ||
276 | } | ||
277 | |||
278 | static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) | ||
279 | { | ||
280 | struct alps_data *priv = psmouse->private; | ||
281 | |||
282 | if (psmouse->pktcnt < 6) | ||
283 | return PSMOUSE_GOOD_DATA; | ||
284 | |||
285 | if (psmouse->pktcnt == 6) { | ||
286 | /* | ||
287 | * Start a timer to flush the packet if it ends up last | ||
288 | * 6-byte packet in the stream. Timer needs to fire | ||
289 | * psmouse core times out itself. 20 ms should be enough | ||
290 | * to decide if we are getting more data or not. | ||
291 | */ | ||
292 | mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); | ||
293 | return PSMOUSE_GOOD_DATA; | ||
294 | } | ||
295 | |||
296 | del_timer(&priv->timer); | ||
297 | |||
298 | if (psmouse->packet[6] & 0x80) { | ||
299 | |||
300 | /* | ||
301 | * Highest bit is set - that means we either had | ||
302 | * complete ALPS packet and this is start of the | ||
303 | * next packet or we got garbage. | ||
304 | */ | ||
305 | |||
306 | if (((psmouse->packet[3] | | ||
307 | psmouse->packet[4] | | ||
308 | psmouse->packet[5]) & 0x80) || | ||
309 | (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { | ||
310 | dbg("refusing packet %x %x %x %x " | ||
311 | "(suspected interleaved ps/2)\n", | ||
312 | psmouse->packet[3], psmouse->packet[4], | ||
313 | psmouse->packet[5], psmouse->packet[6]); | ||
314 | return PSMOUSE_BAD_DATA; | ||
315 | } | ||
316 | |||
317 | alps_process_packet(psmouse); | ||
318 | |||
319 | /* Continue with the next packet */ | ||
320 | psmouse->packet[0] = psmouse->packet[6]; | ||
321 | psmouse->pktcnt = 1; | ||
322 | |||
323 | } else { | ||
324 | |||
325 | /* | ||
326 | * High bit is 0 - that means that we indeed got a PS/2 | ||
327 | * packet in the middle of ALPS packet. | ||
328 | * | ||
329 | * There is also possibility that we got 6-byte ALPS | ||
330 | * packet followed by 3-byte packet from trackpoint. We | ||
331 | * can not distinguish between these 2 scenarios but | ||
332 | * becase the latter is unlikely to happen in course of | ||
333 | * normal operation (user would need to press all | ||
334 | * buttons on the pad and start moving trackpoint | ||
335 | * without touching the pad surface) we assume former. | ||
336 | * Even if we are wrong the wost thing that would happen | ||
337 | * the cursor would jump but we should not get protocol | ||
338 | * desynchronization. | ||
339 | */ | ||
340 | |||
341 | alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], | ||
342 | false); | ||
343 | |||
344 | /* | ||
345 | * Continue with the standard ALPS protocol handling, | ||
346 | * but make sure we won't process it as an interleaved | ||
347 | * packet again, which may happen if all buttons are | ||
348 | * pressed. To avoid this let's reset the 4th bit which | ||
349 | * is normally 1. | ||
350 | */ | ||
351 | psmouse->packet[3] = psmouse->packet[6] & 0xf7; | ||
352 | psmouse->pktcnt = 4; | ||
353 | } | ||
354 | |||
355 | return PSMOUSE_GOOD_DATA; | ||
356 | } | ||
357 | |||
358 | static void alps_flush_packet(unsigned long data) | ||
359 | { | ||
360 | struct psmouse *psmouse = (struct psmouse *)data; | ||
361 | |||
362 | serio_pause_rx(psmouse->ps2dev.serio); | ||
363 | |||
364 | if (psmouse->pktcnt == 6) { | ||
365 | |||
366 | /* | ||
367 | * We did not any more data in reasonable amount of time. | ||
368 | * Validate the last 3 bytes and process as a standard | ||
369 | * ALPS packet. | ||
370 | */ | ||
371 | if ((psmouse->packet[3] | | ||
372 | psmouse->packet[4] | | ||
373 | psmouse->packet[5]) & 0x80) { | ||
374 | dbg("refusing packet %x %x %x " | ||
375 | "(suspected interleaved ps/2)\n", | ||
376 | psmouse->packet[3], psmouse->packet[4], | ||
377 | psmouse->packet[5]); | ||
378 | } else { | ||
379 | alps_process_packet(psmouse); | ||
380 | } | ||
381 | psmouse->pktcnt = 0; | ||
382 | } | ||
383 | |||
384 | serio_continue_rx(psmouse->ps2dev.serio); | ||
385 | } | ||
386 | |||
205 | static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) | 387 | static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) |
206 | { | 388 | { |
207 | struct alps_data *priv = psmouse->private; | 389 | struct alps_data *priv = psmouse->private; |
390 | const struct alps_model_info *model = priv->i; | ||
208 | 391 | ||
209 | if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ | 392 | if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ |
210 | if (psmouse->pktcnt == 3) { | 393 | if (psmouse->pktcnt == 3) { |
211 | alps_process_packet(psmouse); | 394 | alps_report_bare_ps2_packet(psmouse, psmouse->packet, |
395 | true); | ||
212 | return PSMOUSE_FULL_PACKET; | 396 | return PSMOUSE_FULL_PACKET; |
213 | } | 397 | } |
214 | return PSMOUSE_GOOD_DATA; | 398 | return PSMOUSE_GOOD_DATA; |
215 | } | 399 | } |
216 | 400 | ||
217 | if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0) | 401 | /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ |
402 | |||
403 | if ((model->flags & ALPS_PS2_INTERLEAVED) && | ||
404 | psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { | ||
405 | return alps_handle_interleaved_ps2(psmouse); | ||
406 | } | ||
407 | |||
408 | if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { | ||
409 | dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", | ||
410 | psmouse->packet[0], model->mask0, model->byte0); | ||
218 | return PSMOUSE_BAD_DATA; | 411 | return PSMOUSE_BAD_DATA; |
412 | } | ||
219 | 413 | ||
220 | /* Bytes 2 - 6 should have 0 in the highest bit */ | 414 | /* Bytes 2 - 6 should have 0 in the highest bit */ |
221 | if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && | 415 | if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && |
222 | (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) | 416 | (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { |
417 | dbg("refusing packet[%i] = %x\n", | ||
418 | psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); | ||
223 | return PSMOUSE_BAD_DATA; | 419 | return PSMOUSE_BAD_DATA; |
420 | } | ||
224 | 421 | ||
225 | if (psmouse->pktcnt == 6) { | 422 | if (psmouse->pktcnt == 6) { |
226 | alps_process_packet(psmouse); | 423 | alps_process_packet(psmouse); |
@@ -459,6 +656,7 @@ static void alps_disconnect(struct psmouse *psmouse) | |||
459 | struct alps_data *priv = psmouse->private; | 656 | struct alps_data *priv = psmouse->private; |
460 | 657 | ||
461 | psmouse_reset(psmouse); | 658 | psmouse_reset(psmouse); |
659 | del_timer_sync(&priv->timer); | ||
462 | input_unregister_device(priv->dev2); | 660 | input_unregister_device(priv->dev2); |
463 | kfree(priv); | 661 | kfree(priv); |
464 | } | 662 | } |
@@ -476,6 +674,8 @@ int alps_init(struct psmouse *psmouse) | |||
476 | goto init_fail; | 674 | goto init_fail; |
477 | 675 | ||
478 | priv->dev2 = dev2; | 676 | priv->dev2 = dev2; |
677 | setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); | ||
678 | |||
479 | psmouse->private = priv; | 679 | psmouse->private = priv; |
480 | 680 | ||
481 | model = alps_get_model(psmouse, &version); | 681 | model = alps_get_model(psmouse, &version); |