2 * ALPS touchpad PS/2 mouse driver
4 * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
5 * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
6 * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
8 * ALPS detection, tap switching and status querying info is taken from
9 * tpconfig utility (by C. Scott Ananian and Bruce Kall).
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 as published by
13 * the Free Software Foundation.
16 #include <linux/input.h>
17 #include <linux/serio.h>
18 #include <linux/libps2.h>
25 #define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
27 #define dbg(format, arg...) do {} while (0)
30 #define ALPS_MODEL_GLIDEPOINT 1
31 #define ALPS_MODEL_DUALPOINT 2
33 struct alps_model_info {
34 unsigned char signature[3];
36 } alps_model_data[] = {
37 /* { { 0x33, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT }, */
38 { { 0x53, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
39 { { 0x53, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
40 { { 0x63, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
41 { { 0x63, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
42 { { 0x73, 0x02, 0x0a }, ALPS_MODEL_GLIDEPOINT },
43 { { 0x73, 0x02, 0x14 }, ALPS_MODEL_GLIDEPOINT },
44 { { 0x63, 0x02, 0x28 }, ALPS_MODEL_GLIDEPOINT },
45 /* { { 0x63, 0x02, 0x3c }, ALPS_MODEL_GLIDEPOINT }, */
46 /* { { 0x63, 0x02, 0x50 }, ALPS_MODEL_GLIDEPOINT }, */
47 { { 0x63, 0x02, 0x64 }, ALPS_MODEL_GLIDEPOINT },
48 { { 0x20, 0x02, 0x0e }, ALPS_MODEL_DUALPOINT },
49 { { 0x22, 0x02, 0x0a }, ALPS_MODEL_DUALPOINT },
50 { { 0x22, 0x02, 0x14 }, ALPS_MODEL_DUALPOINT },
51 { { 0x63, 0x03, 0xc8 }, ALPS_MODEL_DUALPOINT },
56 * byte 0: 1 1 1 1 1 mid0 rig0 lef0
57 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
58 * byte 2: 0 x10 x9 x8 x7 up1 fin ges
59 * byte 3: 0 y9 y8 y7 1 mid1 rig1 lef1
60 * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
61 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
63 * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad.
64 * We just 'or' them together for now.
66 * We used to send 'ges'tures as BTN_TOUCH but this made it impossible
67 * to disable tap events in the synaptics driver since the driver
68 * was unable to distinguish a gesture tap from an actual button click.
69 * A tap gesture now creates an emulated touch that the synaptics
70 * driver can interpret as a tap event, if MaxTapTime=0 and
71 * MaxTapMove=0 then the driver will ignore taps.
73 * The touchpad on an 'Acer Aspire' has 4 buttons:
75 * This device always sets {mid,rig,lef}0 to 1 and
76 * reflects left,right,down,up in lef1,rig1,mid1,up1.
79 static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
81 unsigned char *packet = psmouse->packet;
82 struct input_dev *dev = &psmouse->dev;
84 int left = 0, right = 0, middle = 0;
86 input_regs(dev, regs);
88 if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
95 left = (packet[0] ) & 1;
96 right = (packet[0] >> 1) & 1;
98 input_report_rel(dev, REL_X, x);
99 input_report_rel(dev, REL_Y, -y);
100 input_report_key(dev, BTN_A, left);
101 input_report_key(dev, BTN_B, right);
106 x = (packet[1] & 0x7f) | ((packet[2] & 0x78)<<(7-3));
107 y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4));
110 if (z == 127) { /* DualPoint stick is relative, not absolute */
115 left = packet[3] & 1;
116 right = (packet[3] >> 1) & 1;
118 input_report_rel(dev, REL_X, x);
119 input_report_rel(dev, REL_Y, -y);
120 input_report_key(dev, BTN_LEFT, left);
121 input_report_key(dev, BTN_RIGHT, right);
126 if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
127 if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
130 input_report_abs(dev, ABS_X, x);
131 input_report_abs(dev, ABS_Y, y);
133 input_report_abs(dev, ABS_PRESSURE, z);
134 input_report_key(dev, BTN_TOOL_FINGER, z > 0);
136 left |= (packet[2] ) & 1;
137 left |= (packet[3] ) & 1;
138 right |= (packet[3] >> 1) & 1;
139 if (packet[0] == 0xff) {
140 int back = (packet[3] >> 2) & 1;
141 int forward = (packet[2] >> 2) & 1;
142 if (back && forward) {
147 input_report_key(dev, BTN_BACK, back);
148 input_report_key(dev, BTN_FORWARD, forward);
150 left |= (packet[0] ) & 1;
151 right |= (packet[0] >> 1) & 1;
152 middle |= (packet[0] >> 2) & 1;
153 middle |= (packet[3] >> 2) & 1;
156 input_report_key(dev, BTN_LEFT, left);
157 input_report_key(dev, BTN_RIGHT, right);
158 input_report_key(dev, BTN_MIDDLE, middle);
163 static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
165 if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
166 if (psmouse->pktcnt == 3) {
167 alps_process_packet(psmouse, regs);
168 return PSMOUSE_FULL_PACKET;
170 return PSMOUSE_GOOD_DATA;
173 /* ALPS absolute mode packets start with 0b11111mrl */
174 if ((psmouse->packet[0] & 0xf8) != 0xf8)
175 return PSMOUSE_BAD_DATA;
177 /* Bytes 2 - 6 should have 0 in the highest bit */
178 if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
179 (psmouse->packet[psmouse->pktcnt-1] & 0x80))
180 return PSMOUSE_BAD_DATA;
182 if (psmouse->pktcnt == 6) {
183 alps_process_packet(psmouse, regs);
184 return PSMOUSE_FULL_PACKET;
187 return PSMOUSE_GOOD_DATA;
190 int alps_get_model(struct psmouse *psmouse)
192 struct ps2dev *ps2dev = &psmouse->ps2dev;
193 unsigned char param[4];
197 * First try "E6 report".
198 * ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
201 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
202 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
203 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
204 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
207 param[0] = param[1] = param[2] = 0xff;
208 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
211 dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
213 if (param[0] != 0x00 || param[1] != 0x00 || (param[2] != 0x0a && param[2] != 0x64))
216 /* Now try "E7 report". ALPS should return 0x33 in byte 1 */
218 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
219 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
220 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
221 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
224 param[0] = param[1] = param[2] = 0xff;
225 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
228 dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
230 for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
231 if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature)))
232 return alps_model_data[i].model;
238 * For DualPoint devices select the device that should respond to
239 * subsequent commands. It looks like glidepad is behind stickpointer,
240 * I'd thought it would be other way around...
242 static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
244 struct ps2dev *ps2dev = &psmouse->ps2dev;
245 unsigned char param[3];
246 int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
248 if (ps2_command(ps2dev, NULL, cmd) ||
249 ps2_command(ps2dev, NULL, cmd) ||
250 ps2_command(ps2dev, NULL, cmd) ||
251 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
254 /* we may get 3 more bytes, just ignore them */
255 ps2_command(ps2dev, param, 0x0300);
260 static int alps_absolute_mode(struct psmouse *psmouse)
262 struct ps2dev *ps2dev = &psmouse->ps2dev;
264 /* Try ALPS magic knock - 4 disable before enable */
265 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
266 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
267 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
268 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
269 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
273 * Switch mouse to poll (remote) mode so motion data will not
276 return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
279 static int alps_get_status(struct psmouse *psmouse, char *param)
281 struct ps2dev *ps2dev = &psmouse->ps2dev;
283 /* Get status: 0xF5 0xF5 0xF5 0xE9 */
284 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
285 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
286 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
287 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
290 dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
296 * Turn touchpad tapping on or off. The sequences are:
297 * 0xE9 0xF5 0xF5 0xF3 0x0A to enable,
298 * 0xE9 0xF5 0xF5 0xE8 0x00 to disable.
299 * My guess that 0xE9 (GetInfo) is here as a sync point.
300 * For models that also have stickpointer (DualPoints) its tapping
301 * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but
302 * we don't fiddle with it.
304 static int alps_tap_mode(struct psmouse *psmouse, int enable)
306 struct ps2dev *ps2dev = &psmouse->ps2dev;
307 int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
308 unsigned char tap_arg = enable ? 0x0A : 0x00;
309 unsigned char param[4];
311 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
312 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
313 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
314 ps2_command(ps2dev, &tap_arg, cmd))
317 if (alps_get_status(psmouse, param))
323 static int alps_reconnect(struct psmouse *psmouse)
326 unsigned char param[4];
328 if ((model = alps_get_model(psmouse)) < 0)
331 if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
334 if (alps_get_status(psmouse, param))
338 alps_tap_mode(psmouse, 0);
340 if (alps_absolute_mode(psmouse)) {
341 printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
345 if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
351 static void alps_disconnect(struct psmouse *psmouse)
353 psmouse_reset(psmouse);
356 int alps_init(struct psmouse *psmouse)
358 unsigned char param[4];
361 if ((model = alps_get_model(psmouse)) < 0)
364 printk(KERN_INFO "ALPS Touchpad (%s) detected\n",
365 model == ALPS_MODEL_GLIDEPOINT ? "Glidepoint" : "Dualpoint");
367 if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
370 if (alps_get_status(psmouse, param)) {
371 printk(KERN_ERR "alps.c: touchpad status report request failed\n");
375 if (param[0] & 0x04) {
376 printk(KERN_INFO " Disabling hardware tapping\n");
377 if (alps_tap_mode(psmouse, 0))
378 printk(KERN_WARNING "alps.c: Failed to disable hardware tapping\n");
381 if (alps_absolute_mode(psmouse)) {
382 printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
386 if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
389 psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
390 psmouse->dev.relbit[LONG(REL_X)] |= BIT(REL_X);
391 psmouse->dev.relbit[LONG(REL_Y)] |= BIT(REL_Y);
392 psmouse->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A);
393 psmouse->dev.keybit[LONG(BTN_B)] |= BIT(BTN_B);
395 psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
396 input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0);
397 input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1023, 0, 0);
398 input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
400 psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
401 psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
402 psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
403 psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
405 psmouse->protocol_handler = alps_process_byte;
406 psmouse->disconnect = alps_disconnect;
407 psmouse->reconnect = alps_reconnect;
408 psmouse->pktsize = 6;
413 int alps_detect(struct psmouse *psmouse, int set_properties)
415 if (alps_get_model(psmouse) < 0)
418 if (set_properties) {
419 psmouse->vendor = "ALPS";
420 psmouse->name = "TouchPad";