aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/mouse
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/Kconfig138
-rw-r--r--drivers/input/mouse/Makefile18
-rw-r--r--drivers/input/mouse/alps.c477
-rw-r--r--drivers/input/mouse/alps.h32
-rw-r--r--drivers/input/mouse/amimouse.c137
-rw-r--r--drivers/input/mouse/hil_ptr.c414
-rw-r--r--drivers/input/mouse/inport.c196
-rw-r--r--drivers/input/mouse/logibm.c183
-rw-r--r--drivers/input/mouse/logips2pp.c397
-rw-r--r--drivers/input/mouse/logips2pp.h16
-rw-r--r--drivers/input/mouse/maplemouse.c134
-rw-r--r--drivers/input/mouse/pc110pad.c178
-rw-r--r--drivers/input/mouse/psmouse-base.c1011
-rw-r--r--drivers/input/mouse/psmouse.h106
-rw-r--r--drivers/input/mouse/rpcmouse.c107
-rw-r--r--drivers/input/mouse/sermouse.c370
-rw-r--r--drivers/input/mouse/synaptics.c700
-rw-r--r--drivers/input/mouse/synaptics.h110
-rw-r--r--drivers/input/mouse/vsxxxaa.c591
19 files changed, 5315 insertions, 0 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
new file mode 100644
index 000000000000..537154dd7a87
--- /dev/null
+++ b/drivers/input/mouse/Kconfig
@@ -0,0 +1,138 @@
1#
2# Mouse driver configuration
3#
4menuconfig INPUT_MOUSE
5 bool "Mouse"
6 default y
7 help
8 Say Y here, and a list of supported mice will be displayed.
9 This option doesn't affect the kernel.
10
11 If unsure, say Y.
12
13if INPUT_MOUSE
14
15config MOUSE_PS2
16 tristate "PS/2 mouse"
17 default y
18 select SERIO
19 select SERIO_LIBPS2
20 select SERIO_I8042 if PC
21 select SERIO_GSCPS2 if GSC
22 ---help---
23 Say Y here if you have a PS/2 mouse connected to your system. This
24 includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
25 mice with wheels and extra buttons, Microsoft, Logitech or Genius
26 compatible.
27
28 Synaptics TouchPad users might be interested in a specialized
29 XFree86 driver at:
30 <http://w1.894.telia.com/~u89404340/touchpad/index.html>
31 and a new version of GPM at:
32 <http://www.geocities.com/dt_or/gpm/gpm.html>
33 to take advantage of the advanced features of the touchpad.
34
35 If unsure, say Y.
36
37 To compile this driver as a module, choose M here: the
38 module will be called psmouse.
39
40config MOUSE_SERIAL
41 tristate "Serial mouse"
42 select SERIO
43 ---help---
44 Say Y here if you have a serial (RS-232, COM port) mouse connected
45 to your system. This includes Sun, MouseSystems, Microsoft,
46 Logitech and all other compatible serial mice.
47
48 If unsure, say N.
49
50 To compile this driver as a module, choose M here: the
51 module will be called sermouse.
52
53config MOUSE_INPORT
54 tristate "InPort/MS/ATIXL busmouse"
55 depends on ISA
56 help
57 Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
58 They are rather rare these days.
59
60 To compile this driver as a module, choose M here: the
61 module will be called inport.
62
63config MOUSE_ATIXL
64 bool "ATI XL variant"
65 depends on MOUSE_INPORT
66 help
67 Say Y here if your mouse is of the ATI XL variety.
68
69config MOUSE_LOGIBM
70 tristate "Logitech busmouse"
71 depends on ISA
72 help
73 Say Y here if you have a Logitech busmouse.
74 They are rather rare these days.
75
76 To compile this driver as a module, choose M here: the
77 module will be called logibm.
78
79config MOUSE_PC110PAD
80 tristate "IBM PC110 touchpad"
81 depends on ISA
82 help
83 Say Y if you have the IBM PC-110 micro-notebook and want its
84 touchpad supported.
85
86 To compile this driver as a module, choose M here: the
87 module will be called pc110pad.
88
89config MOUSE_MAPLE
90 tristate "Maple bus mouse"
91 depends on SH_DREAMCAST && MAPLE
92 help
93 Say Y if you have a DreamCast console and a mouse attached to
94 its Maple bus.
95
96 To compile this driver as a module, choose M here: the
97 module will be called maplemouse.
98
99config MOUSE_AMIGA
100 tristate "Amiga mouse"
101 depends on AMIGA
102 help
103 Say Y here if you have an Amiga and want its native mouse
104 supported by the kernel.
105
106 To compile this driver as a module, choose M here: the
107 module will be called amimouse.
108
109config MOUSE_RISCPC
110 tristate "Acorn RiscPC mouse"
111 depends on ARCH_ACORN
112 help
113 Say Y here if you have the Acorn RiscPC computer and want its
114 native mouse supported.
115
116 To compile this driver as a module, choose M here: the
117 module will be called rpcmouse.
118
119config MOUSE_VSXXXAA
120 tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet"
121 select SERIO
122 help
123 Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
124 puck) or a VSXXX-GA (rectangular) mouse. Theses mice are
125 typically used on DECstations or VAXstations, but can also
126 be used on any box capable of RS232 (with some adaptor
127 described in the source file). This driver also works with the
128 digitizer (VSXXX-AB) DEC produced.
129
130config MOUSE_HIL
131 tristate "HIL pointers (mice etc)."
132 depends on GSC
133 select HP_SDC
134 select HIL_MLC
135 help
136 Say Y here to support HIL pointers.
137
138endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
new file mode 100644
index 000000000000..a7864195806a
--- /dev/null
+++ b/drivers/input/mouse/Makefile
@@ -0,0 +1,18 @@
1#
2# Makefile for the mouse drivers.
3#
4
5# Each configuration option enables a list of files.
6
7obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
8obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
9obj-$(CONFIG_MOUSE_INPORT) += inport.o
10obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
11obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
12obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
13obj-$(CONFIG_MOUSE_PS2) += psmouse.o
14obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
15obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
16obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
17
18psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
new file mode 100644
index 000000000000..1f85a9718c89
--- /dev/null
+++ b/drivers/input/mouse/alps.c
@@ -0,0 +1,477 @@
1/*
2 * ALPS touchpad PS/2 mouse driver
3 *
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>
7 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
8 *
9 * ALPS detection, tap switching and status querying info is taken from
10 * tpconfig utility (by C. Scott Ananian and Bruce Kall).
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 */
16
17#include <linux/input.h>
18#include <linux/serio.h>
19#include <linux/libps2.h>
20
21#include "psmouse.h"
22#include "alps.h"
23
24#undef DEBUG
25#ifdef DEBUG
26#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
27#else
28#define dbg(format, arg...) do {} while (0)
29#endif
30
31#define ALPS_DUALPOINT 0x01
32#define ALPS_WHEEL 0x02
33#define ALPS_FW_BK 0x04
34#define ALPS_4BTN 0x08
35#define ALPS_OLDPROTO 0x10
36#define ALPS_PASS 0x20
37
38static struct alps_model_info alps_model_data[] = {
39 { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
40 { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
41 { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
42 { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
43 { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
44 { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 },
45 { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
46 { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK }, /* NEC Versa L320 */
47 { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
48 { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
49 { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
50 { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
51 { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
52 { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
53 { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
54};
55
56/*
57 * XXX - this entry is suspicious. First byte has zero lower nibble,
58 * which is what a normal mouse would report. Also, the value 0x0e
59 * isn't valid per PS/2 spec.
60 */
61
62/*
63 * ALPS abolute Mode - new format
64 *
65 * byte 0: 1 ? ? ? 1 ? ? ?
66 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
67 * byte 2: 0 x10 x9 x8 x7 ? fin ges
68 * byte 3: 0 y9 y8 y7 1 M R L
69 * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
70 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
71 *
72 * ?'s can have different meanings on different models,
73 * such as wheel rotation, extra buttons, stick buttons
74 * on a dualpoint, etc.
75 */
76
77static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
78{
79 struct alps_data *priv = psmouse->private;
80 unsigned char *packet = psmouse->packet;
81 struct input_dev *dev = &psmouse->dev;
82 struct input_dev *dev2 = &priv->dev2;
83 int x, y, z, ges, fin, left, right, middle;
84
85 input_regs(dev, regs);
86
87 if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
88 input_report_key(dev2, BTN_LEFT, packet[0] & 1);
89 input_report_key(dev2, BTN_RIGHT, packet[0] & 2);
90 input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
91 input_report_rel(dev2, REL_X,
92 packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
93 input_report_rel(dev2, REL_Y,
94 packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
95 input_sync(dev2);
96 return;
97 }
98
99 if (priv->i->flags & ALPS_OLDPROTO) {
100 left = packet[2] & 0x08;
101 right = packet[2] & 0x10;
102 middle = 0;
103 x = packet[1] | ((packet[0] & 0x07) << 7);
104 y = packet[4] | ((packet[3] & 0x07) << 7);
105 z = packet[5];
106 } else {
107 left = packet[3] & 1;
108 right = packet[3] & 2;
109 middle = packet[3] & 4;
110 x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
111 y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
112 z = packet[5];
113 }
114
115 ges = packet[2] & 1;
116 fin = packet[2] & 2;
117
118 input_report_key(dev, BTN_LEFT, left);
119 input_report_key(dev, BTN_RIGHT, right);
120 input_report_key(dev, BTN_MIDDLE, middle);
121
122 if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) {
123 input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
124 input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
125 input_sync(dev);
126 input_sync(dev2);
127 return;
128 }
129
130 /* Convert hardware tap to a reasonable Z value */
131 if (ges && !fin) z = 40;
132
133 /*
134 * A "tap and drag" operation is reported by the hardware as a transition
135 * from (!fin && ges) to (fin && ges). This should be translated to the
136 * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually.
137 */
138 if (ges && fin && !priv->prev_fin) {
139 input_report_abs(dev, ABS_X, x);
140 input_report_abs(dev, ABS_Y, y);
141 input_report_abs(dev, ABS_PRESSURE, 0);
142 input_report_key(dev, BTN_TOOL_FINGER, 0);
143 input_sync(dev);
144 }
145 priv->prev_fin = fin;
146
147 if (z > 30) input_report_key(dev, BTN_TOUCH, 1);
148 if (z < 25) input_report_key(dev, BTN_TOUCH, 0);
149
150 if (z > 0) {
151 input_report_abs(dev, ABS_X, x);
152 input_report_abs(dev, ABS_Y, y);
153 }
154
155 input_report_abs(dev, ABS_PRESSURE, z);
156 input_report_key(dev, BTN_TOOL_FINGER, z > 0);
157
158
159 if (priv->i->flags & ALPS_WHEEL)
160 input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
161
162 if (priv->i->flags & ALPS_FW_BK) {
163 input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
164 input_report_key(dev, BTN_BACK, packet[2] & 0x04);
165 }
166
167 input_sync(dev);
168}
169
170static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
171{
172 struct alps_data *priv = psmouse->private;
173
174 if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
175 if (psmouse->pktcnt == 3) {
176 alps_process_packet(psmouse, regs);
177 return PSMOUSE_FULL_PACKET;
178 }
179 return PSMOUSE_GOOD_DATA;
180 }
181
182 if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0)
183 return PSMOUSE_BAD_DATA;
184
185 /* Bytes 2 - 6 should have 0 in the highest bit */
186 if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
187 (psmouse->packet[psmouse->pktcnt - 1] & 0x80))
188 return PSMOUSE_BAD_DATA;
189
190 if (psmouse->pktcnt == 6) {
191 alps_process_packet(psmouse, regs);
192 return PSMOUSE_FULL_PACKET;
193 }
194
195 return PSMOUSE_GOOD_DATA;
196}
197
198static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
199{
200 struct ps2dev *ps2dev = &psmouse->ps2dev;
201 unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
202 unsigned char param[4];
203 int i;
204
205 /*
206 * First try "E6 report".
207 * ALPS should return 0,0,10 or 0,0,100
208 */
209 param[0] = 0;
210 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
211 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
212 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
213 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
214 return NULL;
215
216 param[0] = param[1] = param[2] = 0xff;
217 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
218 return NULL;
219
220 dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
221
222 if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
223 return NULL;
224
225 /*
226 * Now try "E7 report". Allowed responses are in
227 * alps_model_data[].signature
228 */
229 param[0] = 0;
230 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
231 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
232 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
233 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
234 return NULL;
235
236 param[0] = param[1] = param[2] = 0xff;
237 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
238 return NULL;
239
240 dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
241
242 for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++);
243 *version = (param[0] << 8) | (param[1] << 4) | i;
244
245 for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
246 if (!memcmp(param, alps_model_data[i].signature, sizeof(alps_model_data[i].signature)))
247 return alps_model_data + i;
248
249 return NULL;
250}
251
252/*
253 * For DualPoint devices select the device that should respond to
254 * subsequent commands. It looks like glidepad is behind stickpointer,
255 * I'd thought it would be other way around...
256 */
257static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
258{
259 struct ps2dev *ps2dev = &psmouse->ps2dev;
260 unsigned char param[3];
261 int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
262
263 if (ps2_command(ps2dev, NULL, cmd) ||
264 ps2_command(ps2dev, NULL, cmd) ||
265 ps2_command(ps2dev, NULL, cmd) ||
266 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
267 return -1;
268
269 /* we may get 3 more bytes, just ignore them */
270 ps2_command(ps2dev, param, 0x0300);
271
272 return 0;
273}
274
275static int alps_absolute_mode(struct psmouse *psmouse)
276{
277 struct ps2dev *ps2dev = &psmouse->ps2dev;
278
279 /* Try ALPS magic knock - 4 disable before enable */
280 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
281 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
282 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
283 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
284 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
285 return -1;
286
287 /*
288 * Switch mouse to poll (remote) mode so motion data will not
289 * get in our way
290 */
291 return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
292}
293
294static int alps_get_status(struct psmouse *psmouse, char *param)
295{
296 struct ps2dev *ps2dev = &psmouse->ps2dev;
297
298 /* Get status: 0xF5 0xF5 0xF5 0xE9 */
299 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
300 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
301 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
302 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
303 return -1;
304
305 dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
306
307 return 0;
308}
309
310/*
311 * Turn touchpad tapping on or off. The sequences are:
312 * 0xE9 0xF5 0xF5 0xF3 0x0A to enable,
313 * 0xE9 0xF5 0xF5 0xE8 0x00 to disable.
314 * My guess that 0xE9 (GetInfo) is here as a sync point.
315 * For models that also have stickpointer (DualPoints) its tapping
316 * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but
317 * we don't fiddle with it.
318 */
319static int alps_tap_mode(struct psmouse *psmouse, int enable)
320{
321 struct ps2dev *ps2dev = &psmouse->ps2dev;
322 int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
323 unsigned char tap_arg = enable ? 0x0A : 0x00;
324 unsigned char param[4];
325
326 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
327 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
328 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
329 ps2_command(ps2dev, &tap_arg, cmd))
330 return -1;
331
332 if (alps_get_status(psmouse, param))
333 return -1;
334
335 return 0;
336}
337
338static int alps_reconnect(struct psmouse *psmouse)
339{
340 struct alps_data *priv = psmouse->private;
341 unsigned char param[4];
342 int version;
343
344 if (!(priv->i = alps_get_model(psmouse, &version)))
345 return -1;
346
347 if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1))
348 return -1;
349
350 if (alps_get_status(psmouse, param))
351 return -1;
352
353 if (param[0] & 0x04)
354 alps_tap_mode(psmouse, 1);
355
356 if (alps_absolute_mode(psmouse)) {
357 printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
358 return -1;
359 }
360
361 if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0))
362 return -1;
363
364 return 0;
365}
366
367static void alps_disconnect(struct psmouse *psmouse)
368{
369 struct alps_data *priv = psmouse->private;
370 psmouse_reset(psmouse);
371 input_unregister_device(&priv->dev2);
372 kfree(priv);
373}
374
375int alps_init(struct psmouse *psmouse)
376{
377 struct alps_data *priv;
378 unsigned char param[4];
379 int version;
380
381 psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL);
382 if (!priv)
383 goto init_fail;
384 memset(priv, 0, sizeof(struct alps_data));
385
386 if (!(priv->i = alps_get_model(psmouse, &version)))
387 goto init_fail;
388
389 if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
390 goto init_fail;
391
392 if (alps_get_status(psmouse, param)) {
393 printk(KERN_ERR "alps.c: touchpad status report request failed\n");
394 goto init_fail;
395 }
396
397 if (param[0] & 0x04) {
398 printk(KERN_INFO " Enabling hardware tapping\n");
399 if (alps_tap_mode(psmouse, 1))
400 printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
401 }
402
403 if (alps_absolute_mode(psmouse)) {
404 printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
405 goto init_fail;
406 }
407
408 if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
409 goto init_fail;
410
411 psmouse->dev.evbit[LONG(EV_KEY)] |= BIT(EV_KEY);
412 psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
413 psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
414 psmouse->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
415
416 psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
417 input_set_abs_params(&psmouse->dev, ABS_X, 0, 1023, 0, 0);
418 input_set_abs_params(&psmouse->dev, ABS_Y, 0, 767, 0, 0);
419 input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0);
420
421 if (priv->i->flags & ALPS_WHEEL) {
422 psmouse->dev.evbit[LONG(EV_REL)] |= BIT(EV_REL);
423 psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
424 }
425
426 if (priv->i->flags & ALPS_FW_BK) {
427 psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
428 psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
429 }
430
431 sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys);
432 priv->dev2.phys = priv->phys;
433 priv->dev2.name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
434 priv->dev2.id.bustype = BUS_I8042;
435 priv->dev2.id.vendor = 0x0002;
436 priv->dev2.id.product = PSMOUSE_ALPS;
437 priv->dev2.id.version = 0x0000;
438
439 priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
440 priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
441 priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
442
443 input_register_device(&priv->dev2);
444
445 printk(KERN_INFO "input: %s on %s\n", priv->dev2.name, psmouse->ps2dev.serio->phys);
446
447 psmouse->protocol_handler = alps_process_byte;
448 psmouse->disconnect = alps_disconnect;
449 psmouse->reconnect = alps_reconnect;
450 psmouse->pktsize = 6;
451
452 return 0;
453
454init_fail:
455 kfree(priv);
456 return -1;
457}
458
459int alps_detect(struct psmouse *psmouse, int set_properties)
460{
461 int version;
462 struct alps_model_info *model;
463
464 if (!(model = alps_get_model(psmouse, &version)))
465 return -1;
466
467 if (set_properties) {
468 psmouse->vendor = "ALPS";
469 if (model->flags & ALPS_DUALPOINT)
470 psmouse->name = "DualPoint TouchPad";
471 else
472 psmouse->name = "GlidePoint";
473 psmouse->model = version;
474 }
475 return 0;
476}
477
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
new file mode 100644
index 000000000000..aba103dd65b7
--- /dev/null
+++ b/drivers/input/mouse/alps.h
@@ -0,0 +1,32 @@
1/*
2 * ALPS touchpad PS/2 mouse driver
3 *
4 * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
5 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11
12#ifndef _ALPS_H
13#define _ALPS_H
14
15int alps_detect(struct psmouse *psmouse, int set_properties);
16int alps_init(struct psmouse *psmouse);
17
18struct alps_model_info {
19 unsigned char signature[3];
20 unsigned char byte0, mask0;
21 unsigned char flags;
22};
23
24struct alps_data {
25 struct input_dev dev2; /* Relative device */
26 char name[32]; /* Name */
27 char phys[32]; /* Phys */
28 struct alps_model_info *i; /* Info */
29 int prev_fin; /* Finger bit from previous packet */
30};
31
32#endif
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
new file mode 100644
index 000000000000..7baa09cca7c5
--- /dev/null
+++ b/drivers/input/mouse/amimouse.c
@@ -0,0 +1,137 @@
1/*
2 * Amiga mouse driver for Linux/m68k
3 *
4 * Copyright (c) 2000-2002 Vojtech Pavlik
5 *
6 * Based on the work of:
7 * Michael Rausch James Banks
8 * Matther Dillon David Giller
9 * Nathan Laredo Linus Torvalds
10 * Johan Myreen Jes Sorensen
11 * Russell King
12 */
13
14/*
15 * This program is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License version 2 as published by
17 * the Free Software Foundation
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/input.h>
23#include <linux/interrupt.h>
24
25#include <asm/irq.h>
26#include <asm/setup.h>
27#include <asm/system.h>
28#include <asm/uaccess.h>
29#include <asm/amigahw.h>
30#include <asm/amigaints.h>
31
32MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
33MODULE_DESCRIPTION("Amiga mouse driver");
34MODULE_LICENSE("GPL");
35
36static int amimouse_used = 0;
37static int amimouse_lastx, amimouse_lasty;
38static struct input_dev amimouse_dev;
39
40static char *amimouse_name = "Amiga mouse";
41static char *amimouse_phys = "amimouse/input0";
42
43static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
44{
45 unsigned short joy0dat, potgor;
46 int nx, ny, dx, dy;
47
48 joy0dat = custom.joy0dat;
49
50 nx = joy0dat & 0xff;
51 ny = joy0dat >> 8;
52
53 dx = nx - amimouse_lastx;
54 dy = ny - amimouse_lasty;
55
56 if (dx < -127) dx = (256 + nx) - amimouse_lastx;
57 if (dx > 127) dx = (nx - 256) - amimouse_lastx;
58 if (dy < -127) dy = (256 + ny) - amimouse_lasty;
59 if (dy > 127) dy = (ny - 256) - amimouse_lasty;
60
61 amimouse_lastx = nx;
62 amimouse_lasty = ny;
63
64 potgor = custom.potgor;
65
66 input_regs(&amimouse_dev, fp);
67
68 input_report_rel(&amimouse_dev, REL_X, dx);
69 input_report_rel(&amimouse_dev, REL_Y, dy);
70
71 input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40);
72 input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
73 input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400);
74
75 input_sync(&amimouse_dev);
76
77 return IRQ_HANDLED;
78}
79
80static int amimouse_open(struct input_dev *dev)
81{
82 unsigned short joy0dat;
83
84 if (amimouse_used++)
85 return 0;
86
87 joy0dat = custom.joy0dat;
88
89 amimouse_lastx = joy0dat & 0xff;
90 amimouse_lasty = joy0dat >> 8;
91
92 if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
93 amimouse_used--;
94 printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
95 return -EBUSY;
96 }
97
98 return 0;
99}
100
101static void amimouse_close(struct input_dev *dev)
102{
103 if (!--amimouse_used)
104 free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
105}
106
107static int __init amimouse_init(void)
108{
109 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
110 return -ENODEV;
111
112 amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
113 amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
114 amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
115 amimouse_dev.open = amimouse_open;
116 amimouse_dev.close = amimouse_close;
117
118 amimouse_dev.name = amimouse_name;
119 amimouse_dev.phys = amimouse_phys;
120 amimouse_dev.id.bustype = BUS_AMIGA;
121 amimouse_dev.id.vendor = 0x0001;
122 amimouse_dev.id.product = 0x0002;
123 amimouse_dev.id.version = 0x0100;
124
125 input_register_device(&amimouse_dev);
126
127 printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
128 return 0;
129}
130
131static void __exit amimouse_exit(void)
132{
133 input_unregister_device(&amimouse_dev);
134}
135
136module_init(amimouse_init);
137module_exit(amimouse_exit);
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
new file mode 100644
index 000000000000..bc22849c6c79
--- /dev/null
+++ b/drivers/input/mouse/hil_ptr.c
@@ -0,0 +1,414 @@
1/*
2 * Generic linux-input device driver for axis-bearing devices
3 *
4 * Copyright (c) 2001 Brian S. Julin
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL").
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 *
29 * References:
30 * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A
31 *
32 */
33
34#include <linux/hil.h>
35#include <linux/input.h>
36#include <linux/serio.h>
37#include <linux/kernel.h>
38#include <linux/module.h>
39#include <linux/init.h>
40#include <linux/slab.h>
41#include <linux/pci_ids.h>
42
43#define PREFIX "HIL PTR: "
44#define HIL_GENERIC_NAME "HIL pointer device"
45
46MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
47MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
48MODULE_LICENSE("Dual BSD/GPL");
49
50
51#define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */
52#undef TABLET_AUTOADJUST /* auto-adjust valid tablet ranges */
53
54
55#define HIL_PTR_MAX_LENGTH 16
56
57struct hil_ptr {
58 struct input_dev dev;
59 struct serio *serio;
60
61 /* Input buffer and index for packets from HIL bus. */
62 hil_packet data[HIL_PTR_MAX_LENGTH];
63 int idx4; /* four counts per packet */
64
65 /* Raw device info records from HIL bus, see hil.h for fields. */
66 char idd[HIL_PTR_MAX_LENGTH]; /* DID byte and IDD record */
67 char rsc[HIL_PTR_MAX_LENGTH]; /* RSC record */
68 char exd[HIL_PTR_MAX_LENGTH]; /* EXD record */
69 char rnm[HIL_PTR_MAX_LENGTH + 1]; /* RNM record + NULL term. */
70
71 /* Extra device details not contained in struct input_dev. */
72 unsigned int nbtn, naxes;
73 unsigned int btnmap[7];
74
75 /* Something to sleep around with. */
76 struct semaphore sem;
77};
78
79/* Process a complete packet after transfer from the HIL */
80static void hil_ptr_process_record(struct hil_ptr *ptr)
81{
82 struct input_dev *dev = &ptr->dev;
83 hil_packet *data = ptr->data;
84 hil_packet p;
85 int idx, i, cnt, laxis;
86 int ax16, absdev;
87
88 idx = ptr->idx4/4;
89 p = data[idx - 1];
90
91 if ((p & ~HIL_CMDCT_POL) ==
92 (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
93 if ((p & ~HIL_CMDCT_RPL) ==
94 (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
95
96 /* Not a poll response. See if we are loading config records. */
97 switch (p & HIL_PKT_DATA_MASK) {
98 case HIL_CMD_IDD:
99 for (i = 0; i < idx; i++)
100 ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
101 for (; i < HIL_PTR_MAX_LENGTH; i++)
102 ptr->idd[i] = 0;
103 break;
104 case HIL_CMD_RSC:
105 for (i = 0; i < idx; i++)
106 ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
107 for (; i < HIL_PTR_MAX_LENGTH; i++)
108 ptr->rsc[i] = 0;
109 break;
110 case HIL_CMD_EXD:
111 for (i = 0; i < idx; i++)
112 ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
113 for (; i < HIL_PTR_MAX_LENGTH; i++)
114 ptr->exd[i] = 0;
115 break;
116 case HIL_CMD_RNM:
117 for (i = 0; i < idx; i++)
118 ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
119 for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
120 ptr->rnm[i] = '\0';
121 break;
122 default:
123 /* These occur when device isn't present */
124 if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break;
125 /* Anything else we'd like to know about. */
126 printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
127 break;
128 }
129 goto out;
130
131 report:
132 if ((p & HIL_CMDCT_POL) != idx - 1) {
133 printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx);
134 goto out;
135 }
136
137 i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0;
138 laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK;
139 laxis += i;
140
141 ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
142 absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
143
144 for (cnt = 1; i < laxis; i++) {
145 unsigned int lo,hi,val;
146 lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
147 hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
148 if (absdev) {
149 val = lo + (hi<<8);
150#ifdef TABLET_AUTOADJUST
151 if (val < ptr->dev.absmin[ABS_X + i])
152 ptr->dev.absmin[ABS_X + i] = val;
153 if (val > ptr->dev.absmax[ABS_X + i])
154 ptr->dev.absmax[ABS_X + i] = val;
155#endif
156 if (i%3) val = ptr->dev.absmax[ABS_X + i] - val;
157 input_report_abs(dev, ABS_X + i, val);
158 } else {
159 val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
160 if (i%3) val *= -1;
161 input_report_rel(dev, REL_X + i, val);
162 }
163 }
164
165 while (cnt < idx - 1) {
166 unsigned int btn;
167 int up;
168 btn = ptr->data[cnt++];
169 up = btn & 1;
170 btn &= 0xfe;
171 if (btn == 0x8e) {
172 continue; /* TODO: proximity == touch? */
173 }
174 else if ((btn > 0x8c) || (btn < 0x80)) continue;
175 btn = (btn - 0x80) >> 1;
176 btn = ptr->btnmap[btn];
177 input_report_key(dev, btn, !up);
178 }
179 input_sync(dev);
180 out:
181 ptr->idx4 = 0;
182 up(&ptr->sem);
183}
184
185static void hil_ptr_process_err(struct hil_ptr *ptr) {
186 printk(KERN_WARNING PREFIX "errored HIL packet\n");
187 ptr->idx4 = 0;
188 up(&ptr->sem);
189 return;
190}
191
192static irqreturn_t hil_ptr_interrupt(struct serio *serio,
193 unsigned char data, unsigned int flags, struct pt_regs *regs)
194{
195 struct hil_ptr *ptr;
196 hil_packet packet;
197 int idx;
198
199 ptr = (struct hil_ptr *)serio->private;
200 if (ptr == NULL) {
201 BUG();
202 return IRQ_HANDLED;
203 }
204
205 if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
206 hil_ptr_process_err(ptr);
207 return IRQ_HANDLED;
208 }
209 idx = ptr->idx4/4;
210 if (!(ptr->idx4 % 4)) ptr->data[idx] = 0;
211 packet = ptr->data[idx];
212 packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
213 ptr->data[idx] = packet;
214
215 /* Records of N 4-byte hil_packets must terminate with a command. */
216 if ((++(ptr->idx4)) % 4) return IRQ_HANDLED;
217 if ((packet & 0xffff0000) != HIL_ERR_INT) {
218 hil_ptr_process_err(ptr);
219 return IRQ_HANDLED;
220 }
221 if (packet & HIL_PKT_CMD)
222 hil_ptr_process_record(ptr);
223 return IRQ_HANDLED;
224}
225
226static void hil_ptr_disconnect(struct serio *serio)
227{
228 struct hil_ptr *ptr;
229
230 ptr = (struct hil_ptr *)serio->private;
231 if (ptr == NULL) {
232 BUG();
233 return;
234 }
235
236 input_unregister_device(&ptr->dev);
237 serio_close(serio);
238 kfree(ptr);
239}
240
241static void hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
242{
243 struct hil_ptr *ptr;
244 char *txt;
245 unsigned int i, naxsets, btntype;
246 uint8_t did, *idd;
247
248 if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return;
249
250 if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return;
251 memset(ptr, 0, sizeof(struct hil_ptr));
252
253 if (serio_open(serio, driver)) goto bail0;
254
255 serio->private = ptr;
256 ptr->serio = serio;
257 ptr->dev.private = ptr;
258
259 init_MUTEX_LOCKED(&(ptr->sem));
260
261 /* Get device info. MLC driver supplies devid/status/etc. */
262 serio->write(serio, 0);
263 serio->write(serio, 0);
264 serio->write(serio, HIL_PKT_CMD >> 8);
265 serio->write(serio, HIL_CMD_IDD);
266 down(&(ptr->sem));
267
268 serio->write(serio, 0);
269 serio->write(serio, 0);
270 serio->write(serio, HIL_PKT_CMD >> 8);
271 serio->write(serio, HIL_CMD_RSC);
272 down(&(ptr->sem));
273
274 serio->write(serio, 0);
275 serio->write(serio, 0);
276 serio->write(serio, HIL_PKT_CMD >> 8);
277 serio->write(serio, HIL_CMD_RNM);
278 down(&(ptr->sem));
279
280 serio->write(serio, 0);
281 serio->write(serio, 0);
282 serio->write(serio, HIL_PKT_CMD >> 8);
283 serio->write(serio, HIL_CMD_EXD);
284 down(&(ptr->sem));
285
286 up(&(ptr->sem));
287
288 init_input_dev(&ptr->dev);
289 did = ptr->idd[0];
290 idd = ptr->idd + 1;
291 txt = "unknown";
292 if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
293 ptr->dev.evbit[0] = BIT(EV_REL);
294 txt = "relative";
295 }
296
297 if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
298 ptr->dev.evbit[0] = BIT(EV_ABS);
299 txt = "absolute";
300 }
301 if (!ptr->dev.evbit[0]) {
302 goto bail1;
303 }
304
305 ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
306 if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY);
307
308 naxsets = HIL_IDD_NUM_AXSETS(*idd);
309 ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
310
311 printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n",
312 did, txt);
313 printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
314 ptr->nbtn, naxsets, ptr->naxes);
315
316 btntype = BTN_MISC;
317 if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
318#ifdef TABLET_SIMULATES_MOUSE
319 btntype = BTN_TOUCH;
320#else
321 btntype = BTN_DIGI;
322#endif
323 if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
324 btntype = BTN_TOUCH;
325
326 if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
327 btntype = BTN_MOUSE;
328
329 for (i = 0; i < ptr->nbtn; i++) {
330 set_bit(btntype | i, ptr->dev.keybit);
331 ptr->btnmap[i] = btntype | i;
332 }
333
334 if (btntype == BTN_MOUSE) {
335 /* Swap buttons 2 and 3 */
336 ptr->btnmap[1] = BTN_MIDDLE;
337 ptr->btnmap[2] = BTN_RIGHT;
338 }
339
340 if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
341 for (i = 0; i < ptr->naxes; i++) {
342 set_bit(REL_X + i, ptr->dev.relbit);
343 }
344 for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
345 set_bit(REL_X + i, ptr->dev.relbit);
346 }
347 } else {
348 for (i = 0; i < ptr->naxes; i++) {
349 set_bit(ABS_X + i, ptr->dev.absbit);
350 ptr->dev.absmin[ABS_X + i] = 0;
351 ptr->dev.absmax[ABS_X + i] =
352 HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
353 }
354 for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
355 set_bit(ABS_X + i, ptr->dev.absbit);
356 ptr->dev.absmin[ABS_X + i] = 0;
357 ptr->dev.absmax[ABS_X + i] =
358 HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
359 }
360#ifdef TABLET_AUTOADJUST
361 for (i = 0; i < ABS_MAX; i++) {
362 int diff = ptr->dev.absmax[ABS_X + i] / 10;
363 ptr->dev.absmin[ABS_X + i] += diff;
364 ptr->dev.absmax[ABS_X + i] -= diff;
365 }
366#endif
367 }
368
369 ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
370
371 ptr->dev.id.bustype = BUS_HIL;
372 ptr->dev.id.vendor = PCI_VENDOR_ID_HP;
373 ptr->dev.id.product = 0x0001; /* TODO: get from ptr->rsc */
374 ptr->dev.id.version = 0x0100; /* TODO: get from ptr->rsc */
375 ptr->dev.dev = &serio->dev;
376
377 input_register_device(&ptr->dev);
378 printk(KERN_INFO "input: %s (%s), ID: %d\n",
379 ptr->dev.name,
380 (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
381 did);
382
383 return;
384 bail1:
385 serio_close(serio);
386 bail0:
387 kfree(ptr);
388 return;
389}
390
391
392static struct serio_driver hil_ptr_serio_driver = {
393 .driver = {
394 .name = "hil_ptr",
395 },
396 .description = "HP HIL mouse/tablet driver",
397 .connect = hil_ptr_connect,
398 .disconnect = hil_ptr_disconnect,
399 .interrupt = hil_ptr_interrupt
400};
401
402static int __init hil_ptr_init(void)
403{
404 serio_register_driver(&hil_ptr_serio_driver);
405 return 0;
406}
407
408static void __exit hil_ptr_exit(void)
409{
410 serio_unregister_driver(&hil_ptr_serio_driver);
411}
412
413module_init(hil_ptr_init);
414module_exit(hil_ptr_exit);
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
new file mode 100644
index 000000000000..ca4e96886627
--- /dev/null
+++ b/drivers/input/mouse/inport.c
@@ -0,0 +1,196 @@
1/*
2 * $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
3 *
4 * Copyright (c) 1999-2001 Vojtech Pavlik
5 *
6 * Based on the work of:
7 * Teemu Rantanen Derrick Cole
8 * Peter Cervasio Christoph Niemann
9 * Philip Blundell Russell King
10 * Bob Harris
11 */
12
13/*
14 * Inport (ATI XL and Microsoft) busmouse driver for Linux
15 */
16
17/*
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 *
32 * Should you need to contact me, the author, you can do so either by
33 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
34 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
35 */
36
37#include <linux/module.h>
38#include <linux/moduleparam.h>
39#include <linux/config.h>
40#include <linux/ioport.h>
41#include <linux/init.h>
42#include <linux/interrupt.h>
43#include <linux/input.h>
44
45#include <asm/io.h>
46#include <asm/irq.h>
47
48MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
49MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
50MODULE_LICENSE("GPL");
51
52#define INPORT_BASE 0x23c
53#define INPORT_EXTENT 4
54
55#define INPORT_CONTROL_PORT INPORT_BASE + 0
56#define INPORT_DATA_PORT INPORT_BASE + 1
57#define INPORT_SIGNATURE_PORT INPORT_BASE + 2
58
59#define INPORT_REG_BTNS 0x00
60#define INPORT_REG_X 0x01
61#define INPORT_REG_Y 0x02
62#define INPORT_REG_MODE 0x07
63#define INPORT_RESET 0x80
64
65#ifdef CONFIG_INPUT_ATIXL
66#define INPORT_NAME "ATI XL Mouse"
67#define INPORT_VENDOR 0x0002
68#define INPORT_SPEED_30HZ 0x01
69#define INPORT_SPEED_50HZ 0x02
70#define INPORT_SPEED_100HZ 0x03
71#define INPORT_SPEED_200HZ 0x04
72#define INPORT_MODE_BASE INPORT_SPEED_100HZ
73#define INPORT_MODE_IRQ 0x08
74#else
75#define INPORT_NAME "Microsoft InPort Mouse"
76#define INPORT_VENDOR 0x0001
77#define INPORT_MODE_BASE 0x10
78#define INPORT_MODE_IRQ 0x01
79#endif
80#define INPORT_MODE_HOLD 0x20
81
82#define INPORT_IRQ 5
83
84static int inport_irq = INPORT_IRQ;
85module_param_named(irq, inport_irq, uint, 0);
86MODULE_PARM_DESC(irq, "IRQ number (5=default)");
87
88__obsolete_setup("inport_irq=");
89
90static int inport_used;
91
92static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
93
94static int inport_open(struct input_dev *dev)
95{
96 if (!inport_used++) {
97 if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
98 return -EBUSY;
99 outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
100 outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
101 }
102
103 return 0;
104}
105
106static void inport_close(struct input_dev *dev)
107{
108 if (!--inport_used) {
109 outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
110 outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
111 free_irq(inport_irq, NULL);
112 }
113}
114
115static struct input_dev inport_dev = {
116 .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
117 .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
118 .relbit = { BIT(REL_X) | BIT(REL_Y) },
119 .open = inport_open,
120 .close = inport_close,
121 .name = INPORT_NAME,
122 .phys = "isa023c/input0",
123 .id = {
124 .bustype = BUS_ISA,
125 .vendor = INPORT_VENDOR,
126 .product = 0x0001,
127 .version = 0x0100,
128 },
129};
130
131static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
132{
133 unsigned char buttons;
134
135 outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
136 outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
137
138 input_regs(&inport_dev, regs);
139
140 outb(INPORT_REG_X, INPORT_CONTROL_PORT);
141 input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT));
142
143 outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
144 input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT));
145
146 outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
147 buttons = inb(INPORT_DATA_PORT);
148
149 input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1);
150 input_report_key(&inport_dev, BTN_LEFT, buttons & 2);
151 input_report_key(&inport_dev, BTN_RIGHT, buttons & 4);
152
153 outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
154 outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
155
156 input_sync(&inport_dev);
157 return IRQ_HANDLED;
158}
159
160static int __init inport_init(void)
161{
162 unsigned char a,b,c;
163
164 if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
165 printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
166 return -EBUSY;
167 }
168
169 a = inb(INPORT_SIGNATURE_PORT);
170 b = inb(INPORT_SIGNATURE_PORT);
171 c = inb(INPORT_SIGNATURE_PORT);
172 if (( a == b ) || ( a != c )) {
173 release_region(INPORT_BASE, INPORT_EXTENT);
174 printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
175 return -ENODEV;
176 }
177
178 outb(INPORT_RESET, INPORT_CONTROL_PORT);
179 outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
180 outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
181
182 input_register_device(&inport_dev);
183
184 printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq);
185
186 return 0;
187}
188
189static void __exit inport_exit(void)
190{
191 input_unregister_device(&inport_dev);
192 release_region(INPORT_BASE, INPORT_EXTENT);
193}
194
195module_init(inport_init);
196module_exit(inport_exit);
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
new file mode 100644
index 000000000000..77eb83e87f61
--- /dev/null
+++ b/drivers/input/mouse/logibm.c
@@ -0,0 +1,183 @@
1/*
2 * $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
3 *
4 * Copyright (c) 1999-2001 Vojtech Pavlik
5 *
6 * Based on the work of:
7 * James Banks Matthew Dillon
8 * David Giller Nathan Laredo
9 * Linus Torvalds Johan Myreen
10 * Cliff Matthews Philip Blundell
11 * Russell King
12 */
13
14/*
15 * Logitech Bus Mouse Driver for Linux
16 */
17
18/*
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 *
33 * Should you need to contact me, the author, you can do so either by
34 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
35 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
36 */
37
38#include <linux/module.h>
39#include <linux/moduleparam.h>
40#include <linux/delay.h>
41#include <linux/ioport.h>
42#include <linux/init.h>
43#include <linux/input.h>
44#include <linux/interrupt.h>
45
46#include <asm/io.h>
47#include <asm/irq.h>
48
49MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
50MODULE_DESCRIPTION("Logitech busmouse driver");
51MODULE_LICENSE("GPL");
52
53#define LOGIBM_BASE 0x23c
54#define LOGIBM_EXTENT 4
55
56#define LOGIBM_DATA_PORT LOGIBM_BASE + 0
57#define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1
58#define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2
59#define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3
60
61#define LOGIBM_ENABLE_IRQ 0x00
62#define LOGIBM_DISABLE_IRQ 0x10
63#define LOGIBM_READ_X_LOW 0x80
64#define LOGIBM_READ_X_HIGH 0xa0
65#define LOGIBM_READ_Y_LOW 0xc0
66#define LOGIBM_READ_Y_HIGH 0xe0
67
68#define LOGIBM_DEFAULT_MODE 0x90
69#define LOGIBM_CONFIG_BYTE 0x91
70#define LOGIBM_SIGNATURE_BYTE 0xa5
71
72#define LOGIBM_IRQ 5
73
74static int logibm_irq = LOGIBM_IRQ;
75module_param_named(irq, logibm_irq, uint, 0);
76MODULE_PARM_DESC(irq, "IRQ number (5=default)");
77
78__obsolete_setup("logibm_irq=");
79
80static int logibm_used = 0;
81
82static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
83
84static int logibm_open(struct input_dev *dev)
85{
86 if (logibm_used++)
87 return 0;
88 if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
89 logibm_used--;
90 printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
91 return -EBUSY;
92 }
93 outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
94 return 0;
95}
96
97static void logibm_close(struct input_dev *dev)
98{
99 if (--logibm_used)
100 return;
101 outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
102 free_irq(logibm_irq, NULL);
103}
104
105static struct input_dev logibm_dev = {
106 .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
107 .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
108 .relbit = { BIT(REL_X) | BIT(REL_Y) },
109 .open = logibm_open,
110 .close = logibm_close,
111 .name = "Logitech bus mouse",
112 .phys = "isa023c/input0",
113 .id = {
114 .bustype = BUS_ISA,
115 .vendor = 0x0003,
116 .product = 0x0001,
117 .version = 0x0100,
118 },
119};
120
121static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
122{
123 char dx, dy;
124 unsigned char buttons;
125
126 outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT);
127 dx = (inb(LOGIBM_DATA_PORT) & 0xf);
128 outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT);
129 dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4;
130 outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT);
131 dy = (inb(LOGIBM_DATA_PORT) & 0xf);
132 outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT);
133 buttons = inb(LOGIBM_DATA_PORT);
134 dy |= (buttons & 0xf) << 4;
135 buttons = ~buttons >> 5;
136
137 input_regs(&logibm_dev, regs);
138 input_report_rel(&logibm_dev, REL_X, dx);
139 input_report_rel(&logibm_dev, REL_Y, dy);
140 input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1);
141 input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2);
142 input_report_key(&logibm_dev, BTN_LEFT, buttons & 4);
143 input_sync(&logibm_dev);
144
145 outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
146 return IRQ_HANDLED;
147}
148
149static int __init logibm_init(void)
150{
151 if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) {
152 printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE);
153 return -EBUSY;
154 }
155
156 outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT);
157 outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT);
158 udelay(100);
159
160 if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
161 release_region(LOGIBM_BASE, LOGIBM_EXTENT);
162 printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
163 return -ENODEV;
164 }
165
166 outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT);
167 outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
168
169 input_register_device(&logibm_dev);
170
171 printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
172
173 return 0;
174}
175
176static void __exit logibm_exit(void)
177{
178 input_unregister_device(&logibm_dev);
179 release_region(LOGIBM_BASE, LOGIBM_EXTENT);
180}
181
182module_init(logibm_init);
183module_exit(logibm_exit);
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
new file mode 100644
index 000000000000..5ab1bd7d529d
--- /dev/null
+++ b/drivers/input/mouse/logips2pp.c
@@ -0,0 +1,397 @@
1/*
2 * Logitech PS/2++ mouse driver
3 *
4 * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
5 * Copyright (c) 2003 Eric Wong <eric@yhbt.net>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11
12#include <linux/input.h>
13#include <linux/serio.h>
14#include <linux/libps2.h>
15#include "psmouse.h"
16#include "logips2pp.h"
17
18/* Logitech mouse types */
19#define PS2PP_KIND_WHEEL 1
20#define PS2PP_KIND_MX 2
21#define PS2PP_KIND_TP3 3
22
23/* Logitech mouse features */
24#define PS2PP_WHEEL 0x01
25#define PS2PP_HWHEEL 0x02
26#define PS2PP_SIDE_BTN 0x04
27#define PS2PP_EXTRA_BTN 0x08
28#define PS2PP_TASK_BTN 0x10
29#define PS2PP_NAV_BTN 0x20
30
31struct ps2pp_info {
32 const int model;
33 unsigned const int kind;
34 unsigned const int features;
35};
36
37/*
38 * Process a PS2++ or PS2T++ packet.
39 */
40
41static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
42{
43 struct input_dev *dev = &psmouse->dev;
44 unsigned char *packet = psmouse->packet;
45
46 if (psmouse->pktcnt < 3)
47 return PSMOUSE_GOOD_DATA;
48
49/*
50 * Full packet accumulated, process it
51 */
52
53 input_regs(dev, regs);
54
55 if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
56
57 /* Logitech extended packet */
58 switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
59
60 case 0x0d: /* Mouse extra info */
61
62 input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
63 (int) (packet[2] & 8) - (int) (packet[2] & 7));
64 input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
65 input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
66
67 break;
68
69 case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
70
71 input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
72 input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
73 input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
74 input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
75 input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
76
77 break;
78
79 case 0x0f: /* TouchPad extra info */
80
81 input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
82 (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
83 packet[0] = packet[2] | 0x08;
84 break;
85
86#ifdef DEBUG
87 default:
88 printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
89 (packet[1] >> 4) | (packet[0] & 0x30));
90#endif
91 }
92 } else {
93 /* Standard PS/2 motion data */
94 input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
95 input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
96 }
97
98 input_report_key(dev, BTN_LEFT, packet[0] & 1);
99 input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
100 input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
101
102 input_sync(dev);
103
104 return PSMOUSE_FULL_PACKET;
105
106}
107
108/*
109 * ps2pp_cmd() sends a PS2++ command, sliced into two bit
110 * pieces through the SETRES command. This is needed to send extended
111 * commands to mice on notebooks that try to understand the PS/2 protocol
112 * Ugly.
113 */
114
115static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
116{
117 if (psmouse_sliced_command(psmouse, command))
118 return -1;
119
120 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL))
121 return -1;
122
123 return 0;
124}
125
126/*
127 * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
128 * enabled if we do nothing to it. Of course I put this in because I want it
129 * disabled :P
130 * 1 - enabled (if previously disabled, also default)
131 * 0 - disabled
132 */
133
134static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll)
135{
136 struct ps2dev *ps2dev = &psmouse->ps2dev;
137 unsigned char param[4];
138
139 if (smartscroll > 1)
140 smartscroll = 1;
141
142 ps2pp_cmd(psmouse, param, 0x32);
143
144 param[0] = 0;
145 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
146 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
147 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
148
149 param[0] = smartscroll;
150 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
151}
152
153static ssize_t psmouse_attr_show_smartscroll(struct psmouse *psmouse, char *buf)
154{
155 return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0);
156}
157
158static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char *buf, size_t count)
159{
160 unsigned long value;
161 char *rest;
162
163 value = simple_strtoul(buf, &rest, 10);
164 if (*rest || value > 1)
165 return -EINVAL;
166
167 ps2pp_set_smartscroll(psmouse, value);
168 psmouse->smartscroll = value;
169 return count;
170}
171
172PSMOUSE_DEFINE_ATTR(smartscroll);
173
174/*
175 * Support 800 dpi resolution _only_ if the user wants it (there are good
176 * reasons to not use it even if the mouse supports it, and of course there are
177 * also good reasons to use it, let the user decide).
178 */
179
180static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution)
181{
182 if (resolution > 400) {
183 struct ps2dev *ps2dev = &psmouse->ps2dev;
184 unsigned char param = 3;
185
186 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
187 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
188 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
189 ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
190 psmouse->resolution = 800;
191 } else
192 psmouse_set_resolution(psmouse, resolution);
193}
194
195static void ps2pp_disconnect(struct psmouse *psmouse)
196{
197 device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll);
198}
199
200static struct ps2pp_info *get_model_info(unsigned char model)
201{
202 static struct ps2pp_info ps2pp_list[] = {
203 { 12, 0, PS2PP_SIDE_BTN},
204 { 13, 0, 0 },
205 { 15, PS2PP_KIND_MX, /* MX1000 */
206 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
207 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
208 { 40, 0, PS2PP_SIDE_BTN },
209 { 41, 0, PS2PP_SIDE_BTN },
210 { 42, 0, PS2PP_SIDE_BTN },
211 { 43, 0, PS2PP_SIDE_BTN },
212 { 50, 0, 0 },
213 { 51, 0, 0 },
214 { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
215 { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
216 { 61, PS2PP_KIND_MX, /* MX700 */
217 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
218 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
219 { 73, 0, PS2PP_SIDE_BTN },
220 { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
221 { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
222 { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
223 { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
224 { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
225 { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
226 { 96, 0, 0 },
227 { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
228 { 100, PS2PP_KIND_MX, /* MX510 */
229 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
230 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
231 { 111, PS2PP_KIND_MX, /* MX300 */
232 PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN },
233 { 112, PS2PP_KIND_MX, /* MX500 */
234 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
235 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
236 { 114, PS2PP_KIND_MX, /* MX310 */
237 PS2PP_WHEEL | PS2PP_SIDE_BTN |
238 PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },
239 { }
240 };
241 int i;
242
243 for (i = 0; ps2pp_list[i].model; i++)
244 if (model == ps2pp_list[i].model)
245 return &ps2pp_list[i];
246
247 printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
248 return NULL;
249}
250
251/*
252 * Set up input device's properties based on the detected mouse model.
253 */
254
255static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info,
256 int using_ps2pp)
257{
258 if (model_info->features & PS2PP_SIDE_BTN)
259 set_bit(BTN_SIDE, psmouse->dev.keybit);
260
261 if (model_info->features & PS2PP_EXTRA_BTN)
262 set_bit(BTN_EXTRA, psmouse->dev.keybit);
263
264 if (model_info->features & PS2PP_TASK_BTN)
265 set_bit(BTN_TASK, psmouse->dev.keybit);
266
267 if (model_info->features & PS2PP_NAV_BTN) {
268 set_bit(BTN_FORWARD, psmouse->dev.keybit);
269 set_bit(BTN_BACK, psmouse->dev.keybit);
270 }
271
272 if (model_info->features & PS2PP_WHEEL)
273 set_bit(REL_WHEEL, psmouse->dev.relbit);
274
275 if (model_info->features & PS2PP_HWHEEL)
276 set_bit(REL_HWHEEL, psmouse->dev.relbit);
277
278 switch (model_info->kind) {
279 case PS2PP_KIND_WHEEL:
280 psmouse->name = "Wheel Mouse";
281 break;
282
283 case PS2PP_KIND_MX:
284 psmouse->name = "MX Mouse";
285 break;
286
287 case PS2PP_KIND_TP3:
288 psmouse->name = "TouchPad 3";
289 break;
290
291 default:
292 /*
293 * Set name to "Mouse" only when using PS2++,
294 * otherwise let other protocols define suitable
295 * name
296 */
297 if (using_ps2pp)
298 psmouse->name = "Mouse";
299 break;
300 }
301}
302
303
304/*
305 * Logitech magic init. Detect whether the mouse is a Logitech one
306 * and its exact model and try turning on extended protocol for ones
307 * that support it.
308 */
309
310int ps2pp_init(struct psmouse *psmouse, int set_properties)
311{
312 struct ps2dev *ps2dev = &psmouse->ps2dev;
313 unsigned char param[4];
314 unsigned char model, buttons;
315 struct ps2pp_info *model_info;
316 int use_ps2pp = 0;
317
318 param[0] = 0;
319 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
320 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
321 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
322 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
323 param[1] = 0;
324 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
325
326 if (!param[1])
327 return -1;
328
329 model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
330 buttons = param[1];
331
332 if ((model_info = get_model_info(model)) != NULL) {
333
334/*
335 * Do Logitech PS2++ / PS2T++ magic init.
336 */
337 if (model == 97) { /* Touch Pad 3 */
338
339 /* Unprotect RAM */
340 param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
341 ps2_command(ps2dev, param, 0x30d1);
342 /* Enable features */
343 param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
344 ps2_command(ps2dev, param, 0x30d1);
345 /* Enable PS2++ */
346 param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
347 ps2_command(ps2dev, param, 0x30d1);
348
349 param[0] = 0;
350 if (!ps2_command(ps2dev, param, 0x13d1) &&
351 param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
352 use_ps2pp = 1;
353 }
354
355 } else {
356
357 param[0] = param[1] = param[2] = 0;
358 ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
359 ps2pp_cmd(psmouse, param, 0xDB);
360
361 if ((param[0] & 0x78) == 0x48 &&
362 (param[1] & 0xf3) == 0xc2 &&
363 (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
364 ps2pp_set_smartscroll(psmouse, psmouse->smartscroll);
365 use_ps2pp = 1;
366 }
367 }
368 }
369
370 if (set_properties) {
371 psmouse->vendor = "Logitech";
372 psmouse->model = model;
373
374 if (use_ps2pp) {
375 psmouse->protocol_handler = ps2pp_process_byte;
376 psmouse->pktsize = 3;
377
378 if (model_info->kind != PS2PP_KIND_TP3) {
379 psmouse->set_resolution = ps2pp_set_resolution;
380 psmouse->disconnect = ps2pp_disconnect;
381
382 device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll);
383 }
384 }
385
386 if (buttons < 3)
387 clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
388 if (buttons < 2)
389 clear_bit(BTN_RIGHT, psmouse->dev.keybit);
390
391 if (model_info)
392 ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
393 }
394
395 return use_ps2pp ? 0 : -1;
396}
397
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
new file mode 100644
index 000000000000..64a8ec52ea6d
--- /dev/null
+++ b/drivers/input/mouse/logips2pp.h
@@ -0,0 +1,16 @@
1/*
2 * Logitech PS/2++ mouse driver header
3 *
4 * Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#ifndef _LOGIPS2PP_H
12#define _LOGIPS2PP_H
13
14int ps2pp_init(struct psmouse *psmouse, int set_properties);
15
16#endif
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
new file mode 100644
index 000000000000..12dc0ef5020f
--- /dev/null
+++ b/drivers/input/mouse/maplemouse.c
@@ -0,0 +1,134 @@
1/*
2 * $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
3 * SEGA Dreamcast mouse driver
4 * Based on drivers/usb/usbmouse.c
5 */
6
7#include <linux/kernel.h>
8#include <linux/slab.h>
9#include <linux/input.h>
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/timer.h>
13#include <linux/maple.h>
14
15MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
16MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
17
18struct dc_mouse {
19 struct input_dev dev;
20 int open;
21};
22
23
24static void dc_mouse_callback(struct mapleq *mq)
25{
26 int buttons, relx, rely, relz;
27 struct maple_device *mapledev = mq->dev;
28 struct dc_mouse *mouse = mapledev->private_data;
29 struct input_dev *dev = &mouse->dev;
30 unsigned char *res = mq->recvbuf;
31
32 buttons = ~res[8];
33 relx=*(unsigned short *)(res+12)-512;
34 rely=*(unsigned short *)(res+14)-512;
35 relz=*(unsigned short *)(res+16)-512;
36
37 input_report_key(dev, BTN_LEFT, buttons&4);
38 input_report_key(dev, BTN_MIDDLE, buttons&9);
39 input_report_key(dev, BTN_RIGHT, buttons&2);
40 input_report_rel(dev, REL_X, relx);
41 input_report_rel(dev, REL_Y, rely);
42 input_report_rel(dev, REL_WHEEL, relz);
43 input_sync(dev);
44}
45
46
47static int dc_mouse_open(struct input_dev *dev)
48{
49 struct dc_mouse *mouse = dev->private;
50 mouse->open++;
51 return 0;
52}
53
54
55static void dc_mouse_close(struct input_dev *dev)
56{
57 struct dc_mouse *mouse = dev->private;
58 mouse->open--;
59}
60
61
62static int dc_mouse_connect(struct maple_device *dev)
63{
64 unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
65 struct dc_mouse *mouse;
66
67 if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
68 return -1;
69 memset(mouse, 0, sizeof(struct dc_mouse));
70
71 dev->private_data = mouse;
72
73 mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
74 mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
75 mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
76
77 init_input_dev(&mouse->dev);
78
79 mouse->dev.private = mouse;
80 mouse->dev.open = dc_mouse_open;
81 mouse->dev.close = dc_mouse_close;
82 mouse->dev.event = NULL;
83
84 mouse->dev.name = dev->product_name;
85 mouse->dev.id.bustype = BUS_MAPLE;
86
87 input_register_device(&mouse->dev);
88
89 maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
90
91 printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
92
93 return 0;
94}
95
96
97static void dc_mouse_disconnect(struct maple_device *dev)
98{
99 struct dc_mouse *mouse = dev->private_data;
100
101 input_unregister_device(&mouse->dev);
102 kfree(mouse);
103}
104
105
106static struct maple_driver dc_mouse_driver = {
107 .function = MAPLE_FUNC_MOUSE,
108 .name = "Dreamcast mouse",
109 .connect = dc_mouse_connect,
110 .disconnect = dc_mouse_disconnect,
111};
112
113
114static int __init dc_mouse_init(void)
115{
116 maple_register_driver(&dc_mouse_driver);
117 return 0;
118}
119
120
121static void __exit dc_mouse_exit(void)
122{
123 maple_unregister_driver(&dc_mouse_driver);
124}
125
126
127module_init(dc_mouse_init);
128module_exit(dc_mouse_exit);
129
130/*
131 * Local variables:
132 * c-basic-offset: 8
133 * End:
134 */
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
new file mode 100644
index 000000000000..0c74918fe254
--- /dev/null
+++ b/drivers/input/mouse/pc110pad.c
@@ -0,0 +1,178 @@
1/*
2 * $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik
5 *
6 * Based on the work of:
7 * Alan Cox Robin O'Leary
8 */
9
10/*
11 * IBM PC110 touchpad driver for Linux
12 */
13
14/*
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 * Should you need to contact me, the author, you can do so either by
30 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
31 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
32 */
33
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/errno.h>
37#include <linux/ioport.h>
38#include <linux/input.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/pci.h>
42
43#include <asm/io.h>
44#include <asm/irq.h>
45
46MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
47MODULE_DESCRIPTION("IBM PC110 touchpad driver");
48MODULE_LICENSE("GPL");
49
50#define PC110PAD_OFF 0x30
51#define PC110PAD_ON 0x38
52
53static int pc110pad_irq = 10;
54static int pc110pad_io = 0x15e0;
55
56static struct input_dev pc110pad_dev;
57static int pc110pad_data[3];
58static int pc110pad_count;
59static int pc110pad_used;
60
61static char *pc110pad_name = "IBM PC110 TouchPad";
62static char *pc110pad_phys = "isa15e0/input0";
63
64static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
65{
66 int value = inb_p(pc110pad_io);
67 int handshake = inb_p(pc110pad_io + 2);
68
69 outb_p(handshake | 1, pc110pad_io + 2);
70 outb_p(handshake & ~1, pc110pad_io + 2);
71 inb_p(0x64);
72
73 pc110pad_data[pc110pad_count++] = value;
74
75 if (pc110pad_count < 3)
76 return IRQ_HANDLED;
77
78 input_regs(&pc110pad_dev, regs);
79 input_report_key(&pc110pad_dev, BTN_TOUCH,
80 pc110pad_data[0] & 0x01);
81 input_report_abs(&pc110pad_dev, ABS_X,
82 pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
83 input_report_abs(&pc110pad_dev, ABS_Y,
84 pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
85 input_sync(&pc110pad_dev);
86
87 pc110pad_count = 0;
88 return IRQ_HANDLED;
89}
90
91static void pc110pad_close(struct input_dev *dev)
92{
93 if (!--pc110pad_used)
94 outb(PC110PAD_OFF, pc110pad_io + 2);
95}
96
97static int pc110pad_open(struct input_dev *dev)
98{
99 if (pc110pad_used++)
100 return 0;
101
102 pc110pad_interrupt(0,NULL,NULL);
103 pc110pad_interrupt(0,NULL,NULL);
104 pc110pad_interrupt(0,NULL,NULL);
105 outb(PC110PAD_ON, pc110pad_io + 2);
106 pc110pad_count = 0;
107
108 return 0;
109}
110
111/*
112 * We try to avoid enabling the hardware if it's not
113 * there, but we don't know how to test. But we do know
114 * that the PC110 is not a PCI system. So if we find any
115 * PCI devices in the machine, we don't have a PC110.
116 */
117static int __init pc110pad_init(void)
118{
119 struct pci_dev *dev;
120
121 dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
122 if (dev) {
123 pci_dev_put(dev);
124 return -ENOENT;
125 }
126
127 if (!request_region(pc110pad_io, 4, "pc110pad")) {
128 printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n",
129 pc110pad_io, pc110pad_io + 4);
130 return -EBUSY;
131 }
132
133 outb(PC110PAD_OFF, pc110pad_io + 2);
134
135 if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL))
136 {
137 release_region(pc110pad_io, 4);
138 printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
139 return -EBUSY;
140 }
141
142 pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
143 pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
144 pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
145
146 pc110pad_dev.absmax[ABS_X] = 0x1ff;
147 pc110pad_dev.absmax[ABS_Y] = 0x0ff;
148
149 pc110pad_dev.open = pc110pad_open;
150 pc110pad_dev.close = pc110pad_close;
151
152 pc110pad_dev.name = pc110pad_name;
153 pc110pad_dev.phys = pc110pad_phys;
154 pc110pad_dev.id.bustype = BUS_ISA;
155 pc110pad_dev.id.vendor = 0x0003;
156 pc110pad_dev.id.product = 0x0001;
157 pc110pad_dev.id.version = 0x0100;
158
159 input_register_device(&pc110pad_dev);
160
161 printk(KERN_INFO "input: %s at %#x irq %d\n",
162 pc110pad_name, pc110pad_io, pc110pad_irq);
163
164 return 0;
165}
166
167static void __exit pc110pad_exit(void)
168{
169 input_unregister_device(&pc110pad_dev);
170
171 outb(PC110PAD_OFF, pc110pad_io + 2);
172
173 free_irq(pc110pad_irq, NULL);
174 release_region(pc110pad_io, 4);
175}
176
177module_init(pc110pad_init);
178module_exit(pc110pad_exit);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
new file mode 100644
index 000000000000..cd8509549eac
--- /dev/null
+++ b/drivers/input/mouse/psmouse-base.c
@@ -0,0 +1,1011 @@
1/*
2 * PS/2 mouse driver
3 *
4 * Copyright (c) 1999-2002 Vojtech Pavlik
5 * Copyright (c) 2003-2004 Dmitry Torokhov
6 */
7
8/*
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 */
13
14#include <linux/delay.h>
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/slab.h>
18#include <linux/interrupt.h>
19#include <linux/input.h>
20#include <linux/serio.h>
21#include <linux/init.h>
22#include <linux/libps2.h>
23#include "psmouse.h"
24#include "synaptics.h"
25#include "logips2pp.h"
26#include "alps.h"
27
28#define DRIVER_DESC "PS/2 mouse driver"
29
30MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
31MODULE_DESCRIPTION(DRIVER_DESC);
32MODULE_LICENSE("GPL");
33
34static unsigned int psmouse_max_proto = -1U;
35static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
36static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
37static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
38#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
39#define param_set_proto_abbrev psmouse_set_maxproto
40#define param_get_proto_abbrev psmouse_get_maxproto
41module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
42MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
43
44static unsigned int psmouse_resolution = 200;
45module_param_named(resolution, psmouse_resolution, uint, 0644);
46MODULE_PARM_DESC(resolution, "Resolution, in dpi.");
47
48static unsigned int psmouse_rate = 100;
49module_param_named(rate, psmouse_rate, uint, 0644);
50MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
51
52static unsigned int psmouse_smartscroll = 1;
53module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
54MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
55
56static unsigned int psmouse_resetafter;
57module_param_named(resetafter, psmouse_resetafter, uint, 0644);
58MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
59
60PSMOUSE_DEFINE_ATTR(rate);
61PSMOUSE_DEFINE_ATTR(resolution);
62PSMOUSE_DEFINE_ATTR(resetafter);
63
64__obsolete_setup("psmouse_noext");
65__obsolete_setup("psmouse_resolution=");
66__obsolete_setup("psmouse_smartscroll=");
67__obsolete_setup("psmouse_resetafter=");
68__obsolete_setup("psmouse_rate=");
69
70static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
71
72/*
73 * psmouse_process_byte() analyzes the PS/2 data stream and reports
74 * relevant events to the input module once full packet has arrived.
75 */
76
77static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
78{
79 struct input_dev *dev = &psmouse->dev;
80 unsigned char *packet = psmouse->packet;
81
82 if (psmouse->pktcnt < psmouse->pktsize)
83 return PSMOUSE_GOOD_DATA;
84
85/*
86 * Full packet accumulated, process it
87 */
88
89 input_regs(dev, regs);
90
91/*
92 * Scroll wheel on IntelliMice, scroll buttons on NetMice
93 */
94
95 if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
96 input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
97
98/*
99 * Scroll wheel and buttons on IntelliMouse Explorer
100 */
101
102 if (psmouse->type == PSMOUSE_IMEX) {
103 input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
104 input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
105 input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
106 }
107
108/*
109 * Extra buttons on Genius NewNet 3D
110 */
111
112 if (psmouse->type == PSMOUSE_GENPS) {
113 input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
114 input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
115 }
116
117/*
118 * Extra button on ThinkingMouse
119 */
120 if (psmouse->type == PSMOUSE_THINKPS) {
121 input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
122 /* Without this bit of weirdness moving up gives wildly high Y changes. */
123 packet[1] |= (packet[0] & 0x40) << 1;
124 }
125
126/*
127 * Generic PS/2 Mouse
128 */
129
130 input_report_key(dev, BTN_LEFT, packet[0] & 1);
131 input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
132 input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
133
134 input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
135 input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
136
137 input_sync(dev);
138
139 return PSMOUSE_FULL_PACKET;
140}
141
142/*
143 * psmouse_interrupt() handles incoming characters, either gathering them into
144 * packets or passing them to the command routine as command output.
145 */
146
147static irqreturn_t psmouse_interrupt(struct serio *serio,
148 unsigned char data, unsigned int flags, struct pt_regs *regs)
149{
150 struct psmouse *psmouse = serio_get_drvdata(serio);
151 psmouse_ret_t rc;
152
153 if (psmouse->state == PSMOUSE_IGNORE)
154 goto out;
155
156 if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) {
157 if (psmouse->state == PSMOUSE_ACTIVATED)
158 printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
159 flags & SERIO_TIMEOUT ? " timeout" : "",
160 flags & SERIO_PARITY ? " bad parity" : "");
161 ps2_cmd_aborted(&psmouse->ps2dev);
162 goto out;
163 }
164
165 if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
166 if (ps2_handle_ack(&psmouse->ps2dev, data))
167 goto out;
168
169 if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
170 if (ps2_handle_response(&psmouse->ps2dev, data))
171 goto out;
172
173 if (psmouse->state == PSMOUSE_INITIALIZING)
174 goto out;
175
176 if (psmouse->state == PSMOUSE_ACTIVATED &&
177 psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
178 printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
179 psmouse->name, psmouse->phys, psmouse->pktcnt);
180 psmouse->pktcnt = 0;
181 }
182
183 psmouse->last = jiffies;
184 psmouse->packet[psmouse->pktcnt++] = data;
185
186 if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
187 if (psmouse->pktcnt == 1)
188 goto out;
189
190 if (psmouse->pktcnt == 2) {
191 if (psmouse->packet[1] == PSMOUSE_RET_ID) {
192 psmouse->state = PSMOUSE_IGNORE;
193 serio_reconnect(serio);
194 goto out;
195 }
196 if (psmouse->type == PSMOUSE_SYNAPTICS) {
197 /* neither 0xAA nor 0x00 are valid first bytes
198 * for a packet in absolute mode
199 */
200 psmouse->pktcnt = 0;
201 goto out;
202 }
203 }
204 }
205
206 rc = psmouse->protocol_handler(psmouse, regs);
207
208 switch (rc) {
209 case PSMOUSE_BAD_DATA:
210 printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
211 psmouse->name, psmouse->phys, psmouse->pktcnt);
212 psmouse->pktcnt = 0;
213
214 if (++psmouse->out_of_sync == psmouse->resetafter) {
215 psmouse->state = PSMOUSE_IGNORE;
216 printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
217 serio_reconnect(psmouse->ps2dev.serio);
218 }
219 break;
220
221 case PSMOUSE_FULL_PACKET:
222 psmouse->pktcnt = 0;
223 if (psmouse->out_of_sync) {
224 psmouse->out_of_sync = 0;
225 printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
226 psmouse->name, psmouse->phys);
227 }
228 break;
229
230 case PSMOUSE_GOOD_DATA:
231 break;
232 }
233out:
234 return IRQ_HANDLED;
235}
236
237
238/*
239 * psmouse_sliced_command() sends an extended PS/2 command to the mouse
240 * using sliced syntax, understood by advanced devices, such as Logitech
241 * or Synaptics touchpads. The command is encoded as:
242 * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
243 * is the command.
244 */
245int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
246{
247 int i;
248
249 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
250 return -1;
251
252 for (i = 6; i >= 0; i -= 2) {
253 unsigned char d = (command >> i) & 3;
254 if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
255 return -1;
256 }
257
258 return 0;
259}
260
261
262/*
263 * psmouse_reset() resets the mouse into power-on state.
264 */
265int psmouse_reset(struct psmouse *psmouse)
266{
267 unsigned char param[2];
268
269 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT))
270 return -1;
271
272 if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
273 return -1;
274
275 return 0;
276}
277
278
279/*
280 * Genius NetMouse magic init.
281 */
282static int genius_detect(struct psmouse *psmouse, int set_properties)
283{
284 struct ps2dev *ps2dev = &psmouse->ps2dev;
285 unsigned char param[4];
286
287 param[0] = 3;
288 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
289 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
290 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
291 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
292 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
293
294 if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55)
295 return -1;
296
297 if (set_properties) {
298 set_bit(BTN_EXTRA, psmouse->dev.keybit);
299 set_bit(BTN_SIDE, psmouse->dev.keybit);
300 set_bit(REL_WHEEL, psmouse->dev.relbit);
301
302 psmouse->vendor = "Genius";
303 psmouse->name = "Wheel Mouse";
304 psmouse->pktsize = 4;
305 }
306
307 return 0;
308}
309
310/*
311 * IntelliMouse magic init.
312 */
313static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
314{
315 struct ps2dev *ps2dev = &psmouse->ps2dev;
316 unsigned char param[2];
317
318 param[0] = 200;
319 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
320 param[0] = 100;
321 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
322 param[0] = 80;
323 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
324 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
325
326 if (param[0] != 3)
327 return -1;
328
329 if (set_properties) {
330 set_bit(REL_WHEEL, psmouse->dev.relbit);
331
332 if (!psmouse->vendor) psmouse->vendor = "Generic";
333 if (!psmouse->name) psmouse->name = "Wheel Mouse";
334 psmouse->pktsize = 4;
335 }
336
337 return 0;
338}
339
340/*
341 * Try IntelliMouse/Explorer magic init.
342 */
343static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
344{
345 struct ps2dev *ps2dev = &psmouse->ps2dev;
346 unsigned char param[2];
347
348 intellimouse_detect(psmouse, 0);
349
350 param[0] = 200;
351 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
352 param[0] = 200;
353 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
354 param[0] = 80;
355 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
356 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
357
358 if (param[0] != 4)
359 return -1;
360
361 if (set_properties) {
362 set_bit(REL_WHEEL, psmouse->dev.relbit);
363 set_bit(BTN_SIDE, psmouse->dev.keybit);
364 set_bit(BTN_EXTRA, psmouse->dev.keybit);
365
366 if (!psmouse->vendor) psmouse->vendor = "Generic";
367 if (!psmouse->name) psmouse->name = "Explorer Mouse";
368 psmouse->pktsize = 4;
369 }
370
371 return 0;
372}
373
374/*
375 * Kensington ThinkingMouse / ExpertMouse magic init.
376 */
377static int thinking_detect(struct psmouse *psmouse, int set_properties)
378{
379 struct ps2dev *ps2dev = &psmouse->ps2dev;
380 unsigned char param[2];
381 unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 };
382 int i;
383
384 param[0] = 10;
385 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
386 param[0] = 0;
387 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
388 for (i = 0; seq[i]; i++)
389 ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
390 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
391
392 if (param[0] != 2)
393 return -1;
394
395 if (set_properties) {
396 set_bit(BTN_EXTRA, psmouse->dev.keybit);
397
398 psmouse->vendor = "Kensington";
399 psmouse->name = "ThinkingMouse";
400 }
401
402 return 0;
403}
404
405/*
406 * Bare PS/2 protocol "detection". Always succeeds.
407 */
408static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
409{
410 if (!psmouse->vendor) psmouse->vendor = "Generic";
411 if (!psmouse->name) psmouse->name = "Mouse";
412
413 return 0;
414}
415
416/*
417 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
418 * the mouse may have.
419 */
420
421static int psmouse_extensions(struct psmouse *psmouse,
422 unsigned int max_proto, int set_properties)
423{
424 int synaptics_hardware = 0;
425
426/*
427 * Try Kensington ThinkingMouse (we try first, because synaptics probe
428 * upsets the thinkingmouse).
429 */
430
431 if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0)
432 return PSMOUSE_THINKPS;
433
434/*
435 * Try Synaptics TouchPad
436 */
437 if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
438 synaptics_hardware = 1;
439
440 if (max_proto > PSMOUSE_IMEX) {
441 if (!set_properties || synaptics_init(psmouse) == 0)
442 return PSMOUSE_SYNAPTICS;
443/*
444 * Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
445 * Unfortunately Logitech/Genius probes confuse some firmware versions so
446 * we'll have to skip them.
447 */
448 max_proto = PSMOUSE_IMEX;
449 }
450/*
451 * Make sure that touchpad is in relative mode, gestures (taps) are enabled
452 */
453 synaptics_reset(psmouse);
454 }
455
456/*
457 * Try ALPS TouchPad
458 */
459 if (max_proto > PSMOUSE_IMEX) {
460 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
461 if (alps_detect(psmouse, set_properties) == 0) {
462 if (!set_properties || alps_init(psmouse) == 0)
463 return PSMOUSE_ALPS;
464/*
465 * Init failed, try basic relative protocols
466 */
467 max_proto = PSMOUSE_IMEX;
468 }
469 }
470
471 if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
472 return PSMOUSE_GENPS;
473
474 if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
475 return PSMOUSE_PS2PP;
476
477/*
478 * Reset to defaults in case the device got confused by extended
479 * protocol probes.
480 */
481 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
482
483 if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
484 return PSMOUSE_IMEX;
485
486 if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
487 return PSMOUSE_IMPS;
488
489/*
490 * Okay, all failed, we have a standard mouse here. The number of the buttons
491 * is still a question, though. We assume 3.
492 */
493 ps2bare_detect(psmouse, set_properties);
494
495 if (synaptics_hardware) {
496/*
497 * We detected Synaptics hardware but it did not respond to IMPS/2 probes.
498 * We need to reset the touchpad because if there is a track point on the
499 * pass through port it could get disabled while probing for protocol
500 * extensions.
501 */
502 psmouse_reset(psmouse);
503 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
504 }
505
506 return PSMOUSE_PS2;
507}
508
509/*
510 * psmouse_probe() probes for a PS/2 mouse.
511 */
512
513static int psmouse_probe(struct psmouse *psmouse)
514{
515 struct ps2dev *ps2dev = &psmouse->ps2dev;
516 unsigned char param[2];
517
518/*
519 * First, we check if it's a mouse. It should send 0x00 or 0x03
520 * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
521 */
522
523 param[0] = 0xa5;
524 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
525 return -1;
526
527 if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
528 return -1;
529
530/*
531 * Then we reset and disable the mouse so that it doesn't generate events.
532 */
533
534 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
535 printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
536
537 return 0;
538}
539
540/*
541 * Here we set the mouse resolution.
542 */
543
544void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
545{
546 unsigned char params[] = { 0, 1, 2, 2, 3 };
547
548 if (resolution == 0 || resolution > 200)
549 resolution = 200;
550
551 ps2_command(&psmouse->ps2dev, &params[resolution / 50], PSMOUSE_CMD_SETRES);
552 psmouse->resolution = 25 << params[resolution / 50];
553}
554
555/*
556 * Here we set the mouse report rate.
557 */
558
559static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
560{
561 unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
562 int i = 0;
563
564 while (rates[i] > rate) i++;
565 ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE);
566 psmouse->rate = rates[i];
567}
568
569/*
570 * psmouse_initialize() initializes the mouse to a sane state.
571 */
572
573static void psmouse_initialize(struct psmouse *psmouse)
574{
575/*
576 * We set the mouse into streaming mode.
577 */
578
579 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM);
580
581/*
582 * We set the mouse report rate, resolution and scaling.
583 */
584
585 if (psmouse_max_proto != PSMOUSE_PS2) {
586 psmouse->set_rate(psmouse, psmouse->rate);
587 psmouse->set_resolution(psmouse, psmouse->resolution);
588 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
589 }
590}
591
592/*
593 * psmouse_set_state() sets new psmouse state and resets all flags and
594 * counters while holding serio lock so fighting with interrupt handler
595 * is not a concern.
596 */
597
598static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
599{
600 serio_pause_rx(psmouse->ps2dev.serio);
601 psmouse->state = new_state;
602 psmouse->pktcnt = psmouse->out_of_sync = 0;
603 psmouse->ps2dev.flags = 0;
604 serio_continue_rx(psmouse->ps2dev.serio);
605}
606
607/*
608 * psmouse_activate() enables the mouse so that we get motion reports from it.
609 */
610
611static void psmouse_activate(struct psmouse *psmouse)
612{
613 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
614 printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
615 psmouse->ps2dev.serio->phys);
616
617 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
618}
619
620
621/*
622 * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
623 * reports from it unless we explicitely request it.
624 */
625
626static void psmouse_deactivate(struct psmouse *psmouse)
627{
628 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
629 printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
630 psmouse->ps2dev.serio->phys);
631
632 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
633}
634
635
636/*
637 * psmouse_cleanup() resets the mouse into power-on state.
638 */
639
640static void psmouse_cleanup(struct serio *serio)
641{
642 struct psmouse *psmouse = serio_get_drvdata(serio);
643
644 psmouse_reset(psmouse);
645}
646
647/*
648 * psmouse_disconnect() closes and frees.
649 */
650
651static void psmouse_disconnect(struct serio *serio)
652{
653 struct psmouse *psmouse, *parent;
654
655 device_remove_file(&serio->dev, &psmouse_attr_rate);
656 device_remove_file(&serio->dev, &psmouse_attr_resolution);
657 device_remove_file(&serio->dev, &psmouse_attr_resetafter);
658
659 psmouse = serio_get_drvdata(serio);
660 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
661
662 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
663 parent = serio_get_drvdata(serio->parent);
664 if (parent->pt_deactivate)
665 parent->pt_deactivate(parent);
666 }
667
668 if (psmouse->disconnect)
669 psmouse->disconnect(psmouse);
670
671 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
672
673 input_unregister_device(&psmouse->dev);
674 serio_close(serio);
675 serio_set_drvdata(serio, NULL);
676 kfree(psmouse);
677}
678
679/*
680 * psmouse_connect() is a callback from the serio module when
681 * an unhandled serio port is found.
682 */
683static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
684{
685 struct psmouse *psmouse, *parent = NULL;
686 int retval;
687
688 /*
689 * If this is a pass-through port deactivate parent so the device
690 * connected to this port can be successfully identified
691 */
692 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
693 parent = serio_get_drvdata(serio->parent);
694 psmouse_deactivate(parent);
695 }
696
697 if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
698 retval = -ENOMEM;
699 goto out;
700 }
701
702 memset(psmouse, 0, sizeof(struct psmouse));
703
704 ps2_init(&psmouse->ps2dev, serio);
705 sprintf(psmouse->phys, "%s/input0", serio->phys);
706 psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
707 psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
708 psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
709 psmouse->dev.private = psmouse;
710 psmouse->dev.dev = &serio->dev;
711 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
712
713 serio_set_drvdata(serio, psmouse);
714
715 retval = serio_open(serio, drv);
716 if (retval) {
717 serio_set_drvdata(serio, NULL);
718 kfree(psmouse);
719 goto out;
720 }
721
722 if (psmouse_probe(psmouse) < 0) {
723 serio_close(serio);
724 serio_set_drvdata(serio, NULL);
725 kfree(psmouse);
726 retval = -ENODEV;
727 goto out;
728 }
729
730 psmouse->rate = psmouse_rate;
731 psmouse->resolution = psmouse_resolution;
732 psmouse->resetafter = psmouse_resetafter;
733 psmouse->smartscroll = psmouse_smartscroll;
734 psmouse->set_rate = psmouse_set_rate;
735 psmouse->set_resolution = psmouse_set_resolution;
736 psmouse->protocol_handler = psmouse_process_byte;
737 psmouse->pktsize = 3;
738
739 psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
740
741 sprintf(psmouse->devname, "%s %s %s",
742 psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
743
744 psmouse->dev.name = psmouse->devname;
745 psmouse->dev.phys = psmouse->phys;
746 psmouse->dev.id.bustype = BUS_I8042;
747 psmouse->dev.id.vendor = 0x0002;
748 psmouse->dev.id.product = psmouse->type;
749 psmouse->dev.id.version = psmouse->model;
750
751 input_register_device(&psmouse->dev);
752
753 printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
754
755 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
756
757 psmouse_initialize(psmouse);
758
759 if (parent && parent->pt_activate)
760 parent->pt_activate(parent);
761
762 device_create_file(&serio->dev, &psmouse_attr_rate);
763 device_create_file(&serio->dev, &psmouse_attr_resolution);
764 device_create_file(&serio->dev, &psmouse_attr_resetafter);
765
766 psmouse_activate(psmouse);
767
768 retval = 0;
769
770out:
771 /* If this is a pass-through port the parent awaits to be activated */
772 if (parent)
773 psmouse_activate(parent);
774
775 return retval;
776}
777
778
779static int psmouse_reconnect(struct serio *serio)
780{
781 struct psmouse *psmouse = serio_get_drvdata(serio);
782 struct psmouse *parent = NULL;
783 struct serio_driver *drv = serio->drv;
784 int rc = -1;
785
786 if (!drv || !psmouse) {
787 printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
788 return -1;
789 }
790
791 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
792 parent = serio_get_drvdata(serio->parent);
793 psmouse_deactivate(parent);
794 }
795
796 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
797
798 if (psmouse->reconnect) {
799 if (psmouse->reconnect(psmouse))
800 goto out;
801 } else if (psmouse_probe(psmouse) < 0 ||
802 psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
803 goto out;
804
805 /* ok, the device type (and capabilities) match the old one,
806 * we can continue using it, complete intialization
807 */
808 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
809
810 psmouse_initialize(psmouse);
811
812 if (parent && parent->pt_activate)
813 parent->pt_activate(parent);
814
815 psmouse_activate(psmouse);
816 rc = 0;
817
818out:
819 /* If this is a pass-through port the parent waits to be activated */
820 if (parent)
821 psmouse_activate(parent);
822
823 return rc;
824}
825
826static struct serio_device_id psmouse_serio_ids[] = {
827 {
828 .type = SERIO_8042,
829 .proto = SERIO_ANY,
830 .id = SERIO_ANY,
831 .extra = SERIO_ANY,
832 },
833 {
834 .type = SERIO_PS_PSTHRU,
835 .proto = SERIO_ANY,
836 .id = SERIO_ANY,
837 .extra = SERIO_ANY,
838 },
839 { 0 }
840};
841
842MODULE_DEVICE_TABLE(serio, psmouse_serio_ids);
843
844static struct serio_driver psmouse_drv = {
845 .driver = {
846 .name = "psmouse",
847 },
848 .description = DRIVER_DESC,
849 .id_table = psmouse_serio_ids,
850 .interrupt = psmouse_interrupt,
851 .connect = psmouse_connect,
852 .reconnect = psmouse_reconnect,
853 .disconnect = psmouse_disconnect,
854 .cleanup = psmouse_cleanup,
855};
856
857ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
858 ssize_t (*handler)(struct psmouse *, char *))
859{
860 struct serio *serio = to_serio_port(dev);
861 int retval;
862
863 retval = serio_pin_driver(serio);
864 if (retval)
865 return retval;
866
867 if (serio->drv != &psmouse_drv) {
868 retval = -ENODEV;
869 goto out;
870 }
871
872 retval = handler(serio_get_drvdata(serio), buf);
873
874out:
875 serio_unpin_driver(serio);
876 return retval;
877}
878
879ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count,
880 ssize_t (*handler)(struct psmouse *, const char *, size_t))
881{
882 struct serio *serio = to_serio_port(dev);
883 struct psmouse *psmouse = serio_get_drvdata(serio);
884 struct psmouse *parent = NULL;
885 int retval;
886
887 retval = serio_pin_driver(serio);
888 if (retval)
889 return retval;
890
891 if (serio->drv != &psmouse_drv) {
892 retval = -ENODEV;
893 goto out;
894 }
895
896 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
897 parent = serio_get_drvdata(serio->parent);
898 psmouse_deactivate(parent);
899 }
900 psmouse_deactivate(psmouse);
901
902 retval = handler(psmouse, buf, count);
903
904 psmouse_activate(psmouse);
905 if (parent)
906 psmouse_activate(parent);
907
908out:
909 serio_unpin_driver(serio);
910 return retval;
911}
912
913static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
914{
915 return sprintf(buf, "%d\n", psmouse->rate);
916}
917
918static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, size_t count)
919{
920 unsigned long value;
921 char *rest;
922
923 value = simple_strtoul(buf, &rest, 10);
924 if (*rest)
925 return -EINVAL;
926
927 psmouse->set_rate(psmouse, value);
928 return count;
929}
930
931static ssize_t psmouse_attr_show_resolution(struct psmouse *psmouse, char *buf)
932{
933 return sprintf(buf, "%d\n", psmouse->resolution);
934}
935
936static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *buf, size_t count)
937{
938 unsigned long value;
939 char *rest;
940
941 value = simple_strtoul(buf, &rest, 10);
942 if (*rest)
943 return -EINVAL;
944
945 psmouse->set_resolution(psmouse, value);
946 return count;
947}
948
949static ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf)
950{
951 return sprintf(buf, "%d\n", psmouse->resetafter);
952}
953
954static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count)
955{
956 unsigned long value;
957 char *rest;
958
959 value = simple_strtoul(buf, &rest, 10);
960 if (*rest)
961 return -EINVAL;
962
963 psmouse->resetafter = value;
964 return count;
965}
966
967static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
968{
969 int i;
970
971 if (!val)
972 return -EINVAL;
973
974 if (!strncmp(val, "any", 3)) {
975 *((unsigned int *)kp->arg) = -1UL;
976 return 0;
977 }
978
979 for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
980 if (!psmouse_proto_abbrev[i])
981 continue;
982
983 if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
984 *((unsigned int *)kp->arg) = i;
985 return 0;
986 }
987 }
988
989 return -EINVAL; \
990}
991
992static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
993{
994 return sprintf(buffer, "%s\n",
995 psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
996 psmouse_proto_abbrev[psmouse_max_proto] : "any");
997}
998
999static int __init psmouse_init(void)
1000{
1001 serio_register_driver(&psmouse_drv);
1002 return 0;
1003}
1004
1005static void __exit psmouse_exit(void)
1006{
1007 serio_unregister_driver(&psmouse_drv);
1008}
1009
1010module_init(psmouse_init);
1011module_exit(psmouse_exit);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
new file mode 100644
index 000000000000..bda5b065d03c
--- /dev/null
+++ b/drivers/input/mouse/psmouse.h
@@ -0,0 +1,106 @@
1#ifndef _PSMOUSE_H
2#define _PSMOUSE_H
3
4#define PSMOUSE_CMD_SETSCALE11 0x00e6
5#define PSMOUSE_CMD_SETSCALE21 0x00e7
6#define PSMOUSE_CMD_SETRES 0x10e8
7#define PSMOUSE_CMD_GETINFO 0x03e9
8#define PSMOUSE_CMD_SETSTREAM 0x00ea
9#define PSMOUSE_CMD_SETPOLL 0x00f0
10#define PSMOUSE_CMD_POLL 0x03eb
11#define PSMOUSE_CMD_GETID 0x02f2
12#define PSMOUSE_CMD_SETRATE 0x10f3
13#define PSMOUSE_CMD_ENABLE 0x00f4
14#define PSMOUSE_CMD_DISABLE 0x00f5
15#define PSMOUSE_CMD_RESET_DIS 0x00f6
16#define PSMOUSE_CMD_RESET_BAT 0x02ff
17
18#define PSMOUSE_RET_BAT 0xaa
19#define PSMOUSE_RET_ID 0x00
20#define PSMOUSE_RET_ACK 0xfa
21#define PSMOUSE_RET_NAK 0xfe
22
23enum psmouse_state {
24 PSMOUSE_IGNORE,
25 PSMOUSE_INITIALIZING,
26 PSMOUSE_CMD_MODE,
27 PSMOUSE_ACTIVATED,
28};
29
30/* psmouse protocol handler return codes */
31typedef enum {
32 PSMOUSE_BAD_DATA,
33 PSMOUSE_GOOD_DATA,
34 PSMOUSE_FULL_PACKET
35} psmouse_ret_t;
36
37struct psmouse {
38 void *private;
39 struct input_dev dev;
40 struct ps2dev ps2dev;
41 char *vendor;
42 char *name;
43 unsigned char packet[8];
44 unsigned char pktcnt;
45 unsigned char pktsize;
46 unsigned char type;
47 unsigned int model;
48 unsigned long last;
49 unsigned long out_of_sync;
50 enum psmouse_state state;
51 char devname[64];
52 char phys[32];
53
54 unsigned int rate;
55 unsigned int resolution;
56 unsigned int resetafter;
57 unsigned int smartscroll; /* Logitech only */
58
59 psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
60 void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
61 void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
62
63 int (*reconnect)(struct psmouse *psmouse);
64 void (*disconnect)(struct psmouse *psmouse);
65
66 void (*pt_activate)(struct psmouse *psmouse);
67 void (*pt_deactivate)(struct psmouse *psmouse);
68};
69
70enum psmouse_type {
71 PSMOUSE_NONE,
72 PSMOUSE_PS2,
73 PSMOUSE_PS2PP,
74 PSMOUSE_THINKPS,
75 PSMOUSE_GENPS,
76 PSMOUSE_IMPS,
77 PSMOUSE_IMEX,
78 PSMOUSE_SYNAPTICS,
79 PSMOUSE_ALPS,
80};
81
82int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
83int psmouse_reset(struct psmouse *psmouse);
84void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
85
86ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
87 ssize_t (*handler)(struct psmouse *, char *));
88ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count,
89 ssize_t (*handler)(struct psmouse *, const char *, size_t));
90
91#define PSMOUSE_DEFINE_ATTR(_name) \
92static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \
93static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\
94static ssize_t psmouse_do_show_##_name(struct device *d, char *b) \
95{ \
96 return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \
97} \
98static ssize_t psmouse_do_set_##_name(struct device *d, const char *b, size_t s)\
99{ \
100 return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \
101} \
102static struct device_attribute psmouse_attr_##_name = \
103 __ATTR(_name, S_IWUSR | S_IRUGO, \
104 psmouse_do_show_##_name, psmouse_do_set_##_name);
105
106#endif /* _PSMOUSE_H */
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
new file mode 100644
index 000000000000..7280f68afcee
--- /dev/null
+++ b/drivers/input/mouse/rpcmouse.c
@@ -0,0 +1,107 @@
1/*
2 * Acorn RiscPC mouse driver for Linux/ARM
3 *
4 * Copyright (c) 2000-2002 Vojtech Pavlik
5 * Copyright (C) 1996-2002 Russell King
6 *
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This handles the Acorn RiscPCs mouse. We basically have a couple of
15 * hardware registers that track the sensor count for the X-Y movement and
16 * another register holding the button state. On every VSYNC interrupt we read
17 * the complete state and then work out if something has changed.
18 */
19
20#include <linux/module.h>
21#include <linux/sched.h>
22#include <linux/ptrace.h>
23#include <linux/interrupt.h>
24#include <linux/init.h>
25#include <linux/input.h>
26
27#include <asm/hardware.h>
28#include <asm/irq.h>
29#include <asm/io.h>
30#include <asm/hardware/iomd.h>
31
32MODULE_AUTHOR("Vojtech Pavlik, Russell King");
33MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
34MODULE_LICENSE("GPL");
35
36static short rpcmouse_lastx, rpcmouse_lasty;
37
38static struct input_dev rpcmouse_dev = {
39 .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
40 .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
41 .relbit = { BIT(REL_X) | BIT(REL_Y) },
42 .name = "Acorn RiscPC Mouse",
43 .phys = "rpcmouse/input0",
44 .id = {
45 .bustype = BUS_HOST,
46 .vendor = 0x0005,
47 .product = 0x0001,
48 .version = 0x0100,
49 },
50};
51
52static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
53{
54 struct input_dev *dev = dev_id;
55 short x, y, dx, dy, b;
56
57 x = (short) iomd_readl(IOMD_MOUSEX);
58 y = (short) iomd_readl(IOMD_MOUSEY);
59 b = (short) (__raw_readl(0xe0310000) ^ 0x70);
60
61 dx = x - rpcmouse_lastx;
62 dy = y - rpcmouse_lasty;
63
64 rpcmouse_lastx = x;
65 rpcmouse_lasty = y;
66
67 input_regs(dev, regs);
68
69 input_report_rel(dev, REL_X, dx);
70 input_report_rel(dev, REL_Y, -dy);
71
72 input_report_key(dev, BTN_LEFT, b & 0x40);
73 input_report_key(dev, BTN_MIDDLE, b & 0x20);
74 input_report_key(dev, BTN_RIGHT, b & 0x10);
75
76 input_sync(dev);
77
78 return IRQ_HANDLED;
79}
80
81static int __init rpcmouse_init(void)
82{
83 init_input_dev(&rpcmouse_dev);
84
85 rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
86 rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
87
88 if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", &rpcmouse_dev)) {
89 printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
90 return -1;
91 }
92
93 input_register_device(&rpcmouse_dev);
94
95 printk(KERN_INFO "input: Acorn RiscPC mouse\n");
96
97 return 0;
98}
99
100static void __exit rpcmouse_exit(void)
101{
102 input_unregister_device(&rpcmouse_dev);
103 free_irq(IRQ_VSYNCPULSE, &rpcmouse_dev);
104}
105
106module_init(rpcmouse_init);
107module_exit(rpcmouse_exit);
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
new file mode 100644
index 000000000000..d12b93ae3900
--- /dev/null
+++ b/drivers/input/mouse/sermouse.c
@@ -0,0 +1,370 @@
1/*
2 * $Id: sermouse.c,v 1.17 2002/03/13 10:03:43 vojtech Exp $
3 *
4 * Copyright (c) 1999-2001 Vojtech Pavlik
5 */
6
7/*
8 * Serial mouse driver for Linux
9 */
10
11/*
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
28 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
29 */
30
31#include <linux/delay.h>
32#include <linux/module.h>
33#include <linux/slab.h>
34#include <linux/interrupt.h>
35#include <linux/input.h>
36#include <linux/config.h>
37#include <linux/serio.h>
38#include <linux/init.h>
39
40#define DRIVER_DESC "Serial mouse driver"
41
42MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
43MODULE_DESCRIPTION(DRIVER_DESC);
44MODULE_LICENSE("GPL");
45
46static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
47 "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
48 "Logitech MZ++ Mouse"};
49
50struct sermouse {
51 struct input_dev dev;
52 signed char buf[8];
53 unsigned char count;
54 unsigned char type;
55 unsigned long last;
56 char phys[32];
57};
58
59/*
60 * sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
61 * applies some prediction to the data, resulting in 96 updates per
62 * second, which is as good as a PS/2 or USB mouse.
63 */
64
65static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
66{
67 struct input_dev *dev = &sermouse->dev;
68 signed char *buf = sermouse->buf;
69
70 input_regs(dev, regs);
71
72 switch (sermouse->count) {
73
74 case 0:
75 if ((data & 0xf8) != 0x80) return;
76 input_report_key(dev, BTN_LEFT, !(data & 4));
77 input_report_key(dev, BTN_RIGHT, !(data & 1));
78 input_report_key(dev, BTN_MIDDLE, !(data & 2));
79 break;
80
81 case 1:
82 case 3:
83 input_report_rel(dev, REL_X, data / 2);
84 input_report_rel(dev, REL_Y, -buf[1]);
85 buf[0] = data - data / 2;
86 break;
87
88 case 2:
89 case 4:
90 input_report_rel(dev, REL_X, buf[0]);
91 input_report_rel(dev, REL_Y, buf[1] - data);
92 buf[1] = data / 2;
93 break;
94 }
95
96 input_sync(dev);
97
98 if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
99 sermouse->count = 0;
100}
101
102/*
103 * sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
104 * generates events. With prediction it gets 80 updates/sec, assuming
105 * standard 3-byte packets and 1200 bps.
106 */
107
108static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
109{
110 struct input_dev *dev = &sermouse->dev;
111 signed char *buf = sermouse->buf;
112
113 if (data & 0x40) sermouse->count = 0;
114
115 input_regs(dev, regs);
116
117 switch (sermouse->count) {
118
119 case 0:
120 buf[1] = data;
121 input_report_key(dev, BTN_LEFT, (data >> 5) & 1);
122 input_report_key(dev, BTN_RIGHT, (data >> 4) & 1);
123 break;
124
125 case 1:
126 buf[2] = data;
127 data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
128 input_report_rel(dev, REL_X, data / 2);
129 input_report_rel(dev, REL_Y, buf[4]);
130 buf[3] = data - data / 2;
131 break;
132
133 case 2:
134 /* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
135 if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
136 input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
137 buf[0] = buf[1];
138
139 data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
140 input_report_rel(dev, REL_X, buf[3]);
141 input_report_rel(dev, REL_Y, data - buf[4]);
142 buf[4] = data / 2;
143 break;
144
145 case 3:
146
147 switch (sermouse->type) {
148
149 case SERIO_MS:
150 sermouse->type = SERIO_MP;
151
152 case SERIO_MP:
153 if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */
154 input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
155 input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
156 break;
157
158 case SERIO_MZP:
159 case SERIO_MZPP:
160 input_report_key(dev, BTN_SIDE, (data >> 5) & 1);
161
162 case SERIO_MZ:
163 input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
164 input_report_rel(dev, REL_WHEEL, (data & 8) - (data & 7));
165 break;
166 }
167
168 break;
169
170 case 4:
171 case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
172 buf[1] = (data >> 2) & 0x0f;
173 break;
174
175 case 5:
176 case 7: /* Ignore anything besides MZ++ */
177 if (sermouse->type != SERIO_MZPP) break;
178
179 switch (buf[1]) {
180
181 case 1: /* Extra mouse info */
182
183 input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
184 input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
185 input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
186
187 break;
188
189 default: /* We don't decode anything else yet. */
190
191 printk(KERN_WARNING
192 "sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
193 break;
194 }
195
196 break;
197 }
198
199 input_sync(dev);
200
201 sermouse->count++;
202}
203
204/*
205 * sermouse_interrupt() handles incoming characters, either gathering them into
206 * packets or passing them to the command routine as command output.
207 */
208
209static irqreturn_t sermouse_interrupt(struct serio *serio,
210 unsigned char data, unsigned int flags, struct pt_regs *regs)
211{
212 struct sermouse *sermouse = serio_get_drvdata(serio);
213
214 if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
215 sermouse->last = jiffies;
216
217 if (sermouse->type > SERIO_SUN)
218 sermouse_process_ms(sermouse, data, regs);
219 else
220 sermouse_process_msc(sermouse, data, regs);
221 return IRQ_HANDLED;
222}
223
224/*
225 * sermouse_disconnect() cleans up after we don't want talk
226 * to the mouse anymore.
227 */
228
229static void sermouse_disconnect(struct serio *serio)
230{
231 struct sermouse *sermouse = serio_get_drvdata(serio);
232
233 input_unregister_device(&sermouse->dev);
234 serio_close(serio);
235 serio_set_drvdata(serio, NULL);
236 kfree(sermouse);
237}
238
239/*
240 * sermouse_connect() is a callback form the serio module when
241 * an unhandled serio port is found.
242 */
243
244static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
245{
246 struct sermouse *sermouse;
247 unsigned char c;
248 int err;
249
250 if (!serio->id.proto || serio->id.proto > SERIO_MZPP)
251 return -ENODEV;
252
253 if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
254 return -ENOMEM;
255
256 memset(sermouse, 0, sizeof(struct sermouse));
257
258 init_input_dev(&sermouse->dev);
259 sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
260 sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
261 sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
262 sermouse->dev.private = sermouse;
263
264 sermouse->type = serio->id.proto;
265 c = serio->id.extra;
266
267 if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit);
268 if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit);
269 if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit);
270 if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit);
271 if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit);
272
273 sprintf(sermouse->phys, "%s/input0", serio->phys);
274
275 sermouse->dev.name = sermouse_protocols[sermouse->type];
276 sermouse->dev.phys = sermouse->phys;
277 sermouse->dev.id.bustype = BUS_RS232;
278 sermouse->dev.id.vendor = sermouse->type;
279 sermouse->dev.id.product = c;
280 sermouse->dev.id.version = 0x0100;
281 sermouse->dev.dev = &serio->dev;
282
283 serio_set_drvdata(serio, sermouse);
284
285 err = serio_open(serio, drv);
286 if (err) {
287 serio_set_drvdata(serio, NULL);
288 kfree(sermouse);
289 return err;
290 }
291
292 input_register_device(&sermouse->dev);
293
294 printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
295
296 return 0;
297}
298
299static struct serio_device_id sermouse_serio_ids[] = {
300 {
301 .type = SERIO_RS232,
302 .proto = SERIO_MSC,
303 .id = SERIO_ANY,
304 .extra = SERIO_ANY,
305 },
306 {
307 .type = SERIO_RS232,
308 .proto = SERIO_SUN,
309 .id = SERIO_ANY,
310 .extra = SERIO_ANY,
311 },
312 {
313 .type = SERIO_RS232,
314 .proto = SERIO_MS,
315 .id = SERIO_ANY,
316 .extra = SERIO_ANY,
317 },
318 {
319 .type = SERIO_RS232,
320 .proto = SERIO_MP,
321 .id = SERIO_ANY,
322 .extra = SERIO_ANY,
323 },
324 {
325 .type = SERIO_RS232,
326 .proto = SERIO_MZ,
327 .id = SERIO_ANY,
328 .extra = SERIO_ANY,
329 },
330 {
331 .type = SERIO_RS232,
332 .proto = SERIO_MZP,
333 .id = SERIO_ANY,
334 .extra = SERIO_ANY,
335 },
336 {
337 .type = SERIO_RS232,
338 .proto = SERIO_MZPP,
339 .id = SERIO_ANY,
340 .extra = SERIO_ANY,
341 },
342 { 0 }
343};
344
345MODULE_DEVICE_TABLE(serio, sermouse_serio_ids);
346
347static struct serio_driver sermouse_drv = {
348 .driver = {
349 .name = "sermouse",
350 },
351 .description = DRIVER_DESC,
352 .id_table = sermouse_serio_ids,
353 .interrupt = sermouse_interrupt,
354 .connect = sermouse_connect,
355 .disconnect = sermouse_disconnect,
356};
357
358static int __init sermouse_init(void)
359{
360 serio_register_driver(&sermouse_drv);
361 return 0;
362}
363
364static void __exit sermouse_exit(void)
365{
366 serio_unregister_driver(&sermouse_drv);
367}
368
369module_init(sermouse_init);
370module_exit(sermouse_exit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
new file mode 100644
index 000000000000..69832f8fb720
--- /dev/null
+++ b/drivers/input/mouse/synaptics.c
@@ -0,0 +1,700 @@
1/*
2 * Synaptics TouchPad PS/2 mouse driver
3 *
4 * 2003 Dmitry Torokhov <dtor@mail.ru>
5 * Added support for pass-through port. Special thanks to Peter Berg Larsen
6 * for explaining various Synaptics quirks.
7 *
8 * 2003 Peter Osterlund <petero2@telia.com>
9 * Ported to 2.5 input device infrastructure.
10 *
11 * Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
12 * start merging tpconfig and gpm code to a xfree-input module
13 * adding some changes and extensions (ex. 3rd and 4th button)
14 *
15 * Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
16 * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
17 * code for the special synaptics commands (from the tpconfig-source)
18 *
19 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License version 2 as published by
21 * the Free Software Foundation.
22 *
23 * Trademarks are the property of their respective owners.
24 */
25
26#include <linux/module.h>
27#include <linux/input.h>
28#include <linux/serio.h>
29#include <linux/libps2.h>
30#include "psmouse.h"
31#include "synaptics.h"
32
33/*
34 * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
35 * section 2.3.2, which says that they should be valid regardless of the
36 * actual size of the sensor.
37 */
38#define XMIN_NOMINAL 1472
39#define XMAX_NOMINAL 5472
40#define YMIN_NOMINAL 1408
41#define YMAX_NOMINAL 4448
42
43/*****************************************************************************
44 * Synaptics communications functions
45 ****************************************************************************/
46
47/*
48 * Send a command to the synpatics touchpad by special commands
49 */
50static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
51{
52 if (psmouse_sliced_command(psmouse, c))
53 return -1;
54 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
55 return -1;
56 return 0;
57}
58
59/*
60 * Set the synaptics touchpad mode byte by special commands
61 */
62static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
63{
64 unsigned char param[1];
65
66 if (psmouse_sliced_command(psmouse, mode))
67 return -1;
68 param[0] = SYN_PS_SET_MODE2;
69 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
70 return -1;
71 return 0;
72}
73
74/*
75 * Read the model-id bytes from the touchpad
76 * see also SYN_MODEL_* macros
77 */
78static int synaptics_model_id(struct psmouse *psmouse)
79{
80 struct synaptics_data *priv = psmouse->private;
81 unsigned char mi[3];
82
83 if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
84 return -1;
85 priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
86 return 0;
87}
88
89/*
90 * Read the capability-bits from the touchpad
91 * see also the SYN_CAP_* macros
92 */
93static int synaptics_capability(struct psmouse *psmouse)
94{
95 struct synaptics_data *priv = psmouse->private;
96 unsigned char cap[3];
97
98 if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
99 return -1;
100 priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
101 priv->ext_cap = 0;
102 if (!SYN_CAP_VALID(priv->capabilities))
103 return -1;
104
105 /*
106 * Unless capExtended is set the rest of the flags should be ignored
107 */
108 if (!SYN_CAP_EXTENDED(priv->capabilities))
109 priv->capabilities = 0;
110
111 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
112 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
113 printk(KERN_ERR "Synaptics claims to have extended capabilities,"
114 " but I'm not able to read them.");
115 } else {
116 priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
117
118 /*
119 * if nExtBtn is greater than 8 it should be considered
120 * invalid and treated as 0
121 */
122 if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
123 priv->ext_cap &= 0xff0fff;
124 }
125 }
126 return 0;
127}
128
129/*
130 * Identify Touchpad
131 * See also the SYN_ID_* macros
132 */
133static int synaptics_identify(struct psmouse *psmouse)
134{
135 struct synaptics_data *priv = psmouse->private;
136 unsigned char id[3];
137
138 if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
139 return -1;
140 priv->identity = (id[0]<<16) | (id[1]<<8) | id[2];
141 if (SYN_ID_IS_SYNAPTICS(priv->identity))
142 return 0;
143 return -1;
144}
145
146static void print_ident(struct synaptics_data *priv)
147{
148 printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
149 printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
150 SYN_ID_MINOR(priv->identity));
151 if (SYN_MODEL_ROT180(priv->model_id))
152 printk(KERN_INFO " 180 degree mounted touchpad\n");
153 if (SYN_MODEL_PORTRAIT(priv->model_id))
154 printk(KERN_INFO " portrait touchpad\n");
155 printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
156 if (SYN_MODEL_NEWABS(priv->model_id))
157 printk(KERN_INFO " new absolute packet format\n");
158 if (SYN_MODEL_PEN(priv->model_id))
159 printk(KERN_INFO " pen detection\n");
160
161 if (SYN_CAP_EXTENDED(priv->capabilities)) {
162 printk(KERN_INFO " Touchpad has extended capability bits\n");
163 if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
164 printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
165 (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
166 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
167 printk(KERN_INFO " -> middle button\n");
168 if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
169 printk(KERN_INFO " -> four buttons\n");
170 if (SYN_CAP_MULTIFINGER(priv->capabilities))
171 printk(KERN_INFO " -> multifinger detection\n");
172 if (SYN_CAP_PALMDETECT(priv->capabilities))
173 printk(KERN_INFO " -> palm detection\n");
174 if (SYN_CAP_PASS_THROUGH(priv->capabilities))
175 printk(KERN_INFO " -> pass-through port\n");
176 }
177}
178
179static int synaptics_query_hardware(struct psmouse *psmouse)
180{
181 int retries = 0;
182
183 while ((retries++ < 3) && psmouse_reset(psmouse))
184 printk(KERN_ERR "synaptics reset failed\n");
185
186 if (synaptics_identify(psmouse))
187 return -1;
188 if (synaptics_model_id(psmouse))
189 return -1;
190 if (synaptics_capability(psmouse))
191 return -1;
192
193 return 0;
194}
195
196static int synaptics_set_absolute_mode(struct psmouse *psmouse)
197{
198 struct synaptics_data *priv = psmouse->private;
199
200 priv->mode = SYN_BIT_ABSOLUTE_MODE;
201 if (SYN_ID_MAJOR(priv->identity) >= 4)
202 priv->mode |= SYN_BIT_DISABLE_GESTURE;
203 if (SYN_CAP_EXTENDED(priv->capabilities))
204 priv->mode |= SYN_BIT_W_MODE;
205
206 if (synaptics_mode_cmd(psmouse, priv->mode))
207 return -1;
208
209 return 0;
210}
211
212static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
213{
214 struct synaptics_data *priv = psmouse->private;
215
216 if (rate >= 80) {
217 priv->mode |= SYN_BIT_HIGH_RATE;
218 psmouse->rate = 80;
219 } else {
220 priv->mode &= ~SYN_BIT_HIGH_RATE;
221 psmouse->rate = 40;
222 }
223
224 synaptics_mode_cmd(psmouse, priv->mode);
225}
226
227/*****************************************************************************
228 * Synaptics pass-through PS/2 port support
229 ****************************************************************************/
230static int synaptics_pt_write(struct serio *serio, unsigned char c)
231{
232 struct psmouse *parent = serio_get_drvdata(serio->parent);
233 char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
234
235 if (psmouse_sliced_command(parent, c))
236 return -1;
237 if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
238 return -1;
239 return 0;
240}
241
242static inline int synaptics_is_pt_packet(unsigned char *buf)
243{
244 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
245}
246
247static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
248{
249 struct psmouse *child = serio_get_drvdata(ptport);
250
251 if (child && child->state == PSMOUSE_ACTIVATED) {
252 serio_interrupt(ptport, packet[1], 0, NULL);
253 serio_interrupt(ptport, packet[4], 0, NULL);
254 serio_interrupt(ptport, packet[5], 0, NULL);
255 if (child->type >= PSMOUSE_GENPS)
256 serio_interrupt(ptport, packet[2], 0, NULL);
257 } else
258 serio_interrupt(ptport, packet[1], 0, NULL);
259}
260
261static void synaptics_pt_activate(struct psmouse *psmouse)
262{
263 struct serio *ptport = psmouse->ps2dev.serio->child;
264 struct psmouse *child = serio_get_drvdata(ptport);
265 struct synaptics_data *priv = psmouse->private;
266
267 /* adjust the touchpad to child's choice of protocol */
268 if (child) {
269 if (child->type >= PSMOUSE_GENPS)
270 priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
271 else
272 priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
273
274 if (synaptics_mode_cmd(psmouse, priv->mode))
275 printk(KERN_INFO "synaptics: failed to switch guest protocol\n");
276 }
277}
278
279static void synaptics_pt_create(struct psmouse *psmouse)
280{
281 struct serio *serio;
282
283 serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
284 if (!serio) {
285 printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
286 return;
287 }
288
289 memset(serio, 0, sizeof(struct serio));
290
291 serio->id.type = SERIO_PS_PSTHRU;
292 strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
293 strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
294 serio->write = synaptics_pt_write;
295 serio->parent = psmouse->ps2dev.serio;
296
297 psmouse->pt_activate = synaptics_pt_activate;
298
299 printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
300 serio_register_port(serio);
301}
302
303/*****************************************************************************
304 * Functions to interpret the absolute mode packets
305 ****************************************************************************/
306
307static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
308{
309 memset(hw, 0, sizeof(struct synaptics_hw_state));
310
311 if (SYN_MODEL_NEWABS(priv->model_id)) {
312 hw->x = (((buf[3] & 0x10) << 8) |
313 ((buf[1] & 0x0f) << 8) |
314 buf[4]);
315 hw->y = (((buf[3] & 0x20) << 7) |
316 ((buf[1] & 0xf0) << 4) |
317 buf[5]);
318
319 hw->z = buf[2];
320 hw->w = (((buf[0] & 0x30) >> 2) |
321 ((buf[0] & 0x04) >> 1) |
322 ((buf[3] & 0x04) >> 2));
323
324 hw->left = (buf[0] & 0x01) ? 1 : 0;
325 hw->right = (buf[0] & 0x02) ? 1 : 0;
326
327 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
328 hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
329 if (hw->w == 2)
330 hw->scroll = (signed char)(buf[1]);
331 }
332
333 if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
334 hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
335 hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
336 }
337
338 if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
339 ((buf[0] ^ buf[3]) & 0x02)) {
340 switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
341 default:
342 /*
343 * if nExtBtn is greater than 8 it should be
344 * considered invalid and treated as 0
345 */
346 break;
347 case 8:
348 hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
349 hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
350 case 6:
351 hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
352 hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
353 case 4:
354 hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
355 hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
356 case 2:
357 hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
358 hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
359 }
360 }
361 } else {
362 hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
363 hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
364
365 hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
366 hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
367
368 hw->left = (buf[0] & 0x01) ? 1 : 0;
369 hw->right = (buf[0] & 0x02) ? 1 : 0;
370 }
371}
372
373/*
374 * called for each full received packet from the touchpad
375 */
376static void synaptics_process_packet(struct psmouse *psmouse)
377{
378 struct input_dev *dev = &psmouse->dev;
379 struct synaptics_data *priv = psmouse->private;
380 struct synaptics_hw_state hw;
381 int num_fingers;
382 int finger_width;
383 int i;
384
385 synaptics_parse_hw_state(psmouse->packet, priv, &hw);
386
387 if (hw.scroll) {
388 priv->scroll += hw.scroll;
389
390 while (priv->scroll >= 4) {
391 input_report_key(dev, BTN_BACK, !hw.down);
392 input_sync(dev);
393 input_report_key(dev, BTN_BACK, hw.down);
394 input_sync(dev);
395 priv->scroll -= 4;
396 }
397 while (priv->scroll <= -4) {
398 input_report_key(dev, BTN_FORWARD, !hw.up);
399 input_sync(dev);
400 input_report_key(dev, BTN_FORWARD, hw.up);
401 input_sync(dev);
402 priv->scroll += 4;
403 }
404 return;
405 }
406
407 if (hw.z > 0) {
408 num_fingers = 1;
409 finger_width = 5;
410 if (SYN_CAP_EXTENDED(priv->capabilities)) {
411 switch (hw.w) {
412 case 0 ... 1:
413 if (SYN_CAP_MULTIFINGER(priv->capabilities))
414 num_fingers = hw.w + 2;
415 break;
416 case 2:
417 if (SYN_MODEL_PEN(priv->model_id))
418 ; /* Nothing, treat a pen as a single finger */
419 break;
420 case 4 ... 15:
421 if (SYN_CAP_PALMDETECT(priv->capabilities))
422 finger_width = hw.w;
423 break;
424 }
425 }
426 } else {
427 num_fingers = 0;
428 finger_width = 0;
429 }
430
431 /* Post events
432 * BTN_TOUCH has to be first as mousedev relies on it when doing
433 * absolute -> relative conversion
434 */
435 if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
436 if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
437
438 if (hw.z > 0) {
439 input_report_abs(dev, ABS_X, hw.x);
440 input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
441 }
442 input_report_abs(dev, ABS_PRESSURE, hw.z);
443
444 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
445 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
446 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
447 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
448
449 input_report_key(dev, BTN_LEFT, hw.left);
450 input_report_key(dev, BTN_RIGHT, hw.right);
451
452 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
453 input_report_key(dev, BTN_MIDDLE, hw.middle);
454
455 if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
456 input_report_key(dev, BTN_FORWARD, hw.up);
457 input_report_key(dev, BTN_BACK, hw.down);
458 }
459
460 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
461 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
462
463 input_sync(dev);
464}
465
466static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
467{
468 static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
469 static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
470 static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
471 static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
472 static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
473
474 if (idx < 0 || idx > 4)
475 return 0;
476
477 switch (pkt_type) {
478 case SYN_NEWABS:
479 case SYN_NEWABS_RELAXED:
480 return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
481
482 case SYN_NEWABS_STRICT:
483 return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
484
485 case SYN_OLDABS:
486 return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
487
488 default:
489 printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
490 return 0;
491 }
492}
493
494static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
495{
496 int i;
497
498 for (i = 0; i < 5; i++)
499 if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
500 printk(KERN_INFO "synaptics: using relaxed packet validation\n");
501 return SYN_NEWABS_RELAXED;
502 }
503
504 return SYN_NEWABS_STRICT;
505}
506
507static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
508{
509 struct input_dev *dev = &psmouse->dev;
510 struct synaptics_data *priv = psmouse->private;
511
512 input_regs(dev, regs);
513
514 if (psmouse->pktcnt >= 6) { /* Full packet received */
515 if (unlikely(priv->pkt_type == SYN_NEWABS))
516 priv->pkt_type = synaptics_detect_pkt_type(psmouse);
517
518 if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
519 if (psmouse->ps2dev.serio->child)
520 synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
521 } else
522 synaptics_process_packet(psmouse);
523
524 return PSMOUSE_FULL_PACKET;
525 }
526
527 return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
528 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
529}
530
531/*****************************************************************************
532 * Driver initialization/cleanup functions
533 ****************************************************************************/
534static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
535{
536 int i;
537
538 set_bit(EV_ABS, dev->evbit);
539 input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
540 input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
541 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
542 set_bit(ABS_TOOL_WIDTH, dev->absbit);
543
544 set_bit(EV_KEY, dev->evbit);
545 set_bit(BTN_TOUCH, dev->keybit);
546 set_bit(BTN_TOOL_FINGER, dev->keybit);
547 set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
548 set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
549
550 set_bit(BTN_LEFT, dev->keybit);
551 set_bit(BTN_RIGHT, dev->keybit);
552
553 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
554 set_bit(BTN_MIDDLE, dev->keybit);
555
556 if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
557 SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
558 set_bit(BTN_FORWARD, dev->keybit);
559 set_bit(BTN_BACK, dev->keybit);
560 }
561
562 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
563 set_bit(BTN_0 + i, dev->keybit);
564
565 clear_bit(EV_REL, dev->evbit);
566 clear_bit(REL_X, dev->relbit);
567 clear_bit(REL_Y, dev->relbit);
568}
569
570void synaptics_reset(struct psmouse *psmouse)
571{
572 /* reset touchpad back to relative mode, gestures enabled */
573 synaptics_mode_cmd(psmouse, 0);
574}
575
576static void synaptics_disconnect(struct psmouse *psmouse)
577{
578 synaptics_reset(psmouse);
579 kfree(psmouse->private);
580 psmouse->private = NULL;
581}
582
583static int synaptics_reconnect(struct psmouse *psmouse)
584{
585 struct synaptics_data *priv = psmouse->private;
586 struct synaptics_data old_priv = *priv;
587
588 if (synaptics_detect(psmouse, 0))
589 return -1;
590
591 if (synaptics_query_hardware(psmouse)) {
592 printk(KERN_ERR "Unable to query Synaptics hardware.\n");
593 return -1;
594 }
595
596 if (old_priv.identity != priv->identity ||
597 old_priv.model_id != priv->model_id ||
598 old_priv.capabilities != priv->capabilities ||
599 old_priv.ext_cap != priv->ext_cap)
600 return -1;
601
602 if (synaptics_set_absolute_mode(psmouse)) {
603 printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
604 return -1;
605 }
606
607 return 0;
608}
609
610int synaptics_detect(struct psmouse *psmouse, int set_properties)
611{
612 struct ps2dev *ps2dev = &psmouse->ps2dev;
613 unsigned char param[4];
614
615 param[0] = 0;
616
617 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
618 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
619 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
620 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
621 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
622
623 if (param[1] != 0x47)
624 return -1;
625
626 if (set_properties) {
627 psmouse->vendor = "Synaptics";
628 psmouse->name = "TouchPad";
629 }
630
631 return 0;
632}
633
634#if defined(__i386__)
635#include <linux/dmi.h>
636static struct dmi_system_id toshiba_dmi_table[] = {
637 {
638 .ident = "Toshiba Satellite",
639 .matches = {
640 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
641 DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"),
642 },
643 },
644 { }
645};
646#endif
647
648int synaptics_init(struct psmouse *psmouse)
649{
650 struct synaptics_data *priv;
651
652 psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
653 if (!priv)
654 return -1;
655 memset(priv, 0, sizeof(struct synaptics_data));
656
657 if (synaptics_query_hardware(psmouse)) {
658 printk(KERN_ERR "Unable to query Synaptics hardware.\n");
659 goto init_fail;
660 }
661
662 if (synaptics_set_absolute_mode(psmouse)) {
663 printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
664 goto init_fail;
665 }
666
667 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
668
669 print_ident(priv);
670 set_input_params(&psmouse->dev, priv);
671
672 psmouse->protocol_handler = synaptics_process_byte;
673 psmouse->set_rate = synaptics_set_rate;
674 psmouse->disconnect = synaptics_disconnect;
675 psmouse->reconnect = synaptics_reconnect;
676 psmouse->pktsize = 6;
677
678 if (SYN_CAP_PASS_THROUGH(priv->capabilities))
679 synaptics_pt_create(psmouse);
680
681#if defined(__i386__)
682 /*
683 * Toshiba's KBC seems to have trouble handling data from
684 * Synaptics as full rate, switch to lower rate which is roughly
685 * thye same as rate of standard PS/2 mouse.
686 */
687 if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
688 printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n");
689 psmouse->rate = 40;
690 }
691#endif
692
693 return 0;
694
695 init_fail:
696 kfree(priv);
697 return -1;
698}
699
700
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
new file mode 100644
index 000000000000..68fff1dcd7de
--- /dev/null
+++ b/drivers/input/mouse/synaptics.h
@@ -0,0 +1,110 @@
1/*
2 * Synaptics TouchPad PS/2 mouse driver
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 */
8
9#ifndef _SYNAPTICS_H
10#define _SYNAPTICS_H
11
12extern int synaptics_detect(struct psmouse *psmouse, int set_properties);
13extern int synaptics_init(struct psmouse *psmouse);
14extern void synaptics_reset(struct psmouse *psmouse);
15
16/* synaptics queries */
17#define SYN_QUE_IDENTIFY 0x00
18#define SYN_QUE_MODES 0x01
19#define SYN_QUE_CAPABILITIES 0x02
20#define SYN_QUE_MODEL 0x03
21#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
22#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
23#define SYN_QUE_RESOLUTION 0x08
24#define SYN_QUE_EXT_CAPAB 0x09
25
26/* synatics modes */
27#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
28#define SYN_BIT_HIGH_RATE (1 << 6)
29#define SYN_BIT_SLEEP_MODE (1 << 3)
30#define SYN_BIT_DISABLE_GESTURE (1 << 2)
31#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1)
32#define SYN_BIT_W_MODE (1 << 0)
33
34/* synaptics model ID bits */
35#define SYN_MODEL_ROT180(m) ((m) & (1 << 23))
36#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22))
37#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f)
38#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f)
39#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7))
40#define SYN_MODEL_PEN(m) ((m) & (1 << 6))
41#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5))
42#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f)
43
44/* synaptics capability bits */
45#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
46#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18))
47#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
48#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
49#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
50#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
51#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
52#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
53#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
54#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
55
56/* synaptics modes query bits */
57#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
58#define SYN_MODE_RATE(m) ((m) & (1 << 6))
59#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3))
60#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2))
61#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1))
62#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
63
64/* synaptics identify query bits */
65#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
66#define SYN_ID_MAJOR(i) ((i) & 0x0f)
67#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
68#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
69
70/* synaptics special commands */
71#define SYN_PS_SET_MODE2 0x14
72#define SYN_PS_CLIENT_CMD 0x28
73
74/* synaptics packet types */
75#define SYN_NEWABS 0
76#define SYN_NEWABS_STRICT 1
77#define SYN_NEWABS_RELAXED 2
78#define SYN_OLDABS 3
79
80/*
81 * A structure to describe the state of the touchpad hardware (buttons and pad)
82 */
83
84struct synaptics_hw_state {
85 int x;
86 int y;
87 int z;
88 int w;
89 unsigned int left:1;
90 unsigned int right:1;
91 unsigned int middle:1;
92 unsigned int up:1;
93 unsigned int down:1;
94 unsigned char ext_buttons;
95 signed char scroll;
96};
97
98struct synaptics_data {
99 /* Data read from the touchpad */
100 unsigned long int model_id; /* Model-ID */
101 unsigned long int capabilities; /* Capabilities */
102 unsigned long int ext_cap; /* Extended Capabilities */
103 unsigned long int identity; /* Identification */
104
105 unsigned char pkt_type; /* packet type - old, new, etc */
106 unsigned char mode; /* current mode byte */
107 int scroll;
108};
109
110#endif /* _SYNAPTICS_H */
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
new file mode 100644
index 000000000000..b2cb101c8110
--- /dev/null
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -0,0 +1,591 @@
1/*
2 * Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
3 * DEC VSXXX-GA mouse (rectangular mouse, with ball)
4 * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
5 *
6 * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
7 *
8 * The packet format was initially taken from a patch to GPM which is (C) 2001
9 * by Karsten Merker <merker@linuxtag.org>
10 * and Maciej W. Rozycki <macro@ds2.pg.gda.pl>
11 * Later on, I had access to the device's documentation (referenced below).
12 */
13
14/*
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
30/*
31 * Building an adaptor to DE9 / DB25 RS232
32 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33 *
34 * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for
35 * anything if you break your mouse, your computer or whatever!
36 *
37 * In theory, this mouse is a simple RS232 device. In practice, it has got
38 * a quite uncommon plug and the requirement to additionally get a power
39 * supply at +5V and -12V.
40 *
41 * If you look at the socket/jack (_not_ at the plug), we use this pin
42 * numbering:
43 * _______
44 * / 7 6 5 \
45 * | 4 --- 3 |
46 * \ 2 1 /
47 * -------
48 *
49 * DEC socket DE9 DB25 Note
50 * 1 (GND) 5 7 -
51 * 2 (RxD) 2 3 -
52 * 3 (TxD) 3 2 -
53 * 4 (-12V) - - Somewhere from the PSU. At ATX, it's
54 * the thin blue wire at pin 12 of the
55 * ATX power connector. Only required for
56 * VSXXX-AA/-GA mice.
57 * 5 (+5V) - - PSU (red wires of ATX power connector
58 * on pin 4, 6, 19 or 20) or HDD power
59 * connector (also red wire).
60 * 6 (+12V) - - HDD power connector, yellow wire. Only
61 * required for VSXXX-AB digitizer.
62 * 7 (dev. avail.) - - The mouse shorts this one to pin 1.
63 * This way, the host computer can detect
64 * the mouse. To use it with the adaptor,
65 * simply don't connect this pin.
66 *
67 * So to get a working adaptor, you need to connect the mouse with three
68 * wires to a RS232 port and two or three additional wires for +5V, +12V and
69 * -12V to the PSU.
70 *
71 * Flow specification for the link is 4800, 8o1.
72 *
73 * The mice and tablet are described in "VCB02 Video Subsystem - Technical
74 * Manual", DEC EK-104AA-TM-001. You'll find it at MANX, a search engine
75 * specific for DEC documentation. Try
76 * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1
77 */
78
79#include <linux/delay.h>
80#include <linux/module.h>
81#include <linux/slab.h>
82#include <linux/interrupt.h>
83#include <linux/input.h>
84#include <linux/config.h>
85#include <linux/serio.h>
86#include <linux/init.h>
87
88#define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"
89
90MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
91MODULE_DESCRIPTION (DRIVER_DESC);
92MODULE_LICENSE ("GPL");
93
94#undef VSXXXAA_DEBUG
95#ifdef VSXXXAA_DEBUG
96#define DBG(x...) printk (x)
97#else
98#define DBG(x...) do {} while (0)
99#endif
100
101#define VSXXXAA_INTRO_MASK 0x80
102#define VSXXXAA_INTRO_HEAD 0x80
103#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \
104 == VSXXXAA_INTRO_HEAD)
105
106#define VSXXXAA_PACKET_MASK 0xe0
107#define VSXXXAA_PACKET_REL 0x80
108#define VSXXXAA_PACKET_ABS 0xc0
109#define VSXXXAA_PACKET_POR 0xa0
110#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == (type))
111
112
113
114struct vsxxxaa {
115 struct input_dev dev;
116 struct serio *serio;
117#define BUFLEN 15 /* At least 5 is needed for a full tablet packet */
118 unsigned char buf[BUFLEN];
119 unsigned char count;
120 unsigned char version;
121 unsigned char country;
122 unsigned char type;
123 char name[64];
124 char phys[32];
125};
126
127static void
128vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num)
129{
130 if (num >= mouse->count)
131 mouse->count = 0;
132 else {
133 memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num);
134 mouse->count -= num;
135 }
136}
137
138static void
139vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte)
140{
141 if (mouse->count == BUFLEN) {
142 printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
143 mouse->name, mouse->phys);
144 vsxxxaa_drop_bytes (mouse, 1);
145 }
146 DBG (KERN_INFO "Queueing byte 0x%02x\n", byte);
147
148 mouse->buf[mouse->count++] = byte;
149}
150
151static void
152vsxxxaa_detection_done (struct vsxxxaa *mouse)
153{
154 switch (mouse->type) {
155 case 0x02:
156 sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse");
157 break;
158
159 case 0x04:
160 sprintf (mouse->name, "DEC VSXXX-AB digitizer");
161 break;
162
163 default:
164 sprintf (mouse->name, "unknown DEC pointer device "
165 "(type = 0x%02x)", mouse->type);
166 break;
167 }
168
169 printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x "
170 "on port %s\n", mouse->name, mouse->version,
171 mouse->country, mouse->phys);
172}
173
174/*
175 * Returns number of bytes to be dropped, 0 if packet is okay.
176 */
177static int
178vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len)
179{
180 int i;
181
182 /* First byte must be a header byte */
183 if (!IS_HDR_BYTE (mouse->buf[0])) {
184 DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
185 return 1;
186 }
187
188 /* Check all following bytes */
189 if (packet_len > 1) {
190 for (i = 1; i < packet_len; i++) {
191 if (IS_HDR_BYTE (mouse->buf[i])) {
192 printk (KERN_ERR "Need to drop %d bytes "
193 "of a broken packet.\n",
194 i - 1);
195 DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
196 packet_len, i, mouse->buf[i]);
197 return i - 1;
198 }
199 }
200 }
201
202 return 0;
203}
204
205static __inline__ int
206vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len)
207{
208 return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type);
209}
210
211static void
212vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
213{
214 struct input_dev *dev = &mouse->dev;
215 unsigned char *buf = mouse->buf;
216 int left, middle, right;
217 int dx, dy;
218
219 /*
220 * Check for normal stream packets. This is three bytes,
221 * with the first byte's 3 MSB set to 100.
222 *
223 * [0]: 1 0 0 SignX SignY Left Middle Right
224 * [1]: 0 dx dx dx dx dx dx dx
225 * [2]: 0 dy dy dy dy dy dy dy
226 */
227
228 /*
229 * Low 7 bit of byte 1 are abs(dx), bit 7 is
230 * 0, bit 4 of byte 0 is direction.
231 */
232 dx = buf[1] & 0x7f;
233 dx *= ((buf[0] >> 4) & 0x01)? 1: -1;
234
235 /*
236 * Low 7 bit of byte 2 are abs(dy), bit 7 is
237 * 0, bit 3 of byte 0 is direction.
238 */
239 dy = buf[2] & 0x7f;
240 dy *= ((buf[0] >> 3) & 0x01)? -1: 1;
241
242 /*
243 * Get button state. It's the low three bits
244 * (for three buttons) of byte 0.
245 */
246 left = (buf[0] & 0x04)? 1: 0;
247 middle = (buf[0] & 0x02)? 1: 0;
248 right = (buf[0] & 0x01)? 1: 0;
249
250 vsxxxaa_drop_bytes (mouse, 3);
251
252 DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
253 mouse->name, mouse->phys, dx, dy,
254 left? "L": "l", middle? "M": "m", right? "R": "r");
255
256 /*
257 * Report what we've found so far...
258 */
259 input_regs (dev, regs);
260 input_report_key (dev, BTN_LEFT, left);
261 input_report_key (dev, BTN_MIDDLE, middle);
262 input_report_key (dev, BTN_RIGHT, right);
263 input_report_key (dev, BTN_TOUCH, 0);
264 input_report_rel (dev, REL_X, dx);
265 input_report_rel (dev, REL_Y, dy);
266 input_sync (dev);
267}
268
269static void
270vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
271{
272 struct input_dev *dev = &mouse->dev;
273 unsigned char *buf = mouse->buf;
274 int left, middle, right, touch;
275 int x, y;
276
277 /*
278 * Tablet position / button packet
279 *
280 * [0]: 1 1 0 B4 B3 B2 B1 Pr
281 * [1]: 0 0 X5 X4 X3 X2 X1 X0
282 * [2]: 0 0 X11 X10 X9 X8 X7 X6
283 * [3]: 0 0 Y5 Y4 Y3 Y2 Y1 Y0
284 * [4]: 0 0 Y11 Y10 Y9 Y8 Y7 Y6
285 */
286
287 /*
288 * Get X/Y position. Y axis needs to be inverted since VSXXX-AB
289 * counts down->top while monitor counts top->bottom.
290 */
291 x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f);
292 y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f);
293 y = 1023 - y;
294
295 /*
296 * Get button state. It's bits <4..1> of byte 0.
297 */
298 left = (buf[0] & 0x02)? 1: 0;
299 middle = (buf[0] & 0x04)? 1: 0;
300 right = (buf[0] & 0x08)? 1: 0;
301 touch = (buf[0] & 0x10)? 1: 0;
302
303 vsxxxaa_drop_bytes (mouse, 5);
304
305 DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
306 mouse->name, mouse->phys, x, y,
307 left? "L": "l", middle? "M": "m",
308 right? "R": "r", touch? "T": "t");
309
310 /*
311 * Report what we've found so far...
312 */
313 input_regs (dev, regs);
314 input_report_key (dev, BTN_LEFT, left);
315 input_report_key (dev, BTN_MIDDLE, middle);
316 input_report_key (dev, BTN_RIGHT, right);
317 input_report_key (dev, BTN_TOUCH, touch);
318 input_report_abs (dev, ABS_X, x);
319 input_report_abs (dev, ABS_Y, y);
320 input_sync (dev);
321}
322
323static void
324vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
325{
326 struct input_dev *dev = &mouse->dev;
327 unsigned char *buf = mouse->buf;
328 int left, middle, right;
329 unsigned char error;
330
331 /*
332 * Check for Power-On-Reset packets. These are sent out
333 * after plugging the mouse in, or when explicitely
334 * requested by sending 'T'.
335 *
336 * [0]: 1 0 1 0 R3 R2 R1 R0
337 * [1]: 0 M2 M1 M0 D3 D2 D1 D0
338 * [2]: 0 E6 E5 E4 E3 E2 E1 E0
339 * [3]: 0 0 0 0 0 Left Middle Right
340 *
341 * M: manufacturer location code
342 * R: revision code
343 * E: Error code. If it's in the range of 0x00..0x1f, only some
344 * minor problem occured. Errors >= 0x20 are considered bad
345 * and the device may not work properly...
346 * D: <0010> == mouse, <0100> == tablet
347 */
348
349 mouse->version = buf[0] & 0x0f;
350 mouse->country = (buf[1] >> 4) & 0x07;
351 mouse->type = buf[1] & 0x0f;
352 error = buf[2] & 0x7f;
353
354 /*
355 * Get button state. It's the low three bits
356 * (for three buttons) of byte 0. Maybe even the bit <3>
357 * has some meaning if a tablet is attached.
358 */
359 left = (buf[0] & 0x04)? 1: 0;
360 middle = (buf[0] & 0x02)? 1: 0;
361 right = (buf[0] & 0x01)? 1: 0;
362
363 vsxxxaa_drop_bytes (mouse, 4);
364 vsxxxaa_detection_done (mouse);
365
366 if (error <= 0x1f) {
367 /* No (serious) error. Report buttons */
368 input_regs (dev, regs);
369 input_report_key (dev, BTN_LEFT, left);
370 input_report_key (dev, BTN_MIDDLE, middle);
371 input_report_key (dev, BTN_RIGHT, right);
372 input_report_key (dev, BTN_TOUCH, 0);
373 input_sync (dev);
374
375 if (error != 0)
376 printk (KERN_INFO "Your %s on %s reports error=0x%02x\n",
377 mouse->name, mouse->phys, error);
378
379 }
380
381 /*
382 * If the mouse was hot-plugged, we need to force differential mode
383 * now... However, give it a second to recover from it's reset.
384 */
385 printk (KERN_NOTICE "%s on %s: Forceing standard packet format, "
386 "incremental streaming mode and 72 samples/sec\n",
387 mouse->name, mouse->phys);
388 mouse->serio->write (mouse->serio, 'S'); /* Standard format */
389 mdelay (50);
390 mouse->serio->write (mouse->serio, 'R'); /* Incremental */
391 mdelay (50);
392 mouse->serio->write (mouse->serio, 'L'); /* 72 samples/sec */
393}
394
395static void
396vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
397{
398 unsigned char *buf = mouse->buf;
399 int stray_bytes;
400
401 /*
402 * Parse buffer to death...
403 */
404 do {
405 /*
406 * Out of sync? Throw away what we don't understand. Each
407 * packet starts with a byte whose bit 7 is set. Unhandled
408 * packets (ie. which we don't know about or simply b0rk3d
409 * data...) will get shifted out of the buffer after some
410 * activity on the mouse.
411 */
412 while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
413 printk (KERN_ERR "%s on %s: Dropping a byte to regain "
414 "sync with mouse data stream...\n",
415 mouse->name, mouse->phys);
416 vsxxxaa_drop_bytes (mouse, 1);
417 }
418
419 /*
420 * Check for packets we know about.
421 */
422
423 if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) {
424 /* Check for broken packet */
425 stray_bytes = vsxxxaa_check_packet (mouse, 3);
426 if (stray_bytes > 0) {
427 printk (KERN_ERR "Dropping %d bytes now...\n",
428 stray_bytes);
429 vsxxxaa_drop_bytes (mouse, stray_bytes);
430 continue;
431 }
432
433 vsxxxaa_handle_REL_packet (mouse, regs);
434 continue; /* More to parse? */
435 }
436
437 if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) {
438 /* Check for broken packet */
439 stray_bytes = vsxxxaa_check_packet (mouse, 5);
440 if (stray_bytes > 0) {
441 printk (KERN_ERR "Dropping %d bytes now...\n",
442 stray_bytes);
443 vsxxxaa_drop_bytes (mouse, stray_bytes);
444 continue;
445 }
446
447 vsxxxaa_handle_ABS_packet (mouse, regs);
448 continue; /* More to parse? */
449 }
450
451 if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) {
452 /* Check for broken packet */
453 stray_bytes = vsxxxaa_check_packet (mouse, 4);
454 if (stray_bytes > 0) {
455 printk (KERN_ERR "Dropping %d bytes now...\n",
456 stray_bytes);
457 vsxxxaa_drop_bytes (mouse, stray_bytes);
458 continue;
459 }
460
461 vsxxxaa_handle_POR_packet (mouse, regs);
462 continue; /* More to parse? */
463 }
464
465 break; /* No REL, ABS or POR packet found */
466 } while (1);
467}
468
469static irqreturn_t
470vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
471 struct pt_regs *regs)
472{
473 struct vsxxxaa *mouse = serio_get_drvdata (serio);
474
475 vsxxxaa_queue_byte (mouse, data);
476 vsxxxaa_parse_buffer (mouse, regs);
477
478 return IRQ_HANDLED;
479}
480
481static void
482vsxxxaa_disconnect (struct serio *serio)
483{
484 struct vsxxxaa *mouse = serio_get_drvdata (serio);
485
486 input_unregister_device (&mouse->dev);
487 serio_close (serio);
488 serio_set_drvdata (serio, NULL);
489 kfree (mouse);
490}
491
492static int
493vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
494{
495 struct vsxxxaa *mouse;
496 int err;
497
498 if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL)))
499 return -ENOMEM;
500
501 memset (mouse, 0, sizeof (struct vsxxxaa));
502
503 init_input_dev (&mouse->dev);
504 set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */
505 set_bit (EV_REL, mouse->dev.evbit);
506 set_bit (EV_ABS, mouse->dev.evbit);
507 set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */
508 set_bit (BTN_MIDDLE, mouse->dev.keybit);
509 set_bit (BTN_RIGHT, mouse->dev.keybit);
510 set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */
511 set_bit (REL_X, mouse->dev.relbit);
512 set_bit (REL_Y, mouse->dev.relbit);
513 set_bit (ABS_X, mouse->dev.absbit);
514 set_bit (ABS_Y, mouse->dev.absbit);
515
516 mouse->dev.absmin[ABS_X] = 0;
517 mouse->dev.absmax[ABS_X] = 1023;
518 mouse->dev.absmin[ABS_Y] = 0;
519 mouse->dev.absmax[ABS_Y] = 1023;
520
521 mouse->dev.private = mouse;
522
523 sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer");
524 sprintf (mouse->phys, "%s/input0", serio->phys);
525 mouse->dev.name = mouse->name;
526 mouse->dev.phys = mouse->phys;
527 mouse->dev.id.bustype = BUS_RS232;
528 mouse->dev.dev = &serio->dev;
529 mouse->serio = serio;
530
531 serio_set_drvdata (serio, mouse);
532
533 err = serio_open (serio, drv);
534 if (err) {
535 serio_set_drvdata (serio, NULL);
536 kfree (mouse);
537 return err;
538 }
539
540 /*
541 * Request selftest. Standard packet format and differential
542 * mode will be requested after the device ID'ed successfully.
543 */
544 mouse->serio->write (mouse->serio, 'T'); /* Test */
545
546 input_register_device (&mouse->dev);
547
548 printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys);
549
550 return 0;
551}
552
553static struct serio_device_id vsxxaa_serio_ids[] = {
554 {
555 .type = SERIO_RS232,
556 .proto = SERIO_VSXXXAA,
557 .id = SERIO_ANY,
558 .extra = SERIO_ANY,
559 },
560 { 0 }
561};
562
563MODULE_DEVICE_TABLE(serio, vsxxaa_serio_ids);
564
565static struct serio_driver vsxxxaa_drv = {
566 .driver = {
567 .name = "vsxxxaa",
568 },
569 .description = DRIVER_DESC,
570 .id_table = vsxxaa_serio_ids,
571 .connect = vsxxxaa_connect,
572 .interrupt = vsxxxaa_interrupt,
573 .disconnect = vsxxxaa_disconnect,
574};
575
576static int __init
577vsxxxaa_init (void)
578{
579 serio_register_driver(&vsxxxaa_drv);
580 return 0;
581}
582
583static void __exit
584vsxxxaa_exit (void)
585{
586 serio_unregister_driver(&vsxxxaa_drv);
587}
588
589module_init (vsxxxaa_init);
590module_exit (vsxxxaa_exit);
591