summaryrefslogtreecommitdiff
path: root/usr/src/dkms_source_tree
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-11-16 14:04:09 +0100
committerHenrik Rydberg <rydberg@euromail.se>2010-11-16 14:04:09 +0100
commite56d270d5dd472219864c1735d8eee16d6f1ccdb (patch)
treea486aeada19c76357bc9042364fcdb1ef04c0336 /usr/src/dkms_source_tree
Add psmouse driver from maverick (Ubuntu-2.6.35-23.36).
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'usr/src/dkms_source_tree')
-rw-r--r--usr/src/dkms_source_tree/Makefile18
-rw-r--r--usr/src/dkms_source_tree/alps.c774
-rw-r--r--usr/src/dkms_source_tree/alps.h43
-rw-r--r--usr/src/dkms_source_tree/dkms.conf10
-rw-r--r--usr/src/dkms_source_tree/elantech.c769
-rw-r--r--usr/src/dkms_source_tree/elantech.h124
-rw-r--r--usr/src/dkms_source_tree/hgpk.c533
-rw-r--r--usr/src/dkms_source_tree/hgpk.h49
-rw-r--r--usr/src/dkms_source_tree/lifebook.c352
-rw-r--r--usr/src/dkms_source_tree/lifebook.h32
-rw-r--r--usr/src/dkms_source_tree/logips2pp.c420
-rw-r--r--usr/src/dkms_source_tree/logips2pp.h23
-rw-r--r--usr/src/dkms_source_tree/psmouse-base.c1733
-rw-r--r--usr/src/dkms_source_tree/psmouse.h153
-rw-r--r--usr/src/dkms_source_tree/sentelic.c871
-rw-r--r--usr/src/dkms_source_tree/sentelic.h98
-rw-r--r--usr/src/dkms_source_tree/synaptics.c863
-rw-r--r--usr/src/dkms_source_tree/synaptics.h122
-rw-r--r--usr/src/dkms_source_tree/touchkit_ps2.c100
-rw-r--r--usr/src/dkms_source_tree/touchkit_ps2.h25
-rw-r--r--usr/src/dkms_source_tree/trackpoint.c335
-rw-r--r--usr/src/dkms_source_tree/trackpoint.h154
22 files changed, 7601 insertions, 0 deletions
diff --git a/usr/src/dkms_source_tree/Makefile b/usr/src/dkms_source_tree/Makefile
new file mode 100644
index 0000000..8a48755
--- /dev/null
+++ b/usr/src/dkms_source_tree/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-m += psmouse.o
8
9psmouse-objs := psmouse-base.o synaptics.o
10
11psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
12psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
13psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
14psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
15psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
16psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
17psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
18psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
diff --git a/usr/src/dkms_source_tree/alps.c b/usr/src/dkms_source_tree/alps.c
new file mode 100644
index 0000000..99d5876
--- /dev/null
+++ b/usr/src/dkms_source_tree/alps.c
@@ -0,0 +1,774 @@
1/*
2 * ALPS touchpad PS/2 mouse driver
3 *
4 * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
5 * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
6 * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
7 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
8 * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net>
9 *
10 * ALPS detection, tap switching and status querying info is taken from
11 * tpconfig utility (by C. Scott Ananian and Bruce Kall).
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License version 2 as published by
15 * the Free Software Foundation.
16 */
17
18#include <linux/slab.h>
19#include <linux/input.h>
20#include <linux/serio.h>
21#include <linux/libps2.h>
22
23#include "psmouse.h"
24#include "alps.h"
25
26#undef DEBUG
27#ifdef DEBUG
28#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
29#else
30#define dbg(format, arg...) do {} while (0)
31#endif
32
33#define ALPS_OLDPROTO 0x01 /* old style input */
34#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
35#define ALPS_PASS 0x04 /* device has a pass-through port */
36
37#define ALPS_WHEEL 0x08 /* hardware wheel present */
38#define ALPS_FW_BK_1 0x10 /* front & back buttons present */
39#define ALPS_FW_BK_2 0x20 /* front & back buttons present */
40#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
41#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
42 6-byte ALPS packet */
43
44static const struct alps_model_info alps_model_data[] = {
45 { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
46 { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
47 { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
48 { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
49 { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */
50 { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
51 { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
52 { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
53 { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
54 { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
55 { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
56 { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
57 { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
58 { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
59 { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
60 { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
61 { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
62 { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
63 /* Dell Latitude E5500, E6400, E6500, Precision M4400 */
64 { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
65 ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
66 { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
67 { { 0x52, 0x01, 0x14 }, 0xff, 0xff,
68 ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
69};
70
71/*
72 * XXX - this entry is suspicious. First byte has zero lower nibble,
73 * which is what a normal mouse would report. Also, the value 0x0e
74 * isn't valid per PS/2 spec.
75 */
76
77/*
78 * PS/2 packet format
79 *
80 * byte 0: 0 0 YSGN XSGN 1 M R L
81 * byte 1: X7 X6 X5 X4 X3 X2 X1 X0
82 * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
83 *
84 * Note that the device never signals overflow condition.
85 *
86 * ALPS absolute Mode - new format
87 *
88 * byte 0: 1 ? ? ? 1 ? ? ?
89 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
90 * byte 2: 0 x10 x9 x8 x7 ? fin ges
91 * byte 3: 0 y9 y8 y7 1 M R L
92 * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
93 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
94 *
95 * Dualpoint device -- interleaved packet format
96 *
97 * byte 0: 1 1 0 0 1 1 1 1
98 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
99 * byte 2: 0 x10 x9 x8 x7 0 fin ges
100 * byte 3: 0 0 YSGN XSGN 1 1 1 1
101 * byte 4: X7 X6 X5 X4 X3 X2 X1 X0
102 * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
103 * byte 6: 0 y9 y8 y7 1 m r l
104 * byte 7: 0 y6 y5 y4 y3 y2 y1 y0
105 * byte 8: 0 z6 z5 z4 z3 z2 z1 z0
106 *
107 * CAPITALS = stick, miniscules = touchpad
108 *
109 * ?'s can have different meanings on different models,
110 * such as wheel rotation, extra buttons, stick buttons
111 * on a dualpoint, etc.
112 */
113
114static bool alps_is_valid_first_byte(const struct alps_model_info *model,
115 unsigned char data)
116{
117 return (data & model->mask0) == model->byte0;
118}
119
120static void alps_report_buttons(struct psmouse *psmouse,
121 struct input_dev *dev1, struct input_dev *dev2,
122 int left, int right, int middle)
123{
124 struct input_dev *dev;
125
126 /*
127 * If shared button has already been reported on the
128 * other device (dev2) then this event should be also
129 * sent through that device.
130 */
131 dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1;
132 input_report_key(dev, BTN_LEFT, left);
133
134 dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1;
135 input_report_key(dev, BTN_RIGHT, right);
136
137 dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1;
138 input_report_key(dev, BTN_MIDDLE, middle);
139
140 /*
141 * Sync the _other_ device now, we'll do the first
142 * device later once we report the rest of the events.
143 */
144 input_sync(dev2);
145}
146
147static void alps_process_packet(struct psmouse *psmouse)
148{
149 struct alps_data *priv = psmouse->private;
150 const struct alps_model_info *model = priv->i;
151 unsigned char *packet = psmouse->packet;
152 struct input_dev *dev = psmouse->dev;
153 struct input_dev *dev2 = priv->dev2;
154 int x, y, z, ges, fin, left, right, middle;
155 int back = 0, forward = 0;
156
157 if (model->flags & ALPS_OLDPROTO) {
158 left = packet[2] & 0x10;
159 right = packet[2] & 0x08;
160 middle = 0;
161 x = packet[1] | ((packet[0] & 0x07) << 7);
162 y = packet[4] | ((packet[3] & 0x07) << 7);
163 z = packet[5];
164 } else {
165 left = packet[3] & 1;
166 right = packet[3] & 2;
167 middle = packet[3] & 4;
168 x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
169 y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
170 z = packet[5];
171 }
172
173 if (model->flags & ALPS_FW_BK_1) {
174 back = packet[0] & 0x10;
175 forward = packet[2] & 4;
176 }
177
178 if (model->flags & ALPS_FW_BK_2) {
179 back = packet[3] & 4;
180 forward = packet[2] & 4;
181 if ((middle = forward && back))
182 forward = back = 0;
183 }
184
185 ges = packet[2] & 1;
186 fin = packet[2] & 2;
187
188 if ((model->flags & ALPS_DUALPOINT) && z == 127) {
189 input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
190 input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
191
192 alps_report_buttons(psmouse, dev2, dev, left, right, middle);
193
194 input_sync(dev2);
195 return;
196 }
197
198 alps_report_buttons(psmouse, dev, dev2, left, right, middle);
199
200 /* Convert hardware tap to a reasonable Z value */
201 if (ges && !fin)
202 z = 40;
203
204 /*
205 * A "tap and drag" operation is reported by the hardware as a transition
206 * from (!fin && ges) to (fin && ges). This should be translated to the
207 * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually.
208 */
209 if (ges && fin && !priv->prev_fin) {
210 input_report_abs(dev, ABS_X, x);
211 input_report_abs(dev, ABS_Y, y);
212 input_report_abs(dev, ABS_PRESSURE, 0);
213 input_report_key(dev, BTN_TOOL_FINGER, 0);
214 input_sync(dev);
215 }
216 priv->prev_fin = fin;
217
218 if (z > 30)
219 input_report_key(dev, BTN_TOUCH, 1);
220 if (z < 25)
221 input_report_key(dev, BTN_TOUCH, 0);
222
223 if (z > 0) {
224 input_report_abs(dev, ABS_X, x);
225 input_report_abs(dev, ABS_Y, y);
226 }
227
228 input_report_abs(dev, ABS_PRESSURE, z);
229 input_report_key(dev, BTN_TOOL_FINGER, z > 0);
230
231 if (model->flags & ALPS_WHEEL)
232 input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07));
233
234 if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
235 input_report_key(dev, BTN_FORWARD, forward);
236 input_report_key(dev, BTN_BACK, back);
237 }
238
239 if (model->flags & ALPS_FOUR_BUTTONS) {
240 input_report_key(dev, BTN_0, packet[2] & 4);
241 input_report_key(dev, BTN_1, packet[0] & 0x10);
242 input_report_key(dev, BTN_2, packet[3] & 4);
243 input_report_key(dev, BTN_3, packet[0] & 0x20);
244 }
245
246 input_sync(dev);
247}
248
249static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
250 unsigned char packet[],
251 bool report_buttons)
252{
253 struct alps_data *priv = psmouse->private;
254 struct input_dev *dev2 = priv->dev2;
255
256 if (report_buttons)
257 alps_report_buttons(psmouse, dev2, psmouse->dev,
258 packet[0] & 1, packet[0] & 2, packet[0] & 4);
259
260 input_report_rel(dev2, REL_X,
261 packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
262 input_report_rel(dev2, REL_Y,
263 packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
264
265 input_sync(dev2);
266}
267
268static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
269{
270 struct alps_data *priv = psmouse->private;
271
272 if (psmouse->pktcnt < 6)
273 return PSMOUSE_GOOD_DATA;
274
275 if (psmouse->pktcnt == 6) {
276 /*
277 * Start a timer to flush the packet if it ends up last
278 * 6-byte packet in the stream. Timer needs to fire
279 * psmouse core times out itself. 20 ms should be enough
280 * to decide if we are getting more data or not.
281 */
282 mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20));
283 return PSMOUSE_GOOD_DATA;
284 }
285
286 del_timer(&priv->timer);
287
288 if (psmouse->packet[6] & 0x80) {
289
290 /*
291 * Highest bit is set - that means we either had
292 * complete ALPS packet and this is start of the
293 * next packet or we got garbage.
294 */
295
296 if (((psmouse->packet[3] |
297 psmouse->packet[4] |
298 psmouse->packet[5]) & 0x80) ||
299 (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
300 dbg("refusing packet %x %x %x %x "
301 "(suspected interleaved ps/2)\n",
302 psmouse->packet[3], psmouse->packet[4],
303 psmouse->packet[5], psmouse->packet[6]);
304 return PSMOUSE_BAD_DATA;
305 }
306
307 alps_process_packet(psmouse);
308
309 /* Continue with the next packet */
310 psmouse->packet[0] = psmouse->packet[6];
311 psmouse->pktcnt = 1;
312
313 } else {
314
315 /*
316 * High bit is 0 - that means that we indeed got a PS/2
317 * packet in the middle of ALPS packet.
318 *
319 * There is also possibility that we got 6-byte ALPS
320 * packet followed by 3-byte packet from trackpoint. We
321 * can not distinguish between these 2 scenarios but
322 * becase the latter is unlikely to happen in course of
323 * normal operation (user would need to press all
324 * buttons on the pad and start moving trackpoint
325 * without touching the pad surface) we assume former.
326 * Even if we are wrong the wost thing that would happen
327 * the cursor would jump but we should not get protocol
328 * desynchronization.
329 */
330
331 alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
332 false);
333
334 /*
335 * Continue with the standard ALPS protocol handling,
336 * but make sure we won't process it as an interleaved
337 * packet again, which may happen if all buttons are
338 * pressed. To avoid this let's reset the 4th bit which
339 * is normally 1.
340 */
341 psmouse->packet[3] = psmouse->packet[6] & 0xf7;
342 psmouse->pktcnt = 4;
343 }
344
345 return PSMOUSE_GOOD_DATA;
346}
347
348static void alps_flush_packet(unsigned long data)
349{
350 struct psmouse *psmouse = (struct psmouse *)data;
351
352 serio_pause_rx(psmouse->ps2dev.serio);
353
354 if (psmouse->pktcnt == 6) {
355
356 /*
357 * We did not any more data in reasonable amount of time.
358 * Validate the last 3 bytes and process as a standard
359 * ALPS packet.
360 */
361 if ((psmouse->packet[3] |
362 psmouse->packet[4] |
363 psmouse->packet[5]) & 0x80) {
364 dbg("refusing packet %x %x %x "
365 "(suspected interleaved ps/2)\n",
366 psmouse->packet[3], psmouse->packet[4],
367 psmouse->packet[5]);
368 } else {
369 alps_process_packet(psmouse);
370 }
371 psmouse->pktcnt = 0;
372 }
373
374 serio_continue_rx(psmouse->ps2dev.serio);
375}
376
377static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
378{
379 struct alps_data *priv = psmouse->private;
380 const struct alps_model_info *model = priv->i;
381
382 if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
383 if (psmouse->pktcnt == 3) {
384 alps_report_bare_ps2_packet(psmouse, psmouse->packet,
385 true);
386 return PSMOUSE_FULL_PACKET;
387 }
388 return PSMOUSE_GOOD_DATA;
389 }
390
391 /* Check for PS/2 packet stuffed in the middle of ALPS packet. */
392
393 if ((model->flags & ALPS_PS2_INTERLEAVED) &&
394 psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) {
395 return alps_handle_interleaved_ps2(psmouse);
396 }
397
398 if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
399 dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
400 psmouse->packet[0], model->mask0, model->byte0);
401 return PSMOUSE_BAD_DATA;
402 }
403
404 /* Bytes 2 - 6 should have 0 in the highest bit */
405 if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
406 (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
407 dbg("refusing packet[%i] = %x\n",
408 psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
409 return PSMOUSE_BAD_DATA;
410 }
411
412 if (psmouse->pktcnt == 6) {
413 alps_process_packet(psmouse);
414 return PSMOUSE_FULL_PACKET;
415 }
416
417 return PSMOUSE_GOOD_DATA;
418}
419
420static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
421{
422 struct ps2dev *ps2dev = &psmouse->ps2dev;
423 static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
424 unsigned char param[4];
425 int i;
426
427 /*
428 * First try "E6 report".
429 * ALPS should return 0,0,10 or 0,0,100
430 */
431 param[0] = 0;
432 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
433 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
434 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
435 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
436 return NULL;
437
438 param[0] = param[1] = param[2] = 0xff;
439 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
440 return NULL;
441
442 dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
443
444 if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
445 return NULL;
446
447 /*
448 * Now try "E7 report". Allowed responses are in
449 * alps_model_data[].signature
450 */
451 param[0] = 0;
452 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
453 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
454 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
455 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
456 return NULL;
457
458 param[0] = param[1] = param[2] = 0xff;
459 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
460 return NULL;
461
462 dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
463
464 if (version) {
465 for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
466 /* empty */;
467 *version = (param[0] << 8) | (param[1] << 4) | i;
468 }
469
470 for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
471 if (!memcmp(param, alps_model_data[i].signature,
472 sizeof(alps_model_data[i].signature)))
473 return alps_model_data + i;
474
475 return NULL;
476}
477
478/*
479 * For DualPoint devices select the device that should respond to
480 * subsequent commands. It looks like glidepad is behind stickpointer,
481 * I'd thought it would be other way around...
482 */
483static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
484{
485 struct ps2dev *ps2dev = &psmouse->ps2dev;
486 int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
487
488 if (ps2_command(ps2dev, NULL, cmd) ||
489 ps2_command(ps2dev, NULL, cmd) ||
490 ps2_command(ps2dev, NULL, cmd) ||
491 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
492 return -1;
493
494 /* we may get 3 more bytes, just ignore them */
495 ps2_drain(ps2dev, 3, 100);
496
497 return 0;
498}
499
500static int alps_absolute_mode(struct psmouse *psmouse)
501{
502 struct ps2dev *ps2dev = &psmouse->ps2dev;
503
504 /* Try ALPS magic knock - 4 disable before enable */
505 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
506 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
507 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
508 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
509 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
510 return -1;
511
512 /*
513 * Switch mouse to poll (remote) mode so motion data will not
514 * get in our way
515 */
516 return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
517}
518
519static int alps_get_status(struct psmouse *psmouse, char *param)
520{
521 struct ps2dev *ps2dev = &psmouse->ps2dev;
522
523 /* Get status: 0xF5 0xF5 0xF5 0xE9 */
524 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
525 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
526 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
527 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
528 return -1;
529
530 dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
531
532 return 0;
533}
534
535/*
536 * Turn touchpad tapping on or off. The sequences are:
537 * 0xE9 0xF5 0xF5 0xF3 0x0A to enable,
538 * 0xE9 0xF5 0xF5 0xE8 0x00 to disable.
539 * My guess that 0xE9 (GetInfo) is here as a sync point.
540 * For models that also have stickpointer (DualPoints) its tapping
541 * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but
542 * we don't fiddle with it.
543 */
544static int alps_tap_mode(struct psmouse *psmouse, int enable)
545{
546 struct ps2dev *ps2dev = &psmouse->ps2dev;
547 int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
548 unsigned char tap_arg = enable ? 0x0A : 0x00;
549 unsigned char param[4];
550
551 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
552 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
553 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
554 ps2_command(ps2dev, &tap_arg, cmd))
555 return -1;
556
557 if (alps_get_status(psmouse, param))
558 return -1;
559
560 return 0;
561}
562
563/*
564 * alps_poll() - poll the touchpad for current motion packet.
565 * Used in resync.
566 */
567static int alps_poll(struct psmouse *psmouse)
568{
569 struct alps_data *priv = psmouse->private;
570 unsigned char buf[6];
571 bool poll_failed;
572
573 if (priv->i->flags & ALPS_PASS)
574 alps_passthrough_mode(psmouse, true);
575
576 poll_failed = ps2_command(&psmouse->ps2dev, buf,
577 PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
578
579 if (priv->i->flags & ALPS_PASS)
580 alps_passthrough_mode(psmouse, false);
581
582 if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
583 return -1;
584
585 if ((psmouse->badbyte & 0xc8) == 0x08) {
586/*
587 * Poll the track stick ...
588 */
589 if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8)))
590 return -1;
591 }
592
593 memcpy(psmouse->packet, buf, sizeof(buf));
594 return 0;
595}
596
597static int alps_hw_init(struct psmouse *psmouse)
598{
599 struct alps_data *priv = psmouse->private;
600 const struct alps_model_info *model = priv->i;
601
602 if ((model->flags & ALPS_PASS) &&
603 alps_passthrough_mode(psmouse, true)) {
604 return -1;
605 }
606
607 if (alps_tap_mode(psmouse, true)) {
608 printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
609 return -1;
610 }
611
612 if (alps_absolute_mode(psmouse)) {
613 printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
614 return -1;
615 }
616
617 if ((model->flags & ALPS_PASS) &&
618 alps_passthrough_mode(psmouse, false)) {
619 return -1;
620 }
621
622 /* ALPS needs stream mode, otherwise it won't report any data */
623 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
624 printk(KERN_ERR "alps.c: Failed to enable stream mode\n");
625 return -1;
626 }
627
628 return 0;
629}
630
631static int alps_reconnect(struct psmouse *psmouse)
632{
633 const struct alps_model_info *model;
634
635 psmouse_reset(psmouse);
636
637 model = alps_get_model(psmouse, NULL);
638 if (!model)
639 return -1;
640
641 return alps_hw_init(psmouse);
642}
643
644static void alps_disconnect(struct psmouse *psmouse)
645{
646 struct alps_data *priv = psmouse->private;
647
648 psmouse_reset(psmouse);
649 del_timer_sync(&priv->timer);
650 input_unregister_device(priv->dev2);
651 kfree(priv);
652}
653
654int alps_init(struct psmouse *psmouse)
655{
656 struct alps_data *priv;
657 const struct alps_model_info *model;
658 struct input_dev *dev1 = psmouse->dev, *dev2;
659 int version;
660
661 priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
662 dev2 = input_allocate_device();
663 if (!priv || !dev2)
664 goto init_fail;
665
666 priv->dev2 = dev2;
667 setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
668
669 psmouse->private = priv;
670
671 model = alps_get_model(psmouse, &version);
672 if (!model)
673 goto init_fail;
674
675 priv->i = model;
676
677 if (alps_hw_init(psmouse))
678 goto init_fail;
679
680 /*
681 * Undo part of setup done for us by psmouse core since touchpad
682 * is not a relative device.
683 */
684 __clear_bit(EV_REL, dev1->evbit);
685 __clear_bit(REL_X, dev1->relbit);
686 __clear_bit(REL_Y, dev1->relbit);
687
688 /*
689 * Now set up our capabilities.
690 */
691 dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
692 dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
693 dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER);
694 dev1->keybit[BIT_WORD(BTN_LEFT)] |=
695 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
696
697 dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
698 input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
699 input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
700 input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
701
702 if (model->flags & ALPS_WHEEL) {
703 dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
704 dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL);
705 }
706
707 if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
708 dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD);
709 dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK);
710 }
711
712 if (model->flags & ALPS_FOUR_BUTTONS) {
713 dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0);
714 dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
715 dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
716 dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
717 } else {
718 dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
719 }
720
721 snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
722 dev2->phys = priv->phys;
723 dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
724 dev2->id.bustype = BUS_I8042;
725 dev2->id.vendor = 0x0002;
726 dev2->id.product = PSMOUSE_ALPS;
727 dev2->id.version = 0x0000;
728 dev2->dev.parent = &psmouse->ps2dev.serio->dev;
729
730 dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
731 dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
732 dev2->keybit[BIT_WORD(BTN_LEFT)] =
733 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
734
735 if (input_register_device(priv->dev2))
736 goto init_fail;
737
738 psmouse->protocol_handler = alps_process_byte;
739 psmouse->poll = alps_poll;
740 psmouse->disconnect = alps_disconnect;
741 psmouse->reconnect = alps_reconnect;
742 psmouse->pktsize = 6;
743
744 /* We are having trouble resyncing ALPS touchpads so disable it for now */
745 psmouse->resync_time = 0;
746
747 return 0;
748
749init_fail:
750 psmouse_reset(psmouse);
751 input_free_device(dev2);
752 kfree(priv);
753 psmouse->private = NULL;
754 return -1;
755}
756
757int alps_detect(struct psmouse *psmouse, bool set_properties)
758{
759 int version;
760 const struct alps_model_info *model;
761
762 model = alps_get_model(psmouse, &version);
763 if (!model)
764 return -1;
765
766 if (set_properties) {
767 psmouse->vendor = "ALPS";
768 psmouse->name = model->flags & ALPS_DUALPOINT ?
769 "DualPoint TouchPad" : "GlidePoint";
770 psmouse->model = version;
771 }
772 return 0;
773}
774
diff --git a/usr/src/dkms_source_tree/alps.h b/usr/src/dkms_source_tree/alps.h
new file mode 100644
index 0000000..904ed8b
--- /dev/null
+++ b/usr/src/dkms_source_tree/alps.h
@@ -0,0 +1,43 @@
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
15struct alps_model_info {
16 unsigned char signature[3];
17 unsigned char byte0, mask0;
18 unsigned char flags;
19};
20
21struct alps_data {
22 struct input_dev *dev2; /* Relative device */
23 char phys[32]; /* Phys */
24 const struct alps_model_info *i;/* Info */
25 int prev_fin; /* Finger bit from previous packet */
26 struct timer_list timer;
27};
28
29#ifdef CONFIG_MOUSE_PS2_ALPS
30int alps_detect(struct psmouse *psmouse, bool set_properties);
31int alps_init(struct psmouse *psmouse);
32#else
33inline int alps_detect(struct psmouse *psmouse, bool set_properties)
34{
35 return -ENOSYS;
36}
37inline int alps_init(struct psmouse *psmouse)
38{
39 return -ENOSYS;
40}
41#endif /* CONFIG_MOUSE_PS2_ALPS */
42
43#endif
diff --git a/usr/src/dkms_source_tree/dkms.conf b/usr/src/dkms_source_tree/dkms.conf
new file mode 100644
index 0000000..c7da472
--- /dev/null
+++ b/usr/src/dkms_source_tree/dkms.conf
@@ -0,0 +1,10 @@
1NAME=synaptics
2VERSION=1.0.0
3PACKAGE_NAME="$NAME"
4PACKAGE_VERSION="$VERSION"
5MAKE[0]="make -C ${kernel_source_dir}
6 SUBDIRS=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build modules"
7BUILT_MODULE_NAME[0]="psmouse"
8DEST_MODULE_LOCATION[0]="/kernel/drivers/input/mouse"
9POST_INSTALL="scripts/synaptics-post-install"
10AUTOINSTALL="yes"
diff --git a/usr/src/dkms_source_tree/elantech.c b/usr/src/dkms_source_tree/elantech.c
new file mode 100644
index 0000000..b18862b
--- /dev/null
+++ b/usr/src/dkms_source_tree/elantech.c
@@ -0,0 +1,769 @@
1/*
2 * Elantech Touchpad driver (v6)
3 *
4 * Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net>
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
8 * by the Free Software Foundation.
9 *
10 * Trademarks are the property of their respective owners.
11 */
12
13#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
14
15#include <linux/delay.h>
16#include <linux/slab.h>
17#include <linux/module.h>
18#include <linux/input.h>
19#include <linux/serio.h>
20#include <linux/libps2.h>
21#include "psmouse.h"
22#include "elantech.h"
23
24#define elantech_debug(fmt, ...) \
25 do { \
26 if (etd->debug) \
27 printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
28 } while (0)
29
30static bool force_elantech;
31module_param_named(force_elantech, force_elantech, bool, 0644);
32MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default).");
33
34/*
35 * Send a Synaptics style sliced query command
36 */
37static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c,
38 unsigned char *param)
39{
40 if (psmouse_sliced_command(psmouse, c) ||
41 ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
42 pr_err("synaptics_send_cmd query 0x%02x failed.\n", c);
43 return -1;
44 }
45
46 return 0;
47}
48
49/*
50 * A retrying version of ps2_command
51 */
52static int elantech_ps2_command(struct psmouse *psmouse,
53 unsigned char *param, int command)
54{
55 struct ps2dev *ps2dev = &psmouse->ps2dev;
56 struct elantech_data *etd = psmouse->private;
57 int rc;
58 int tries = ETP_PS2_COMMAND_TRIES;
59
60 do {
61 rc = ps2_command(ps2dev, param, command);
62 if (rc == 0)
63 break;
64 tries--;
65 elantech_debug("retrying ps2 command 0x%02x (%d).\n",
66 command, tries);
67 msleep(ETP_PS2_COMMAND_DELAY);
68 } while (tries > 0);
69
70 if (rc)
71 pr_err("ps2 command 0x%02x failed.\n", command);
72
73 return rc;
74}
75
76/*
77 * Send an Elantech style special command to read a value from a register
78 */
79static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
80 unsigned char *val)
81{
82 struct elantech_data *etd = psmouse->private;
83 unsigned char param[3];
84 int rc = 0;
85
86 if (reg < 0x10 || reg > 0x26)
87 return -1;
88
89 if (reg > 0x11 && reg < 0x20)
90 return -1;
91
92 switch (etd->hw_version) {
93 case 1:
94 if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) ||
95 psmouse_sliced_command(psmouse, reg) ||
96 ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) {
97 rc = -1;
98 }
99 break;
100
101 case 2:
102 if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
103 elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READ) ||
104 elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
105 elantech_ps2_command(psmouse, NULL, reg) ||
106 elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
107 rc = -1;
108 }
109 break;
110 }
111
112 if (rc)
113 pr_err("failed to read register 0x%02x.\n", reg);
114 else
115 *val = param[0];
116
117 return rc;
118}
119
120/*
121 * Send an Elantech style special command to write a register with a value
122 */
123static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
124 unsigned char val)
125{
126 struct elantech_data *etd = psmouse->private;
127 int rc = 0;
128
129 if (reg < 0x10 || reg > 0x26)
130 return -1;
131
132 if (reg > 0x11 && reg < 0x20)
133 return -1;
134
135 switch (etd->hw_version) {
136 case 1:
137 if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) ||
138 psmouse_sliced_command(psmouse, reg) ||
139 psmouse_sliced_command(psmouse, val) ||
140 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) {
141 rc = -1;
142 }
143 break;
144
145 case 2:
146 if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
147 elantech_ps2_command(psmouse, NULL, ETP_REGISTER_WRITE) ||
148 elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
149 elantech_ps2_command(psmouse, NULL, reg) ||
150 elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
151 elantech_ps2_command(psmouse, NULL, val) ||
152 elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
153 rc = -1;
154 }
155 break;
156 }
157
158 if (rc)
159 pr_err("failed to write register 0x%02x with value 0x%02x.\n",
160 reg, val);
161
162 return rc;
163}
164
165/*
166 * Dump a complete mouse movement packet to the syslog
167 */
168static void elantech_packet_dump(unsigned char *packet, int size)
169{
170 int i;
171
172 printk(KERN_DEBUG pr_fmt("PS/2 packet ["));
173 for (i = 0; i < size; i++)
174 printk("%s0x%02x ", (i) ? ", " : " ", packet[i]);
175 printk("]\n");
176}
177
178/*
179 * Interpret complete data packets and report absolute mode input events for
180 * hardware version 1. (4 byte packets)
181 */
182static void elantech_report_absolute_v1(struct psmouse *psmouse)
183{
184 struct input_dev *dev = psmouse->dev;
185 struct elantech_data *etd = psmouse->private;
186 unsigned char *packet = psmouse->packet;
187 int fingers;
188 static int old_fingers;
189
190 if (etd->fw_version < 0x020000) {
191 /*
192 * byte 0: D U p1 p2 1 p3 R L
193 * byte 1: f 0 th tw x9 x8 y9 y8
194 */
195 fingers = ((packet[1] & 0x80) >> 7) +
196 ((packet[1] & 0x30) >> 4);
197 } else {
198 /*
199 * byte 0: n1 n0 p2 p1 1 p3 R L
200 * byte 1: 0 0 0 0 x9 x8 y9 y8
201 */
202 fingers = (packet[0] & 0xc0) >> 6;
203 }
204
205 if (etd->jumpy_cursor) {
206 /* Discard packets that are likely to have bogus coordinates */
207 if (fingers > old_fingers) {
208 elantech_debug("discarding packet\n");
209 goto discard_packet_v1;
210 }
211 }
212
213 input_report_key(dev, BTN_TOUCH, fingers != 0);
214
215 /*
216 * byte 2: x7 x6 x5 x4 x3 x2 x1 x0
217 * byte 3: y7 y6 y5 y4 y3 y2 y1 y0
218 */
219 if (fingers) {
220 input_report_abs(dev, ABS_X,
221 ((packet[1] & 0x0c) << 6) | packet[2]);
222 input_report_abs(dev, ABS_Y,
223 ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3]));
224 }
225
226 input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
227 input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
228 input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
229 input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
230 input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
231
232 if (etd->fw_version < 0x020000 &&
233 (etd->capabilities & ETP_CAP_HAS_ROCKER)) {
234 /* rocker up */
235 input_report_key(dev, BTN_FORWARD, packet[0] & 0x40);
236 /* rocker down */
237 input_report_key(dev, BTN_BACK, packet[0] & 0x80);
238 }
239
240 input_sync(dev);
241
242 discard_packet_v1:
243 old_fingers = fingers;
244}
245
246/*
247 * Interpret complete data packets and report absolute mode input events for
248 * hardware version 2. (6 byte packets)
249 */
250static void elantech_report_absolute_v2(struct psmouse *psmouse)
251{
252 struct input_dev *dev = psmouse->dev;
253 unsigned char *packet = psmouse->packet;
254 int fingers, x1, y1, x2, y2;
255
256 /* byte 0: n1 n0 . . . . R L */
257 fingers = (packet[0] & 0xc0) >> 6;
258 input_report_key(dev, BTN_TOUCH, fingers != 0);
259
260 switch (fingers) {
261 case 1:
262 /*
263 * byte 1: . . . . . x10 x9 x8
264 * byte 2: x7 x6 x5 x4 x4 x2 x1 x0
265 */
266 input_report_abs(dev, ABS_X,
267 ((packet[1] & 0x07) << 8) | packet[2]);
268 /*
269 * byte 4: . . . . . . y9 y8
270 * byte 5: y7 y6 y5 y4 y3 y2 y1 y0
271 */
272 input_report_abs(dev, ABS_Y,
273 ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
274 break;
275
276 case 2:
277 /*
278 * The coordinate of each finger is reported separately
279 * with a lower resolution for two finger touches:
280 * byte 0: . . ay8 ax8 . . . .
281 * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
282 */
283 x1 = ((packet[0] & 0x10) << 4) | packet[1];
284 /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */
285 y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]);
286 /*
287 * byte 3: . . by8 bx8 . . . .
288 * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
289 */
290 x2 = ((packet[3] & 0x10) << 4) | packet[4];
291 /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */
292 y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]);
293 /*
294 * For compatibility with the X Synaptics driver scale up
295 * one coordinate and report as ordinary mouse movent
296 */
297 input_report_abs(dev, ABS_X, x1 << 2);
298 input_report_abs(dev, ABS_Y, y1 << 2);
299 /*
300 * For compatibility with the proprietary X Elantech driver
301 * report both coordinates as hat coordinates
302 */
303 input_report_abs(dev, ABS_HAT0X, x1);
304 input_report_abs(dev, ABS_HAT0Y, y1);
305 input_report_abs(dev, ABS_HAT1X, x2);
306 input_report_abs(dev, ABS_HAT1Y, y2);
307 break;
308 }
309
310 input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
311 input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
312 input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
313 input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
314 input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
315
316 input_sync(dev);
317}
318
319static int elantech_check_parity_v1(struct psmouse *psmouse)
320{
321 struct elantech_data *etd = psmouse->private;
322 unsigned char *packet = psmouse->packet;
323 unsigned char p1, p2, p3;
324
325 /* Parity bits are placed differently */
326 if (etd->fw_version < 0x020000) {
327 /* byte 0: D U p1 p2 1 p3 R L */
328 p1 = (packet[0] & 0x20) >> 5;
329 p2 = (packet[0] & 0x10) >> 4;
330 } else {
331 /* byte 0: n1 n0 p2 p1 1 p3 R L */
332 p1 = (packet[0] & 0x10) >> 4;
333 p2 = (packet[0] & 0x20) >> 5;
334 }
335
336 p3 = (packet[0] & 0x04) >> 2;
337
338 return etd->parity[packet[1]] == p1 &&
339 etd->parity[packet[2]] == p2 &&
340 etd->parity[packet[3]] == p3;
341}
342
343/*
344 * Process byte stream from mouse and handle complete packets
345 */
346static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
347{
348 struct elantech_data *etd = psmouse->private;
349
350 if (psmouse->pktcnt < psmouse->pktsize)
351 return PSMOUSE_GOOD_DATA;
352
353 if (etd->debug > 1)
354 elantech_packet_dump(psmouse->packet, psmouse->pktsize);
355
356 switch (etd->hw_version) {
357 case 1:
358 if (etd->paritycheck && !elantech_check_parity_v1(psmouse))
359 return PSMOUSE_BAD_DATA;
360
361 elantech_report_absolute_v1(psmouse);
362 break;
363
364 case 2:
365 /* We don't know how to check parity in protocol v2 */
366 elantech_report_absolute_v2(psmouse);
367 break;
368 }
369
370 return PSMOUSE_FULL_PACKET;
371}
372
373/*
374 * Put the touchpad into absolute mode
375 */
376static int elantech_set_absolute_mode(struct psmouse *psmouse)
377{
378 struct elantech_data *etd = psmouse->private;
379 unsigned char val;
380 int tries = ETP_READ_BACK_TRIES;
381 int rc = 0;
382
383 switch (etd->hw_version) {
384 case 1:
385 etd->reg_10 = 0x16;
386 etd->reg_11 = 0x8f;
387 if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
388 elantech_write_reg(psmouse, 0x11, etd->reg_11)) {
389 rc = -1;
390 }
391 break;
392
393 case 2:
394 /* Windows driver values */
395 etd->reg_10 = 0x54;
396 etd->reg_11 = 0x88; /* 0x8a */
397 etd->reg_21 = 0x60; /* 0x00 */
398 if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
399 elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
400 elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
401 rc = -1;
402 break;
403 }
404 }
405
406 if (rc == 0) {
407 /*
408 * Read back reg 0x10. For hardware version 1 we must make
409 * sure the absolute mode bit is set. For hardware version 2
410 * the touchpad is probably initalising and not ready until
411 * we read back the value we just wrote.
412 */
413 do {
414 rc = elantech_read_reg(psmouse, 0x10, &val);
415 if (rc == 0)
416 break;
417 tries--;
418 elantech_debug("retrying read (%d).\n", tries);
419 msleep(ETP_READ_BACK_DELAY);
420 } while (tries > 0);
421
422 if (rc) {
423 pr_err("failed to read back register 0x10.\n");
424 } else if (etd->hw_version == 1 &&
425 !(val & ETP_R10_ABSOLUTE_MODE)) {
426 pr_err("touchpad refuses to switch to absolute mode.\n");
427 rc = -1;
428 }
429 }
430
431 if (rc)
432 pr_err("failed to initialise registers.\n");
433
434 return rc;
435}
436
437/*
438 * Set the appropriate event bits for the input subsystem
439 */
440static void elantech_set_input_params(struct psmouse *psmouse)
441{
442 struct input_dev *dev = psmouse->dev;
443 struct elantech_data *etd = psmouse->private;
444
445 __set_bit(EV_KEY, dev->evbit);
446 __set_bit(EV_ABS, dev->evbit);
447 __clear_bit(EV_REL, dev->evbit);
448
449 __set_bit(BTN_LEFT, dev->keybit);
450 __set_bit(BTN_RIGHT, dev->keybit);
451
452 __set_bit(BTN_TOUCH, dev->keybit);
453 __set_bit(BTN_TOOL_FINGER, dev->keybit);
454 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
455 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
456
457 switch (etd->hw_version) {
458 case 1:
459 /* Rocker button */
460 if (etd->fw_version < 0x020000 &&
461 (etd->capabilities & ETP_CAP_HAS_ROCKER)) {
462 __set_bit(BTN_FORWARD, dev->keybit);
463 __set_bit(BTN_BACK, dev->keybit);
464 }
465 input_set_abs_params(dev, ABS_X, ETP_XMIN_V1, ETP_XMAX_V1, 0, 0);
466 input_set_abs_params(dev, ABS_Y, ETP_YMIN_V1, ETP_YMAX_V1, 0, 0);
467 break;
468
469 case 2:
470 input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
471 input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
472 input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
473 input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
474 input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
475 input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
476 break;
477 }
478}
479
480struct elantech_attr_data {
481 size_t field_offset;
482 unsigned char reg;
483};
484
485/*
486 * Display a register value by reading a sysfs entry
487 */
488static ssize_t elantech_show_int_attr(struct psmouse *psmouse, void *data,
489 char *buf)
490{
491 struct elantech_data *etd = psmouse->private;
492 struct elantech_attr_data *attr = data;
493 unsigned char *reg = (unsigned char *) etd + attr->field_offset;
494 int rc = 0;
495
496 if (attr->reg)
497 rc = elantech_read_reg(psmouse, attr->reg, reg);
498
499 return sprintf(buf, "0x%02x\n", (attr->reg && rc) ? -1 : *reg);
500}
501
502/*
503 * Write a register value by writing a sysfs entry
504 */
505static ssize_t elantech_set_int_attr(struct psmouse *psmouse,
506 void *data, const char *buf, size_t count)
507{
508 struct elantech_data *etd = psmouse->private;
509 struct elantech_attr_data *attr = data;
510 unsigned char *reg = (unsigned char *) etd + attr->field_offset;
511 unsigned long value;
512 int err;
513
514 err = strict_strtoul(buf, 16, &value);
515 if (err)
516 return err;
517
518 if (value > 0xff)
519 return -EINVAL;
520
521 /* Do we need to preserve some bits for version 2 hardware too? */
522 if (etd->hw_version == 1) {
523 if (attr->reg == 0x10)
524 /* Force absolute mode always on */
525 value |= ETP_R10_ABSOLUTE_MODE;
526 else if (attr->reg == 0x11)
527 /* Force 4 byte mode always on */
528 value |= ETP_R11_4_BYTE_MODE;
529 }
530
531 if (!attr->reg || elantech_write_reg(psmouse, attr->reg, value) == 0)
532 *reg = value;
533
534 return count;
535}
536
537#define ELANTECH_INT_ATTR(_name, _register) \
538 static struct elantech_attr_data elantech_attr_##_name = { \
539 .field_offset = offsetof(struct elantech_data, _name), \
540 .reg = _register, \
541 }; \
542 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
543 &elantech_attr_##_name, \
544 elantech_show_int_attr, \
545 elantech_set_int_attr)
546
547ELANTECH_INT_ATTR(reg_10, 0x10);
548ELANTECH_INT_ATTR(reg_11, 0x11);
549ELANTECH_INT_ATTR(reg_20, 0x20);
550ELANTECH_INT_ATTR(reg_21, 0x21);
551ELANTECH_INT_ATTR(reg_22, 0x22);
552ELANTECH_INT_ATTR(reg_23, 0x23);
553ELANTECH_INT_ATTR(reg_24, 0x24);
554ELANTECH_INT_ATTR(reg_25, 0x25);
555ELANTECH_INT_ATTR(reg_26, 0x26);
556ELANTECH_INT_ATTR(debug, 0);
557ELANTECH_INT_ATTR(paritycheck, 0);
558
559static struct attribute *elantech_attrs[] = {
560 &psmouse_attr_reg_10.dattr.attr,
561 &psmouse_attr_reg_11.dattr.attr,
562 &psmouse_attr_reg_20.dattr.attr,
563 &psmouse_attr_reg_21.dattr.attr,
564 &psmouse_attr_reg_22.dattr.attr,
565 &psmouse_attr_reg_23.dattr.attr,
566 &psmouse_attr_reg_24.dattr.attr,
567 &psmouse_attr_reg_25.dattr.attr,
568 &psmouse_attr_reg_26.dattr.attr,
569 &psmouse_attr_debug.dattr.attr,
570 &psmouse_attr_paritycheck.dattr.attr,
571 NULL
572};
573
574static struct attribute_group elantech_attr_group = {
575 .attrs = elantech_attrs,
576};
577
578static bool elantech_is_signature_valid(const unsigned char *param)
579{
580 static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 };
581 int i;
582
583 if (param[0] == 0)
584 return false;
585
586 if (param[1] == 0)
587 return true;
588
589 for (i = 0; i < ARRAY_SIZE(rates); i++)
590 if (param[2] == rates[i])
591 return false;
592
593 return true;
594}
595
596/*
597 * Use magic knock to detect Elantech touchpad
598 */
599int elantech_detect(struct psmouse *psmouse, bool set_properties)
600{
601 struct ps2dev *ps2dev = &psmouse->ps2dev;
602 unsigned char param[3];
603
604 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
605
606 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
607 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
608 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
609 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
610 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
611 pr_debug("sending Elantech magic knock failed.\n");
612 return -1;
613 }
614
615 /*
616 * Report this in case there are Elantech models that use a different
617 * set of magic numbers
618 */
619 if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
620 pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
621 param[0], param[1], param[2]);
622 return -1;
623 }
624
625 /*
626 * Query touchpad's firmware version and see if it reports known
627 * value to avoid mis-detection. Logitech mice are known to respond
628 * to Elantech magic knock and there might be more.
629 */
630 if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
631 pr_debug("failed to query firmware version.\n");
632 return -1;
633 }
634
635 pr_debug("Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n",
636 param[0], param[1], param[2]);
637
638 if (!elantech_is_signature_valid(param)) {
639 if (!force_elantech) {
640 pr_debug("Probably not a real Elantech touchpad. Aborting.\n");
641 return -1;
642 }
643
644 pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n");
645 }
646
647 if (set_properties) {
648 psmouse->vendor = "Elantech";
649 psmouse->name = "Touchpad";
650 }
651
652 return 0;
653}
654
655/*
656 * Clean up sysfs entries when disconnecting
657 */
658static void elantech_disconnect(struct psmouse *psmouse)
659{
660 sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
661 &elantech_attr_group);
662 kfree(psmouse->private);
663 psmouse->private = NULL;
664}
665
666/*
667 * Put the touchpad back into absolute mode when reconnecting
668 */
669static int elantech_reconnect(struct psmouse *psmouse)
670{
671 if (elantech_detect(psmouse, 0))
672 return -1;
673
674 if (elantech_set_absolute_mode(psmouse)) {
675 pr_err("failed to put touchpad back into absolute mode.\n");
676 return -1;
677 }
678
679 return 0;
680}
681
682/*
683 * Initialize the touchpad and create sysfs entries
684 */
685int elantech_init(struct psmouse *psmouse)
686{
687 struct elantech_data *etd;
688 int i, error;
689 unsigned char param[3];
690
691 psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
692 if (!etd)
693 return -1;
694
695 etd->parity[0] = 1;
696 for (i = 1; i < 256; i++)
697 etd->parity[i] = etd->parity[i & (i - 1)] ^ 1;
698
699 /*
700 * Do the version query again so we can store the result
701 */
702 if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
703 pr_err("failed to query firmware version.\n");
704 goto init_fail;
705 }
706
707 etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
708
709 /*
710 * Assume every version greater than this is new EeePC style
711 * hardware with 6 byte packets
712 */
713 if (etd->fw_version >= 0x020030) {
714 etd->hw_version = 2;
715 /* For now show extra debug information */
716 etd->debug = 1;
717 /* Don't know how to do parity checking for version 2 */
718 etd->paritycheck = 0;
719 } else {
720 etd->hw_version = 1;
721 etd->paritycheck = 1;
722 }
723
724 pr_info("assuming hardware version %d, firmware version %d.%d.%d\n",
725 etd->hw_version, param[0], param[1], param[2]);
726
727 if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) {
728 pr_err("failed to query capabilities.\n");
729 goto init_fail;
730 }
731 pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
732 param[0], param[1], param[2]);
733 etd->capabilities = param[0];
734
735 /*
736 * This firmware seems to suffer from misreporting coordinates when
737 * a touch action starts causing the mouse cursor or scrolled page
738 * to jump. Enable a workaround.
739 */
740 if (etd->fw_version == 0x020022) {
741 pr_info("firmware version 2.0.34 detected, enabling jumpy cursor workaround\n");
742 etd->jumpy_cursor = 1;
743 }
744
745 if (elantech_set_absolute_mode(psmouse)) {
746 pr_err("failed to put touchpad into absolute mode.\n");
747 goto init_fail;
748 }
749
750 elantech_set_input_params(psmouse);
751
752 error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
753 &elantech_attr_group);
754 if (error) {
755 pr_err("failed to create sysfs attributes, error: %d.\n", error);
756 goto init_fail;
757 }
758
759 psmouse->protocol_handler = elantech_process_byte;
760 psmouse->disconnect = elantech_disconnect;
761 psmouse->reconnect = elantech_reconnect;
762 psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
763
764 return 0;
765
766 init_fail:
767 kfree(etd);
768 return -1;
769}
diff --git a/usr/src/dkms_source_tree/elantech.h b/usr/src/dkms_source_tree/elantech.h
new file mode 100644
index 0000000..ac57bde
--- /dev/null
+++ b/usr/src/dkms_source_tree/elantech.h
@@ -0,0 +1,124 @@
1/*
2 * Elantech Touchpad driver (v6)
3 *
4 * Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net>
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
8 * by the Free Software Foundation.
9 *
10 * Trademarks are the property of their respective owners.
11 */
12
13#ifndef _ELANTECH_H
14#define _ELANTECH_H
15
16/*
17 * Command values for Synaptics style queries
18 */
19#define ETP_FW_VERSION_QUERY 0x01
20#define ETP_CAPABILITIES_QUERY 0x02
21
22/*
23 * Command values for register reading or writing
24 */
25#define ETP_REGISTER_READ 0x10
26#define ETP_REGISTER_WRITE 0x11
27
28/*
29 * Hardware version 2 custom PS/2 command value
30 */
31#define ETP_PS2_CUSTOM_COMMAND 0xf8
32
33/*
34 * Times to retry a ps2_command and millisecond delay between tries
35 */
36#define ETP_PS2_COMMAND_TRIES 3
37#define ETP_PS2_COMMAND_DELAY 500
38
39/*
40 * Times to try to read back a register and millisecond delay between tries
41 */
42#define ETP_READ_BACK_TRIES 5
43#define ETP_READ_BACK_DELAY 2000
44
45/*
46 * Register bitmasks for hardware version 1
47 */
48#define ETP_R10_ABSOLUTE_MODE 0x04
49#define ETP_R11_4_BYTE_MODE 0x02
50
51/*
52 * Capability bitmasks
53 */
54#define ETP_CAP_HAS_ROCKER 0x04
55
56/*
57 * One hard to find application note states that X axis range is 0 to 576
58 * and Y axis range is 0 to 384 for harware version 1.
59 * Edge fuzz might be necessary because of bezel around the touchpad
60 */
61#define ETP_EDGE_FUZZ_V1 32
62
63#define ETP_XMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1)
64#define ETP_XMAX_V1 (576 - ETP_EDGE_FUZZ_V1)
65#define ETP_YMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1)
66#define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1)
67
68/*
69 * It seems the resolution for hardware version 2 doubled.
70 * Hence the X and Y ranges are doubled too.
71 * The bezel around the pad also appears to be smaller
72 */
73#define ETP_EDGE_FUZZ_V2 8
74
75#define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
76#define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2)
77#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
78#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2)
79
80/*
81 * For two finger touches the coordinate of each finger gets reported
82 * separately but with reduced resolution.
83 */
84#define ETP_2FT_FUZZ 4
85
86#define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ)
87#define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ)
88#define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ)
89#define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ)
90
91struct elantech_data {
92 unsigned char reg_10;
93 unsigned char reg_11;
94 unsigned char reg_20;
95 unsigned char reg_21;
96 unsigned char reg_22;
97 unsigned char reg_23;
98 unsigned char reg_24;
99 unsigned char reg_25;
100 unsigned char reg_26;
101 unsigned char debug;
102 unsigned char capabilities;
103 unsigned char paritycheck;
104 unsigned char jumpy_cursor;
105 unsigned char hw_version;
106 unsigned int fw_version;
107 unsigned char parity[256];
108};
109
110#ifdef CONFIG_MOUSE_PS2_ELANTECH
111int elantech_detect(struct psmouse *psmouse, bool set_properties);
112int elantech_init(struct psmouse *psmouse);
113#else
114static inline int elantech_detect(struct psmouse *psmouse, bool set_properties)
115{
116 return -ENOSYS;
117}
118static inline int elantech_init(struct psmouse *psmouse)
119{
120 return -ENOSYS;
121}
122#endif /* CONFIG_MOUSE_PS2_ELANTECH */
123
124#endif
diff --git a/usr/src/dkms_source_tree/hgpk.c b/usr/src/dkms_source_tree/hgpk.c
new file mode 100644
index 0000000..1d2205b
--- /dev/null
+++ b/usr/src/dkms_source_tree/hgpk.c
@@ -0,0 +1,533 @@
1/*
2 * OLPC HGPK (XO-1) touchpad PS/2 mouse driver
3 *
4 * Copyright (c) 2006-2008 One Laptop Per Child
5 * Authors:
6 * Zephaniah E. Hull
7 * Andres Salomon <dilinger@debian.org>
8 *
9 * This driver is partly based on the ALPS driver, which is:
10 *
11 * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
12 * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
13 * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
14 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
20
21/*
22 * The spec from ALPS is available from
23 * <http://wiki.laptop.org/go/Touch_Pad/Tablet>. It refers to this
24 * device as HGPK (Hybrid GS, PT, and Keymatrix).
25 *
26 * The earliest versions of the device had simultaneous reporting; that
27 * was removed. After that, the device used the Advanced Mode GS/PT streaming
28 * stuff. That turned out to be too buggy to support, so we've finally
29 * switched to Mouse Mode (which utilizes only the center 1/3 of the touchpad).
30 */
31
32#define DEBUG
33#include <linux/slab.h>
34#include <linux/input.h>
35#include <linux/serio.h>
36#include <linux/libps2.h>
37#include <linux/delay.h>
38#include <asm/olpc.h>
39
40#include "psmouse.h"
41#include "hgpk.h"
42
43static bool tpdebug;
44module_param(tpdebug, bool, 0644);
45MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
46
47static int recalib_delta = 100;
48module_param(recalib_delta, int, 0644);
49MODULE_PARM_DESC(recalib_delta,
50 "packets containing a delta this large will cause a recalibration.");
51
52static int jumpy_delay = 1000;
53module_param(jumpy_delay, int, 0644);
54MODULE_PARM_DESC(jumpy_delay,
55 "delay (ms) before recal after jumpiness detected");
56
57static int spew_delay = 1000;
58module_param(spew_delay, int, 0644);
59MODULE_PARM_DESC(spew_delay,
60 "delay (ms) before recal after packet spew detected");
61
62static int recal_guard_time = 2000;
63module_param(recal_guard_time, int, 0644);
64MODULE_PARM_DESC(recal_guard_time,
65 "interval (ms) during which recal will be restarted if packet received");
66
67static int post_interrupt_delay = 1000;
68module_param(post_interrupt_delay, int, 0644);
69MODULE_PARM_DESC(post_interrupt_delay,
70 "delay (ms) before recal after recal interrupt detected");
71
72/*
73 * When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
74 * above the pad and still have it send packets. This causes a jump cursor
75 * when one places their finger on the pad. We can probably detect the
76 * jump as we see a large deltas (>= 100px). In mouse mode, I've been
77 * unable to even come close to 100px deltas during normal usage, so I think
78 * this threshold is safe. If a large delta occurs, trigger a recalibration.
79 */
80static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
81{
82 struct hgpk_data *priv = psmouse->private;
83
84 if (abs(x) > recalib_delta || abs(y) > recalib_delta) {
85 hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n",
86 recalib_delta, x, y);
87 /* My car gets forty rods to the hogshead and that's the
88 * way I likes it! */
89 psmouse_queue_work(psmouse, &priv->recalib_wq,
90 msecs_to_jiffies(jumpy_delay));
91 }
92}
93
94/*
95 * We have no idea why this particular hardware bug occurs. The touchpad
96 * will randomly start spewing packets without anything touching the
97 * pad. This wouldn't necessarily be bad, but it's indicative of a
98 * severely miscalibrated pad; attempting to use the touchpad while it's
99 * spewing means the cursor will jump all over the place, and act "drunk".
100 *
101 * The packets that are spewed tend to all have deltas between -2 and 2, and
102 * the cursor will move around without really going very far. It will
103 * tend to end up in the same location; if we tally up the changes over
104 * 100 packets, we end up w/ a final delta of close to 0. This happens
105 * pretty regularly when the touchpad is spewing, and is pretty hard to
106 * manually trigger (at least for *my* fingers). So, it makes a perfect
107 * scheme for detecting spews.
108 */
109static void hgpk_spewing_hack(struct psmouse *psmouse,
110 int l, int r, int x, int y)
111{
112 struct hgpk_data *priv = psmouse->private;
113
114 /* ignore button press packets; many in a row could trigger
115 * a false-positive! */
116 if (l || r)
117 return;
118
119 priv->x_tally += x;
120 priv->y_tally += y;
121
122 if (++priv->count > 100) {
123 if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
124 hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
125 priv->x_tally, priv->y_tally);
126 psmouse_queue_work(psmouse, &priv->recalib_wq,
127 msecs_to_jiffies(spew_delay));
128 }
129 /* reset every 100 packets */
130 priv->count = 0;
131 priv->x_tally = 0;
132 priv->y_tally = 0;
133 }
134}
135
136/*
137 * HGPK Mouse Mode format (standard mouse format, sans middle button)
138 *
139 * byte 0: y-over x-over y-neg x-neg 1 0 swr swl
140 * byte 1: x7 x6 x5 x4 x3 x2 x1 x0
141 * byte 2: y7 y6 y5 y4 y3 y2 y1 y0
142 *
143 * swr/swl are the left/right buttons.
144 * x-neg/y-neg are the x and y delta negative bits
145 * x-over/y-over are the x and y overflow bits
146 */
147static int hgpk_validate_byte(unsigned char *packet)
148{
149 return (packet[0] & 0x0C) != 0x08;
150}
151
152static void hgpk_process_packet(struct psmouse *psmouse)
153{
154 struct input_dev *dev = psmouse->dev;
155 unsigned char *packet = psmouse->packet;
156 int x, y, left, right;
157
158 left = packet[0] & 1;
159 right = (packet[0] >> 1) & 1;
160
161 x = packet[1] - ((packet[0] << 4) & 0x100);
162 y = ((packet[0] << 3) & 0x100) - packet[2];
163
164 hgpk_jumpy_hack(psmouse, x, y);
165 hgpk_spewing_hack(psmouse, left, right, x, y);
166
167 if (tpdebug)
168 hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
169
170 input_report_key(dev, BTN_LEFT, left);
171 input_report_key(dev, BTN_RIGHT, right);
172
173 input_report_rel(dev, REL_X, x);
174 input_report_rel(dev, REL_Y, y);
175
176 input_sync(dev);
177}
178
179static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
180{
181 struct hgpk_data *priv = psmouse->private;
182
183 if (hgpk_validate_byte(psmouse->packet)) {
184 hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
185 __func__, psmouse->pktcnt, psmouse->packet[0],
186 psmouse->packet[1], psmouse->packet[2]);
187 return PSMOUSE_BAD_DATA;
188 }
189
190 if (psmouse->pktcnt >= psmouse->pktsize) {
191 hgpk_process_packet(psmouse);
192 return PSMOUSE_FULL_PACKET;
193 }
194
195 if (priv->recalib_window) {
196 if (time_before(jiffies, priv->recalib_window)) {
197 /*
198 * ugh, got a packet inside our recalibration
199 * window, schedule another recalibration.
200 */
201 hgpk_dbg(psmouse,
202 "packet inside calibration window, "
203 "queueing another recalibration\n");
204 psmouse_queue_work(psmouse, &priv->recalib_wq,
205 msecs_to_jiffies(post_interrupt_delay));
206 }
207 priv->recalib_window = 0;
208 }
209
210 return PSMOUSE_GOOD_DATA;
211}
212
213static int hgpk_force_recalibrate(struct psmouse *psmouse)
214{
215 struct ps2dev *ps2dev = &psmouse->ps2dev;
216 struct hgpk_data *priv = psmouse->private;
217
218 /* C-series touchpads added the recalibrate command */
219 if (psmouse->model < HGPK_MODEL_C)
220 return 0;
221
222 /* we don't want to race with the irq handler, nor with resyncs */
223 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
224
225 /* start by resetting the device */
226 psmouse_reset(psmouse);
227
228 /* send the recalibrate request */
229 if (ps2_command(ps2dev, NULL, 0xf5) ||
230 ps2_command(ps2dev, NULL, 0xf5) ||
231 ps2_command(ps2dev, NULL, 0xe6) ||
232 ps2_command(ps2dev, NULL, 0xf5)) {
233 return -1;
234 }
235
236 /* according to ALPS, 150mS is required for recalibration */
237 msleep(150);
238
239 /* XXX: If a finger is down during this delay, recalibration will
240 * detect capacitance incorrectly. This is a hardware bug, and
241 * we don't have a good way to deal with it. The 2s window stuff
242 * (below) is our best option for now.
243 */
244
245 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
246 return -1;
247
248 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
249
250 /* After we recalibrate, we shouldn't get any packets for 2s. If
251 * we do, it's likely that someone's finger was on the touchpad.
252 * If someone's finger *was* on the touchpad, it's probably
253 * miscalibrated. So, we should schedule another recalibration
254 */
255 priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time);
256
257 return 0;
258}
259
260/*
261 * This kills power to the touchpad; according to ALPS, current consumption
262 * goes down to 50uA after running this. To turn power back on, we drive
263 * MS-DAT low.
264 */
265static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
266{
267 struct ps2dev *ps2dev = &psmouse->ps2dev;
268 int timeo;
269
270 /* Added on D-series touchpads */
271 if (psmouse->model < HGPK_MODEL_D)
272 return 0;
273
274 if (enable) {
275 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
276
277 /*
278 * Sending a byte will drive MS-DAT low; this will wake up
279 * the controller. Once we get an ACK back from it, it
280 * means we can continue with the touchpad re-init. ALPS
281 * tells us that 1s should be long enough, so set that as
282 * the upper bound.
283 */
284 for (timeo = 20; timeo > 0; timeo--) {
285 if (!ps2_sendbyte(&psmouse->ps2dev,
286 PSMOUSE_CMD_DISABLE, 20))
287 break;
288 msleep(50);
289 }
290
291 psmouse_reset(psmouse);
292
293 /* should be all set, enable the touchpad */
294 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
295 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
296
297 } else {
298 hgpk_dbg(psmouse, "Powering off touchpad.\n");
299 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
300
301 if (ps2_command(ps2dev, NULL, 0xec) ||
302 ps2_command(ps2dev, NULL, 0xec) ||
303 ps2_command(ps2dev, NULL, 0xea)) {
304 return -1;
305 }
306
307 /* probably won't see an ACK, the touchpad will be off */
308 ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
309 }
310
311 return 0;
312}
313
314static int hgpk_poll(struct psmouse *psmouse)
315{
316 /* We can't poll, so always return failure. */
317 return -1;
318}
319
320static int hgpk_reconnect(struct psmouse *psmouse)
321{
322 /* During suspend/resume the ps2 rails remain powered. We don't want
323 * to do a reset because it's flush data out of buffers; however,
324 * earlier prototypes (B1) had some brokenness that required a reset. */
325 if (olpc_board_at_least(olpc_board(0xb2)))
326 if (psmouse->ps2dev.serio->dev.power.power_state.event !=
327 PM_EVENT_ON)
328 return 0;
329
330 psmouse_reset(psmouse);
331
332 return 0;
333}
334
335static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
336{
337 struct hgpk_data *priv = psmouse->private;
338
339 return sprintf(buf, "%d\n", priv->powered);
340}
341
342static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
343 const char *buf, size_t count)
344{
345 struct hgpk_data *priv = psmouse->private;
346 unsigned long value;
347 int err;
348
349 err = strict_strtoul(buf, 10, &value);
350 if (err || value > 1)
351 return -EINVAL;
352
353 if (value != priv->powered) {
354 /*
355 * hgpk_toggle_power will deal w/ state so
356 * we're not racing w/ irq
357 */
358 err = hgpk_toggle_power(psmouse, value);
359 if (!err)
360 priv->powered = value;
361 }
362
363 return err ? err : count;
364}
365
366__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
367 hgpk_show_powered, hgpk_set_powered, false);
368
369static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
370 void *data, char *buf)
371{
372 return -EINVAL;
373}
374
375static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data,
376 const char *buf, size_t count)
377{
378 struct hgpk_data *priv = psmouse->private;
379 unsigned long value;
380 int err;
381
382 err = strict_strtoul(buf, 10, &value);
383 if (err || value != 1)
384 return -EINVAL;
385
386 /*
387 * We queue work instead of doing recalibration right here
388 * to avoid adding locking to to hgpk_force_recalibrate()
389 * since workqueue provides serialization.
390 */
391 psmouse_queue_work(psmouse, &priv->recalib_wq, 0);
392 return count;
393}
394
395__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL,
396 hgpk_trigger_recal_show, hgpk_trigger_recal, false);
397
398static void hgpk_disconnect(struct psmouse *psmouse)
399{
400 struct hgpk_data *priv = psmouse->private;
401
402 device_remove_file(&psmouse->ps2dev.serio->dev,
403 &psmouse_attr_powered.dattr);
404
405 if (psmouse->model >= HGPK_MODEL_C)
406 device_remove_file(&psmouse->ps2dev.serio->dev,
407 &psmouse_attr_recalibrate.dattr);
408
409 psmouse_reset(psmouse);
410 kfree(priv);
411}
412
413static void hgpk_recalib_work(struct work_struct *work)
414{
415 struct delayed_work *w = to_delayed_work(work);
416 struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
417 struct psmouse *psmouse = priv->psmouse;
418
419 hgpk_dbg(psmouse, "recalibrating touchpad..\n");
420
421 if (hgpk_force_recalibrate(psmouse))
422 hgpk_err(psmouse, "recalibration failed!\n");
423}
424
425static int hgpk_register(struct psmouse *psmouse)
426{
427 int err;
428
429 /* register handlers */
430 psmouse->protocol_handler = hgpk_process_byte;
431 psmouse->poll = hgpk_poll;
432 psmouse->disconnect = hgpk_disconnect;
433 psmouse->reconnect = hgpk_reconnect;
434 psmouse->pktsize = 3;
435
436 /* Disable the idle resync. */
437 psmouse->resync_time = 0;
438 /* Reset after a lot of bad bytes. */
439 psmouse->resetafter = 1024;
440
441 err = device_create_file(&psmouse->ps2dev.serio->dev,
442 &psmouse_attr_powered.dattr);
443 if (err) {
444 hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
445 return err;
446 }
447
448 /* C-series touchpads added the recalibrate command */
449 if (psmouse->model >= HGPK_MODEL_C) {
450 err = device_create_file(&psmouse->ps2dev.serio->dev,
451 &psmouse_attr_recalibrate.dattr);
452 if (err) {
453 hgpk_err(psmouse,
454 "Failed creating 'recalibrate' sysfs node\n");
455 device_remove_file(&psmouse->ps2dev.serio->dev,
456 &psmouse_attr_powered.dattr);
457 return err;
458 }
459 }
460
461 return 0;
462}
463
464int hgpk_init(struct psmouse *psmouse)
465{
466 struct hgpk_data *priv;
467 int err = -ENOMEM;
468
469 priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
470 if (!priv)
471 goto alloc_fail;
472
473 psmouse->private = priv;
474 priv->psmouse = psmouse;
475 priv->powered = true;
476 INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
477
478 err = psmouse_reset(psmouse);
479 if (err)
480 goto init_fail;
481
482 err = hgpk_register(psmouse);
483 if (err)
484 goto init_fail;
485
486 return 0;
487
488init_fail:
489 kfree(priv);
490alloc_fail:
491 return err;
492}
493
494static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
495{
496 struct ps2dev *ps2dev = &psmouse->ps2dev;
497 unsigned char param[3];
498
499 /* E7, E7, E7, E9 gets us a 3 byte identifier */
500 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
501 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
502 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
503 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
504 return -EIO;
505 }
506
507 hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]);
508
509 /* HGPK signature: 0x67, 0x00, 0x<model> */
510 if (param[0] != 0x67 || param[1] != 0x00)
511 return -ENODEV;
512
513 hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
514
515 return param[2];
516}
517
518int hgpk_detect(struct psmouse *psmouse, bool set_properties)
519{
520 int version;
521
522 version = hgpk_get_model(psmouse);
523 if (version < 0)
524 return version;
525
526 if (set_properties) {
527 psmouse->vendor = "ALPS";
528 psmouse->name = "HGPK";
529 psmouse->model = version;
530 }
531
532 return 0;
533}
diff --git a/usr/src/dkms_source_tree/hgpk.h b/usr/src/dkms_source_tree/hgpk.h
new file mode 100644
index 0000000..d61cfd3
--- /dev/null
+++ b/usr/src/dkms_source_tree/hgpk.h
@@ -0,0 +1,49 @@
1/*
2 * OLPC HGPK (XO-1) touchpad PS/2 mouse driver
3 */
4
5#ifndef _HGPK_H
6#define _HGPK_H
7
8enum hgpk_model_t {
9 HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
10 HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
11 HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */
12 HGPK_MODEL_C = 0x3c,
13 HGPK_MODEL_D = 0x50, /* C1, mass production */
14};
15
16struct hgpk_data {
17 struct psmouse *psmouse;
18 bool powered;
19 int count, x_tally, y_tally; /* hardware workaround stuff */
20 unsigned long recalib_window;
21 struct delayed_work recalib_wq;
22};
23
24#define hgpk_dbg(psmouse, format, arg...) \
25 dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
26#define hgpk_err(psmouse, format, arg...) \
27 dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
28#define hgpk_info(psmouse, format, arg...) \
29 dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
30#define hgpk_warn(psmouse, format, arg...) \
31 dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
32#define hgpk_notice(psmouse, format, arg...) \
33 dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
34
35#ifdef CONFIG_MOUSE_PS2_OLPC
36int hgpk_detect(struct psmouse *psmouse, bool set_properties);
37int hgpk_init(struct psmouse *psmouse);
38#else
39static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
40{
41 return -ENODEV;
42}
43static inline int hgpk_init(struct psmouse *psmouse)
44{
45 return -ENODEV;
46}
47#endif
48
49#endif
diff --git a/usr/src/dkms_source_tree/lifebook.c b/usr/src/dkms_source_tree/lifebook.c
new file mode 100644
index 0000000..c31ad11
--- /dev/null
+++ b/usr/src/dkms_source_tree/lifebook.c
@@ -0,0 +1,352 @@
1/*
2 * Fujitsu B-series Lifebook PS/2 TouchScreen driver
3 *
4 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
5 * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
6 *
7 * TouchScreen detection, absolute mode setting and packet layout is taken from
8 * Harald Hoyer's description of the device.
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
15#include <linux/input.h>
16#include <linux/serio.h>
17#include <linux/libps2.h>
18#include <linux/dmi.h>
19#include <linux/slab.h>
20
21#include "psmouse.h"
22#include "lifebook.h"
23
24struct lifebook_data {
25 struct input_dev *dev2; /* Relative device */
26 char phys[32];
27};
28
29static bool lifebook_present;
30
31static const char *desired_serio_phys;
32
33static int lifebook_limit_serio3(const struct dmi_system_id *d)
34{
35 desired_serio_phys = "isa0060/serio3";
36 return 0;
37}
38
39static bool lifebook_use_6byte_proto;
40
41static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
42{
43 lifebook_use_6byte_proto = true;
44 return 0;
45}
46
47static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
48 {
49 /* FLORA-ie 55mi */
50 .matches = {
51 DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
52 },
53 },
54 {
55 /* LifeBook B */
56 .matches = {
57 DMI_MATCH(DMI_PRODUCT_NAME, "Lifebook B Series"),
58 },
59 },
60 {
61 /* LifeBook B */
62 .matches = {
63 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
64 },
65 },
66 {
67 /* Lifebook B */
68 .matches = {
69 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
70 },
71 },
72 {
73 /* Lifebook B-2130 */
74 .matches = {
75 DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"),
76 },
77 },
78 {
79 /* Lifebook B213x/B2150 */
80 .matches = {
81 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
82 },
83 },
84 {
85 /* Zephyr */
86 .matches = {
87 DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
88 },
89 },
90 {
91 /* Panasonic CF-18 */
92 .matches = {
93 DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
94 },
95 .callback = lifebook_limit_serio3,
96 },
97 {
98 /* Panasonic CF-28 */
99 .matches = {
100 DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
101 DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
102 },
103 .callback = lifebook_set_6byte_proto,
104 },
105 {
106 /* Panasonic CF-29 */
107 .matches = {
108 DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
109 DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
110 },
111 .callback = lifebook_set_6byte_proto,
112 },
113 {
114 /* Panasonic CF-72 */
115 .matches = {
116 DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
117 },
118 .callback = lifebook_set_6byte_proto,
119 },
120 {
121 /* Lifebook B142 */
122 .matches = {
123 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
124 },
125 },
126 { }
127};
128
129void __init lifebook_module_init(void)
130{
131 lifebook_present = dmi_check_system(lifebook_dmi_table);
132}
133
134static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
135{
136 struct lifebook_data *priv = psmouse->private;
137 struct input_dev *dev1 = psmouse->dev;
138 struct input_dev *dev2 = priv ? priv->dev2 : NULL;
139 unsigned char *packet = psmouse->packet;
140 bool relative_packet = packet[0] & 0x08;
141
142 if (relative_packet || !lifebook_use_6byte_proto) {
143 if (psmouse->pktcnt != 3)
144 return PSMOUSE_GOOD_DATA;
145 } else {
146 switch (psmouse->pktcnt) {
147 case 1:
148 return (packet[0] & 0xf8) == 0x00 ?
149 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
150 case 2:
151 return PSMOUSE_GOOD_DATA;
152 case 3:
153 return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
154 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
155 case 4:
156 return (packet[3] & 0xf8) == 0xc0 ?
157 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
158 case 5:
159 return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
160 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
161 case 6:
162 if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
163 return PSMOUSE_BAD_DATA;
164 if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
165 return PSMOUSE_BAD_DATA;
166 break; /* report data */
167 }
168 }
169
170 if (relative_packet) {
171 if (!dev2)
172 printk(KERN_WARNING "lifebook.c: got relative packet "
173 "but no relative device set up\n");
174 } else {
175 if (lifebook_use_6byte_proto) {
176 input_report_abs(dev1, ABS_X,
177 ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
178 input_report_abs(dev1, ABS_Y,
179 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
180 } else {
181 input_report_abs(dev1, ABS_X,
182 (packet[1] | ((packet[0] & 0x30) << 4)));
183 input_report_abs(dev1, ABS_Y,
184 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
185 }
186 input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
187 input_sync(dev1);
188 }
189
190 if (dev2) {
191 if (relative_packet) {
192 input_report_rel(dev2, REL_X,
193 ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
194 input_report_rel(dev2, REL_Y,
195 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
196 }
197 input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
198 input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
199 input_sync(dev2);
200 }
201
202 return PSMOUSE_FULL_PACKET;
203}
204
205static int lifebook_absolute_mode(struct psmouse *psmouse)
206{
207 struct ps2dev *ps2dev = &psmouse->ps2dev;
208 unsigned char param;
209
210 if (psmouse_reset(psmouse))
211 return -1;
212
213 /*
214 * Enable absolute output -- ps2_command fails always but if
215 * you leave this call out the touchsreen will never send
216 * absolute coordinates
217 */
218 param = lifebook_use_6byte_proto ? 0x08 : 0x07;
219 ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
220
221 return 0;
222}
223
224static void lifebook_relative_mode(struct psmouse *psmouse)
225{
226 struct ps2dev *ps2dev = &psmouse->ps2dev;
227 unsigned char param = 0x06;
228
229 ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
230}
231
232static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
233{
234 static const unsigned char params[] = { 0, 1, 2, 2, 3 };
235 unsigned char p;
236
237 if (resolution == 0 || resolution > 400)
238 resolution = 400;
239
240 p = params[resolution / 100];
241 ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
242 psmouse->resolution = 50 << p;
243}
244
245static void lifebook_disconnect(struct psmouse *psmouse)
246{
247 struct lifebook_data *priv = psmouse->private;
248
249 psmouse_reset(psmouse);
250 if (priv) {
251 input_unregister_device(priv->dev2);
252 kfree(priv);
253 }
254 psmouse->private = NULL;
255}
256
257int lifebook_detect(struct psmouse *psmouse, bool set_properties)
258{
259 if (!lifebook_present)
260 return -1;
261
262 if (desired_serio_phys &&
263 strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
264 return -1;
265
266 if (set_properties) {
267 psmouse->vendor = "Fujitsu";
268 psmouse->name = "Lifebook TouchScreen";
269 }
270
271 return 0;
272}
273
274static int lifebook_create_relative_device(struct psmouse *psmouse)
275{
276 struct input_dev *dev2;
277 struct lifebook_data *priv;
278 int error = -ENOMEM;
279
280 priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
281 dev2 = input_allocate_device();
282 if (!priv || !dev2)
283 goto err_out;
284
285 priv->dev2 = dev2;
286 snprintf(priv->phys, sizeof(priv->phys),
287 "%s/input1", psmouse->ps2dev.serio->phys);
288
289 dev2->phys = priv->phys;
290 dev2->name = "PS/2 Touchpad";
291 dev2->id.bustype = BUS_I8042;
292 dev2->id.vendor = 0x0002;
293 dev2->id.product = PSMOUSE_LIFEBOOK;
294 dev2->id.version = 0x0000;
295 dev2->dev.parent = &psmouse->ps2dev.serio->dev;
296
297 dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
298 dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
299 dev2->keybit[BIT_WORD(BTN_LEFT)] =
300 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
301
302 error = input_register_device(priv->dev2);
303 if (error)
304 goto err_out;
305
306 psmouse->private = priv;
307 return 0;
308
309 err_out:
310 input_free_device(dev2);
311 kfree(priv);
312 return error;
313}
314
315int lifebook_init(struct psmouse *psmouse)
316{
317 struct input_dev *dev1 = psmouse->dev;
318 int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
319
320 if (lifebook_absolute_mode(psmouse))
321 return -1;
322
323 dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
324 dev1->relbit[0] = 0;
325 dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0;
326 dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
327 input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
328 input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
329
330 if (!desired_serio_phys) {
331 if (lifebook_create_relative_device(psmouse)) {
332 lifebook_relative_mode(psmouse);
333 return -1;
334 }
335 }
336
337 psmouse->protocol_handler = lifebook_process_byte;
338 psmouse->set_resolution = lifebook_set_resolution;
339 psmouse->disconnect = lifebook_disconnect;
340 psmouse->reconnect = lifebook_absolute_mode;
341
342 psmouse->model = lifebook_use_6byte_proto ? 6 : 3;
343
344 /*
345 * Use packet size = 3 even when using 6-byte protocol because
346 * that's what POLL will return on Lifebooks (according to spec).
347 */
348 psmouse->pktsize = 3;
349
350 return 0;
351}
352
diff --git a/usr/src/dkms_source_tree/lifebook.h b/usr/src/dkms_source_tree/lifebook.h
new file mode 100644
index 0000000..4c4326c
--- /dev/null
+++ b/usr/src/dkms_source_tree/lifebook.h
@@ -0,0 +1,32 @@
1/*
2 * Fujitsu B-series Lifebook PS/2 TouchScreen driver
3 *
4 * Copyright (c) 2005 Vojtech Pavlik
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 _LIFEBOOK_H
12#define _LIFEBOOK_H
13
14#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
15void lifebook_module_init(void);
16int lifebook_detect(struct psmouse *psmouse, bool set_properties);
17int lifebook_init(struct psmouse *psmouse);
18#else
19inline void lifebook_module_init(void)
20{
21}
22inline int lifebook_detect(struct psmouse *psmouse, bool set_properties)
23{
24 return -ENOSYS;
25}
26inline int lifebook_init(struct psmouse *psmouse)
27{
28 return -ENOSYS;
29}
30#endif
31
32#endif
diff --git a/usr/src/dkms_source_tree/logips2pp.c b/usr/src/dkms_source_tree/logips2pp.c
new file mode 100644
index 0000000..c9983ae
--- /dev/null
+++ b/usr/src/dkms_source_tree/logips2pp.c
@@ -0,0 +1,420 @@
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#define PS2PP_KIND_TRACKMAN 4
23
24/* Logitech mouse features */
25#define PS2PP_WHEEL 0x01
26#define PS2PP_HWHEEL 0x02
27#define PS2PP_SIDE_BTN 0x04
28#define PS2PP_EXTRA_BTN 0x08
29#define PS2PP_TASK_BTN 0x10
30#define PS2PP_NAV_BTN 0x20
31
32struct ps2pp_info {
33 u8 model;
34 u8 kind;
35 u16 features;
36};
37
38/*
39 * Process a PS2++ or PS2T++ packet.
40 */
41
42static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
43{
44 struct input_dev *dev = psmouse->dev;
45 unsigned char *packet = psmouse->packet;
46
47 if (psmouse->pktcnt < 3)
48 return PSMOUSE_GOOD_DATA;
49
50/*
51 * Full packet accumulated, process it
52 */
53
54 if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
55
56 /* Logitech extended packet */
57 switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
58
59 case 0x0d: /* Mouse extra info */
60
61 input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
62 (int) (packet[2] & 8) - (int) (packet[2] & 7));
63 input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
64 input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
65
66 break;
67
68 case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
69
70 input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
71 input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
72 input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
73 input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
74 input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
75
76 break;
77
78 case 0x0f: /* TouchPad extra info */
79
80 input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
81 (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
82 packet[0] = packet[2] | 0x08;
83 break;
84
85#ifdef DEBUG
86 default:
87 printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
88 (packet[1] >> 4) | (packet[0] & 0x30));
89#endif
90 }
91 } else {
92 /* Standard PS/2 motion data */
93 input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
94 input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
95 }
96
97 input_report_key(dev, BTN_LEFT, packet[0] & 1);
98 input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
99 input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
100
101 input_sync(dev);
102
103 return PSMOUSE_FULL_PACKET;
104
105}
106
107/*
108 * ps2pp_cmd() sends a PS2++ command, sliced into two bit
109 * pieces through the SETRES command. This is needed to send extended
110 * commands to mice on notebooks that try to understand the PS/2 protocol
111 * Ugly.
112 */
113
114static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
115{
116 if (psmouse_sliced_command(psmouse, command))
117 return -1;
118
119 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300))
120 return -1;
121
122 return 0;
123}
124
125/*
126 * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
127 * enabled if we do nothing to it. Of course I put this in because I want it
128 * disabled :P
129 * 1 - enabled (if previously disabled, also default)
130 * 0 - disabled
131 */
132
133static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
134{
135 struct ps2dev *ps2dev = &psmouse->ps2dev;
136 unsigned char param[4];
137
138 ps2pp_cmd(psmouse, param, 0x32);
139
140 param[0] = 0;
141 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
142 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
143 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
144
145 param[0] = smartscroll;
146 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
147}
148
149static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
150 void *data, char *buf)
151{
152 return sprintf(buf, "%d\n", psmouse->smartscroll);
153}
154
155static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
156 const char *buf, size_t count)
157{
158 unsigned long value;
159
160 if (strict_strtoul(buf, 10, &value) || value > 1)
161 return -EINVAL;
162
163 ps2pp_set_smartscroll(psmouse, value);
164 psmouse->smartscroll = value;
165 return count;
166}
167
168PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
169 ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
170
171/*
172 * Support 800 dpi resolution _only_ if the user wants it (there are good
173 * reasons to not use it even if the mouse supports it, and of course there are
174 * also good reasons to use it, let the user decide).
175 */
176
177static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution)
178{
179 if (resolution > 400) {
180 struct ps2dev *ps2dev = &psmouse->ps2dev;
181 unsigned char param = 3;
182
183 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
184 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
185 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
186 ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
187 psmouse->resolution = 800;
188 } else
189 psmouse_set_resolution(psmouse, resolution);
190}
191
192static void ps2pp_disconnect(struct psmouse *psmouse)
193{
194 device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
195}
196
197static const struct ps2pp_info *get_model_info(unsigned char model)
198{
199 static const struct ps2pp_info ps2pp_list[] = {
200 { 1, 0, 0 }, /* Simple 2-button mouse */
201 { 12, 0, PS2PP_SIDE_BTN},
202 { 13, 0, 0 },
203 { 15, PS2PP_KIND_MX, /* MX1000 */
204 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
205 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
206 { 40, 0, PS2PP_SIDE_BTN },
207 { 41, 0, PS2PP_SIDE_BTN },
208 { 42, 0, PS2PP_SIDE_BTN },
209 { 43, 0, PS2PP_SIDE_BTN },
210 { 50, 0, 0 },
211 { 51, 0, 0 },
212 { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
213 { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
214 { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
215 { 61, PS2PP_KIND_MX, /* MX700 */
216 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
217 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
218 { 66, PS2PP_KIND_MX, /* MX3100 reciver */
219 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
220 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
221 { 72, PS2PP_KIND_TRACKMAN, 0 }, /* T-CH11: TrackMan Marble */
222 { 73, PS2PP_KIND_TRACKMAN, PS2PP_SIDE_BTN }, /* TrackMan FX */
223 { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
224 { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
225 { 79, PS2PP_KIND_TRACKMAN, PS2PP_WHEEL }, /* TrackMan with wheel */
226 { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
227 { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
228 { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
229 { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
230 { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
231 { 87, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
232 { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
233 { 96, 0, 0 },
234 { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
235 { 99, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
236 { 100, PS2PP_KIND_MX, /* MX510 */
237 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
238 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
239 { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
240 { 112, PS2PP_KIND_MX, /* MX500 */
241 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
242 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
243 { 114, PS2PP_KIND_MX, /* MX310 */
244 PS2PP_WHEEL | PS2PP_SIDE_BTN |
245 PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
246 };
247 int i;
248
249 for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
250 if (model == ps2pp_list[i].model)
251 return &ps2pp_list[i];
252
253 return NULL;
254}
255
256/*
257 * Set up input device's properties based on the detected mouse model.
258 */
259
260static void ps2pp_set_model_properties(struct psmouse *psmouse,
261 const struct ps2pp_info *model_info,
262 bool using_ps2pp)
263{
264 struct input_dev *input_dev = psmouse->dev;
265
266 if (model_info->features & PS2PP_SIDE_BTN)
267 __set_bit(BTN_SIDE, input_dev->keybit);
268
269 if (model_info->features & PS2PP_EXTRA_BTN)
270 __set_bit(BTN_EXTRA, input_dev->keybit);
271
272 if (model_info->features & PS2PP_TASK_BTN)
273 __set_bit(BTN_TASK, input_dev->keybit);
274
275 if (model_info->features & PS2PP_NAV_BTN) {
276 __set_bit(BTN_FORWARD, input_dev->keybit);
277 __set_bit(BTN_BACK, input_dev->keybit);
278 }
279
280 if (model_info->features & PS2PP_WHEEL)
281 __set_bit(REL_WHEEL, input_dev->relbit);
282
283 if (model_info->features & PS2PP_HWHEEL)
284 __set_bit(REL_HWHEEL, input_dev->relbit);
285
286 switch (model_info->kind) {
287
288 case PS2PP_KIND_WHEEL:
289 psmouse->name = "Wheel Mouse";
290 break;
291
292 case PS2PP_KIND_MX:
293 psmouse->name = "MX Mouse";
294 break;
295
296 case PS2PP_KIND_TP3:
297 psmouse->name = "TouchPad 3";
298 break;
299
300 case PS2PP_KIND_TRACKMAN:
301 psmouse->name = "TrackMan";
302 break;
303
304 default:
305 /*
306 * Set name to "Mouse" only when using PS2++,
307 * otherwise let other protocols define suitable
308 * name
309 */
310 if (using_ps2pp)
311 psmouse->name = "Mouse";
312 break;
313 }
314}
315
316
317/*
318 * Logitech magic init. Detect whether the mouse is a Logitech one
319 * and its exact model and try turning on extended protocol for ones
320 * that support it.
321 */
322
323int ps2pp_init(struct psmouse *psmouse, bool set_properties)
324{
325 struct ps2dev *ps2dev = &psmouse->ps2dev;
326 unsigned char param[4];
327 unsigned char model, buttons;
328 const struct ps2pp_info *model_info;
329 bool use_ps2pp = false;
330 int error;
331
332 param[0] = 0;
333 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
334 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
335 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
336 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
337 param[1] = 0;
338 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
339
340 model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
341 buttons = param[1];
342
343 if (!model || !buttons)
344 return -1;
345
346 model_info = get_model_info(model);
347 if (model_info) {
348
349/*
350 * Do Logitech PS2++ / PS2T++ magic init.
351 */
352 if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
353
354 /* Unprotect RAM */
355 param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
356 ps2_command(ps2dev, param, 0x30d1);
357 /* Enable features */
358 param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
359 ps2_command(ps2dev, param, 0x30d1);
360 /* Enable PS2++ */
361 param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
362 ps2_command(ps2dev, param, 0x30d1);
363
364 param[0] = 0;
365 if (!ps2_command(ps2dev, param, 0x13d1) &&
366 param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
367 use_ps2pp = true;
368 }
369
370 } else {
371
372 param[0] = param[1] = param[2] = 0;
373 ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
374 ps2pp_cmd(psmouse, param, 0xDB);
375
376 if ((param[0] & 0x78) == 0x48 &&
377 (param[1] & 0xf3) == 0xc2 &&
378 (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
379 ps2pp_set_smartscroll(psmouse, false);
380 use_ps2pp = true;
381 }
382 }
383
384 } else {
385 printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
386 }
387
388 if (set_properties) {
389 psmouse->vendor = "Logitech";
390 psmouse->model = model;
391
392 if (use_ps2pp) {
393 psmouse->protocol_handler = ps2pp_process_byte;
394 psmouse->pktsize = 3;
395
396 if (model_info->kind != PS2PP_KIND_TP3) {
397 psmouse->set_resolution = ps2pp_set_resolution;
398 psmouse->disconnect = ps2pp_disconnect;
399
400 error = device_create_file(&psmouse->ps2dev.serio->dev,
401 &psmouse_attr_smartscroll.dattr);
402 if (error) {
403 printk(KERN_ERR
404 "logips2pp.c: failed to create smartscroll "
405 "sysfs attribute, error: %d\n", error);
406 return -1;
407 }
408 }
409 }
410
411 if (buttons >= 3)
412 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
413
414 if (model_info)
415 ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
416 }
417
418 return use_ps2pp ? 0 : -1;
419}
420
diff --git a/usr/src/dkms_source_tree/logips2pp.h b/usr/src/dkms_source_tree/logips2pp.h
new file mode 100644
index 0000000..0c186f0
--- /dev/null
+++ b/usr/src/dkms_source_tree/logips2pp.h
@@ -0,0 +1,23 @@
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
14#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
15int ps2pp_init(struct psmouse *psmouse, bool set_properties);
16#else
17inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
18{
19 return -ENOSYS;
20}
21#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */
22
23#endif
diff --git a/usr/src/dkms_source_tree/psmouse-base.c b/usr/src/dkms_source_tree/psmouse-base.c
new file mode 100644
index 0000000..979c502
--- /dev/null
+++ b/usr/src/dkms_source_tree/psmouse-base.c
@@ -0,0 +1,1733 @@
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/slab.h>
17#include <linux/interrupt.h>
18#include <linux/input.h>
19#include <linux/serio.h>
20#include <linux/init.h>
21#include <linux/libps2.h>
22#include <linux/mutex.h>
23
24#include "psmouse.h"
25#include "synaptics.h"
26#include "logips2pp.h"
27#include "alps.h"
28#include "hgpk.h"
29#include "lifebook.h"
30#include "trackpoint.h"
31#include "touchkit_ps2.h"
32#include "elantech.h"
33#include "sentelic.h"
34
35#define DRIVER_DESC "PS/2 mouse driver"
36
37MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
38MODULE_DESCRIPTION(DRIVER_DESC);
39MODULE_LICENSE("GPL");
40
41static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
42static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
43static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
44#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
45#define param_set_proto_abbrev psmouse_set_maxproto
46#define param_get_proto_abbrev psmouse_get_maxproto
47module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
48MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
49
50static unsigned int psmouse_resolution = 200;
51module_param_named(resolution, psmouse_resolution, uint, 0644);
52MODULE_PARM_DESC(resolution, "Resolution, in dpi.");
53
54static unsigned int psmouse_rate = 100;
55module_param_named(rate, psmouse_rate, uint, 0644);
56MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
57
58static unsigned int psmouse_smartscroll = 1;
59module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
60MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
61
62static unsigned int psmouse_resetafter = 5;
63module_param_named(resetafter, psmouse_resetafter, uint, 0644);
64MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
65
66static unsigned int psmouse_resync_time;
67module_param_named(resync_time, psmouse_resync_time, uint, 0644);
68MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never).");
69
70PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO,
71 NULL,
72 psmouse_attr_show_protocol, psmouse_attr_set_protocol);
73PSMOUSE_DEFINE_ATTR(rate, S_IWUSR | S_IRUGO,
74 (void *) offsetof(struct psmouse, rate),
75 psmouse_show_int_attr, psmouse_attr_set_rate);
76PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO,
77 (void *) offsetof(struct psmouse, resolution),
78 psmouse_show_int_attr, psmouse_attr_set_resolution);
79PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO,
80 (void *) offsetof(struct psmouse, resetafter),
81 psmouse_show_int_attr, psmouse_set_int_attr);
82PSMOUSE_DEFINE_ATTR(resync_time, S_IWUSR | S_IRUGO,
83 (void *) offsetof(struct psmouse, resync_time),
84 psmouse_show_int_attr, psmouse_set_int_attr);
85
86static struct attribute *psmouse_attributes[] = {
87 &psmouse_attr_protocol.dattr.attr,
88 &psmouse_attr_rate.dattr.attr,
89 &psmouse_attr_resolution.dattr.attr,
90 &psmouse_attr_resetafter.dattr.attr,
91 &psmouse_attr_resync_time.dattr.attr,
92 NULL
93};
94
95static struct attribute_group psmouse_attribute_group = {
96 .attrs = psmouse_attributes,
97};
98
99/*
100 * psmouse_mutex protects all operations changing state of mouse
101 * (connecting, disconnecting, changing rate or resolution via
102 * sysfs). We could use a per-device semaphore but since there
103 * rarely more than one PS/2 mouse connected and since semaphore
104 * is taken in "slow" paths it is not worth it.
105 */
106static DEFINE_MUTEX(psmouse_mutex);
107
108static struct workqueue_struct *kpsmoused_wq;
109
110struct psmouse_protocol {
111 enum psmouse_type type;
112 bool maxproto;
113 bool ignore_parity; /* Protocol should ignore parity errors from KBC */
114 const char *name;
115 const char *alias;
116 int (*detect)(struct psmouse *, bool);
117 int (*init)(struct psmouse *);
118};
119
120/*
121 * psmouse_process_byte() analyzes the PS/2 data stream and reports
122 * relevant events to the input module once full packet has arrived.
123 */
124
125static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
126{
127 struct input_dev *dev = psmouse->dev;
128 unsigned char *packet = psmouse->packet;
129
130 if (psmouse->pktcnt < psmouse->pktsize)
131 return PSMOUSE_GOOD_DATA;
132
133/*
134 * Full packet accumulated, process it
135 */
136
137/*
138 * Scroll wheel on IntelliMice, scroll buttons on NetMice
139 */
140
141 if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
142 input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
143
144/*
145 * Scroll wheel and buttons on IntelliMouse Explorer
146 */
147
148 if (psmouse->type == PSMOUSE_IMEX) {
149 switch (packet[3] & 0xC0) {
150 case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
151 input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
152 break;
153 case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
154 input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
155 break;
156 case 0x00:
157 case 0xC0:
158 input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
159 input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
160 input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
161 break;
162 }
163 }
164
165/*
166 * Extra buttons on Genius NewNet 3D
167 */
168
169 if (psmouse->type == PSMOUSE_GENPS) {
170 input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
171 input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
172 }
173
174/*
175 * Extra button on ThinkingMouse
176 */
177 if (psmouse->type == PSMOUSE_THINKPS) {
178 input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1);
179 /* Without this bit of weirdness moving up gives wildly high Y changes. */
180 packet[1] |= (packet[0] & 0x40) << 1;
181 }
182
183/*
184 * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first
185 * byte.
186 */
187 if (psmouse->type == PSMOUSE_CORTRON) {
188 input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
189 packet[0] |= 0x08;
190 }
191
192/*
193 * Generic PS/2 Mouse
194 */
195
196 input_report_key(dev, BTN_LEFT, packet[0] & 1);
197 input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
198 input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
199
200 input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
201 input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
202
203 input_sync(dev);
204
205 return PSMOUSE_FULL_PACKET;
206}
207
208void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
209 unsigned long delay)
210{
211 queue_delayed_work(kpsmoused_wq, work, delay);
212}
213
214/*
215 * __psmouse_set_state() sets new psmouse state and resets all flags.
216 */
217
218static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
219{
220 psmouse->state = new_state;
221 psmouse->pktcnt = psmouse->out_of_sync_cnt = 0;
222 psmouse->ps2dev.flags = 0;
223 psmouse->last = jiffies;
224}
225
226
227/*
228 * psmouse_set_state() sets new psmouse state and resets all flags and
229 * counters while holding serio lock so fighting with interrupt handler
230 * is not a concern.
231 */
232
233void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
234{
235 serio_pause_rx(psmouse->ps2dev.serio);
236 __psmouse_set_state(psmouse, new_state);
237 serio_continue_rx(psmouse->ps2dev.serio);
238}
239
240/*
241 * psmouse_handle_byte() processes one byte of the input data stream
242 * by calling corresponding protocol handler.
243 */
244
245static int psmouse_handle_byte(struct psmouse *psmouse)
246{
247 psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
248
249 switch (rc) {
250 case PSMOUSE_BAD_DATA:
251 if (psmouse->state == PSMOUSE_ACTIVATED) {
252 printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
253 psmouse->name, psmouse->phys, psmouse->pktcnt);
254 if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
255 __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
256 printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
257 serio_reconnect(psmouse->ps2dev.serio);
258 return -1;
259 }
260 }
261 psmouse->pktcnt = 0;
262 break;
263
264 case PSMOUSE_FULL_PACKET:
265 psmouse->pktcnt = 0;
266 if (psmouse->out_of_sync_cnt) {
267 psmouse->out_of_sync_cnt = 0;
268 printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
269 psmouse->name, psmouse->phys);
270 }
271 break;
272
273 case PSMOUSE_GOOD_DATA:
274 break;
275 }
276 return 0;
277}
278
279/*
280 * psmouse_interrupt() handles incoming characters, either passing them
281 * for normal processing or gathering them as command response.
282 */
283
284static irqreturn_t psmouse_interrupt(struct serio *serio,
285 unsigned char data, unsigned int flags)
286{
287 struct psmouse *psmouse = serio_get_drvdata(serio);
288
289 if (psmouse->state == PSMOUSE_IGNORE)
290 goto out;
291
292 if (unlikely((flags & SERIO_TIMEOUT) ||
293 ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) {
294
295 if (psmouse->state == PSMOUSE_ACTIVATED)
296 printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
297 flags & SERIO_TIMEOUT ? " timeout" : "",
298 flags & SERIO_PARITY ? " bad parity" : "");
299 ps2_cmd_aborted(&psmouse->ps2dev);
300 goto out;
301 }
302
303 if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
304 if (ps2_handle_ack(&psmouse->ps2dev, data))
305 goto out;
306
307 if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
308 if (ps2_handle_response(&psmouse->ps2dev, data))
309 goto out;
310
311 if (psmouse->state <= PSMOUSE_RESYNCING)
312 goto out;
313
314 if (psmouse->state == PSMOUSE_ACTIVATED &&
315 psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
316 printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
317 psmouse->name, psmouse->phys, psmouse->pktcnt);
318 psmouse->badbyte = psmouse->packet[0];
319 __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
320 psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
321 goto out;
322 }
323
324 psmouse->packet[psmouse->pktcnt++] = data;
325/*
326 * Check if this is a new device announcement (0xAA 0x00)
327 */
328 if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
329 if (psmouse->pktcnt == 1) {
330 psmouse->last = jiffies;
331 goto out;
332 }
333
334 if (psmouse->packet[1] == PSMOUSE_RET_ID ||
335 (psmouse->type == PSMOUSE_HGPK &&
336 psmouse->packet[1] == PSMOUSE_RET_BAT)) {
337 __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
338 serio_reconnect(serio);
339 goto out;
340 }
341/*
342 * Not a new device, try processing first byte normally
343 */
344 psmouse->pktcnt = 1;
345 if (psmouse_handle_byte(psmouse))
346 goto out;
347
348 psmouse->packet[psmouse->pktcnt++] = data;
349 }
350
351/*
352 * See if we need to force resync because mouse was idle for too long
353 */
354 if (psmouse->state == PSMOUSE_ACTIVATED &&
355 psmouse->pktcnt == 1 && psmouse->resync_time &&
356 time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
357 psmouse->badbyte = psmouse->packet[0];
358 __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
359 psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
360 goto out;
361 }
362
363 psmouse->last = jiffies;
364 psmouse_handle_byte(psmouse);
365
366 out:
367 return IRQ_HANDLED;
368}
369
370
371/*
372 * psmouse_sliced_command() sends an extended PS/2 command to the mouse
373 * using sliced syntax, understood by advanced devices, such as Logitech
374 * or Synaptics touchpads. The command is encoded as:
375 * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
376 * is the command.
377 */
378int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
379{
380 int i;
381
382 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
383 return -1;
384
385 for (i = 6; i >= 0; i -= 2) {
386 unsigned char d = (command >> i) & 3;
387 if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
388 return -1;
389 }
390
391 return 0;
392}
393
394
395/*
396 * psmouse_reset() resets the mouse into power-on state.
397 */
398int psmouse_reset(struct psmouse *psmouse)
399{
400 unsigned char param[2];
401
402 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT))
403 return -1;
404
405 if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
406 return -1;
407
408 return 0;
409}
410
411
412/*
413 * Genius NetMouse magic init.
414 */
415static int genius_detect(struct psmouse *psmouse, bool set_properties)
416{
417 struct ps2dev *ps2dev = &psmouse->ps2dev;
418 unsigned char param[4];
419
420 param[0] = 3;
421 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
422 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
423 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
424 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
425 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
426
427 if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55)
428 return -1;
429
430 if (set_properties) {
431 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
432 __set_bit(BTN_EXTRA, psmouse->dev->keybit);
433 __set_bit(BTN_SIDE, psmouse->dev->keybit);
434 __set_bit(REL_WHEEL, psmouse->dev->relbit);
435
436 psmouse->vendor = "Genius";
437 psmouse->name = "Mouse";
438 psmouse->pktsize = 4;
439 }
440
441 return 0;
442}
443
444/*
445 * IntelliMouse magic init.
446 */
447static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
448{
449 struct ps2dev *ps2dev = &psmouse->ps2dev;
450 unsigned char param[2];
451
452 param[0] = 200;
453 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
454 param[0] = 100;
455 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
456 param[0] = 80;
457 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
458 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
459
460 if (param[0] != 3)
461 return -1;
462
463 if (set_properties) {
464 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
465 __set_bit(REL_WHEEL, psmouse->dev->relbit);
466
467 if (!psmouse->vendor)
468 psmouse->vendor = "Generic";
469 if (!psmouse->name)
470 psmouse->name = "Wheel Mouse";
471 psmouse->pktsize = 4;
472 }
473
474 return 0;
475}
476
477/*
478 * Try IntelliMouse/Explorer magic init.
479 */
480static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
481{
482 struct ps2dev *ps2dev = &psmouse->ps2dev;
483 unsigned char param[2];
484
485 intellimouse_detect(psmouse, 0);
486
487 param[0] = 200;
488 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
489 param[0] = 200;
490 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
491 param[0] = 80;
492 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
493 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
494
495 if (param[0] != 4)
496 return -1;
497
498/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
499 param[0] = 200;
500 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
501 param[0] = 80;
502 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
503 param[0] = 40;
504 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
505
506 if (set_properties) {
507 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
508 __set_bit(REL_WHEEL, psmouse->dev->relbit);
509 __set_bit(REL_HWHEEL, psmouse->dev->relbit);
510 __set_bit(BTN_SIDE, psmouse->dev->keybit);
511 __set_bit(BTN_EXTRA, psmouse->dev->keybit);
512
513 if (!psmouse->vendor)
514 psmouse->vendor = "Generic";
515 if (!psmouse->name)
516 psmouse->name = "Explorer Mouse";
517 psmouse->pktsize = 4;
518 }
519
520 return 0;
521}
522
523/*
524 * Kensington ThinkingMouse / ExpertMouse magic init.
525 */
526static int thinking_detect(struct psmouse *psmouse, bool set_properties)
527{
528 struct ps2dev *ps2dev = &psmouse->ps2dev;
529 unsigned char param[2];
530 static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
531 int i;
532
533 param[0] = 10;
534 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
535 param[0] = 0;
536 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
537 for (i = 0; i < ARRAY_SIZE(seq); i++) {
538 param[0] = seq[i];
539 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
540 }
541 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
542
543 if (param[0] != 2)
544 return -1;
545
546 if (set_properties) {
547 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
548 __set_bit(BTN_EXTRA, psmouse->dev->keybit);
549
550 psmouse->vendor = "Kensington";
551 psmouse->name = "ThinkingMouse";
552 }
553
554 return 0;
555}
556
557/*
558 * Bare PS/2 protocol "detection". Always succeeds.
559 */
560static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
561{
562 if (set_properties) {
563 if (!psmouse->vendor)
564 psmouse->vendor = "Generic";
565 if (!psmouse->name)
566 psmouse->name = "Mouse";
567
568/*
569 * We have no way of figuring true number of buttons so let's
570 * assume that the device has 3.
571 */
572 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
573 }
574
575 return 0;
576}
577
578/*
579 * Cortron PS/2 protocol detection. There's no special way to detect it, so it
580 * must be forced by sysfs protocol writing.
581 */
582static int cortron_detect(struct psmouse *psmouse, bool set_properties)
583{
584 if (set_properties) {
585 psmouse->vendor = "Cortron";
586 psmouse->name = "PS/2 Trackball";
587
588 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
589 __set_bit(BTN_SIDE, psmouse->dev->keybit);
590 }
591
592 return 0;
593}
594
595/*
596 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
597 * the mouse may have.
598 */
599
600static int psmouse_extensions(struct psmouse *psmouse,
601 unsigned int max_proto, bool set_properties)
602{
603 bool synaptics_hardware = false;
604
605/*
606 * We always check for lifebook because it does not disturb mouse
607 * (it only checks DMI information).
608 */
609 if (lifebook_detect(psmouse, set_properties) == 0) {
610 if (max_proto > PSMOUSE_IMEX) {
611 if (!set_properties || lifebook_init(psmouse) == 0)
612 return PSMOUSE_LIFEBOOK;
613 }
614 }
615
616/*
617 * Try Kensington ThinkingMouse (we try first, because synaptics probe
618 * upsets the thinkingmouse).
619 */
620
621 if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0)
622 return PSMOUSE_THINKPS;
623
624/*
625 * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
626 * support is disabled in config - we need to know if it is synaptics so we
627 * can reset it properly after probing for intellimouse.
628 */
629 if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
630 synaptics_hardware = true;
631
632 if (max_proto > PSMOUSE_IMEX) {
633/*
634 * Try activating protocol, but check if support is enabled first, since
635 * we try detecting Synaptics even when protocol is disabled.
636 */
637 if (synaptics_supported() &&
638 (!set_properties || synaptics_init(psmouse) == 0)) {
639 return PSMOUSE_SYNAPTICS;
640 }
641
642/*
643 * Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
644 * Unfortunately Logitech/Genius probes confuse some firmware versions so
645 * we'll have to skip them.
646 */
647 max_proto = PSMOUSE_IMEX;
648 }
649/*
650 * Make sure that touchpad is in relative mode, gestures (taps) are enabled
651 */
652 synaptics_reset(psmouse);
653 }
654
655/*
656 * Try ALPS TouchPad
657 */
658 if (max_proto > PSMOUSE_IMEX) {
659 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
660 if (alps_detect(psmouse, set_properties) == 0) {
661 if (!set_properties || alps_init(psmouse) == 0)
662 return PSMOUSE_ALPS;
663/*
664 * Init failed, try basic relative protocols
665 */
666 max_proto = PSMOUSE_IMEX;
667 }
668 }
669
670/*
671 * Try OLPC HGPK touchpad.
672 */
673 if (max_proto > PSMOUSE_IMEX &&
674 hgpk_detect(psmouse, set_properties) == 0) {
675 if (!set_properties || hgpk_init(psmouse) == 0)
676 return PSMOUSE_HGPK;
677/*
678 * Init failed, try basic relative protocols
679 */
680 max_proto = PSMOUSE_IMEX;
681 }
682
683/*
684 * Try Elantech touchpad.
685 */
686 if (max_proto > PSMOUSE_IMEX &&
687 elantech_detect(psmouse, set_properties) == 0) {
688 if (!set_properties || elantech_init(psmouse) == 0)
689 return PSMOUSE_ELANTECH;
690/*
691 * Init failed, try basic relative protocols
692 */
693 max_proto = PSMOUSE_IMEX;
694 }
695
696
697 if (max_proto > PSMOUSE_IMEX) {
698 if (genius_detect(psmouse, set_properties) == 0)
699 return PSMOUSE_GENPS;
700
701 if (ps2pp_init(psmouse, set_properties) == 0)
702 return PSMOUSE_PS2PP;
703
704 if (trackpoint_detect(psmouse, set_properties) == 0)
705 return PSMOUSE_TRACKPOINT;
706
707 if (touchkit_ps2_detect(psmouse, set_properties) == 0)
708 return PSMOUSE_TOUCHKIT_PS2;
709 }
710
711/*
712 * Try Finger Sensing Pad. We do it here because its probe upsets
713 * Trackpoint devices (causing TP_READ_ID command to time out).
714 */
715 if (max_proto > PSMOUSE_IMEX) {
716 if (fsp_detect(psmouse, set_properties) == 0) {
717 if (!set_properties || fsp_init(psmouse) == 0)
718 return PSMOUSE_FSP;
719/*
720 * Init failed, try basic relative protocols
721 */
722 max_proto = PSMOUSE_IMEX;
723 }
724 }
725
726/*
727 * Reset to defaults in case the device got confused by extended
728 * protocol probes. Note that we follow up with full reset because
729 * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
730 */
731 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
732 psmouse_reset(psmouse);
733
734 if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
735 return PSMOUSE_IMEX;
736
737 if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
738 return PSMOUSE_IMPS;
739
740/*
741 * Okay, all failed, we have a standard mouse here. The number of the buttons
742 * is still a question, though. We assume 3.
743 */
744 ps2bare_detect(psmouse, set_properties);
745
746 if (synaptics_hardware) {
747/*
748 * We detected Synaptics hardware but it did not respond to IMPS/2 probes.
749 * We need to reset the touchpad because if there is a track point on the
750 * pass through port it could get disabled while probing for protocol
751 * extensions.
752 */
753 psmouse_reset(psmouse);
754 }
755
756 return PSMOUSE_PS2;
757}
758
759static const struct psmouse_protocol psmouse_protocols[] = {
760 {
761 .type = PSMOUSE_PS2,
762 .name = "PS/2",
763 .alias = "bare",
764 .maxproto = true,
765 .ignore_parity = true,
766 .detect = ps2bare_detect,
767 },
768#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
769 {
770 .type = PSMOUSE_PS2PP,
771 .name = "PS2++",
772 .alias = "logitech",
773 .detect = ps2pp_init,
774 },
775#endif
776 {
777 .type = PSMOUSE_THINKPS,
778 .name = "ThinkPS/2",
779 .alias = "thinkps",
780 .detect = thinking_detect,
781 },
782 {
783 .type = PSMOUSE_GENPS,
784 .name = "GenPS/2",
785 .alias = "genius",
786 .detect = genius_detect,
787 },
788 {
789 .type = PSMOUSE_IMPS,
790 .name = "ImPS/2",
791 .alias = "imps",
792 .maxproto = true,
793 .ignore_parity = true,
794 .detect = intellimouse_detect,
795 },
796 {
797 .type = PSMOUSE_IMEX,
798 .name = "ImExPS/2",
799 .alias = "exps",
800 .maxproto = true,
801 .ignore_parity = true,
802 .detect = im_explorer_detect,
803 },
804#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
805 {
806 .type = PSMOUSE_SYNAPTICS,
807 .name = "SynPS/2",
808 .alias = "synaptics",
809 .detect = synaptics_detect,
810 .init = synaptics_init,
811 },
812#endif
813#ifdef CONFIG_MOUSE_PS2_ALPS
814 {
815 .type = PSMOUSE_ALPS,
816 .name = "AlpsPS/2",
817 .alias = "alps",
818 .detect = alps_detect,
819 .init = alps_init,
820 },
821#endif
822#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
823 {
824 .type = PSMOUSE_LIFEBOOK,
825 .name = "LBPS/2",
826 .alias = "lifebook",
827 .init = lifebook_init,
828 },
829#endif
830#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
831 {
832 .type = PSMOUSE_TRACKPOINT,
833 .name = "TPPS/2",
834 .alias = "trackpoint",
835 .detect = trackpoint_detect,
836 },
837#endif
838#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
839 {
840 .type = PSMOUSE_TOUCHKIT_PS2,
841 .name = "touchkitPS/2",
842 .alias = "touchkit",
843 .detect = touchkit_ps2_detect,
844 },
845#endif
846#ifdef CONFIG_MOUSE_PS2_OLPC
847 {
848 .type = PSMOUSE_HGPK,
849 .name = "OLPC HGPK",
850 .alias = "hgpk",
851 .detect = hgpk_detect,
852 },
853#endif
854#ifdef CONFIG_MOUSE_PS2_ELANTECH
855 {
856 .type = PSMOUSE_ELANTECH,
857 .name = "ETPS/2",
858 .alias = "elantech",
859 .detect = elantech_detect,
860 .init = elantech_init,
861 },
862#endif
863#ifdef CONFIG_MOUSE_PS2_SENTELIC
864 {
865 .type = PSMOUSE_FSP,
866 .name = "FSPPS/2",
867 .alias = "fsp",
868 .detect = fsp_detect,
869 .init = fsp_init,
870 },
871#endif
872 {
873 .type = PSMOUSE_CORTRON,
874 .name = "CortronPS/2",
875 .alias = "cortps",
876 .detect = cortron_detect,
877 },
878 {
879 .type = PSMOUSE_AUTO,
880 .name = "auto",
881 .alias = "any",
882 .maxproto = true,
883 },
884};
885
886static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
887{
888 int i;
889
890 for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
891 if (psmouse_protocols[i].type == type)
892 return &psmouse_protocols[i];
893
894 WARN_ON(1);
895 return &psmouse_protocols[0];
896}
897
898static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
899{
900 const struct psmouse_protocol *p;
901 int i;
902
903 for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
904 p = &psmouse_protocols[i];
905
906 if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
907 (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
908 return &psmouse_protocols[i];
909 }
910
911 return NULL;
912}
913
914
915/*
916 * psmouse_probe() probes for a PS/2 mouse.
917 */
918
919static int psmouse_probe(struct psmouse *psmouse)
920{
921 struct ps2dev *ps2dev = &psmouse->ps2dev;
922 unsigned char param[2];
923
924/*
925 * First, we check if it's a mouse. It should send 0x00 or 0x03
926 * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
927 * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent
928 * ID queries, probably due to a firmware bug.
929 */
930
931 param[0] = 0xa5;
932 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
933 return -1;
934
935 if (param[0] != 0x00 && param[0] != 0x03 &&
936 param[0] != 0x04 && param[0] != 0xff)
937 return -1;
938
939/*
940 * Then we reset and disable the mouse so that it doesn't generate events.
941 */
942
943 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
944 printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
945
946 return 0;
947}
948
949/*
950 * Here we set the mouse resolution.
951 */
952
953void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
954{
955 static const unsigned char params[] = { 0, 1, 2, 2, 3 };
956 unsigned char p;
957
958 if (resolution == 0 || resolution > 200)
959 resolution = 200;
960
961 p = params[resolution / 50];
962 ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
963 psmouse->resolution = 25 << p;
964}
965
966/*
967 * Here we set the mouse report rate.
968 */
969
970static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
971{
972 static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
973 unsigned char r;
974 int i = 0;
975
976 while (rates[i] > rate) i++;
977 r = rates[i];
978 ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
979 psmouse->rate = r;
980}
981
982/*
983 * psmouse_initialize() initializes the mouse to a sane state.
984 */
985
986static void psmouse_initialize(struct psmouse *psmouse)
987{
988/*
989 * We set the mouse report rate, resolution and scaling.
990 */
991
992 if (psmouse_max_proto != PSMOUSE_PS2) {
993 psmouse->set_rate(psmouse, psmouse->rate);
994 psmouse->set_resolution(psmouse, psmouse->resolution);
995 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
996 }
997}
998
999/*
1000 * psmouse_activate() enables the mouse so that we get motion reports from it.
1001 */
1002
1003static void psmouse_activate(struct psmouse *psmouse)
1004{
1005 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
1006 printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
1007 psmouse->ps2dev.serio->phys);
1008
1009 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
1010}
1011
1012
1013/*
1014 * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
1015 * reports from it unless we explicitly request it.
1016 */
1017
1018static void psmouse_deactivate(struct psmouse *psmouse)
1019{
1020 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
1021 printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
1022 psmouse->ps2dev.serio->phys);
1023
1024 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1025}
1026
1027/*
1028 * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it.
1029 */
1030
1031static int psmouse_poll(struct psmouse *psmouse)
1032{
1033 return ps2_command(&psmouse->ps2dev, psmouse->packet,
1034 PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
1035}
1036
1037
1038/*
1039 * psmouse_resync() attempts to re-validate current protocol.
1040 */
1041
1042static void psmouse_resync(struct work_struct *work)
1043{
1044 struct psmouse *parent = NULL, *psmouse =
1045 container_of(work, struct psmouse, resync_work.work);
1046 struct serio *serio = psmouse->ps2dev.serio;
1047 psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
1048 bool failed = false, enabled = false;
1049 int i;
1050
1051 mutex_lock(&psmouse_mutex);
1052
1053 if (psmouse->state != PSMOUSE_RESYNCING)
1054 goto out;
1055
1056 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1057 parent = serio_get_drvdata(serio->parent);
1058 psmouse_deactivate(parent);
1059 }
1060
1061/*
1062 * Some mice don't ACK commands sent while they are in the middle of
1063 * transmitting motion packet. To avoid delay we use ps2_sendbyte()
1064 * instead of ps2_command() which would wait for 200ms for an ACK
1065 * that may never come.
1066 * As an additional quirk ALPS touchpads may not only forget to ACK
1067 * disable command but will stop reporting taps, so if we see that
1068 * mouse at least once ACKs disable we will do full reconnect if ACK
1069 * is missing.
1070 */
1071 psmouse->num_resyncs++;
1072
1073 if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
1074 if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
1075 failed = true;
1076 } else
1077 psmouse->acks_disable_command = true;
1078
1079/*
1080 * Poll the mouse. If it was reset the packet will be shorter than
1081 * psmouse->pktsize and ps2_command will fail. We do not expect and
1082 * do not handle scenario when mouse "upgrades" its protocol while
1083 * disconnected since it would require additional delay. If we ever
1084 * see a mouse that does it we'll adjust the code.
1085 */
1086 if (!failed) {
1087 if (psmouse->poll(psmouse))
1088 failed = true;
1089 else {
1090 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1091 for (i = 0; i < psmouse->pktsize; i++) {
1092 psmouse->pktcnt++;
1093 rc = psmouse->protocol_handler(psmouse);
1094 if (rc != PSMOUSE_GOOD_DATA)
1095 break;
1096 }
1097 if (rc != PSMOUSE_FULL_PACKET)
1098 failed = true;
1099 psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
1100 }
1101 }
1102/*
1103 * Now try to enable mouse. We try to do that even if poll failed and also
1104 * repeat our attempts 5 times, otherwise we may be left out with disabled
1105 * mouse.
1106 */
1107 for (i = 0; i < 5; i++) {
1108 if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
1109 enabled = true;
1110 break;
1111 }
1112 msleep(200);
1113 }
1114
1115 if (!enabled) {
1116 printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
1117 psmouse->ps2dev.serio->phys);
1118 failed = true;
1119 }
1120
1121 if (failed) {
1122 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
1123 printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n");
1124 serio_reconnect(serio);
1125 } else
1126 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
1127
1128 if (parent)
1129 psmouse_activate(parent);
1130 out:
1131 mutex_unlock(&psmouse_mutex);
1132}
1133
1134/*
1135 * psmouse_cleanup() resets the mouse into power-on state.
1136 */
1137
1138static void psmouse_cleanup(struct serio *serio)
1139{
1140 struct psmouse *psmouse = serio_get_drvdata(serio);
1141 struct psmouse *parent = NULL;
1142
1143 mutex_lock(&psmouse_mutex);
1144
1145 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1146 parent = serio_get_drvdata(serio->parent);
1147 psmouse_deactivate(parent);
1148 }
1149
1150 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
1151
1152 /*
1153 * Disable stream mode so cleanup routine can proceed undisturbed.
1154 */
1155 if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
1156 printk(KERN_WARNING "psmouse.c: Failed to disable mouse on %s\n",
1157 psmouse->ps2dev.serio->phys);
1158
1159 if (psmouse->cleanup)
1160 psmouse->cleanup(psmouse);
1161
1162/*
1163 * Reset the mouse to defaults (bare PS/2 protocol).
1164 */
1165 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
1166
1167/*
1168 * Some boxes, such as HP nx7400, get terribly confused if mouse
1169 * is not fully enabled before suspending/shutting down.
1170 */
1171 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
1172
1173 if (parent) {
1174 if (parent->pt_deactivate)
1175 parent->pt_deactivate(parent);
1176
1177 psmouse_activate(parent);
1178 }
1179
1180 mutex_unlock(&psmouse_mutex);
1181}
1182
1183/*
1184 * psmouse_disconnect() closes and frees.
1185 */
1186
1187static void psmouse_disconnect(struct serio *serio)
1188{
1189 struct psmouse *psmouse, *parent = NULL;
1190
1191 psmouse = serio_get_drvdata(serio);
1192
1193 sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group);
1194
1195 mutex_lock(&psmouse_mutex);
1196
1197 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1198
1199 /* make sure we don't have a resync in progress */
1200 mutex_unlock(&psmouse_mutex);
1201 flush_workqueue(kpsmoused_wq);
1202 mutex_lock(&psmouse_mutex);
1203
1204 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1205 parent = serio_get_drvdata(serio->parent);
1206 psmouse_deactivate(parent);
1207 }
1208
1209 if (psmouse->disconnect)
1210 psmouse->disconnect(psmouse);
1211
1212 if (parent && parent->pt_deactivate)
1213 parent->pt_deactivate(parent);
1214
1215 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
1216
1217 serio_close(serio);
1218 serio_set_drvdata(serio, NULL);
1219 input_unregister_device(psmouse->dev);
1220 kfree(psmouse);
1221
1222 if (parent)
1223 psmouse_activate(parent);
1224
1225 mutex_unlock(&psmouse_mutex);
1226}
1227
1228static int psmouse_switch_protocol(struct psmouse *psmouse,
1229 const struct psmouse_protocol *proto)
1230{
1231 const struct psmouse_protocol *selected_proto;
1232 struct input_dev *input_dev = psmouse->dev;
1233
1234 input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
1235
1236 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
1237 input_dev->keybit[BIT_WORD(BTN_MOUSE)] =
1238 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
1239 input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
1240
1241 psmouse->set_rate = psmouse_set_rate;
1242 psmouse->set_resolution = psmouse_set_resolution;
1243 psmouse->poll = psmouse_poll;
1244 psmouse->protocol_handler = psmouse_process_byte;
1245 psmouse->pktsize = 3;
1246
1247 if (proto && (proto->detect || proto->init)) {
1248 if (proto->detect && proto->detect(psmouse, true) < 0)
1249 return -1;
1250
1251 if (proto->init && proto->init(psmouse) < 0)
1252 return -1;
1253
1254 psmouse->type = proto->type;
1255 selected_proto = proto;
1256 } else {
1257 psmouse->type = psmouse_extensions(psmouse,
1258 psmouse_max_proto, true);
1259 selected_proto = psmouse_protocol_by_type(psmouse->type);
1260 }
1261
1262 psmouse->ignore_parity = selected_proto->ignore_parity;
1263
1264 /*
1265 * If mouse's packet size is 3 there is no point in polling the
1266 * device in hopes to detect protocol reset - we won't get less
1267 * than 3 bytes response anyhow.
1268 */
1269 if (psmouse->pktsize == 3)
1270 psmouse->resync_time = 0;
1271
1272 /*
1273 * Some smart KVMs fake response to POLL command returning just
1274 * 3 bytes and messing up our resync logic, so if initial poll
1275 * fails we won't try polling the device anymore. Hopefully
1276 * such KVM will maintain initially selected protocol.
1277 */
1278 if (psmouse->resync_time && psmouse->poll(psmouse))
1279 psmouse->resync_time = 0;
1280
1281 snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s",
1282 selected_proto->name, psmouse->vendor, psmouse->name);
1283
1284 input_dev->name = psmouse->devname;
1285 input_dev->phys = psmouse->phys;
1286 input_dev->id.bustype = BUS_I8042;
1287 input_dev->id.vendor = 0x0002;
1288 input_dev->id.product = psmouse->type;
1289 input_dev->id.version = psmouse->model;
1290
1291 return 0;
1292}
1293
1294/*
1295 * psmouse_connect() is a callback from the serio module when
1296 * an unhandled serio port is found.
1297 */
1298static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
1299{
1300 struct psmouse *psmouse, *parent = NULL;
1301 struct input_dev *input_dev;
1302 int retval = 0, error = -ENOMEM;
1303
1304 mutex_lock(&psmouse_mutex);
1305
1306 /*
1307 * If this is a pass-through port deactivate parent so the device
1308 * connected to this port can be successfully identified
1309 */
1310 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1311 parent = serio_get_drvdata(serio->parent);
1312 psmouse_deactivate(parent);
1313 }
1314
1315 psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL);
1316 input_dev = input_allocate_device();
1317 if (!psmouse || !input_dev)
1318 goto err_free;
1319
1320 ps2_init(&psmouse->ps2dev, serio);
1321 INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
1322 psmouse->dev = input_dev;
1323 snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
1324
1325 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
1326
1327 serio_set_drvdata(serio, psmouse);
1328
1329 error = serio_open(serio, drv);
1330 if (error)
1331 goto err_clear_drvdata;
1332
1333 if (psmouse_probe(psmouse) < 0) {
1334 error = -ENODEV;
1335 goto err_close_serio;
1336 }
1337
1338 psmouse->rate = psmouse_rate;
1339 psmouse->resolution = psmouse_resolution;
1340 psmouse->resetafter = psmouse_resetafter;
1341 psmouse->resync_time = parent ? 0 : psmouse_resync_time;
1342 psmouse->smartscroll = psmouse_smartscroll;
1343
1344 psmouse_switch_protocol(psmouse, NULL);
1345
1346 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1347 psmouse_initialize(psmouse);
1348
1349 error = input_register_device(psmouse->dev);
1350 if (error)
1351 goto err_protocol_disconnect;
1352
1353 if (parent && parent->pt_activate)
1354 parent->pt_activate(parent);
1355
1356 error = sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);
1357 if (error)
1358 goto err_pt_deactivate;
1359
1360 psmouse_activate(psmouse);
1361
1362 out:
1363 /* If this is a pass-through port the parent needs to be re-activated */
1364 if (parent)
1365 psmouse_activate(parent);
1366
1367 mutex_unlock(&psmouse_mutex);
1368 return retval;
1369
1370 err_pt_deactivate:
1371 if (parent && parent->pt_deactivate)
1372 parent->pt_deactivate(parent);
1373 input_unregister_device(psmouse->dev);
1374 input_dev = NULL; /* so we don't try to free it below */
1375 err_protocol_disconnect:
1376 if (psmouse->disconnect)
1377 psmouse->disconnect(psmouse);
1378 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
1379 err_close_serio:
1380 serio_close(serio);
1381 err_clear_drvdata:
1382 serio_set_drvdata(serio, NULL);
1383 err_free:
1384 input_free_device(input_dev);
1385 kfree(psmouse);
1386
1387 retval = error;
1388 goto out;
1389}
1390
1391
1392static int psmouse_reconnect(struct serio *serio)
1393{
1394 struct psmouse *psmouse = serio_get_drvdata(serio);
1395 struct psmouse *parent = NULL;
1396 struct serio_driver *drv = serio->drv;
1397 unsigned char type;
1398 int rc = -1;
1399
1400 if (!drv || !psmouse) {
1401 printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
1402 return -1;
1403 }
1404
1405 mutex_lock(&psmouse_mutex);
1406
1407 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1408 parent = serio_get_drvdata(serio->parent);
1409 psmouse_deactivate(parent);
1410 }
1411
1412 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
1413
1414 if (psmouse->reconnect) {
1415 if (psmouse->reconnect(psmouse))
1416 goto out;
1417 } else {
1418 psmouse_reset(psmouse);
1419
1420 if (psmouse_probe(psmouse) < 0)
1421 goto out;
1422
1423 type = psmouse_extensions(psmouse, psmouse_max_proto, false);
1424 if (psmouse->type != type)
1425 goto out;
1426 }
1427
1428 /* ok, the device type (and capabilities) match the old one,
1429 * we can continue using it, complete intialization
1430 */
1431 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1432
1433 psmouse_initialize(psmouse);
1434
1435 if (parent && parent->pt_activate)
1436 parent->pt_activate(parent);
1437
1438 psmouse_activate(psmouse);
1439 rc = 0;
1440
1441out:
1442 /* If this is a pass-through port the parent waits to be activated */
1443 if (parent)
1444 psmouse_activate(parent);
1445
1446 mutex_unlock(&psmouse_mutex);
1447 return rc;
1448}
1449
1450static struct serio_device_id psmouse_serio_ids[] = {
1451 {
1452 .type = SERIO_8042,
1453 .proto = SERIO_ANY,
1454 .id = SERIO_ANY,
1455 .extra = SERIO_ANY,
1456 },
1457 {
1458 .type = SERIO_PS_PSTHRU,
1459 .proto = SERIO_ANY,
1460 .id = SERIO_ANY,
1461 .extra = SERIO_ANY,
1462 },
1463 { 0 }
1464};
1465
1466MODULE_DEVICE_TABLE(serio, psmouse_serio_ids);
1467
1468static struct serio_driver psmouse_drv = {
1469 .driver = {
1470 .name = "psmouse",
1471 },
1472 .description = DRIVER_DESC,
1473 .id_table = psmouse_serio_ids,
1474 .interrupt = psmouse_interrupt,
1475 .connect = psmouse_connect,
1476 .reconnect = psmouse_reconnect,
1477 .disconnect = psmouse_disconnect,
1478 .cleanup = psmouse_cleanup,
1479};
1480
1481ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *devattr,
1482 char *buf)
1483{
1484 struct serio *serio = to_serio_port(dev);
1485 struct psmouse_attribute *attr = to_psmouse_attr(devattr);
1486 struct psmouse *psmouse;
1487
1488 psmouse = serio_get_drvdata(serio);
1489
1490 return attr->show(psmouse, attr->data, buf);
1491}
1492
1493ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr,
1494 const char *buf, size_t count)
1495{
1496 struct serio *serio = to_serio_port(dev);
1497 struct psmouse_attribute *attr = to_psmouse_attr(devattr);
1498 struct psmouse *psmouse, *parent = NULL;
1499 int retval;
1500
1501 retval = mutex_lock_interruptible(&psmouse_mutex);
1502 if (retval)
1503 goto out;
1504
1505 psmouse = serio_get_drvdata(serio);
1506
1507 if (attr->protect) {
1508 if (psmouse->state == PSMOUSE_IGNORE) {
1509 retval = -ENODEV;
1510 goto out_unlock;
1511 }
1512
1513 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1514 parent = serio_get_drvdata(serio->parent);
1515 psmouse_deactivate(parent);
1516 }
1517
1518 psmouse_deactivate(psmouse);
1519 }
1520
1521 retval = attr->set(psmouse, attr->data, buf, count);
1522
1523 if (attr->protect) {
1524 if (retval != -ENODEV)
1525 psmouse_activate(psmouse);
1526
1527 if (parent)
1528 psmouse_activate(parent);
1529 }
1530
1531 out_unlock:
1532 mutex_unlock(&psmouse_mutex);
1533 out:
1534 return retval;
1535}
1536
1537static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf)
1538{
1539 unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
1540
1541 return sprintf(buf, "%u\n", *field);
1542}
1543
1544static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count)
1545{
1546 unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
1547 unsigned long value;
1548
1549 if (strict_strtoul(buf, 10, &value))
1550 return -EINVAL;
1551
1552 if ((unsigned int)value != value)
1553 return -EINVAL;
1554
1555 *field = value;
1556
1557 return count;
1558}
1559
1560static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf)
1561{
1562 return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
1563}
1564
1565static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count)
1566{
1567 struct serio *serio = psmouse->ps2dev.serio;
1568 struct psmouse *parent = NULL;
1569 struct input_dev *old_dev, *new_dev;
1570 const struct psmouse_protocol *proto, *old_proto;
1571 int error;
1572 int retry = 0;
1573
1574 proto = psmouse_protocol_by_name(buf, count);
1575 if (!proto)
1576 return -EINVAL;
1577
1578 if (psmouse->type == proto->type)
1579 return count;
1580
1581 new_dev = input_allocate_device();
1582 if (!new_dev)
1583 return -ENOMEM;
1584
1585 while (serio->child) {
1586 if (++retry > 3) {
1587 printk(KERN_WARNING
1588 "psmouse: failed to destroy child port, "
1589 "protocol change aborted.\n");
1590 input_free_device(new_dev);
1591 return -EIO;
1592 }
1593
1594 mutex_unlock(&psmouse_mutex);
1595 serio_unregister_child_port(serio);
1596 mutex_lock(&psmouse_mutex);
1597
1598 if (serio->drv != &psmouse_drv) {
1599 input_free_device(new_dev);
1600 return -ENODEV;
1601 }
1602
1603 if (psmouse->type == proto->type) {
1604 input_free_device(new_dev);
1605 return count; /* switched by other thread */
1606 }
1607 }
1608
1609 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
1610 parent = serio_get_drvdata(serio->parent);
1611 if (parent->pt_deactivate)
1612 parent->pt_deactivate(parent);
1613 }
1614
1615 old_dev = psmouse->dev;
1616 old_proto = psmouse_protocol_by_type(psmouse->type);
1617
1618 if (psmouse->disconnect)
1619 psmouse->disconnect(psmouse);
1620
1621 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
1622
1623 psmouse->dev = new_dev;
1624 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
1625
1626 if (psmouse_switch_protocol(psmouse, proto) < 0) {
1627 psmouse_reset(psmouse);
1628 /* default to PSMOUSE_PS2 */
1629 psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
1630 }
1631
1632 psmouse_initialize(psmouse);
1633 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1634
1635 error = input_register_device(psmouse->dev);
1636 if (error) {
1637 if (psmouse->disconnect)
1638 psmouse->disconnect(psmouse);
1639
1640 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
1641 input_free_device(new_dev);
1642 psmouse->dev = old_dev;
1643 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
1644 psmouse_switch_protocol(psmouse, old_proto);
1645 psmouse_initialize(psmouse);
1646 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
1647
1648 return error;
1649 }
1650
1651 input_unregister_device(old_dev);
1652
1653 if (parent && parent->pt_activate)
1654 parent->pt_activate(parent);
1655
1656 return count;
1657}
1658
1659static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
1660{
1661 unsigned long value;
1662
1663 if (strict_strtoul(buf, 10, &value))
1664 return -EINVAL;
1665
1666 psmouse->set_rate(psmouse, value);
1667 return count;
1668}
1669
1670static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
1671{
1672 unsigned long value;
1673
1674 if (strict_strtoul(buf, 10, &value))
1675 return -EINVAL;
1676
1677 psmouse->set_resolution(psmouse, value);
1678 return count;
1679}
1680
1681
1682static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
1683{
1684 const struct psmouse_protocol *proto;
1685
1686 if (!val)
1687 return -EINVAL;
1688
1689 proto = psmouse_protocol_by_name(val, strlen(val));
1690
1691 if (!proto || !proto->maxproto)
1692 return -EINVAL;
1693
1694 *((unsigned int *)kp->arg) = proto->type;
1695
1696 return 0;
1697}
1698
1699static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
1700{
1701 int type = *((unsigned int *)kp->arg);
1702
1703 return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
1704}
1705
1706static int __init psmouse_init(void)
1707{
1708 int err;
1709
1710 lifebook_module_init();
1711 synaptics_module_init();
1712
1713 kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
1714 if (!kpsmoused_wq) {
1715 printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
1716 return -ENOMEM;
1717 }
1718
1719 err = serio_register_driver(&psmouse_drv);
1720 if (err)
1721 destroy_workqueue(kpsmoused_wq);
1722
1723 return err;
1724}
1725
1726static void __exit psmouse_exit(void)
1727{
1728 serio_unregister_driver(&psmouse_drv);
1729 destroy_workqueue(kpsmoused_wq);
1730}
1731
1732module_init(psmouse_init);
1733module_exit(psmouse_exit);
diff --git a/usr/src/dkms_source_tree/psmouse.h b/usr/src/dkms_source_tree/psmouse.h
new file mode 100644
index 0000000..593e910
--- /dev/null
+++ b/usr/src/dkms_source_tree/psmouse.h
@@ -0,0 +1,153 @@
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 0x00eb /* caller sets number of bytes to receive */
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_RESYNCING,
27 PSMOUSE_CMD_MODE,
28 PSMOUSE_ACTIVATED,
29};
30
31/* psmouse protocol handler return codes */
32typedef enum {
33 PSMOUSE_BAD_DATA,
34 PSMOUSE_GOOD_DATA,
35 PSMOUSE_FULL_PACKET
36} psmouse_ret_t;
37
38struct psmouse {
39 void *private;
40 struct input_dev *dev;
41 struct ps2dev ps2dev;
42 struct delayed_work resync_work;
43 char *vendor;
44 char *name;
45 unsigned char packet[8];
46 unsigned char badbyte;
47 unsigned char pktcnt;
48 unsigned char pktsize;
49 unsigned char type;
50 bool ignore_parity;
51 bool acks_disable_command;
52 unsigned int model;
53 unsigned long last;
54 unsigned long out_of_sync_cnt;
55 unsigned long num_resyncs;
56 enum psmouse_state state;
57 char devname[64];
58 char phys[32];
59
60 unsigned int rate;
61 unsigned int resolution;
62 unsigned int resetafter;
63 unsigned int resync_time;
64 bool smartscroll; /* Logitech only */
65
66 psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
67 void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
68 void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
69
70 int (*reconnect)(struct psmouse *psmouse);
71 void (*disconnect)(struct psmouse *psmouse);
72 void (*cleanup)(struct psmouse *psmouse);
73 int (*poll)(struct psmouse *psmouse);
74
75 void (*pt_activate)(struct psmouse *psmouse);
76 void (*pt_deactivate)(struct psmouse *psmouse);
77};
78
79enum psmouse_type {
80 PSMOUSE_NONE,
81 PSMOUSE_PS2,
82 PSMOUSE_PS2PP,
83 PSMOUSE_THINKPS,
84 PSMOUSE_GENPS,
85 PSMOUSE_IMPS,
86 PSMOUSE_IMEX,
87 PSMOUSE_SYNAPTICS,
88 PSMOUSE_ALPS,
89 PSMOUSE_LIFEBOOK,
90 PSMOUSE_TRACKPOINT,
91 PSMOUSE_TOUCHKIT_PS2,
92 PSMOUSE_CORTRON,
93 PSMOUSE_HGPK,
94 PSMOUSE_ELANTECH,
95 PSMOUSE_FSP,
96 PSMOUSE_AUTO /* This one should always be last */
97};
98
99void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
100 unsigned long delay);
101int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
102int psmouse_reset(struct psmouse *psmouse);
103void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
104void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
105
106struct psmouse_attribute {
107 struct device_attribute dattr;
108 void *data;
109 ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
110 ssize_t (*set)(struct psmouse *psmouse, void *data,
111 const char *buf, size_t count);
112 bool protect;
113};
114#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr)
115
116ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *attr,
117 char *buf);
118ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
119 const char *buf, size_t count);
120
121#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) \
122static struct psmouse_attribute psmouse_attr_##_name = { \
123 .dattr = { \
124 .attr = { \
125 .name = __stringify(_name), \
126 .mode = _mode, \
127 }, \
128 .show = psmouse_attr_show_helper, \
129 .store = psmouse_attr_set_helper, \
130 }, \
131 .data = _data, \
132 .show = _show, \
133 .set = _set, \
134 .protect = _protect, \
135}
136
137#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \
138 static ssize_t _show(struct psmouse *, void *, char *); \
139 static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
140 __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect)
141
142#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
143 __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, true)
144
145#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \
146 static ssize_t _show(struct psmouse *, void *, char *); \
147 __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, true)
148
149#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \
150 static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
151 __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true)
152
153#endif /* _PSMOUSE_H */
diff --git a/usr/src/dkms_source_tree/sentelic.c b/usr/src/dkms_source_tree/sentelic.c
new file mode 100644
index 0000000..1242775
--- /dev/null
+++ b/usr/src/dkms_source_tree/sentelic.c
@@ -0,0 +1,871 @@
1/*-
2 * Finger Sensing Pad PS/2 mouse driver.
3 *
4 * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
5 * Copyright (C) 2005-2010 Tai-hwa Liang, Sentelic Corporation.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/version.h>
24#include <linux/input.h>
25#include <linux/ctype.h>
26#include <linux/libps2.h>
27#include <linux/serio.h>
28#include <linux/jiffies.h>
29#include <linux/slab.h>
30
31#include "psmouse.h"
32#include "sentelic.h"
33
34/*
35 * Timeout for FSP PS/2 command only (in milliseconds).
36 */
37#define FSP_CMD_TIMEOUT 200
38#define FSP_CMD_TIMEOUT2 30
39
40/** Driver version. */
41static const char fsp_drv_ver[] = "1.0.0-K";
42
43/*
44 * Make sure that the value being sent to FSP will not conflict with
45 * possible sample rate values.
46 */
47static unsigned char fsp_test_swap_cmd(unsigned char reg_val)
48{
49 switch (reg_val) {
50 case 10: case 20: case 40: case 60: case 80: case 100: case 200:
51 /*
52 * The requested value being sent to FSP matched to possible
53 * sample rates, swap the given value such that the hardware
54 * wouldn't get confused.
55 */
56 return (reg_val >> 4) | (reg_val << 4);
57 default:
58 return reg_val; /* swap isn't necessary */
59 }
60}
61
62/*
63 * Make sure that the value being sent to FSP will not conflict with certain
64 * commands.
65 */
66static unsigned char fsp_test_invert_cmd(unsigned char reg_val)
67{
68 switch (reg_val) {
69 case 0xe9: case 0xee: case 0xf2: case 0xff:
70 /*
71 * The requested value being sent to FSP matched to certain
72 * commands, inverse the given value such that the hardware
73 * wouldn't get confused.
74 */
75 return ~reg_val;
76 default:
77 return reg_val; /* inversion isn't necessary */
78 }
79}
80
81static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
82{
83 struct ps2dev *ps2dev = &psmouse->ps2dev;
84 unsigned char param[3];
85 unsigned char addr;
86 int rc = -1;
87
88 /*
89 * We need to shut off the device and switch it into command
90 * mode so we don't confuse our protocol handler. We don't need
91 * to do that for writes because sysfs set helper does this for
92 * us.
93 */
94 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
95 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
96
97 ps2_begin_command(ps2dev);
98
99 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
100 goto out;
101
102 /* should return 0xfe(request for resending) */
103 ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
104 /* should return 0xfc(failed) */
105 ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
106
107 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
108 goto out;
109
110 if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
111 ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2);
112 } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
113 /* swapping is required */
114 ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2);
115 /* expect 0xfe */
116 } else {
117 /* swapping isn't necessary */
118 ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
119 /* expect 0xfe */
120 }
121 /* should return 0xfc(failed) */
122 ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT);
123
124 if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0)
125 goto out;
126
127 *reg_val = param[2];
128 rc = 0;
129
130 out:
131 ps2_end_command(ps2dev);
132 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
133 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
134 dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
135 reg_addr, *reg_val, rc);
136 return rc;
137}
138
139static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
140{
141 struct ps2dev *ps2dev = &psmouse->ps2dev;
142 unsigned char v;
143 int rc = -1;
144
145 ps2_begin_command(ps2dev);
146
147 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
148 goto out;
149
150 if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
151 /* inversion is required */
152 ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2);
153 } else {
154 if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
155 /* swapping is required */
156 ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2);
157 } else {
158 /* swapping isn't necessary */
159 ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2);
160 }
161 }
162 /* write the register address in correct order */
163 ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
164
165 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
166 return -1;
167
168 if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
169 /* inversion is required */
170 ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
171 } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
172 /* swapping is required */
173 ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
174 } else {
175 /* swapping isn't necessary */
176 ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
177 }
178
179 /* write the register value in correct order */
180 ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
181 rc = 0;
182
183 out:
184 ps2_end_command(ps2dev);
185 dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
186 reg_addr, reg_val, rc);
187 return rc;
188}
189
190/* Enable register clock gating for writing certain registers */
191static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable)
192{
193 int v, nv;
194
195 if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1)
196 return -1;
197
198 if (enable)
199 nv = v | FSP_BIT_EN_REG_CLK;
200 else
201 nv = v & ~FSP_BIT_EN_REG_CLK;
202
203 /* only write if necessary */
204 if (nv != v)
205 if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1)
206 return -1;
207
208 return 0;
209}
210
211static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
212{
213 struct ps2dev *ps2dev = &psmouse->ps2dev;
214 unsigned char param[3];
215 int rc = -1;
216
217 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
218 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
219
220 ps2_begin_command(ps2dev);
221
222 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
223 goto out;
224
225 ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
226 ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
227
228 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
229 goto out;
230
231 ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2);
232 ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
233
234 /* get the returned result */
235 if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
236 goto out;
237
238 *reg_val = param[2];
239 rc = 0;
240
241 out:
242 ps2_end_command(ps2dev);
243 ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
244 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
245 dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
246 *reg_val, rc);
247 return rc;
248}
249
250static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
251{
252 struct ps2dev *ps2dev = &psmouse->ps2dev;
253 unsigned char v;
254 int rc = -1;
255
256 ps2_begin_command(ps2dev);
257
258 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
259 goto out;
260
261 ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2);
262 ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
263
264 if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
265 return -1;
266
267 if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
268 ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
269 } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
270 /* swapping is required */
271 ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
272 } else {
273 /* swapping isn't necessary */
274 ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
275 }
276
277 ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
278 rc = 0;
279
280 out:
281 ps2_end_command(ps2dev);
282 dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
283 reg_val, rc);
284 return rc;
285}
286
287static int fsp_get_version(struct psmouse *psmouse, int *version)
288{
289 if (fsp_reg_read(psmouse, FSP_REG_VERSION, version))
290 return -EIO;
291
292 return 0;
293}
294
295static int fsp_get_revision(struct psmouse *psmouse, int *rev)
296{
297 if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev))
298 return -EIO;
299
300 return 0;
301}
302
303static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
304{
305 static const int buttons[] = {
306 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
307 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */
308 0x04, /* Left/Middle/Right & Scroll Up/Down */
309 0x02, /* Left/Middle/Right */
310 };
311 int val;
312
313 if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1)
314 return -EIO;
315
316 *btn = buttons[(val & 0x30) >> 4];
317 return 0;
318}
319
320/* Enable on-pad command tag output */
321static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
322{
323 int v, nv;
324 int res = 0;
325
326 if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
327 dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n");
328 return -EIO;
329 }
330
331 if (enable)
332 nv = v | FSP_BIT_EN_OPC_TAG;
333 else
334 nv = v & ~FSP_BIT_EN_OPC_TAG;
335
336 /* only write if necessary */
337 if (nv != v) {
338 fsp_reg_write_enable(psmouse, true);
339 res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv);
340 fsp_reg_write_enable(psmouse, false);
341 }
342
343 if (res != 0) {
344 dev_err(&psmouse->ps2dev.serio->dev,
345 "Unable to enable OPC tag.\n");
346 res = -EIO;
347 }
348
349 return res;
350}
351
352static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable)
353{
354 struct fsp_data *pad = psmouse->private;
355 int val;
356
357 if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
358 return -EIO;
359
360 pad->vscroll = enable;
361
362 if (enable)
363 val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE);
364 else
365 val &= ~FSP_BIT_FIX_VSCR;
366
367 if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
368 return -EIO;
369
370 return 0;
371}
372
373static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable)
374{
375 struct fsp_data *pad = psmouse->private;
376 int val, v2;
377
378 if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
379 return -EIO;
380
381 if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2))
382 return -EIO;
383
384 pad->hscroll = enable;
385
386 if (enable) {
387 val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE);
388 v2 |= FSP_BIT_EN_MSID6;
389 } else {
390 val &= ~FSP_BIT_FIX_HSCR;
391 v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8);
392 }
393
394 if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
395 return -EIO;
396
397 /* reconfigure horizontal scrolling packet output */
398 if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2))
399 return -EIO;
400
401 return 0;
402}
403
404/*
405 * Write device specific initial parameters.
406 *
407 * ex: 0xab 0xcd - write oxcd into register 0xab
408 */
409static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
410 const char *buf, size_t count)
411{
412 unsigned long reg, val;
413 char *rest;
414 ssize_t retval;
415
416 reg = simple_strtoul(buf, &rest, 16);
417 if (rest == buf || *rest != ' ' || reg > 0xff)
418 return -EINVAL;
419
420 if (strict_strtoul(rest + 1, 16, &val) || val > 0xff)
421 return -EINVAL;
422
423 if (fsp_reg_write_enable(psmouse, true))
424 return -EIO;
425
426 retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count;
427
428 fsp_reg_write_enable(psmouse, false);
429
430 return count;
431}
432
433PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
434
435static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse,
436 void *data, char *buf)
437{
438 struct fsp_data *pad = psmouse->private;
439
440 return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val);
441}
442
443/*
444 * Read a register from device.
445 *
446 * ex: 0xab -- read content from register 0xab
447 */
448static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data,
449 const char *buf, size_t count)
450{
451 struct fsp_data *pad = psmouse->private;
452 unsigned long reg;
453 int val;
454
455 if (strict_strtoul(buf, 16, &reg) || reg > 0xff)
456 return -EINVAL;
457
458 if (fsp_reg_read(psmouse, reg, &val))
459 return -EIO;
460
461 pad->last_reg = reg;
462 pad->last_val = val;
463
464 return count;
465}
466
467PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
468 fsp_attr_show_getreg, fsp_attr_set_getreg);
469
470static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
471 void *data, char *buf)
472{
473 int val = 0;
474
475 if (fsp_page_reg_read(psmouse, &val))
476 return -EIO;
477
478 return sprintf(buf, "%02x\n", val);
479}
480
481static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
482 const char *buf, size_t count)
483{
484 unsigned long val;
485
486 if (strict_strtoul(buf, 16, &val) || val > 0xff)
487 return -EINVAL;
488
489 if (fsp_page_reg_write(psmouse, val))
490 return -EIO;
491
492 return count;
493}
494
495PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
496 fsp_attr_show_pagereg, fsp_attr_set_pagereg);
497
498static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
499 void *data, char *buf)
500{
501 struct fsp_data *pad = psmouse->private;
502
503 return sprintf(buf, "%d\n", pad->vscroll);
504}
505
506static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
507 const char *buf, size_t count)
508{
509 unsigned long val;
510
511 if (strict_strtoul(buf, 10, &val) || val > 1)
512 return -EINVAL;
513
514 fsp_onpad_vscr(psmouse, val);
515
516 return count;
517}
518
519PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL,
520 fsp_attr_show_vscroll, fsp_attr_set_vscroll);
521
522static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
523 void *data, char *buf)
524{
525 struct fsp_data *pad = psmouse->private;
526
527 return sprintf(buf, "%d\n", pad->hscroll);
528}
529
530static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
531 const char *buf, size_t count)
532{
533 unsigned long val;
534
535 if (strict_strtoul(buf, 10, &val) || val > 1)
536 return -EINVAL;
537
538 fsp_onpad_hscr(psmouse, val);
539
540 return count;
541}
542
543PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL,
544 fsp_attr_show_hscroll, fsp_attr_set_hscroll);
545
546static ssize_t fsp_attr_show_flags(struct psmouse *psmouse,
547 void *data, char *buf)
548{
549 struct fsp_data *pad = psmouse->private;
550
551 return sprintf(buf, "%c\n",
552 pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
553}
554
555static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data,
556 const char *buf, size_t count)
557{
558 struct fsp_data *pad = psmouse->private;
559 size_t i;
560
561 for (i = 0; i < count; i++) {
562 switch (buf[i]) {
563 case 'C':
564 pad->flags |= FSPDRV_FLAG_EN_OPC;
565 break;
566 case 'c':
567 pad->flags &= ~FSPDRV_FLAG_EN_OPC;
568 break;
569 default:
570 return -EINVAL;
571 }
572 }
573 return count;
574}
575
576PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL,
577 fsp_attr_show_flags, fsp_attr_set_flags);
578
579static ssize_t fsp_attr_show_ver(struct psmouse *psmouse,
580 void *data, char *buf)
581{
582 return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver);
583}
584
585PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver);
586
587static struct attribute *fsp_attributes[] = {
588 &psmouse_attr_setreg.dattr.attr,
589 &psmouse_attr_getreg.dattr.attr,
590 &psmouse_attr_page.dattr.attr,
591 &psmouse_attr_vscroll.dattr.attr,
592 &psmouse_attr_hscroll.dattr.attr,
593 &psmouse_attr_flags.dattr.attr,
594 &psmouse_attr_ver.dattr.attr,
595 NULL
596};
597
598static struct attribute_group fsp_attribute_group = {
599 .attrs = fsp_attributes,
600};
601
602#ifdef FSP_DEBUG
603static void fsp_packet_debug(unsigned char packet[])
604{
605 static unsigned int ps2_packet_cnt;
606 static unsigned int ps2_last_second;
607 unsigned int jiffies_msec;
608
609 ps2_packet_cnt++;
610 jiffies_msec = jiffies_to_msecs(jiffies);
611 printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
612 jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
613
614 if (jiffies_msec - ps2_last_second > 1000) {
615 printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
616 ps2_packet_cnt = 0;
617 ps2_last_second = jiffies_msec;
618 }
619}
620#else
621static void fsp_packet_debug(unsigned char packet[])
622{
623}
624#endif
625
626static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
627{
628 struct input_dev *dev = psmouse->dev;
629 struct fsp_data *ad = psmouse->private;
630 unsigned char *packet = psmouse->packet;
631 unsigned char button_status = 0, lscroll = 0, rscroll = 0;
632 int rel_x, rel_y;
633
634 if (psmouse->pktcnt < 4)
635 return PSMOUSE_GOOD_DATA;
636
637 /*
638 * Full packet accumulated, process it
639 */
640
641 switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
642 case FSP_PKT_TYPE_ABS:
643 dev_warn(&psmouse->ps2dev.serio->dev,
644 "Unexpected absolute mode packet, ignored.\n");
645 break;
646
647 case FSP_PKT_TYPE_NORMAL_OPC:
648 /* on-pad click, filter it if necessary */
649 if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
650 packet[0] &= ~BIT(0);
651 /* fall through */
652
653 case FSP_PKT_TYPE_NORMAL:
654 /* normal packet */
655 /* special packet data translation from on-pad packets */
656 if (packet[3] != 0) {
657 if (packet[3] & BIT(0))
658 button_status |= 0x01; /* wheel down */
659 if (packet[3] & BIT(1))
660 button_status |= 0x0f; /* wheel up */
661 if (packet[3] & BIT(2))
662 button_status |= BIT(4);/* horizontal left */
663 if (packet[3] & BIT(3))
664 button_status |= BIT(5);/* horizontal right */
665 /* push back to packet queue */
666 if (button_status != 0)
667 packet[3] = button_status;
668 rscroll = (packet[3] >> 4) & 1;
669 lscroll = (packet[3] >> 5) & 1;
670 }
671 /*
672 * Processing wheel up/down and extra button events
673 */
674 input_report_rel(dev, REL_WHEEL,
675 (int)(packet[3] & 8) - (int)(packet[3] & 7));
676 input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
677 input_report_key(dev, BTN_BACK, lscroll);
678 input_report_key(dev, BTN_FORWARD, rscroll);
679
680 /*
681 * Standard PS/2 Mouse
682 */
683 input_report_key(dev, BTN_LEFT, packet[0] & 1);
684 input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
685 input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
686
687 rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
688 rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
689
690 input_report_rel(dev, REL_X, rel_x);
691 input_report_rel(dev, REL_Y, rel_y);
692 break;
693 }
694
695 input_sync(dev);
696
697 fsp_packet_debug(packet);
698
699 return PSMOUSE_FULL_PACKET;
700}
701
702static int fsp_activate_protocol(struct psmouse *psmouse)
703{
704 struct fsp_data *pad = psmouse->private;
705 struct ps2dev *ps2dev = &psmouse->ps2dev;
706 unsigned char param[2];
707 int val;
708
709 /*
710 * Standard procedure to enter FSP Intellimouse mode
711 * (scrolling wheel, 4th and 5th buttons)
712 */
713 param[0] = 200;
714 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
715 param[0] = 200;
716 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
717 param[0] = 80;
718 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
719
720 ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
721 if (param[0] != 0x04) {
722 dev_err(&psmouse->ps2dev.serio->dev,
723 "Unable to enable 4 bytes packet format.\n");
724 return -EIO;
725 }
726
727 if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
728 dev_err(&psmouse->ps2dev.serio->dev,
729 "Unable to read SYSCTL5 register.\n");
730 return -EIO;
731 }
732
733 val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
734 /* Ensure we are not in absolute mode */
735 val &= ~FSP_BIT_EN_PKT_G0;
736 if (pad->buttons == 0x06) {
737 /* Left/Middle/Right & Scroll Up/Down/Right/Left */
738 val |= FSP_BIT_EN_MSID6;
739 }
740
741 if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
742 dev_err(&psmouse->ps2dev.serio->dev,
743 "Unable to set up required mode bits.\n");
744 return -EIO;
745 }
746
747 /*
748 * Enable OPC tags such that driver can tell the difference between
749 * on-pad and real button click
750 */
751 if (fsp_opc_tag_enable(psmouse, true))
752 dev_warn(&psmouse->ps2dev.serio->dev,
753 "Failed to enable OPC tag mode.\n");
754
755 /* Enable on-pad vertical and horizontal scrolling */
756 fsp_onpad_vscr(psmouse, true);
757 fsp_onpad_hscr(psmouse, true);
758
759 return 0;
760}
761
762int fsp_detect(struct psmouse *psmouse, bool set_properties)
763{
764 int id;
765
766 if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
767 return -EIO;
768
769 if (id != 0x01)
770 return -ENODEV;
771
772 if (set_properties) {
773 psmouse->vendor = "Sentelic";
774 psmouse->name = "FingerSensingPad";
775 }
776
777 return 0;
778}
779
780static void fsp_reset(struct psmouse *psmouse)
781{
782 fsp_opc_tag_enable(psmouse, false);
783 fsp_onpad_vscr(psmouse, false);
784 fsp_onpad_hscr(psmouse, false);
785}
786
787static void fsp_disconnect(struct psmouse *psmouse)
788{
789 sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
790 &fsp_attribute_group);
791
792 fsp_reset(psmouse);
793 kfree(psmouse->private);
794}
795
796static int fsp_reconnect(struct psmouse *psmouse)
797{
798 int version;
799
800 if (fsp_detect(psmouse, 0))
801 return -ENODEV;
802
803 if (fsp_get_version(psmouse, &version))
804 return -ENODEV;
805
806 if (fsp_activate_protocol(psmouse))
807 return -EIO;
808
809 return 0;
810}
811
812int fsp_init(struct psmouse *psmouse)
813{
814 struct fsp_data *priv;
815 int ver, rev, buttons;
816 int error;
817
818 if (fsp_get_version(psmouse, &ver) ||
819 fsp_get_revision(psmouse, &rev) ||
820 fsp_get_buttons(psmouse, &buttons)) {
821 return -ENODEV;
822 }
823
824 printk(KERN_INFO
825 "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
826 ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
827
828 psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
829 if (!priv)
830 return -ENOMEM;
831
832 priv->ver = ver;
833 priv->rev = rev;
834 priv->buttons = buttons;
835
836 /* enable on-pad click by default */
837 priv->flags |= FSPDRV_FLAG_EN_OPC;
838
839 /* Set up various supported input event bits */
840 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
841 __set_bit(BTN_BACK, psmouse->dev->keybit);
842 __set_bit(BTN_FORWARD, psmouse->dev->keybit);
843 __set_bit(REL_WHEEL, psmouse->dev->relbit);
844 __set_bit(REL_HWHEEL, psmouse->dev->relbit);
845
846 psmouse->protocol_handler = fsp_process_byte;
847 psmouse->disconnect = fsp_disconnect;
848 psmouse->reconnect = fsp_reconnect;
849 psmouse->cleanup = fsp_reset;
850 psmouse->pktsize = 4;
851
852 /* set default packet output based on number of buttons we found */
853 error = fsp_activate_protocol(psmouse);
854 if (error)
855 goto err_out;
856
857 error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
858 &fsp_attribute_group);
859 if (error) {
860 dev_err(&psmouse->ps2dev.serio->dev,
861 "Failed to create sysfs attributes (%d)", error);
862 goto err_out;
863 }
864
865 return 0;
866
867 err_out:
868 kfree(psmouse->private);
869 psmouse->private = NULL;
870 return error;
871}
diff --git a/usr/src/dkms_source_tree/sentelic.h b/usr/src/dkms_source_tree/sentelic.h
new file mode 100644
index 0000000..ed1395a
--- /dev/null
+++ b/usr/src/dkms_source_tree/sentelic.h
@@ -0,0 +1,98 @@
1/*-
2 * Finger Sensing Pad PS/2 mouse driver.
3 *
4 * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
5 * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef __SENTELIC_H
23#define __SENTELIC_H
24
25/* Finger-sensing Pad information registers */
26#define FSP_REG_DEVICE_ID 0x00
27#define FSP_REG_VERSION 0x01
28#define FSP_REG_REVISION 0x04
29#define FSP_REG_TMOD_STATUS1 0x0B
30#define FSP_BIT_NO_ROTATION BIT(3)
31#define FSP_REG_PAGE_CTRL 0x0F
32
33/* Finger-sensing Pad control registers */
34#define FSP_REG_SYSCTL1 0x10
35#define FSP_BIT_EN_REG_CLK BIT(5)
36#define FSP_REG_OPC_QDOWN 0x31
37#define FSP_BIT_EN_OPC_TAG BIT(7)
38#define FSP_REG_OPTZ_XLO 0x34
39#define FSP_REG_OPTZ_XHI 0x35
40#define FSP_REG_OPTZ_YLO 0x36
41#define FSP_REG_OPTZ_YHI 0x37
42#define FSP_REG_SYSCTL5 0x40
43#define FSP_BIT_90_DEGREE BIT(0)
44#define FSP_BIT_EN_MSID6 BIT(1)
45#define FSP_BIT_EN_MSID7 BIT(2)
46#define FSP_BIT_EN_MSID8 BIT(3)
47#define FSP_BIT_EN_AUTO_MSID8 BIT(5)
48#define FSP_BIT_EN_PKT_G0 BIT(6)
49
50#define FSP_REG_ONPAD_CTL 0x43
51#define FSP_BIT_ONPAD_ENABLE BIT(0)
52#define FSP_BIT_ONPAD_FBBB BIT(1)
53#define FSP_BIT_FIX_VSCR BIT(3)
54#define FSP_BIT_FIX_HSCR BIT(5)
55#define FSP_BIT_DRAG_LOCK BIT(6)
56
57/* Finger-sensing Pad packet formating related definitions */
58
59/* absolute packet type */
60#define FSP_PKT_TYPE_NORMAL (0x00)
61#define FSP_PKT_TYPE_ABS (0x01)
62#define FSP_PKT_TYPE_NOTIFY (0x02)
63#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
64#define FSP_PKT_TYPE_SHIFT (6)
65
66#ifdef __KERNEL__
67
68struct fsp_data {
69 unsigned char ver; /* hardware version */
70 unsigned char rev; /* hardware revison */
71 unsigned char buttons; /* Number of buttons */
72 unsigned int flags;
73#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */
74
75 bool vscroll; /* Vertical scroll zone enabled */
76 bool hscroll; /* Horizontal scroll zone enabled */
77
78 unsigned char last_reg; /* Last register we requested read from */
79 unsigned char last_val;
80};
81
82#ifdef CONFIG_MOUSE_PS2_SENTELIC
83extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
84extern int fsp_init(struct psmouse *psmouse);
85#else
86inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
87{
88 return -ENOSYS;
89}
90inline int fsp_init(struct psmouse *psmouse)
91{
92 return -ENOSYS;
93}
94#endif
95
96#endif /* __KERNEL__ */
97
98#endif /* !__SENTELIC_H */
diff --git a/usr/src/dkms_source_tree/synaptics.c b/usr/src/dkms_source_tree/synaptics.c
new file mode 100644
index 0000000..ae9891c
--- /dev/null
+++ b/usr/src/dkms_source_tree/synaptics.c
@@ -0,0 +1,863 @@
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/dmi.h>
28#include <linux/input.h>
29#include <linux/serio.h>
30#include <linux/libps2.h>
31#include <linux/slab.h>
32#include "psmouse.h"
33#include "synaptics.h"
34
35/*
36 * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
37 * section 2.3.2, which says that they should be valid regardless of the
38 * actual size of the sensor.
39 * Note that newer firmware allows querying device for maximum useable
40 * coordinates.
41 */
42#define XMIN_NOMINAL 1472
43#define XMAX_NOMINAL 5472
44#define YMIN_NOMINAL 1408
45#define YMAX_NOMINAL 4448
46
47
48/*****************************************************************************
49 * Stuff we need even when we do not want native Synaptics support
50 ****************************************************************************/
51
52/*
53 * Set the synaptics touchpad mode byte by special commands
54 */
55static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
56{
57 unsigned char param[1];
58
59 if (psmouse_sliced_command(psmouse, mode))
60 return -1;
61 param[0] = SYN_PS_SET_MODE2;
62 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
63 return -1;
64 return 0;
65}
66
67int synaptics_detect(struct psmouse *psmouse, bool set_properties)
68{
69 struct ps2dev *ps2dev = &psmouse->ps2dev;
70 unsigned char param[4];
71
72 param[0] = 0;
73
74 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
75 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
76 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
77 ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
78 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
79
80 if (param[1] != 0x47)
81 return -ENODEV;
82
83 if (set_properties) {
84 psmouse->vendor = "Synaptics";
85 psmouse->name = "TouchPad";
86 }
87
88 return 0;
89}
90
91void synaptics_reset(struct psmouse *psmouse)
92{
93 /* reset touchpad back to relative mode, gestures enabled */
94 synaptics_mode_cmd(psmouse, 0);
95}
96
97#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
98
99/*****************************************************************************
100 * Synaptics communications functions
101 ****************************************************************************/
102
103/*
104 * Send a command to the synpatics touchpad by special commands
105 */
106static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
107{
108 if (psmouse_sliced_command(psmouse, c))
109 return -1;
110 if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
111 return -1;
112 return 0;
113}
114
115/*
116 * Read the model-id bytes from the touchpad
117 * see also SYN_MODEL_* macros
118 */
119static int synaptics_model_id(struct psmouse *psmouse)
120{
121 struct synaptics_data *priv = psmouse->private;
122 unsigned char mi[3];
123
124 if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
125 return -1;
126 priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
127 return 0;
128}
129
130/*
131 * Read the capability-bits from the touchpad
132 * see also the SYN_CAP_* macros
133 */
134static int synaptics_capability(struct psmouse *psmouse)
135{
136 struct synaptics_data *priv = psmouse->private;
137 unsigned char cap[3];
138
139 if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
140 return -1;
141 priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
142 priv->ext_cap = priv->ext_cap_0c = 0;
143
144 /*
145 * Older firmwares had submodel ID fixed to 0x47
146 */
147 if (SYN_ID_FULL(priv->identity) < 0x705 &&
148 SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) {
149 return -1;
150 }
151
152 /*
153 * Unless capExtended is set the rest of the flags should be ignored
154 */
155 if (!SYN_CAP_EXTENDED(priv->capabilities))
156 priv->capabilities = 0;
157
158 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
159 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
160 printk(KERN_ERR "Synaptics claims to have extended capabilities,"
161 " but I'm not able to read them.\n");
162 } else {
163 priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
164
165 /*
166 * if nExtBtn is greater than 8 it should be considered
167 * invalid and treated as 0
168 */
169 if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
170 priv->ext_cap &= 0xff0fff;
171 }
172 }
173
174 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
175 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
176 printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
177 " but I'm not able to read it.\n");
178 } else {
179 priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
180 }
181 }
182
183 return 0;
184}
185
186/*
187 * Identify Touchpad
188 * See also the SYN_ID_* macros
189 */
190static int synaptics_identify(struct psmouse *psmouse)
191{
192 struct synaptics_data *priv = psmouse->private;
193 unsigned char id[3];
194
195 if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
196 return -1;
197 priv->identity = (id[0]<<16) | (id[1]<<8) | id[2];
198 if (SYN_ID_IS_SYNAPTICS(priv->identity))
199 return 0;
200 return -1;
201}
202
203/*
204 * Read touchpad resolution and maximum reported coordinates
205 * Resolution is left zero if touchpad does not support the query
206 */
207static int synaptics_resolution(struct psmouse *psmouse)
208{
209 struct synaptics_data *priv = psmouse->private;
210 unsigned char res[3];
211 unsigned char max[3];
212
213 if (SYN_ID_MAJOR(priv->identity) < 4)
214 return 0;
215
216 if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) {
217 if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) {
218 priv->x_res = res[0]; /* x resolution in units/mm */
219 priv->y_res = res[2]; /* y resolution in units/mm */
220 }
221 }
222
223 if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
224 SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
225 if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) {
226 printk(KERN_ERR "Synaptics claims to have dimensions query,"
227 " but I'm not able to read it.\n");
228 } else {
229 priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1);
230 priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3);
231 }
232 }
233
234 return 0;
235}
236
237static int synaptics_query_hardware(struct psmouse *psmouse)
238{
239 if (synaptics_identify(psmouse))
240 return -1;
241 if (synaptics_model_id(psmouse))
242 return -1;
243 if (synaptics_capability(psmouse))
244 return -1;
245 if (synaptics_resolution(psmouse))
246 return -1;
247
248 return 0;
249}
250
251static int synaptics_set_absolute_mode(struct psmouse *psmouse)
252{
253 struct synaptics_data *priv = psmouse->private;
254
255 priv->mode = SYN_BIT_ABSOLUTE_MODE;
256 if (SYN_ID_MAJOR(priv->identity) >= 4)
257 priv->mode |= SYN_BIT_DISABLE_GESTURE;
258 if (SYN_CAP_EXTENDED(priv->capabilities))
259 priv->mode |= SYN_BIT_W_MODE;
260
261 if (synaptics_mode_cmd(psmouse, priv->mode))
262 return -1;
263
264 return 0;
265}
266
267static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
268{
269 struct synaptics_data *priv = psmouse->private;
270
271 if (rate >= 80) {
272 priv->mode |= SYN_BIT_HIGH_RATE;
273 psmouse->rate = 80;
274 } else {
275 priv->mode &= ~SYN_BIT_HIGH_RATE;
276 psmouse->rate = 40;
277 }
278
279 synaptics_mode_cmd(psmouse, priv->mode);
280}
281
282/*****************************************************************************
283 * Synaptics pass-through PS/2 port support
284 ****************************************************************************/
285static int synaptics_pt_write(struct serio *serio, unsigned char c)
286{
287 struct psmouse *parent = serio_get_drvdata(serio->parent);
288 char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
289
290 if (psmouse_sliced_command(parent, c))
291 return -1;
292 if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
293 return -1;
294 return 0;
295}
296
297static inline int synaptics_is_pt_packet(unsigned char *buf)
298{
299 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
300}
301
302static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
303{
304 struct psmouse *child = serio_get_drvdata(ptport);
305
306 if (child && child->state == PSMOUSE_ACTIVATED) {
307 serio_interrupt(ptport, packet[1], 0);
308 serio_interrupt(ptport, packet[4], 0);
309 serio_interrupt(ptport, packet[5], 0);
310 if (child->pktsize == 4)
311 serio_interrupt(ptport, packet[2], 0);
312 } else
313 serio_interrupt(ptport, packet[1], 0);
314}
315
316static void synaptics_pt_activate(struct psmouse *psmouse)
317{
318 struct serio *ptport = psmouse->ps2dev.serio->child;
319 struct psmouse *child = serio_get_drvdata(ptport);
320 struct synaptics_data *priv = psmouse->private;
321
322 /* adjust the touchpad to child's choice of protocol */
323 if (child) {
324 if (child->pktsize == 4)
325 priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
326 else
327 priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
328
329 if (synaptics_mode_cmd(psmouse, priv->mode))
330 printk(KERN_INFO "synaptics: failed to switch guest protocol\n");
331 }
332}
333
334static void synaptics_pt_create(struct psmouse *psmouse)
335{
336 struct serio *serio;
337
338 serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
339 if (!serio) {
340 printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
341 return;
342 }
343
344 serio->id.type = SERIO_PS_PSTHRU;
345 strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
346 strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
347 serio->write = synaptics_pt_write;
348 serio->parent = psmouse->ps2dev.serio;
349
350 psmouse->pt_activate = synaptics_pt_activate;
351
352 printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
353 serio_register_port(serio);
354}
355
356/*****************************************************************************
357 * Functions to interpret the absolute mode packets
358 ****************************************************************************/
359
360/* left and right clickpad button ranges;
361 * the gap between them is interpreted as a middle-button click
362 */
363#define CLICKPAD_LEFT_BTN_X \
364 ((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL)
365#define CLICKPAD_RIGHT_BTN_X \
366 ((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL)
367
368/* handle clickpad events */
369static void clickpad_process_packet(struct synaptics_data *priv,
370 struct synaptics_hw_state *hw)
371{
372 /* clickpad mode reports Y range from 0 to YMAX_NOMINAL,
373 * where the area Y < YMIN_NOMINAL is used as click buttons
374 */
375 if (hw->y < YMIN_NOMINAL) {
376 /* button area */
377 hw->z = 0; /* don't move pointer */
378 /* clickpad reports only the middle button, and we need
379 * to fake left/right buttons depending on the touch position
380 */
381 if (hw->middle) { /* clicked? */
382 hw->middle = 0;
383 if (hw->x < CLICKPAD_LEFT_BTN_X)
384 hw->left = 1;
385 else if (hw->x > CLICKPAD_RIGHT_BTN_X)
386 hw->right = 1;
387 else
388 hw->middle = 1;
389 }
390 } else if (hw->middle) {
391 /* dragging */
392 hw->left = priv->prev_hw.left;
393 hw->right = priv->prev_hw.right;
394 hw->middle = priv->prev_hw.middle;
395 }
396 priv->prev_hw = *hw;
397}
398
399static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
400{
401 memset(hw, 0, sizeof(struct synaptics_hw_state));
402
403 if (SYN_MODEL_NEWABS(priv->model_id)) {
404 hw->x = (((buf[3] & 0x10) << 8) |
405 ((buf[1] & 0x0f) << 8) |
406 buf[4]);
407 hw->y = (((buf[3] & 0x20) << 7) |
408 ((buf[1] & 0xf0) << 4) |
409 buf[5]);
410
411 hw->z = buf[2];
412 hw->w = (((buf[0] & 0x30) >> 2) |
413 ((buf[0] & 0x04) >> 1) |
414 ((buf[3] & 0x04) >> 2));
415
416 hw->left = (buf[0] & 0x01) ? 1 : 0;
417 hw->right = (buf[0] & 0x02) ? 1 : 0;
418
419 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
420 /*
421 * Clickpad's button is transmitted as middle button,
422 * however, since it is primary button, we will report
423 * it as BTN_LEFT.
424 */
425 hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
426
427 } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
428 hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
429 if (hw->w == 2)
430 hw->scroll = (signed char)(buf[1]);
431 }
432
433 if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
434 hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
435 hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
436 }
437
438 if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
439 ((buf[0] ^ buf[3]) & 0x02)) {
440 switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
441 default:
442 /*
443 * if nExtBtn is greater than 8 it should be
444 * considered invalid and treated as 0
445 */
446 break;
447 case 8:
448 hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
449 hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
450 case 6:
451 hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
452 hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
453 case 4:
454 hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
455 hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
456 case 2:
457 hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
458 hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
459 }
460 }
461 } else {
462 hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
463 hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
464
465 hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
466 hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
467
468 hw->left = (buf[0] & 0x01) ? 1 : 0;
469 hw->right = (buf[0] & 0x02) ? 1 : 0;
470 }
471}
472
473/*
474 * called for each full received packet from the touchpad
475 */
476static void synaptics_process_packet(struct psmouse *psmouse)
477{
478 struct input_dev *dev = psmouse->dev;
479 struct synaptics_data *priv = psmouse->private;
480 struct synaptics_hw_state hw;
481 int num_fingers;
482 int finger_width;
483 int i;
484
485 synaptics_parse_hw_state(psmouse->packet, priv, &hw);
486
487 if (SYN_CAP_CLICKPAD(priv->ext_cap))
488 clickpad_process_packet(priv, &hw);
489
490 if (hw.scroll) {
491 priv->scroll += hw.scroll;
492
493 while (priv->scroll >= 4) {
494 input_report_key(dev, BTN_BACK, !hw.down);
495 input_sync(dev);
496 input_report_key(dev, BTN_BACK, hw.down);
497 input_sync(dev);
498 priv->scroll -= 4;
499 }
500 while (priv->scroll <= -4) {
501 input_report_key(dev, BTN_FORWARD, !hw.up);
502 input_sync(dev);
503 input_report_key(dev, BTN_FORWARD, hw.up);
504 input_sync(dev);
505 priv->scroll += 4;
506 }
507 return;
508 }
509
510 if (hw.z > 0) {
511 num_fingers = 1;
512 finger_width = 5;
513 if (SYN_CAP_EXTENDED(priv->capabilities)) {
514 switch (hw.w) {
515 case 0 ... 1:
516 if (SYN_CAP_MULTIFINGER(priv->capabilities))
517 num_fingers = hw.w + 2;
518 break;
519 case 2:
520 if (SYN_MODEL_PEN(priv->model_id))
521 ; /* Nothing, treat a pen as a single finger */
522 break;
523 case 4 ... 15:
524 if (SYN_CAP_PALMDETECT(priv->capabilities))
525 finger_width = hw.w;
526 break;
527 }
528 }
529 } else {
530 num_fingers = 0;
531 finger_width = 0;
532 }
533
534 /* Post events
535 * BTN_TOUCH has to be first as mousedev relies on it when doing
536 * absolute -> relative conversion
537 */
538 if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
539 if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
540
541 if (hw.z > 0) {
542 input_report_abs(dev, ABS_X, hw.x);
543 input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
544 }
545 input_report_abs(dev, ABS_PRESSURE, hw.z);
546
547 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
548 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
549 input_report_key(dev, BTN_LEFT, hw.left);
550 input_report_key(dev, BTN_RIGHT, hw.right);
551
552 if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
553 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
554 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
555 }
556
557 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
558 input_report_key(dev, BTN_MIDDLE, hw.middle);
559
560 if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
561 input_report_key(dev, BTN_FORWARD, hw.up);
562 input_report_key(dev, BTN_BACK, hw.down);
563 }
564
565 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
566 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
567
568 input_sync(dev);
569}
570
571static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
572{
573 static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
574 static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
575 static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
576 static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
577 static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
578
579 if (idx < 0 || idx > 4)
580 return 0;
581
582 switch (pkt_type) {
583
584 case SYN_NEWABS:
585 case SYN_NEWABS_RELAXED:
586 return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
587
588 case SYN_NEWABS_STRICT:
589 return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
590
591 case SYN_OLDABS:
592 return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
593
594 default:
595 printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
596 return 0;
597 }
598}
599
600static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
601{
602 int i;
603
604 for (i = 0; i < 5; i++)
605 if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
606 printk(KERN_INFO "synaptics: using relaxed packet validation\n");
607 return SYN_NEWABS_RELAXED;
608 }
609
610 return SYN_NEWABS_STRICT;
611}
612
613static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
614{
615 struct synaptics_data *priv = psmouse->private;
616
617 if (psmouse->pktcnt >= 6) { /* Full packet received */
618 if (unlikely(priv->pkt_type == SYN_NEWABS))
619 priv->pkt_type = synaptics_detect_pkt_type(psmouse);
620
621 if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
622 if (psmouse->ps2dev.serio->child)
623 synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
624 } else
625 synaptics_process_packet(psmouse);
626
627 return PSMOUSE_FULL_PACKET;
628 }
629
630 return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
631 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
632}
633
634/*****************************************************************************
635 * Driver initialization/cleanup functions
636 ****************************************************************************/
637static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
638{
639 int i;
640
641 __set_bit(EV_ABS, dev->evbit);
642 input_set_abs_params(dev, ABS_X,
643 XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0);
644 input_set_abs_params(dev, ABS_Y,
645 YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
646 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
647 __set_bit(ABS_TOOL_WIDTH, dev->absbit);
648
649 __set_bit(EV_KEY, dev->evbit);
650 __set_bit(BTN_TOUCH, dev->keybit);
651 __set_bit(BTN_TOOL_FINGER, dev->keybit);
652 __set_bit(BTN_LEFT, dev->keybit);
653 __set_bit(BTN_RIGHT, dev->keybit);
654
655 if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
656 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
657 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
658 }
659
660 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
661 __set_bit(BTN_MIDDLE, dev->keybit);
662
663 if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
664 SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
665 __set_bit(BTN_FORWARD, dev->keybit);
666 __set_bit(BTN_BACK, dev->keybit);
667 }
668
669 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
670 __set_bit(BTN_0 + i, dev->keybit);
671
672 __clear_bit(EV_REL, dev->evbit);
673 __clear_bit(REL_X, dev->relbit);
674 __clear_bit(REL_Y, dev->relbit);
675
676 dev->absres[ABS_X] = priv->x_res;
677 dev->absres[ABS_Y] = priv->y_res;
678
679 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
680 /* Clickpads report only left button */
681 __clear_bit(BTN_RIGHT, dev->keybit);
682 __clear_bit(BTN_MIDDLE, dev->keybit);
683 }
684}
685
686static void synaptics_disconnect(struct psmouse *psmouse)
687{
688 synaptics_reset(psmouse);
689 kfree(psmouse->private);
690 psmouse->private = NULL;
691}
692
693static int synaptics_reconnect(struct psmouse *psmouse)
694{
695 struct synaptics_data *priv = psmouse->private;
696 struct synaptics_data old_priv = *priv;
697
698 psmouse_reset(psmouse);
699
700 if (synaptics_detect(psmouse, 0))
701 return -1;
702
703 if (synaptics_query_hardware(psmouse)) {
704 printk(KERN_ERR "Unable to query Synaptics hardware.\n");
705 return -1;
706 }
707
708 if (old_priv.identity != priv->identity ||
709 old_priv.model_id != priv->model_id ||
710 old_priv.capabilities != priv->capabilities ||
711 old_priv.ext_cap != priv->ext_cap)
712 return -1;
713
714 if (synaptics_set_absolute_mode(psmouse)) {
715 printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
716 return -1;
717 }
718
719 return 0;
720}
721
722static bool impaired_toshiba_kbc;
723
724static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
725#if defined(CONFIG_DMI) && defined(CONFIG_X86)
726 {
727 /* Toshiba Satellite */
728 .matches = {
729 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
730 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
731 },
732 },
733 {
734 /* Toshiba Dynabook */
735 .matches = {
736 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
737 DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
738 },
739 },
740 {
741 /* Toshiba Portege M300 */
742 .matches = {
743 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
744 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
745 },
746
747 },
748 {
749 /* Toshiba Portege M300 */
750 .matches = {
751 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
752 DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
753 DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"),
754 },
755
756 },
757 { }
758#endif
759};
760
761void __init synaptics_module_init(void)
762{
763 impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
764}
765
766int synaptics_init(struct psmouse *psmouse)
767{
768 struct synaptics_data *priv;
769
770 psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
771 if (!priv)
772 return -1;
773
774 psmouse_reset(psmouse);
775
776 if (synaptics_query_hardware(psmouse)) {
777 printk(KERN_ERR "Unable to query Synaptics hardware.\n");
778 goto init_fail;
779 }
780
781 if (synaptics_set_absolute_mode(psmouse)) {
782 printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
783 goto init_fail;
784 }
785
786 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
787
788 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
789 SYN_ID_MODEL(priv->identity),
790 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
791 priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
792
793 if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
794 printk(KERN_INFO "Synaptics: Clickpad mode enabled\n");
795 /* force to enable the middle button */
796 priv->capabilities |= (1 << 18);
797 }
798
799 set_input_params(psmouse->dev, priv);
800
801 /*
802 * Encode touchpad model so that it can be used to set
803 * input device->id.version and be visible to userspace.
804 * Because version is __u16 we have to drop something.
805 * Hardware info bits seem to be good candidates as they
806 * are documented to be for Synaptics corp. internal use.
807 */
808 psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
809 (priv->model_id & 0x000000ff);
810
811 psmouse->protocol_handler = synaptics_process_byte;
812 psmouse->set_rate = synaptics_set_rate;
813 psmouse->disconnect = synaptics_disconnect;
814 psmouse->reconnect = synaptics_reconnect;
815 psmouse->cleanup = synaptics_reset;
816 psmouse->pktsize = 6;
817 /* Synaptics can usually stay in sync without extra help */
818 psmouse->resync_time = 0;
819
820 if (SYN_CAP_PASS_THROUGH(priv->capabilities))
821 synaptics_pt_create(psmouse);
822
823 /*
824 * Toshiba's KBC seems to have trouble handling data from
825 * Synaptics as full rate, switch to lower rate which is roughly
826 * thye same as rate of standard PS/2 mouse.
827 */
828 if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
829 printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
830 dmi_get_system_info(DMI_PRODUCT_NAME));
831 psmouse->rate = 40;
832 }
833
834 return 0;
835
836 init_fail:
837 kfree(priv);
838 return -1;
839}
840
841bool synaptics_supported(void)
842{
843 return true;
844}
845
846#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
847
848void __init synaptics_module_init(void)
849{
850}
851
852int synaptics_init(struct psmouse *psmouse)
853{
854 return -ENOSYS;
855}
856
857bool synaptics_supported(void)
858{
859 return false;
860}
861
862#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
863
diff --git a/usr/src/dkms_source_tree/synaptics.h b/usr/src/dkms_source_tree/synaptics.h
new file mode 100644
index 0000000..80907d0
--- /dev/null
+++ b/usr/src/dkms_source_tree/synaptics.h
@@ -0,0 +1,122 @@
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
12/* synaptics queries */
13#define SYN_QUE_IDENTIFY 0x00
14#define SYN_QUE_MODES 0x01
15#define SYN_QUE_CAPABILITIES 0x02
16#define SYN_QUE_MODEL 0x03
17#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
18#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
19#define SYN_QUE_RESOLUTION 0x08
20#define SYN_QUE_EXT_CAPAB 0x09
21#define SYN_QUE_EXT_CAPAB_0C 0x0c
22#define SYN_QUE_EXT_DIMENSIONS 0x0d
23
24/* synatics modes */
25#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
26#define SYN_BIT_HIGH_RATE (1 << 6)
27#define SYN_BIT_SLEEP_MODE (1 << 3)
28#define SYN_BIT_DISABLE_GESTURE (1 << 2)
29#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1)
30#define SYN_BIT_W_MODE (1 << 0)
31
32/* synaptics model ID bits */
33#define SYN_MODEL_ROT180(m) ((m) & (1 << 23))
34#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22))
35#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f)
36#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f)
37#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7))
38#define SYN_MODEL_PEN(m) ((m) & (1 << 6))
39#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5))
40#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f)
41
42/* synaptics capability bits */
43#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
44#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18))
45#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
46#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
47#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
48#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
49#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
50#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8)
51#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
52#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
53#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
54#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
55#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
56
57/* synaptics modes query bits */
58#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
59#define SYN_MODE_RATE(m) ((m) & (1 << 6))
60#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3))
61#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2))
62#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1))
63#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
64
65/* synaptics identify query bits */
66#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
67#define SYN_ID_MAJOR(i) ((i) & 0x0f)
68#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
69#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i))
70#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
71
72/* synaptics special commands */
73#define SYN_PS_SET_MODE2 0x14
74#define SYN_PS_CLIENT_CMD 0x28
75
76/* synaptics packet types */
77#define SYN_NEWABS 0
78#define SYN_NEWABS_STRICT 1
79#define SYN_NEWABS_RELAXED 2
80#define SYN_OLDABS 3
81
82/*
83 * A structure to describe the state of the touchpad hardware (buttons and pad)
84 */
85
86struct synaptics_hw_state {
87 int x;
88 int y;
89 int z;
90 int w;
91 unsigned int left:1;
92 unsigned int right:1;
93 unsigned int middle:1;
94 unsigned int up:1;
95 unsigned int down:1;
96 unsigned char ext_buttons;
97 signed char scroll;
98};
99
100struct synaptics_data {
101 /* Data read from the touchpad */
102 unsigned long int model_id; /* Model-ID */
103 unsigned long int capabilities; /* Capabilities */
104 unsigned long int ext_cap; /* Extended Capabilities */
105 unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */
106 unsigned long int identity; /* Identification */
107 unsigned int x_res, y_res; /* X/Y resolution in units/mm */
108 unsigned int x_max, y_max; /* Max dimensions (from FW) */
109
110 unsigned char pkt_type; /* packet type - old, new, etc */
111 unsigned char mode; /* current mode byte */
112 int scroll;
113 struct synaptics_hw_state prev_hw;
114};
115
116void synaptics_module_init(void);
117int synaptics_detect(struct psmouse *psmouse, bool set_properties);
118int synaptics_init(struct psmouse *psmouse);
119void synaptics_reset(struct psmouse *psmouse);
120bool synaptics_supported(void);
121
122#endif /* _SYNAPTICS_H */
diff --git a/usr/src/dkms_source_tree/touchkit_ps2.c b/usr/src/dkms_source_tree/touchkit_ps2.c
new file mode 100644
index 0000000..88121c5
--- /dev/null
+++ b/usr/src/dkms_source_tree/touchkit_ps2.c
@@ -0,0 +1,100 @@
1/* ----------------------------------------------------------------------------
2 * touchkit_ps2.c -- Driver for eGalax TouchKit PS/2 Touchscreens
3 *
4 * Copyright (C) 2005 by Stefan Lucke
5 * Copyright (C) 2004 by Daniel Ritz
6 * Copyright (C) by Todd E. Johnson (mtouchusb.c)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Based upon touchkitusb.c
23 *
24 * Vendor documentation is available in support section of:
25 * http://www.egalax.com.tw/
26 */
27
28#include <linux/kernel.h>
29
30#include <linux/input.h>
31#include <linux/serio.h>
32#include <linux/libps2.h>
33
34#include "psmouse.h"
35#include "touchkit_ps2.h"
36
37#define TOUCHKIT_MAX_XC 0x07ff
38#define TOUCHKIT_MAX_YC 0x07ff
39
40#define TOUCHKIT_CMD 0x0a
41#define TOUCHKIT_CMD_LENGTH 1
42
43#define TOUCHKIT_CMD_ACTIVE 'A'
44#define TOUCHKIT_CMD_FIRMWARE_VERSION 'D'
45#define TOUCHKIT_CMD_CONTROLLER_TYPE 'E'
46
47#define TOUCHKIT_SEND_PARMS(s, r, c) ((s) << 12 | (r) << 8 | (c))
48
49#define TOUCHKIT_GET_TOUCHED(packet) (((packet)[0]) & 0x01)
50#define TOUCHKIT_GET_X(packet) (((packet)[1] << 7) | (packet)[2])
51#define TOUCHKIT_GET_Y(packet) (((packet)[3] << 7) | (packet)[4])
52
53static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
54{
55 unsigned char *packet = psmouse->packet;
56 struct input_dev *dev = psmouse->dev;
57
58 if (psmouse->pktcnt != 5)
59 return PSMOUSE_GOOD_DATA;
60
61 input_report_abs(dev, ABS_X, TOUCHKIT_GET_X(packet));
62 input_report_abs(dev, ABS_Y, TOUCHKIT_GET_Y(packet));
63 input_report_key(dev, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(packet));
64 input_sync(dev);
65
66 return PSMOUSE_FULL_PACKET;
67}
68
69int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties)
70{
71 struct input_dev *dev = psmouse->dev;
72 unsigned char param[3];
73 int command;
74
75 param[0] = TOUCHKIT_CMD_LENGTH;
76 param[1] = TOUCHKIT_CMD_ACTIVE;
77 command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD);
78
79 if (ps2_command(&psmouse->ps2dev, param, command))
80 return -ENODEV;
81
82 if (param[0] != TOUCHKIT_CMD || param[1] != 0x01 ||
83 param[2] != TOUCHKIT_CMD_ACTIVE)
84 return -ENODEV;
85
86 if (set_properties) {
87 dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
88 dev->keybit[BIT_WORD(BTN_MOUSE)] = 0;
89 dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
90 input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
91 input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
92
93 psmouse->vendor = "eGalax";
94 psmouse->name = "Touchscreen";
95 psmouse->protocol_handler = touchkit_ps2_process_byte;
96 psmouse->pktsize = 5;
97 }
98
99 return 0;
100}
diff --git a/usr/src/dkms_source_tree/touchkit_ps2.h b/usr/src/dkms_source_tree/touchkit_ps2.h
new file mode 100644
index 0000000..2efe9ea
--- /dev/null
+++ b/usr/src/dkms_source_tree/touchkit_ps2.h
@@ -0,0 +1,25 @@
1/* ----------------------------------------------------------------------------
2 * touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens
3 *
4 * Copyright (C) 2005 by Stefan Lucke
5 * Copyright (c) 2005 Vojtech Pavlik
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 _TOUCHKIT_PS2_H
13#define _TOUCHKIT_PS2_H
14
15#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
16int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties);
17#else
18static inline int touchkit_ps2_detect(struct psmouse *psmouse,
19 bool set_properties)
20{
21 return -ENOSYS;
22}
23#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */
24
25#endif
diff --git a/usr/src/dkms_source_tree/trackpoint.c b/usr/src/dkms_source_tree/trackpoint.c
new file mode 100644
index 0000000..0643e49
--- /dev/null
+++ b/usr/src/dkms_source_tree/trackpoint.c
@@ -0,0 +1,335 @@
1/*
2 * Stephen Evanchik <evanchsa@gmail.com>
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 * Trademarks are the property of their respective owners.
9 */
10
11#include <linux/slab.h>
12#include <linux/delay.h>
13#include <linux/serio.h>
14#include <linux/module.h>
15#include <linux/input.h>
16#include <linux/libps2.h>
17#include <linux/proc_fs.h>
18#include <asm/uaccess.h>
19#include "psmouse.h"
20#include "trackpoint.h"
21
22/*
23 * Device IO: read, write and toggle bit
24 */
25static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results)
26{
27 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
28 ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
29 return -1;
30 }
31
32 return 0;
33}
34
35static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val)
36{
37 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
38 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
39 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
40 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {
41 return -1;
42 }
43
44 return 0;
45}
46
47static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask)
48{
49 /* Bad things will happen if the loc param isn't in this range */
50 if (loc < 0x20 || loc >= 0x2F)
51 return -1;
52
53 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
54 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||
55 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
56 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {
57 return -1;
58 }
59
60 return 0;
61}
62
63
64/*
65 * Trackpoint-specific attributes
66 */
67struct trackpoint_attr_data {
68 size_t field_offset;
69 unsigned char command;
70 unsigned char mask;
71 unsigned char inverted;
72};
73
74static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf)
75{
76 struct trackpoint_data *tp = psmouse->private;
77 struct trackpoint_attr_data *attr = data;
78 unsigned char value = *(unsigned char *)((char *)tp + attr->field_offset);
79
80 if (attr->inverted)
81 value = !value;
82
83 return sprintf(buf, "%u\n", value);
84}
85
86static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
87 const char *buf, size_t count)
88{
89 struct trackpoint_data *tp = psmouse->private;
90 struct trackpoint_attr_data *attr = data;
91 unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
92 unsigned long value;
93
94 if (strict_strtoul(buf, 10, &value) || value > 255)
95 return -EINVAL;
96
97 *field = value;
98 trackpoint_write(&psmouse->ps2dev, attr->command, value);
99
100 return count;
101}
102
103#define TRACKPOINT_INT_ATTR(_name, _command) \
104 static struct trackpoint_attr_data trackpoint_attr_##_name = { \
105 .field_offset = offsetof(struct trackpoint_data, _name), \
106 .command = _command, \
107 }; \
108 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
109 &trackpoint_attr_##_name, \
110 trackpoint_show_int_attr, trackpoint_set_int_attr)
111
112static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
113 const char *buf, size_t count)
114{
115 struct trackpoint_data *tp = psmouse->private;
116 struct trackpoint_attr_data *attr = data;
117 unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
118 unsigned long value;
119
120 if (strict_strtoul(buf, 10, &value) || value > 1)
121 return -EINVAL;
122
123 if (attr->inverted)
124 value = !value;
125
126 if (*field != value) {
127 *field = value;
128 trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask);
129 }
130
131 return count;
132}
133
134
135#define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv) \
136 static struct trackpoint_attr_data trackpoint_attr_##_name = { \
137 .field_offset = offsetof(struct trackpoint_data, _name), \
138 .command = _command, \
139 .mask = _mask, \
140 .inverted = _inv, \
141 }; \
142 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
143 &trackpoint_attr_##_name, \
144 trackpoint_show_int_attr, trackpoint_set_bit_attr)
145
146TRACKPOINT_INT_ATTR(sensitivity, TP_SENS);
147TRACKPOINT_INT_ATTR(speed, TP_SPEED);
148TRACKPOINT_INT_ATTR(inertia, TP_INERTIA);
149TRACKPOINT_INT_ATTR(reach, TP_REACH);
150TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS);
151TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG);
152TRACKPOINT_INT_ATTR(thresh, TP_THRESH);
153TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH);
154TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME);
155TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV);
156
157TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0);
158TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0);
159TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1);
160
161static struct attribute *trackpoint_attrs[] = {
162 &psmouse_attr_sensitivity.dattr.attr,
163 &psmouse_attr_speed.dattr.attr,
164 &psmouse_attr_inertia.dattr.attr,
165 &psmouse_attr_reach.dattr.attr,
166 &psmouse_attr_draghys.dattr.attr,
167 &psmouse_attr_mindrag.dattr.attr,
168 &psmouse_attr_thresh.dattr.attr,
169 &psmouse_attr_upthresh.dattr.attr,
170 &psmouse_attr_ztime.dattr.attr,
171 &psmouse_attr_jenks.dattr.attr,
172 &psmouse_attr_press_to_select.dattr.attr,
173 &psmouse_attr_skipback.dattr.attr,
174 &psmouse_attr_ext_dev.dattr.attr,
175 NULL
176};
177
178static struct attribute_group trackpoint_attr_group = {
179 .attrs = trackpoint_attrs,
180};
181
182static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id)
183{
184 unsigned char param[2] = { 0 };
185
186 if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
187 return -1;
188
189 if (param[0] != TP_MAGIC_IDENT)
190 return -1;
191
192 if (firmware_id)
193 *firmware_id = param[1];
194
195 return 0;
196}
197
198static int trackpoint_sync(struct psmouse *psmouse)
199{
200 struct trackpoint_data *tp = psmouse->private;
201 unsigned char toggle;
202
203 /* Disable features that may make device unusable with this driver */
204 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);
205 if (toggle & TP_MASK_TWOHAND)
206 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND);
207
208 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle);
209 if (toggle & TP_MASK_SOURCE_TAG)
210 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG);
211
212 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle);
213 if (toggle & TP_MASK_MB)
214 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB);
215
216 /* Push the config to the device */
217 trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity);
218 trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia);
219 trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed);
220
221 trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach);
222 trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys);
223 trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag);
224
225 trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh);
226 trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh);
227
228 trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime);
229 trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks);
230
231 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle);
232 if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select)
233 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON);
234
235 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle);
236 if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback)
237 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK);
238
239 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle);
240 if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev)
241 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV);
242
243 return 0;
244}
245
246static void trackpoint_defaults(struct trackpoint_data *tp)
247{
248 tp->press_to_select = TP_DEF_PTSON;
249 tp->sensitivity = TP_DEF_SENS;
250 tp->speed = TP_DEF_SPEED;
251 tp->reach = TP_DEF_REACH;
252
253 tp->draghys = TP_DEF_DRAGHYS;
254 tp->mindrag = TP_DEF_MINDRAG;
255
256 tp->thresh = TP_DEF_THRESH;
257 tp->upthresh = TP_DEF_UP_THRESH;
258
259 tp->ztime = TP_DEF_Z_TIME;
260 tp->jenks = TP_DEF_JENKS_CURV;
261
262 tp->inertia = TP_DEF_INERTIA;
263 tp->skipback = TP_DEF_SKIPBACK;
264 tp->ext_dev = TP_DEF_EXT_DEV;
265}
266
267static void trackpoint_disconnect(struct psmouse *psmouse)
268{
269 sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);
270
271 kfree(psmouse->private);
272 psmouse->private = NULL;
273}
274
275static int trackpoint_reconnect(struct psmouse *psmouse)
276{
277 if (trackpoint_start_protocol(psmouse, NULL))
278 return -1;
279
280 if (trackpoint_sync(psmouse))
281 return -1;
282
283 return 0;
284}
285
286int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
287{
288 struct ps2dev *ps2dev = &psmouse->ps2dev;
289 unsigned char firmware_id;
290 unsigned char button_info;
291 int error;
292
293 if (trackpoint_start_protocol(psmouse, &firmware_id))
294 return -1;
295
296 if (!set_properties)
297 return 0;
298
299 if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
300 printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");
301 button_info = 0;
302 }
303
304 psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
305 if (!psmouse->private)
306 return -1;
307
308 psmouse->vendor = "IBM";
309 psmouse->name = "TrackPoint";
310
311 psmouse->reconnect = trackpoint_reconnect;
312 psmouse->disconnect = trackpoint_disconnect;
313
314 if ((button_info & 0x0f) >= 3)
315 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
316
317 trackpoint_defaults(psmouse->private);
318 trackpoint_sync(psmouse);
319
320 error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
321 if (error) {
322 printk(KERN_ERR
323 "trackpoint.c: failed to create sysfs attributes, error: %d\n",
324 error);
325 kfree(psmouse->private);
326 psmouse->private = NULL;
327 return -1;
328 }
329
330 printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n",
331 firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f);
332
333 return 0;
334}
335
diff --git a/usr/src/dkms_source_tree/trackpoint.h b/usr/src/dkms_source_tree/trackpoint.h
new file mode 100644
index 0000000..e558a70
--- /dev/null
+++ b/usr/src/dkms_source_tree/trackpoint.h
@@ -0,0 +1,154 @@
1/*
2 * IBM TrackPoint PS/2 mouse driver
3 *
4 * Stephen Evanchik <evanchsa@gmail.com>
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 _TRACKPOINT_H
12#define _TRACKPOINT_H
13
14/*
15 * These constants are from the TrackPoint System
16 * Engineering documentation Version 4 from IBM Watson
17 * research:
18 * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
19 */
20
21#define TP_COMMAND 0xE2 /* Commands start with this */
22
23#define TP_READ_ID 0xE1 /* Sent for device identification */
24#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */
25 /* by the firmware ID */
26
27
28/*
29 * Commands
30 */
31#define TP_RECALIB 0x51 /* Recalibrate */
32#define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */
33#define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */
34#define TP_EXT_BTN 0x4B /* Read extended button status */
35#define TP_POR 0x7F /* Execute Power on Reset */
36#define TP_POR_RESULTS 0x25 /* Read Power on Self test results */
37#define TP_DISABLE_EXT 0x40 /* Disable external pointing device */
38#define TP_ENABLE_EXT 0x41 /* Enable external pointing device */
39
40/*
41 * Mode manipulation
42 */
43#define TP_SET_SOFT_TRANS 0x4E /* Set mode */
44#define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */
45#define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */
46
47
48/*
49 * Register oriented commands/properties
50 */
51#define TP_WRITE_MEM 0x81
52#define TP_READ_MEM 0x80 /* Not used in this implementation */
53
54/*
55* RAM Locations for properties
56 */
57#define TP_SENS 0x4A /* Sensitivity */
58#define TP_MB 0x4C /* Read Middle Button Status (RO) */
59#define TP_INERTIA 0x4D /* Negative Inertia */
60#define TP_SPEED 0x60 /* Speed of TP Cursor */
61#define TP_REACH 0x57 /* Backup for Z-axis press */
62#define TP_DRAGHYS 0x58 /* Drag Hysteresis */
63 /* (how hard it is to drag */
64 /* with Z-axis pressed) */
65
66#define TP_MINDRAG 0x59 /* Minimum amount of force needed */
67 /* to trigger dragging */
68
69#define TP_THRESH 0x5C /* Minimum value for a Z-axis press */
70#define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */
71#define TP_Z_TIME 0x5E /* How sharp of a press */
72#define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */
73
74/*
75 * Toggling Flag bits
76 */
77#define TP_TOGGLE 0x47 /* Toggle command */
78
79#define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */
80#define TP_MASK_MB 0x01
81#define TP_TOGGLE_EXT_DEV 0x23 /* Disable external device */
82#define TP_MASK_EXT_DEV 0x02
83#define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */
84#define TP_MASK_DRIFT 0x80
85#define TP_TOGGLE_BURST 0x28 /* Burst Mode */
86#define TP_MASK_BURST 0x80
87#define TP_TOGGLE_PTSON 0x2C /* Press to Select */
88#define TP_MASK_PTSON 0x01
89#define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */
90#define TP_MASK_HARD_TRANS 0x80
91#define TP_TOGGLE_TWOHAND 0x2D /* Two handed */
92#define TP_MASK_TWOHAND 0x01
93#define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */
94#define TP_MASK_STICKY_TWO 0x04
95#define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */
96#define TP_MASK_SKIPBACK 0x08
97#define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to
98 to the origin of the packet (external or TP) */
99#define TP_MASK_SOURCE_TAG 0x80
100#define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the
101 external device will be forced to 1 */
102#define TP_MASK_EXT_TAG 0x04
103
104
105/* Power on Self Test Results */
106#define TP_POR_SUCCESS 0x3B
107
108/*
109 * Default power on values
110 */
111#define TP_DEF_SENS 0x80
112#define TP_DEF_INERTIA 0x06
113#define TP_DEF_SPEED 0x61
114#define TP_DEF_REACH 0x0A
115
116#define TP_DEF_DRAGHYS 0xFF
117#define TP_DEF_MINDRAG 0x14
118
119#define TP_DEF_THRESH 0x08
120#define TP_DEF_UP_THRESH 0xFF
121#define TP_DEF_Z_TIME 0x26
122#define TP_DEF_JENKS_CURV 0x87
123
124/* Toggles */
125#define TP_DEF_MB 0x00
126#define TP_DEF_PTSON 0x00
127#define TP_DEF_SKIPBACK 0x00
128#define TP_DEF_EXT_DEV 0x00 /* 0 means enabled */
129
130#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
131
132struct trackpoint_data
133{
134 unsigned char sensitivity, speed, inertia, reach;
135 unsigned char draghys, mindrag;
136 unsigned char thresh, upthresh;
137 unsigned char ztime, jenks;
138
139 unsigned char press_to_select;
140 unsigned char skipback;
141
142 unsigned char ext_dev;
143};
144
145#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
146int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
147#else
148inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
149{
150 return -ENOSYS;
151}
152#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */
153
154#endif /* _TRACKPOINT_H */