1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#define DEBUG
33#include <linux/input.h>
34#include <linux/serio.h>
35#include <linux/libps2.h>
36#include <linux/delay.h>
37#include <asm/olpc.h>
38
39#include "psmouse.h"
40#include "hgpk.h"
41
42static int tpdebug;
43module_param(tpdebug, int, 0644);
44MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
45
46static int recalib_delta = 100;
47module_param(recalib_delta, int, 0644);
48MODULE_PARM_DESC(recalib_delta,
49 "packets containing a delta this large will cause a recalibration.");
50
51static int jumpy_delay = 1000;
52module_param(jumpy_delay, int, 0644);
53MODULE_PARM_DESC(jumpy_delay,
54 "delay (ms) before recal after jumpiness detected");
55
56static int spew_delay = 1000;
57module_param(spew_delay, int, 0644);
58MODULE_PARM_DESC(spew_delay,
59 "delay (ms) before recal after packet spew detected");
60
61static int recal_guard_time = 2000;
62module_param(recal_guard_time, int, 0644);
63MODULE_PARM_DESC(recal_guard_time,
64 "interval (ms) during which recal will be restarted if packet received");
65
66static int post_interrupt_delay = 1000;
67module_param(post_interrupt_delay, int, 0644);
68MODULE_PARM_DESC(post_interrupt_delay,
69 "delay (ms) before recal after recal interrupt detected");
70
71static int autorecal = 1;
72module_param(autorecal, int, 0644);
73MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
74
75
76
77
78
79
80
81
82
83static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
84{
85 struct hgpk_data *priv = psmouse->private;
86
87 if (abs(x) > recalib_delta || abs(y) > recalib_delta) {
88 hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n",
89 recalib_delta, x, y);
90
91
92 psmouse_queue_work(psmouse, &priv->recalib_wq,
93 msecs_to_jiffies(jumpy_delay));
94 }
95}
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112static void hgpk_spewing_hack(struct psmouse *psmouse,
113 int l, int r, int x, int y)
114{
115 struct hgpk_data *priv = psmouse->private;
116
117
118
119 if (l || r)
120 return;
121
122 priv->x_tally += x;
123 priv->y_tally += y;
124
125 if (++priv->count > 100) {
126 if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
127 hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
128 priv->x_tally, priv->y_tally);
129 psmouse_queue_work(psmouse, &priv->recalib_wq,
130 msecs_to_jiffies(spew_delay));
131 }
132
133 priv->count = 0;
134 priv->x_tally = 0;
135 priv->y_tally = 0;
136 }
137}
138
139
140
141
142
143
144
145
146
147
148
149
150static int hgpk_validate_byte(unsigned char *packet)
151{
152 return (packet[0] & 0x0C) != 0x08;
153}
154
155static void hgpk_process_packet(struct psmouse *psmouse)
156{
157 struct input_dev *dev = psmouse->dev;
158 unsigned char *packet = psmouse->packet;
159 int x, y, left, right;
160
161 left = packet[0] & 1;
162 right = (packet[0] >> 1) & 1;
163
164 x = packet[1] - ((packet[0] << 4) & 0x100);
165 y = ((packet[0] << 3) & 0x100) - packet[2];
166
167 hgpk_jumpy_hack(psmouse, x, y);
168 hgpk_spewing_hack(psmouse, left, right, x, y);
169
170 if (tpdebug)
171 hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
172
173 input_report_key(dev, BTN_LEFT, left);
174 input_report_key(dev, BTN_RIGHT, right);
175
176 input_report_rel(dev, REL_X, x);
177 input_report_rel(dev, REL_Y, y);
178
179 input_sync(dev);
180}
181
182static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
183{
184 struct hgpk_data *priv = psmouse->private;
185
186 if (hgpk_validate_byte(psmouse->packet)) {
187 hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
188 __func__, psmouse->pktcnt, psmouse->packet[0],
189 psmouse->packet[1], psmouse->packet[2]);
190 return PSMOUSE_BAD_DATA;
191 }
192
193 if (psmouse->pktcnt >= psmouse->pktsize) {
194 hgpk_process_packet(psmouse);
195 return PSMOUSE_FULL_PACKET;
196 }
197
198 if (priv->recalib_window) {
199 if (time_before(jiffies, priv->recalib_window)) {
200
201
202
203
204 hgpk_dbg(psmouse,
205 "packet inside calibration window, "
206 "queueing another recalibration\n");
207 psmouse_queue_work(psmouse, &priv->recalib_wq,
208 msecs_to_jiffies(post_interrupt_delay));
209 }
210 priv->recalib_window = 0;
211 }
212
213 return PSMOUSE_GOOD_DATA;
214}
215
216static int hgpk_force_recalibrate(struct psmouse *psmouse)
217{
218 struct ps2dev *ps2dev = &psmouse->ps2dev;
219 struct hgpk_data *priv = psmouse->private;
220
221
222 if (psmouse->model < HGPK_MODEL_C)
223 return 0;
224
225
226 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
227
228
229 psmouse_reset(psmouse);
230
231
232 if (ps2_command(ps2dev, NULL, 0xf5) ||
233 ps2_command(ps2dev, NULL, 0xf5) ||
234 ps2_command(ps2dev, NULL, 0xe6) ||
235 ps2_command(ps2dev, NULL, 0xf5)) {
236 return -1;
237 }
238
239
240 msleep(150);
241
242
243
244
245
246
247
248 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
249 return -1;
250
251 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
252
253
254
255
256
257
258 priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time);
259
260 return 0;
261}
262
263
264
265
266
267
268static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
269{
270 struct ps2dev *ps2dev = &psmouse->ps2dev;
271 int timeo;
272
273
274 if (psmouse->model < HGPK_MODEL_D)
275 return 0;
276
277 if (enable) {
278 psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
279
280
281
282
283
284
285
286
287 for (timeo = 20; timeo > 0; timeo--) {
288 if (!ps2_sendbyte(&psmouse->ps2dev,
289 PSMOUSE_CMD_DISABLE, 20))
290 break;
291 msleep(50);
292 }
293
294 psmouse_reset(psmouse);
295
296
297 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
298 psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
299
300 } else {
301 hgpk_dbg(psmouse, "Powering off touchpad.\n");
302 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
303
304 if (ps2_command(ps2dev, NULL, 0xec) ||
305 ps2_command(ps2dev, NULL, 0xec) ||
306 ps2_command(ps2dev, NULL, 0xea)) {
307 return -1;
308 }
309
310
311 ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
312 }
313
314 return 0;
315}
316
317static int hgpk_poll(struct psmouse *psmouse)
318{
319
320 return -1;
321}
322
323static int hgpk_reconnect(struct psmouse *psmouse)
324{
325
326
327
328 if (olpc_board_at_least(olpc_board(0xb2)))
329 if (psmouse->ps2dev.serio->dev.power.power_state.event !=
330 PM_EVENT_ON)
331 return 0;
332
333 psmouse_reset(psmouse);
334
335 return 0;
336}
337
338static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
339{
340 struct hgpk_data *priv = psmouse->private;
341
342 return sprintf(buf, "%d\n", priv->powered);
343}
344
345static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
346 const char *buf, size_t count)
347{
348 struct hgpk_data *priv = psmouse->private;
349 unsigned long value;
350 int err;
351
352 err = strict_strtoul(buf, 10, &value);
353 if (err || value > 1)
354 return -EINVAL;
355
356 if (value != priv->powered) {
357
358
359
360
361 err = hgpk_toggle_power(psmouse, value);
362 if (!err)
363 priv->powered = value;
364 }
365
366 return err ? err : count;
367}
368
369__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
370 hgpk_show_powered, hgpk_set_powered, false);
371
372static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
373 void *data, char *buf)
374{
375 return -EINVAL;
376}
377
378static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data,
379 const char *buf, size_t count)
380{
381 struct hgpk_data *priv = psmouse->private;
382 unsigned long value;
383 int err;
384
385 err = strict_strtoul(buf, 10, &value);
386 if (err || value != 1)
387 return -EINVAL;
388
389
390
391
392
393
394 psmouse_queue_work(psmouse, &priv->recalib_wq, 0);
395 return count;
396}
397
398__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL,
399 hgpk_trigger_recal_show, hgpk_trigger_recal, false);
400
401static void hgpk_disconnect(struct psmouse *psmouse)
402{
403 struct hgpk_data *priv = psmouse->private;
404
405 device_remove_file(&psmouse->ps2dev.serio->dev,
406 &psmouse_attr_powered.dattr);
407
408 if (psmouse->model >= HGPK_MODEL_C)
409 device_remove_file(&psmouse->ps2dev.serio->dev,
410 &psmouse_attr_recalibrate.dattr);
411
412 psmouse_reset(psmouse);
413 kfree(priv);
414}
415
416static void hgpk_recalib_work(struct work_struct *work)
417{
418 struct delayed_work *w = to_delayed_work(work);
419 struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
420 struct psmouse *psmouse = priv->psmouse;
421
422 hgpk_dbg(psmouse, "recalibrating touchpad..\n");
423
424 if (hgpk_force_recalibrate(psmouse))
425 hgpk_err(psmouse, "recalibration failed!\n");
426}
427
428static int hgpk_register(struct psmouse *psmouse)
429{
430 struct input_dev *dev = psmouse->dev;
431 int err;
432
433
434 __clear_bit(BTN_MIDDLE, dev->keybit);
435
436
437 __set_bit(EV_KEY, dev->evbit);
438 __set_bit(EV_REL, dev->evbit);
439
440 __set_bit(REL_X, dev->relbit);
441 __set_bit(REL_Y, dev->relbit);
442
443 __set_bit(BTN_LEFT, dev->keybit);
444 __set_bit(BTN_RIGHT, dev->keybit);
445
446
447 psmouse->protocol_handler = hgpk_process_byte;
448 psmouse->poll = hgpk_poll;
449 psmouse->disconnect = hgpk_disconnect;
450 psmouse->reconnect = hgpk_reconnect;
451 psmouse->pktsize = 3;
452
453
454 psmouse->resync_time = 0;
455
456 psmouse->resetafter = 1024;
457
458 err = device_create_file(&psmouse->ps2dev.serio->dev,
459 &psmouse_attr_powered.dattr);
460 if (err) {
461 hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
462 return err;
463 }
464
465
466 if (psmouse->model >= HGPK_MODEL_C) {
467 err = device_create_file(&psmouse->ps2dev.serio->dev,
468 &psmouse_attr_recalibrate.dattr);
469 if (err) {
470 hgpk_err(psmouse,
471 "Failed creating 'recalibrate' sysfs node\n");
472 device_remove_file(&psmouse->ps2dev.serio->dev,
473 &psmouse_attr_powered.dattr);
474 return err;
475 }
476 }
477
478 return 0;
479}
480
481int hgpk_init(struct psmouse *psmouse)
482{
483 struct hgpk_data *priv;
484 int err = -ENOMEM;
485
486 priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
487 if (!priv)
488 goto alloc_fail;
489
490 psmouse->private = priv;
491 priv->psmouse = psmouse;
492 priv->powered = true;
493 INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
494
495 err = psmouse_reset(psmouse);
496 if (err)
497 goto init_fail;
498
499 err = hgpk_register(psmouse);
500 if (err)
501 goto init_fail;
502
503 return 0;
504
505init_fail:
506 kfree(priv);
507alloc_fail:
508 return err;
509}
510
511static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
512{
513 struct ps2dev *ps2dev = &psmouse->ps2dev;
514 unsigned char param[3];
515
516
517 if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
518 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
519 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
520 ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
521 return -EIO;
522 }
523
524 hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]);
525
526
527 if (param[0] != 0x67 || param[1] != 0x00)
528 return -ENODEV;
529
530 hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
531
532 return param[2];
533}
534
535int hgpk_detect(struct psmouse *psmouse, bool set_properties)
536{
537 int version;
538
539 version = hgpk_get_model(psmouse);
540 if (version < 0)
541 return version;
542
543 if (set_properties) {
544 psmouse->vendor = "ALPS";
545 psmouse->name = "HGPK";
546 psmouse->model = version;
547 }
548
549 return 0;
550}
551