lua: Fixed some cross-platform issues for PPC (and probably other architectures)
[openwrt.git] / target / linux / olpc / files-2.6.23 / drivers / input / mouse / olpc.c
1 /*
2 * OLPC touchpad PS/2 mouse driver
3 *
4 * Copyright (c) 2006 One Laptop Per Child, inc.
5 * Authors Zephaniah E. Hull and Andres Salomon <dilinger@laptop.org>
6 *
7 * This driver is partly based on the ALPS driver, which is:
8 *
9 * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
10 * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
11 * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
12 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19 /*
20 * The touchpad on the OLPC is fairly wide, with the entire area usable
21 * as a tablet ("PT mode"), and the center 1/3rd also usable as a touchpad
22 * ("GS mode").
23 *
24 * Earlier version of the device had simultaneous reporting; however, that
25 * was removed. Instead, the device now reports packets in one mode, and
26 * tells the driver when a mode switch needs to happen.
27 */
28
29 #include <linux/input.h>
30 #include <linux/serio.h>
31 #include <linux/libps2.h>
32 #include <linux/delay.h>
33 #include <asm/olpc.h>
34
35 #include "psmouse.h"
36 #include "olpc.h"
37
38 static int tpdebug;
39 module_param(tpdebug, int, 0644);
40
41 #define OLPC_GS 1 /* The GS sensor. */
42 #define OLPC_PT 2 /* The PT sensor. */
43
44 static struct olpc_model_info olpc_model_data[] = {
45 { { 0x67, 0x00, 0x00 }, OLPC_GS | OLPC_PT }, /* unknown ID */
46 { { 0x67, 0x00, 0x0a }, OLPC_GS | OLPC_PT }, /* pre-B1 */
47 { { 0x67, 0x00, 0x14 }, OLPC_GS }, /* B1.*/
48 { { 0x67, 0x00, 0x28 }, OLPC_GS | OLPC_PT }, /* B2 */
49 { { 0x67, 0x00, 0x3c }, OLPC_GS | OLPC_PT }, /* B2-2 */
50 { { 0x67, 0x00, 0x50 }, OLPC_GS | OLPC_PT }, /* C1 */
51 };
52
53 #define OLPC_PKT_PT 0xcf
54 #define OLPC_PKT_GS 0xff
55
56 static int olpc_absolute_mode(struct psmouse *psmouse, int mode);
57
58 /*
59 * OLPC absolute Mode - single-mode format
60 *
61 * byte 0: 1 1 0 0 1 1 1 1
62 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
63 * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw gs-dsw
64 * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
65 * byte 3: 0 y9 y8 y7 1 0 swr swl
66 * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
67 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
68 *
69 * ?'s are not defined in the protocol spec, may vary between models.
70 *
71 * swr/swl are the left/right buttons.
72 *
73 * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
74 * pen/finger
75 */
76
77 static void olpc_process_packet_gspt(struct psmouse *psmouse)
78 {
79 struct olpc_data *priv = psmouse->private;
80 unsigned char *packet = psmouse->packet;
81 struct input_dev *dev = psmouse->dev;
82 struct input_dev *dev2 = priv->dev2;
83 int x, y, z, gs_down = 0, pt_down = 0, left, right;
84 struct timeval now_tv;
85 s64 now_ns;
86
87 left = packet[3] & 1;
88 right = packet[3] & 2;
89 x = packet[1] | ((packet[2] & 0x78) << 4);
90 y = packet[4] | ((packet[3] & 0x70) << 3);
91 z = packet[5];
92
93 if (psmouse->packet[0] == OLPC_PKT_GS) {
94 pt_down = !!(packet[2] & 1);
95 gs_down = !!(packet[2] & 2);
96 } else if (psmouse->packet[0] == OLPC_PKT_PT) {
97 gs_down = !!(packet[2] & 1);
98 pt_down = !!(packet[2] & 2);
99 }
100
101 /*
102 * XXX: Kludge.
103 * If it's been more than 30ms since the last packet,
104 * assume that there was a lift we were never told about.
105 */
106 do_gettimeofday(&now_tv);
107 now_ns = timeval_to_ns (&now_tv);
108 if (now_ns >= priv->late) {
109 input_report_key(dev, BTN_TOUCH, 0);
110 input_report_key(dev, BTN_TOOL_PEN, 0);
111 input_report_key(dev2, BTN_TOUCH, 0);
112 input_report_key(dev2, BTN_TOOL_FINGER, 0);
113
114 input_sync(dev);
115 input_sync(dev2);
116 }
117
118 priv->late = now_ns + (30 * NSEC_PER_MSEC);
119
120
121 if (tpdebug) {
122 printk(KERN_DEBUG "%s %02x %02x %02x %02x %02x %02x\n",
123 __FUNCTION__, psmouse->packet[0], psmouse->packet[1],
124 psmouse->packet[2], psmouse->packet[3], psmouse->packet[4],
125 psmouse->packet[5]);
126 printk(KERN_DEBUG "l=%d r=%d p=%d g=%d x=%d y=%d z=%d\n",
127 left, right, pt_down, gs_down, x, y, z);
128 }
129
130 if (psmouse->packet[0] == OLPC_PKT_PT) {
131 input_report_key(dev, BTN_LEFT, left);
132 input_report_key(dev, BTN_RIGHT, right);
133 } else if (psmouse->packet[0] == OLPC_PKT_GS) {
134 input_report_key(dev, BTN_LEFT, left);
135 input_report_key(dev, BTN_RIGHT, right);
136 input_report_key(dev2, BTN_LEFT, left);
137 input_report_key(dev2, BTN_RIGHT, right);
138 }
139
140 input_report_key(dev, BTN_TOUCH, pt_down);
141 input_report_key(dev, BTN_TOOL_PEN, pt_down);
142 input_report_key(dev2, BTN_TOUCH, gs_down);
143 input_report_key(dev2, BTN_TOOL_FINGER, gs_down);
144
145 input_report_abs(dev2, ABS_PRESSURE, z);
146
147 if (psmouse->packet[0] == OLPC_PKT_PT && pt_down) {
148 input_report_abs(dev, ABS_X, x);
149 input_report_abs(dev, ABS_Y, y);
150 } else if (psmouse->packet[0] == OLPC_PKT_GS && gs_down) {
151 input_report_abs(dev2, ABS_X, x);
152 input_report_abs(dev2, ABS_Y, y);
153 }
154
155 input_sync(dev);
156 input_sync(dev2);
157
158 if (priv->pending_mode == OLPC_GS &&
159 psmouse->packet[0] == OLPC_PKT_PT && pt_down) {
160 priv->pending_mode = 0;
161 cancel_delayed_work(&priv->mode_switch);
162 }
163
164 if (priv->i->flags & (OLPC_PT|OLPC_GS)) {
165 int pending = 0;
166 if (psmouse->packet[0] == OLPC_PKT_PT && !pt_down)
167 pending = OLPC_GS;
168 else if (psmouse->packet[0] == OLPC_PKT_GS && pt_down)
169 pending = OLPC_PT;
170
171 if (priv->current_mode == pending) {
172 priv->pending_mode = 0;
173 pending = priv->current_mode;
174 }
175 else if (priv->pending_mode != pending) {
176 priv->pending_mode = pending;
177 if (tpdebug)
178 printk(KERN_WARNING "Scheduling mode switch to %s.\n",
179 pending == OLPC_GS ? "GS" : "PT");
180
181 /*
182 * Apply a de-bounce when switching from PT to GS, to allow for
183 * spurious PT-up packets.
184 */
185 if (priv->pending_mode == OLPC_GS)
186 queue_delayed_work(kpsmoused_wq, &priv->mode_switch, msecs_to_jiffies(50));
187 else
188 queue_delayed_work(kpsmoused_wq, &priv->mode_switch, 0);
189 }
190 }
191 }
192
193 static psmouse_ret_t olpc_process_byte(struct psmouse *psmouse)
194 {
195 psmouse_ret_t ret = PSMOUSE_BAD_DATA;
196
197 if (psmouse->packet[0] != OLPC_PKT_PT &&
198 psmouse->packet[0] != OLPC_PKT_GS)
199 goto out;
200
201 /* Bytes 2 - 6 should have 0 in the highest bit */
202 if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
203 (psmouse->packet[psmouse->pktcnt - 1] & 0x80))
204 goto out;
205
206 if (psmouse->pktcnt == 6) {
207 olpc_process_packet_gspt(psmouse);
208 ret = PSMOUSE_FULL_PACKET;
209 goto out;
210 }
211
212 ret = PSMOUSE_GOOD_DATA;
213 out:
214 if (ret != PSMOUSE_GOOD_DATA && ret != PSMOUSE_FULL_PACKET)
215 printk(KERN_DEBUG "%s: (%d) %02x %02x %02x %02x %02x %02x\n",
216 __FUNCTION__, psmouse->pktcnt, psmouse->packet[0],
217 psmouse->packet[1], psmouse->packet[2],
218 psmouse->packet[3], psmouse->packet[4],
219 psmouse->packet[5]);
220 return ret;
221 }
222
223 static struct olpc_model_info *olpc_get_model(struct psmouse *psmouse)
224 {
225 struct ps2dev *ps2dev = &psmouse->ps2dev;
226 unsigned char param[4];
227 int i;
228
229 /*
230 * Now try "E7 report". Allowed responses are in
231 * olpc_model_data[].signature
232 */
233 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
234 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
235 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
236 return NULL;
237
238 param[0] = param[1] = param[2] = 0xff;
239 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
240 return NULL;
241
242 pr_debug("olpc.c(%d): E7 report: %2.2x %2.2x %2.2x",
243 __LINE__, param[0], param[1], param[2]);
244
245 for (i = 0; i < ARRAY_SIZE(olpc_model_data); i++) {
246 if (!memcmp(param, olpc_model_data[i].signature,
247 sizeof(olpc_model_data[i].signature))) {
248 printk(KERN_INFO __FILE__ ": OLPC touchpad revision 0x%x.\n", param[2]);
249 return olpc_model_data + i;
250 }
251 }
252
253 /*
254 * ALPS creates new IDs pretty frequently; rather than listing them
255 * all, just assume they support the defaults. We've set aside the
256 * first entry of olpc_model_data as the catch-all.
257 */
258 if (!memcmp(param, olpc_model_data[0].signature, 2)) {
259 printk(KERN_INFO __FILE__ ": unknown ALPS revision %x, assuming default flags.\n", param[2]);
260 return &olpc_model_data[0];
261 }
262
263 return NULL;
264 }
265
266 static int olpc_find_mode(struct psmouse *psmouse)
267 {
268 struct olpc_data *priv = psmouse->private;
269 int mode = priv->i->flags;
270
271 if (mode & OLPC_GS)
272 mode = OLPC_GS;
273 else if (mode & OLPC_PT)
274 mode = OLPC_PT;
275 else
276 mode = -1;
277
278 return mode;
279 }
280
281 /*
282 * Touchpad should be disabled before calling this!
283 */
284 static int olpc_new_mode(struct psmouse *psmouse, int mode)
285 {
286 struct ps2dev *ps2dev = &psmouse->ps2dev;
287 struct olpc_data *priv = psmouse->private;
288 unsigned char param;
289 int ret;
290
291 if (tpdebug)
292 printk(KERN_WARNING __FILE__ ": Switching to %d. [%lu]\n", mode, jiffies);
293
294 if ((ret = ps2_command(ps2dev, &param, 0x01F2)))
295 goto failed;
296 if ((ret = ps2_command(ps2dev, &param, 0x01F2)))
297 goto failed;
298 if ((ret = ps2_command(ps2dev, &param, 0x01F2)))
299 goto failed;
300
301 switch (mode) {
302 default:
303 printk(KERN_WARNING __FILE__ ": Invalid mode %d. Defaulting to OLPC_GS.\n", mode);
304 case OLPC_GS:
305 ret = ps2_command(ps2dev, NULL, 0xE6);
306 break;
307 case OLPC_PT:
308 ret = ps2_command(ps2dev, NULL, 0xE7);
309 break;
310 }
311 if (ret)
312 goto failed;
313
314 /* XXX: This is a bit hacky, make sure this isn't screwing stuff up. */
315 psmouse->pktcnt = psmouse->out_of_sync = 0;
316 psmouse->last = jiffies;
317 psmouse->state = PSMOUSE_ACTIVATED;
318
319 if ((ret = ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)))
320 goto failed;
321
322 priv->current_mode = mode;
323 priv->pending_mode = 0;
324 if (tpdebug)
325 printk(KERN_WARNING __FILE__ ": Switched to mode %d successful.\n", mode);
326
327 failed:
328 if (ret)
329 printk(KERN_WARNING __FILE__ ": Mode switch to %d failed! (%d) [%lu]\n", mode, ret, jiffies);
330 return ret;
331 }
332
333 static int olpc_absolute_mode(struct psmouse *psmouse, int mode)
334 {
335 struct ps2dev *ps2dev = &psmouse->ps2dev;
336
337 /* Switch to 'Advanced mode.', four disables in a row. */
338 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
339 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
340 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
341 ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
342 return -1;
343
344 return olpc_new_mode(psmouse, mode);
345 }
346
347 /*
348 * olpc_poll() - poll the touchpad for current motion packet.
349 * Used in resync.
350 * Note: We can't poll, so always return failure.
351 */
352 static int olpc_poll(struct psmouse *psmouse)
353 {
354 return -1;
355 }
356
357 static int olpc_reconnect(struct psmouse *psmouse)
358 {
359 struct olpc_data *priv = psmouse->private;
360 int mode;
361
362 if (olpc_rev_after(OLPC_REV_B2))
363 if (psmouse->ps2dev.serio->dev.power.power_state.event != PM_EVENT_ON)
364 return 0;
365
366 psmouse_reset(psmouse);
367
368 if (!(priv->i = olpc_get_model(psmouse)))
369 return -1;
370
371 mode = olpc_find_mode(psmouse);
372 if (mode < 0)
373 return -1;
374
375 if (olpc_absolute_mode(psmouse, mode)) {
376 printk(KERN_ERR __FILE__ ": Failed to reenable absolute mode.\n");
377 return -1;
378 }
379
380 return 0;
381 }
382
383 static void olpc_disconnect(struct psmouse *psmouse)
384 {
385 struct olpc_data *priv = psmouse->private;
386
387 psmouse_reset(psmouse);
388 input_unregister_device(priv->dev2);
389 kfree(priv);
390 }
391
392 static void olpc_mode_switch(struct work_struct *w)
393 {
394 struct delayed_work *work = container_of(w, struct delayed_work, work);
395 struct olpc_data *priv = container_of(work, struct olpc_data, mode_switch);
396 struct psmouse *psmouse = priv->psmouse;
397 struct ps2dev *ps2dev = &psmouse->ps2dev;
398 int pending_mode, ret;
399
400 if (priv->pending_mode == priv->current_mode) {
401 priv->pending_mode = 0;
402 printk (KERN_DEBUG __FILE__ ": In switch_mode, no target mode.\n");
403 return;
404 }
405
406 if (tpdebug)
407 printk(KERN_WARNING __FILE__ ": Disable for switch to %d. [%lu]\n", priv->pending_mode, jiffies);
408
409 /* XXX: This is a bit hacky, make sure this isn't screwing stuff up. */
410 psmouse->state = PSMOUSE_INITIALIZING;
411
412 ret = ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
413 if (ret) {
414 /* XXX: if this ever fails, we need to do a full reset! */
415 printk(KERN_WARNING __FILE__ ": Disable failed for switch to %d. (%d) [%lu]\n", priv->pending_mode, ret, jiffies);
416 return;
417 }
418
419 /*
420 * ALPS tells us that it may take up to 20msec for the disable to
421 * take effect; however, ps2_command() will wait up to 200msec for
422 * the ACK to come back (and I'm assuming that by the time the
423 * hardware sends back its ACK, it has stopped sending bytes).
424 */
425 pending_mode = priv->pending_mode;
426
427 if (olpc_new_mode(psmouse, priv->pending_mode))
428 goto bad;
429
430 /*
431 * Deal with a potential race condition.
432 *
433 * If there is a brief tap of a stylus or a fingernail that
434 * triggers a mode switch to PT mode, and the stylus/fingernail is
435 * lifted after the DISABLE above, but before we reenable in the new mode,
436 * then we can get stuck in PT mode.
437 */
438 if (pending_mode == OLPC_PT) {
439 priv->pending_mode = OLPC_GS;
440 queue_delayed_work(kpsmoused_wq, &priv->mode_switch, msecs_to_jiffies(50));
441 }
442
443 return;
444
445 bad:
446 printk(KERN_WARNING __FILE__ ": Failure to switch modes, resetting device...\n");
447 olpc_reconnect(psmouse);
448 }
449
450 int olpc_init(struct psmouse *psmouse)
451 {
452 struct olpc_data *priv;
453 struct input_dev *dev = psmouse->dev;
454 struct input_dev *dev2;
455 int mode;
456
457 priv = kzalloc(sizeof(struct olpc_data), GFP_KERNEL);
458 dev2 = input_allocate_device();
459 if (!priv || !dev2)
460 goto init_fail;
461
462 psmouse->private = priv;
463 priv->dev2 = dev2;
464 priv->psmouse = psmouse;
465
466 psmouse_reset(psmouse);
467 if (!(priv->i = olpc_get_model(psmouse)))
468 goto init_fail;
469
470 mode = olpc_find_mode(psmouse);
471 if (mode < 0) {
472 printk(KERN_ERR __FILE__ ": Failed to identify proper mode\n");
473 goto init_fail;
474 }
475
476 if (olpc_absolute_mode(psmouse, mode)) {
477 printk(KERN_ERR __FILE__ ": Failed to enable absolute mode\n");
478 goto init_fail;
479 }
480
481 /*
482 * Unset some of the default bits for things we don't have.
483 */
484 dev->evbit[LONG(EV_REL)] &= ~BIT(EV_REL);
485 dev->relbit[LONG(REL_X)] &= ~(BIT(REL_X) | BIT(REL_Y));
486 dev->keybit[LONG(BTN_MIDDLE)] &= ~BIT(BTN_MIDDLE);
487
488 dev->evbit[LONG(EV_KEY)] |= BIT(EV_KEY);
489 dev->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
490 dev->keybit[LONG(BTN_TOOL_PEN)] |= BIT(BTN_TOOL_PEN);
491 dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT);
492
493 dev->evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
494 input_set_abs_params(dev, ABS_X, 2, 1000, 0, 0);
495 input_set_abs_params(dev, ABS_Y, 0, 717, 0, 0);
496
497 snprintf(priv->phys, sizeof(priv->phys),
498 "%s/input1", psmouse->ps2dev.serio->phys);
499 dev2->phys = priv->phys;
500 dev2->name = "OLPC ALPS GlideSensor";
501 dev2->id.bustype = BUS_I8042;
502 dev2->id.vendor = 0x0002;
503 dev2->id.product = PSMOUSE_OLPC;
504 dev2->id.version = 0x0000;
505
506 dev2->evbit[LONG(EV_KEY)] |= BIT(EV_KEY);
507 dev2->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
508 dev2->keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
509 dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT);
510
511 dev2->evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
512 input_set_abs_params(dev2, ABS_X, 350, 512, 0, 0);
513 input_set_abs_params(dev2, ABS_Y, 70, 325, 0, 0);
514 input_set_abs_params(dev2, ABS_PRESSURE, 0, 63, 0, 0);
515
516 if (input_register_device(dev2)) {
517 printk(KERN_ERR __FILE__ ": Failed to register GlideSensor\n");
518 goto init_fail;
519 }
520
521 psmouse->protocol_handler = olpc_process_byte;
522 psmouse->poll = olpc_poll;
523 psmouse->disconnect = olpc_disconnect;
524 psmouse->reconnect = olpc_reconnect;
525 psmouse->pktsize = 6;
526
527 /* Disable the idle resync. */
528 psmouse->resync_time = 0;
529 /* Reset after a lot of bad bytes. */
530 psmouse->resetafter = 1024;
531
532 INIT_DELAYED_WORK(&priv->mode_switch, olpc_mode_switch);
533
534 return 0;
535
536 init_fail:
537 input_free_device(dev2);
538 kfree(priv);
539 return -1;
540 }
541
542 int olpc_detect(struct psmouse *psmouse, int set_properties)
543 {
544 if (!olpc_get_model(psmouse))
545 return -1;
546
547 if (set_properties) {
548 psmouse->vendor = "ALPS";
549 psmouse->name = "PenTablet";
550 psmouse->model = 0;
551 }
552 return 0;
553 }
554
This page took 0.06879 seconds and 5 git commands to generate.