Line data Source code
1 : /*
2 : * Input driver to ExplorerPS/2 device driver module.
3 : *
4 : * Copyright (c) 1999-2002 Vojtech Pavlik
5 : * Copyright (c) 2004 Dmitry Torokhov
6 : *
7 : * This program is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License version 2 as published by
9 : * the Free Software Foundation.
10 : */
11 :
12 : #define MOUSEDEV_MINOR_BASE 32
13 : #define MOUSEDEV_MINORS 32
14 : #define MOUSEDEV_MIX 31
15 :
16 : #include <linux/sched.h>
17 : #include <linux/slab.h>
18 : #include <linux/smp_lock.h>
19 : #include <linux/poll.h>
20 : #include <linux/module.h>
21 : #include <linux/init.h>
22 : #include <linux/input.h>
23 : #include <linux/random.h>
24 : #include <linux/major.h>
25 : #include <linux/device.h>
26 : #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
27 : #include <linux/miscdevice.h>
28 : #endif
29 :
30 : MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
31 : MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
32 : MODULE_LICENSE("GPL");
33 :
34 : #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
35 : #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
36 : #endif
37 : #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
38 : #define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
39 : #endif
40 :
41 1 : static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
42 : module_param(xres, uint, 0644);
43 : MODULE_PARM_DESC(xres, "Horizontal screen resolution");
44 :
45 1 : static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
46 : module_param(yres, uint, 0644);
47 : MODULE_PARM_DESC(yres, "Vertical screen resolution");
48 :
49 1 : static unsigned tap_time = 200;
50 : module_param(tap_time, uint, 0644);
51 1 : MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
52 :
53 : struct mousedev_hw_data {
54 : int dx, dy, dz;
55 : int x, y;
56 : int abs_event;
57 : unsigned long buttons;
58 : };
59 1 :
60 : struct mousedev {
61 : int exist;
62 : int open;
63 : int minor;
64 : struct input_handle handle;
65 : wait_queue_head_t wait;
66 : struct list_head client_list;
67 : spinlock_t client_lock; /* protects client_list */
68 : struct mutex mutex;
69 : struct device dev;
70 :
71 : struct list_head mixdev_node;
72 : int mixdev_open;
73 :
74 : struct mousedev_hw_data packet;
75 : unsigned int pkt_count;
76 : int old_x[4], old_y[4];
77 : int frac_dx, frac_dy;
78 : unsigned long touch;
79 : };
80 1 :
81 : enum mousedev_emul {
82 : MOUSEDEV_EMUL_PS2,
83 : MOUSEDEV_EMUL_IMPS,
84 : MOUSEDEV_EMUL_EXPS
85 : };
86 1 :
87 : struct mousedev_motion {
88 : int dx, dy, dz;
89 : unsigned long buttons;
90 : };
91 1 :
92 : #define PACKET_QUEUE_LEN 16
93 : struct mousedev_client {
94 : struct fasync_struct *fasync;
95 : struct mousedev *mousedev;
96 : struct list_head node;
97 :
98 : struct mousedev_motion packets[PACKET_QUEUE_LEN];
99 : unsigned int head, tail;
100 : spinlock_t packet_lock;
101 : int pos_x, pos_y;
102 :
103 : signed char ps2[6];
104 : unsigned char ready, buffer, bufsiz;
105 : unsigned char imexseq, impsseq;
106 : enum mousedev_emul mode;
107 : unsigned long last_buttons;
108 : };
109 :
110 : #define MOUSEDEV_SEQ_LEN 6
111 :
112 1 : static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
113 1 : static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
114 :
115 1 : static struct input_handler mousedev_handler;
116 :
117 1 : static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
118 1 : static DEFINE_MUTEX(mousedev_table_mutex);
119 1 : static struct mousedev *mousedev_mix;
120 1 : static LIST_HEAD(mousedev_mix_list);
121 :
122 : static void mixdev_open_devices(void);
123 : static void mixdev_close_devices(void);
124 :
125 : #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
126 : #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
127 :
128 : static void mousedev_touchpad_event(struct input_dev *dev,
129 : struct mousedev *mousedev,
130 : unsigned int code, int value)
131 1 : {
132 1 : int size, tmp;
133 : enum { FRACTION_DENOM = 128 };
134 :
135 1 : switch (code) {
136 1 :
137 3 : case ABS_X:
138 1 : fx(0) = value;
139 4 : if (mousedev->touch && mousedev->pkt_count >= 2) {
140 1 : size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
141 2 : if (size == 0)
142 1 : size = 256 * 2;
143 1 : tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
144 1 : tmp += mousedev->frac_dx;
145 1 : mousedev->packet.dx = tmp / FRACTION_DENOM;
146 1 : mousedev->frac_dx =
147 : tmp - mousedev->packet.dx * FRACTION_DENOM;
148 : }
149 1 : break;
150 1 :
151 3 : case ABS_Y:
152 1 : fy(0) = value;
153 4 : if (mousedev->touch && mousedev->pkt_count >= 2) {
154 : /* use X size to keep the same scale */
155 1 : size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
156 2 : if (size == 0)
157 1 : size = 256 * 2;
158 1 : tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
159 1 : tmp += mousedev->frac_dy;
160 1 : mousedev->packet.dy = tmp / FRACTION_DENOM;
161 1 : mousedev->frac_dy = tmp -
162 : mousedev->packet.dy * FRACTION_DENOM;
163 : }
164 1 : break;
165 1 : }
166 : }
167 2 :
168 : static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
169 : unsigned int code, int value)
170 : {
171 1 : int size;
172 :
173 1 : switch (code) {
174 1 :
175 3 : case ABS_X:
176 1 : size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
177 2 : if (size == 0)
178 6 : size = xres ? : 1;
179 2 : if (value > dev->absmax[ABS_X])
180 1 : value = dev->absmax[ABS_X];
181 2 : if (value < dev->absmin[ABS_X])
182 1 : value = dev->absmin[ABS_X];
183 1 : mousedev->packet.x =
184 : ((value - dev->absmin[ABS_X]) * xres) / size;
185 1 : mousedev->packet.abs_event = 1;
186 1 : break;
187 1 :
188 3 : case ABS_Y:
189 1 : size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
190 2 : if (size == 0)
191 6 : size = yres ? : 1;
192 2 : if (value > dev->absmax[ABS_Y])
193 1 : value = dev->absmax[ABS_Y];
194 2 : if (value < dev->absmin[ABS_Y])
195 1 : value = dev->absmin[ABS_Y];
196 1 : mousedev->packet.y = yres -
197 : ((value - dev->absmin[ABS_Y]) * yres) / size;
198 1 : mousedev->packet.abs_event = 1;
199 1 : break;
200 1 : }
201 : }
202 2 :
203 : static void mousedev_rel_event(struct mousedev *mousedev,
204 : unsigned int code, int value)
205 : {
206 1 : switch (code) {
207 4 : case REL_X:
208 1 : mousedev->packet.dx += value;
209 1 : break;
210 1 :
211 3 : case REL_Y:
212 1 : mousedev->packet.dy -= value;
213 1 : break;
214 1 :
215 3 : case REL_WHEEL:
216 1 : mousedev->packet.dz -= value;
217 1 : break;
218 1 : }
219 : }
220 2 :
221 : static void mousedev_key_event(struct mousedev *mousedev,
222 : unsigned int code, int value)
223 2 : {
224 : int index;
225 :
226 : switch (code) {
227 :
228 6 : case BTN_TOUCH:
229 6 : case BTN_0:
230 10 : case BTN_LEFT: index = 0; break;
231 2 :
232 8 : case BTN_STYLUS:
233 8 : case BTN_1:
234 10 : case BTN_RIGHT: index = 1; break;
235 2 :
236 8 : case BTN_2:
237 8 : case BTN_FORWARD:
238 8 : case BTN_STYLUS2:
239 10 : case BTN_MIDDLE: index = 2; break;
240 2 :
241 8 : case BTN_3:
242 8 : case BTN_BACK:
243 10 : case BTN_SIDE: index = 3; break;
244 2 :
245 8 : case BTN_4:
246 10 : case BTN_EXTRA: index = 4; break;
247 2 :
248 4 : default: return;
249 2 : }
250 2 :
251 6 : if (value) {
252 4 : set_bit(index, &mousedev->packet.buttons);
253 4 : set_bit(index, &mousedev_mix->packet.buttons);
254 : } else {
255 4 : clear_bit(index, &mousedev->packet.buttons);
256 4 : clear_bit(index, &mousedev_mix->packet.buttons);
257 : }
258 4 : }
259 :
260 : static void mousedev_notify_readers(struct mousedev *mousedev,
261 : struct mousedev_hw_data *packet)
262 4 : {
263 4 : struct mousedev_client *client;
264 4 : struct mousedev_motion *p;
265 4 : unsigned int new_head;
266 8 : int wake_readers = 0;
267 4 :
268 12 : rcu_read_lock();
269 44 : list_for_each_entry_rcu(client, &mousedev->client_list, node) {
270 12 :
271 4 : /* Just acquire the lock, interrupts already disabled */
272 8 : spin_lock(&client->packet_lock);
273 :
274 8 : p = &client->packets[client->head];
275 20 : if (client->ready && p->buttons != mousedev->packet.buttons) {
276 4 : new_head = (client->head + 1) % PACKET_QUEUE_LEN;
277 8 : if (new_head != client->tail) {
278 12 : p = &client->packets[client->head = new_head];
279 4 : memset(p, 0, sizeof(struct mousedev_motion));
280 : }
281 : }
282 :
283 8 : if (packet->abs_event) {
284 4 : p->dx += packet->x - client->pos_x;
285 4 : p->dy += packet->y - client->pos_y;
286 4 : client->pos_x = packet->x;
287 4 : client->pos_y = packet->y;
288 : }
289 :
290 4 : client->pos_x += packet->dx;
291 44 : client->pos_x = client->pos_x < 0 ?
292 : 0 : (client->pos_x >= xres ? xres : client->pos_x);
293 4 : client->pos_y += packet->dy;
294 44 : client->pos_y = client->pos_y < 0 ?
295 : 0 : (client->pos_y >= yres ? yres : client->pos_y);
296 :
297 4 : p->dx += packet->dx;
298 4 : p->dy += packet->dy;
299 4 : p->dz += packet->dz;
300 4 : p->buttons = mousedev->packet.buttons;
301 :
302 24 : if (p->dx || p->dy || p->dz ||
303 : p->buttons != client->last_buttons)
304 4 : client->ready = 1;
305 :
306 8 : spin_unlock(&client->packet_lock);
307 :
308 12 : if (client->ready) {
309 4 : kill_fasync(&client->fasync, SIGIO, POLL_IN);
310 4 : wake_readers = 1;
311 : }
312 : }
313 8 : rcu_read_unlock();
314 :
315 8 : if (wake_readers)
316 4 : wake_up_interruptible(&mousedev->wait);
317 4 : }
318 :
319 : static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
320 : {
321 3 : if (!value) {
322 : if (mousedev->touch &&
323 5 : time_before(jiffies,
324 : mousedev->touch + msecs_to_jiffies(tap_time))) {
325 : /*
326 : * Toggle left button to emulate tap.
327 : * We rely on the fact that mousedev_mix always has 0
328 : * motion packet so we won't mess current position.
329 : */
330 2 : set_bit(0, &mousedev->packet.buttons);
331 2 : set_bit(0, &mousedev_mix->packet.buttons);
332 2 : mousedev_notify_readers(mousedev, &mousedev_mix->packet);
333 2 : mousedev_notify_readers(mousedev_mix,
334 : &mousedev_mix->packet);
335 2 : clear_bit(0, &mousedev->packet.buttons);
336 2 : clear_bit(0, &mousedev_mix->packet.buttons);
337 : }
338 4 : mousedev->touch = mousedev->pkt_count = 0;
339 2 : mousedev->frac_dx = 0;
340 2 : mousedev->frac_dy = 0;
341 :
342 2 : } else if (!mousedev->touch)
343 1 : mousedev->touch = jiffies;
344 2 : }
345 :
346 : static void mousedev_event(struct input_handle *handle,
347 : unsigned int type, unsigned int code, int value)
348 : {
349 3 : struct mousedev *mousedev = handle->private;
350 1 :
351 2 : switch (type) {
352 2 :
353 4 : case EV_ABS:
354 1 : /* Ignore joysticks */
355 4 : if (test_bit(BTN_TRIGGER, handle->dev->keybit))
356 1 : return;
357 :
358 4 : if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
359 2 : mousedev_touchpad_event(handle->dev,
360 : mousedev, code, value);
361 : else
362 2 : mousedev_abs_event(handle->dev, mousedev, code, value);
363 :
364 2 : break;
365 1 :
366 3 : case EV_REL:
367 2 : mousedev_rel_event(mousedev, code, value);
368 1 : break;
369 1 :
370 3 : case EV_KEY:
371 2 : if (value != 2) {
372 6 : if (code == BTN_TOUCH &&
373 : test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
374 3 : mousedev_touchpad_touch(mousedev, value);
375 : else
376 8 : mousedev_key_event(mousedev, code, value);
377 : }
378 4 : break;
379 1 :
380 3 : case EV_SYN:
381 2 : if (code == SYN_REPORT) {
382 2 : if (mousedev->touch) {
383 1 : mousedev->pkt_count++;
384 : /*
385 : * Input system eats duplicate events,
386 : * but we need all of them to do correct
387 : * averaging so apply present one forward
388 : */
389 1 : fx(0) = fx(1);
390 1 : fy(0) = fy(1);
391 : }
392 :
393 2 : mousedev_notify_readers(mousedev, &mousedev->packet);
394 2 : mousedev_notify_readers(mousedev_mix, &mousedev->packet);
395 :
396 5 : mousedev->packet.dx = mousedev->packet.dy =
397 : mousedev->packet.dz = 0;
398 1 : mousedev->packet.abs_event = 0;
399 : }
400 2 : break;
401 1 : }
402 : }
403 9 :
404 : static int mousedev_fasync(int fd, struct file *file, int on)
405 : {
406 3 : struct mousedev_client *client = file->private_data;
407 1 :
408 2 : return fasync_helper(fd, file, on, &client->fasync);
409 : }
410 :
411 : static void mousedev_free(struct device *dev)
412 : {
413 0 : struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
414 0 :
415 0 : input_put_device(mousedev->handle.dev);
416 0 : kfree(mousedev);
417 0 : }
418 :
419 : static int mousedev_open_device(struct mousedev *mousedev)
420 : {
421 2 : int retval;
422 2 :
423 2 : retval = mutex_lock_interruptible(&mousedev->mutex);
424 4 : if (retval)
425 2 : return retval;
426 :
427 4 : if (mousedev->minor == MOUSEDEV_MIX)
428 6 : mixdev_open_devices();
429 4 : else if (!mousedev->exist)
430 2 : retval = -ENODEV;
431 8 : else if (!mousedev->open++) {
432 2 : retval = input_open_device(&mousedev->handle);
433 4 : if (retval)
434 2 : mousedev->open--;
435 : }
436 :
437 4 : mutex_unlock(&mousedev->mutex);
438 4 : return retval;
439 : }
440 :
441 : static void mousedev_close_device(struct mousedev *mousedev)
442 : {
443 2 : mutex_lock(&mousedev->mutex);
444 :
445 4 : if (mousedev->minor == MOUSEDEV_MIX)
446 6 : mixdev_close_devices();
447 10 : else if (mousedev->exist && !--mousedev->open)
448 2 : input_close_device(&mousedev->handle);
449 :
450 4 : mutex_unlock(&mousedev->mutex);
451 4 : }
452 :
453 : /*
454 : * Open all available devices so they can all be multiplexed in one.
455 : * stream. Note that this function is called with mousedev_mix->mutex
456 : * held.
457 : */
458 : static void mixdev_open_devices(void)
459 : {
460 2 : struct mousedev *mousedev;
461 2 :
462 10 : if (mousedev_mix->open++)
463 4 : return;
464 2 :
465 20 : list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
466 10 : if (!mousedev->mixdev_open) {
467 8 : if (mousedev_open_device(mousedev))
468 2 : continue;
469 :
470 2 : mousedev->mixdev_open = 1;
471 : }
472 2 : }
473 : }
474 4 :
475 : /*
476 : * Close all devices that were opened as part of multiplexed
477 : * device. Note that this function is called with mousedev_mix->mutex
478 : * held.
479 : */
480 : static void mixdev_close_devices(void)
481 : {
482 2 : struct mousedev *mousedev;
483 2 :
484 8 : if (--mousedev_mix->open)
485 2 : return;
486 :
487 20 : list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
488 10 : if (mousedev->mixdev_open) {
489 4 : mousedev->mixdev_open = 0;
490 2 : mousedev_close_device(mousedev);
491 : }
492 : }
493 : }
494 2 :
495 :
496 : static void mousedev_attach_client(struct mousedev *mousedev,
497 : struct mousedev_client *client)
498 : {
499 2 : spin_lock(&mousedev->client_lock);
500 2 : list_add_tail_rcu(&client->node, &mousedev->client_list);
501 2 : spin_unlock(&mousedev->client_lock);
502 1 : synchronize_rcu();
503 1 : }
504 :
505 : static void mousedev_detach_client(struct mousedev *mousedev,
506 : struct mousedev_client *client)
507 : {
508 4 : spin_lock(&mousedev->client_lock);
509 4 : list_del_rcu(&client->node);
510 4 : spin_unlock(&mousedev->client_lock);
511 2 : synchronize_rcu();
512 2 : }
513 :
514 : static int mousedev_release(struct inode *inode, struct file *file)
515 : {
516 3 : struct mousedev_client *client = file->private_data;
517 2 : struct mousedev *mousedev = client->mousedev;
518 :
519 2 : mousedev_detach_client(mousedev, client);
520 1 : kfree(client);
521 :
522 3 : mousedev_close_device(mousedev);
523 1 : put_device(&mousedev->dev);
524 :
525 1 : return 0;
526 : }
527 :
528 : static int mousedev_open(struct inode *inode, struct file *file)
529 : {
530 1 : struct mousedev_client *client;
531 1 : struct mousedev *mousedev;
532 1 : int error;
533 1 : int i;
534 1 :
535 1 : #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
536 5 : if (imajor(inode) == MISC_MAJOR)
537 2 : i = MOUSEDEV_MIX;
538 : else
539 : #endif
540 3 : i = iminor(inode) - MOUSEDEV_MINOR_BASE;
541 :
542 4 : if (i >= MOUSEDEV_MINORS)
543 2 : return -ENODEV;
544 :
545 2 : lock_kernel();
546 2 : error = mutex_lock_interruptible(&mousedev_table_mutex);
547 4 : if (error) {
548 2 : unlock_kernel();
549 2 : return error;
550 : }
551 2 : mousedev = mousedev_table[i];
552 4 : if (mousedev)
553 2 : get_device(&mousedev->dev);
554 2 : mutex_unlock(&mousedev_table_mutex);
555 :
556 4 : if (!mousedev) {
557 2 : unlock_kernel();
558 2 : return -ENODEV;
559 : }
560 :
561 5 : client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
562 2 : if (!client) {
563 1 : error = -ENOMEM;
564 1 : goto err_put_mousedev;
565 : }
566 :
567 4 : spin_lock_init(&client->packet_lock);
568 1 : client->pos_x = xres / 2;
569 1 : client->pos_y = yres / 2;
570 1 : client->mousedev = mousedev;
571 2 : mousedev_attach_client(mousedev, client);
572 :
573 3 : error = mousedev_open_device(mousedev);
574 2 : if (error)
575 1 : goto err_free_client;
576 :
577 1 : file->private_data = client;
578 1 : unlock_kernel();
579 1 : return 0;
580 1 :
581 : err_free_client:
582 2 : mousedev_detach_client(mousedev, client);
583 1 : kfree(client);
584 : err_put_mousedev:
585 3 : put_device(&mousedev->dev);
586 2 : unlock_kernel();
587 2 : return error;
588 : }
589 :
590 : static inline int mousedev_limit_delta(int delta, int limit)
591 : {
592 88 : return delta > limit ? limit : (delta < -limit ? -limit : delta);
593 : }
594 :
595 : static void mousedev_packet(struct mousedev_client *client,
596 : signed char *ps2_data)
597 2 : {
598 6 : struct mousedev_motion *p = &client->packets[client->tail];
599 2 :
600 26 : ps2_data[0] = 0x08 |
601 2 : ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
602 6 : ps2_data[1] = mousedev_limit_delta(p->dx, 127);
603 6 : ps2_data[2] = mousedev_limit_delta(p->dy, 127);
604 2 : p->dx -= ps2_data[1];
605 2 : p->dy -= ps2_data[2];
606 :
607 : switch (client->mode) {
608 8 : case MOUSEDEV_EMUL_EXPS:
609 6 : ps2_data[3] = mousedev_limit_delta(p->dz, 7);
610 2 : p->dz -= ps2_data[3];
611 4 : ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
612 2 : client->bufsiz = 4;
613 2 : break;
614 2 :
615 8 : case MOUSEDEV_EMUL_IMPS:
616 2 : ps2_data[0] |=
617 : ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
618 6 : ps2_data[3] = mousedev_limit_delta(p->dz, 127);
619 2 : p->dz -= ps2_data[3];
620 2 : client->bufsiz = 4;
621 2 : break;
622 2 :
623 2 : case MOUSEDEV_EMUL_PS2:
624 : default:
625 4 : ps2_data[0] |=
626 : ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
627 2 : p->dz = 0;
628 2 : client->bufsiz = 3;
629 2 : break;
630 : }
631 :
632 24 : if (!p->dx && !p->dy && !p->dz) {
633 12 : if (client->tail == client->head) {
634 6 : client->ready = 0;
635 6 : client->last_buttons = p->buttons;
636 : } else
637 6 : client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
638 6 : }
639 : }
640 :
641 : static void mousedev_generate_response(struct mousedev_client *client,
642 : int command)
643 1 : {
644 1 : client->ps2[0] = 0xfa; /* ACK */
645 :
646 : switch (command) {
647 :
648 3 : case 0xeb: /* Poll */
649 4 : mousedev_packet(client, &client->ps2[1]);
650 2 : client->bufsiz++; /* account for leading ACK */
651 1 : break;
652 1 :
653 3 : case 0xf2: /* Get ID */
654 1 : switch (client->mode) {
655 5 : case MOUSEDEV_EMUL_PS2:
656 1 : client->ps2[1] = 0;
657 1 : break;
658 5 : case MOUSEDEV_EMUL_IMPS:
659 1 : client->ps2[1] = 3;
660 1 : break;
661 5 : case MOUSEDEV_EMUL_EXPS:
662 1 : client->ps2[1] = 4;
663 1 : break;
664 1 : }
665 1 : client->bufsiz = 2;
666 2 : break;
667 1 :
668 3 : case 0xe9: /* Get info */
669 3 : client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
670 1 : client->bufsiz = 4;
671 1 : break;
672 1 :
673 3 : case 0xff: /* Reset */
674 3 : client->impsseq = client->imexseq = 0;
675 1 : client->mode = MOUSEDEV_EMUL_PS2;
676 2 : client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
677 1 : client->bufsiz = 3;
678 1 : break;
679 1 :
680 1 : default:
681 2 : client->bufsiz = 1;
682 1 : break;
683 : }
684 2 : client->buffer = client->bufsiz;
685 2 : }
686 :
687 : static ssize_t mousedev_write(struct file *file, const char __user *buffer,
688 : size_t count, loff_t *ppos)
689 : {
690 3 : struct mousedev_client *client = file->private_data;
691 1 : unsigned char c;
692 1 : unsigned int i;
693 1 :
694 6 : for (i = 0; i < count; i++) {
695 1 :
696 11 : if (get_user(c, buffer + i))
697 2 : return -EFAULT;
698 :
699 2 : spin_lock_irq(&client->packet_lock);
700 :
701 3 : if (c == mousedev_imex_seq[client->imexseq]) {
702 5 : if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
703 1 : client->imexseq = 0;
704 1 : client->mode = MOUSEDEV_EMUL_EXPS;
705 : }
706 : } else
707 1 : client->imexseq = 0;
708 :
709 3 : if (c == mousedev_imps_seq[client->impsseq]) {
710 5 : if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
711 1 : client->impsseq = 0;
712 1 : client->mode = MOUSEDEV_EMUL_IMPS;
713 : }
714 : } else
715 1 : client->impsseq = 0;
716 :
717 3 : mousedev_generate_response(client, c);
718 :
719 2 : spin_unlock_irq(&client->packet_lock);
720 : }
721 :
722 1 : kill_fasync(&client->fasync, SIGIO, POLL_IN);
723 1 : wake_up_interruptible(&client->mousedev->wait);
724 :
725 1 : return count;
726 : }
727 :
728 : static ssize_t mousedev_read(struct file *file, char __user *buffer,
729 : size_t count, loff_t *ppos)
730 1 : {
731 3 : struct mousedev_client *client = file->private_data;
732 2 : struct mousedev *mousedev = client->mousedev;
733 1 : signed char data[sizeof(client->ps2)];
734 2 : int retval = 0;
735 1 :
736 7 : if (!client->ready && !client->buffer && mousedev->exist &&
737 1 : (file->f_flags & O_NONBLOCK))
738 2 : return -EAGAIN;
739 1 :
740 34 : retval = wait_event_interruptible(mousedev->wait,
741 3 : !mousedev->exist || client->ready || client->buffer);
742 7 : if (retval)
743 3 : return retval;
744 :
745 6 : if (!mousedev->exist)
746 3 : return -ENODEV;
747 :
748 6 : spin_lock_irq(&client->packet_lock);
749 :
750 6 : if (!client->buffer && client->ready) {
751 4 : mousedev_packet(client, client->ps2);
752 1 : client->buffer = client->bufsiz;
753 : }
754 :
755 6 : if (count > client->buffer)
756 4 : count = client->buffer;
757 :
758 6 : memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
759 4 : client->buffer -= count;
760 :
761 4 : spin_unlock_irq(&client->packet_lock);
762 :
763 4 : if (copy_to_user(buffer, data, count))
764 1 : return -EFAULT;
765 :
766 1 : return count;
767 : }
768 :
769 : /* No kernel lock - fine */
770 : static unsigned int mousedev_poll(struct file *file, poll_table *wait)
771 : {
772 3 : struct mousedev_client *client = file->private_data;
773 2 : struct mousedev *mousedev = client->mousedev;
774 :
775 2 : poll_wait(file, &mousedev->wait, wait);
776 11 : return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
777 : (mousedev->exist ? 0 : (POLLHUP | POLLERR));
778 : }
779 :
780 1 : static const struct file_operations mousedev_fops = {
781 : .owner = THIS_MODULE,
782 : .read = mousedev_read,
783 : .write = mousedev_write,
784 : .poll = mousedev_poll,
785 : .open = mousedev_open,
786 : .release = mousedev_release,
787 : .fasync = mousedev_fasync,
788 : };
789 :
790 : static int mousedev_install_chrdev(struct mousedev *mousedev)
791 : {
792 2 : mousedev_table[mousedev->minor] = mousedev;
793 2 : return 0;
794 : }
795 :
796 : static void mousedev_remove_chrdev(struct mousedev *mousedev)
797 : {
798 9 : mutex_lock(&mousedev_table_mutex);
799 9 : mousedev_table[mousedev->minor] = NULL;
800 9 : mutex_unlock(&mousedev_table_mutex);
801 9 : }
802 :
803 : /*
804 : * Mark device non-existent. This disables writes, ioctls and
805 : * prevents new users from opening the device. Already posted
806 : * blocking reads will stay, however new ones will fail.
807 : */
808 : static void mousedev_mark_dead(struct mousedev *mousedev)
809 : {
810 9 : mutex_lock(&mousedev->mutex);
811 9 : mousedev->exist = 0;
812 9 : mutex_unlock(&mousedev->mutex);
813 9 : }
814 :
815 : /*
816 : * Wake up users waiting for IO so they can disconnect from
817 : * dead device.
818 : */
819 : static void mousedev_hangup(struct mousedev *mousedev)
820 : {
821 9 : struct mousedev_client *client;
822 9 :
823 27 : spin_lock(&mousedev->client_lock);
824 72 : list_for_each_entry(client, &mousedev->client_list, node)
825 18 : kill_fasync(&client->fasync, SIGIO, POLL_HUP);
826 36 : spin_unlock(&mousedev->client_lock);
827 :
828 9 : wake_up_interruptible(&mousedev->wait);
829 9 : }
830 :
831 : static void mousedev_cleanup(struct mousedev *mousedev)
832 : {
833 18 : struct input_handle *handle = &mousedev->handle;
834 :
835 18 : mousedev_mark_dead(mousedev);
836 18 : mousedev_hangup(mousedev);
837 18 : mousedev_remove_chrdev(mousedev);
838 :
839 : /* mousedev is marked dead so no one else accesses mousedev->open */
840 18 : if (mousedev->open)
841 9 : input_close_device(handle);
842 9 : }
843 :
844 : static struct mousedev *mousedev_create(struct input_dev *dev,
845 : struct input_handler *handler,
846 : int minor)
847 2 : {
848 2 : struct mousedev *mousedev;
849 2 : int error;
850 2 :
851 8 : mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
852 6 : if (!mousedev) {
853 4 : error = -ENOMEM;
854 2 : goto err_out;
855 : }
856 :
857 4 : INIT_LIST_HEAD(&mousedev->client_list);
858 4 : INIT_LIST_HEAD(&mousedev->mixdev_node);
859 8 : spin_lock_init(&mousedev->client_lock);
860 2 : mutex_init(&mousedev->mutex);
861 : lockdep_set_subclass(&mousedev->mutex,
862 : minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
863 2 : init_waitqueue_head(&mousedev->wait);
864 :
865 4 : if (minor == MOUSEDEV_MIX)
866 2 : dev_set_name(&mousedev->dev, "mice");
867 : else
868 2 : dev_set_name(&mousedev->dev, "mouse%d", minor);
869 :
870 2 : mousedev->minor = minor;
871 2 : mousedev->exist = 1;
872 4 : mousedev->handle.dev = input_get_device(dev);
873 4 : mousedev->handle.name = dev_name(&mousedev->dev);
874 2 : mousedev->handle.handler = handler;
875 2 : mousedev->handle.private = mousedev;
876 :
877 2 : mousedev->dev.class = &input_class;
878 4 : if (dev)
879 2 : mousedev->dev.parent = &dev->dev;
880 2 : mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
881 2 : mousedev->dev.release = mousedev_free;
882 2 : device_initialize(&mousedev->dev);
883 :
884 4 : if (minor != MOUSEDEV_MIX) {
885 2 : error = input_register_handle(&mousedev->handle);
886 4 : if (error)
887 2 : goto err_free_mousedev;
888 : }
889 :
890 4 : error = mousedev_install_chrdev(mousedev);
891 4 : if (error)
892 2 : goto err_unregister_handle;
893 :
894 2 : error = device_add(&mousedev->dev);
895 4 : if (error)
896 2 : goto err_cleanup_mousedev;
897 :
898 2 : return mousedev;
899 2 :
900 : err_cleanup_mousedev:
901 4 : mousedev_cleanup(mousedev);
902 : err_unregister_handle:
903 10 : if (minor != MOUSEDEV_MIX)
904 4 : input_unregister_handle(&mousedev->handle);
905 : err_free_mousedev:
906 6 : put_device(&mousedev->dev);
907 : err_out:
908 24 : return ERR_PTR(error);
909 4 : }
910 :
911 : static void mousedev_destroy(struct mousedev *mousedev)
912 : {
913 7 : device_del(&mousedev->dev);
914 14 : mousedev_cleanup(mousedev);
915 14 : if (mousedev->minor != MOUSEDEV_MIX)
916 7 : input_unregister_handle(&mousedev->handle);
917 7 : put_device(&mousedev->dev);
918 7 : }
919 :
920 : static int mixdev_add_device(struct mousedev *mousedev)
921 : {
922 1 : int retval;
923 :
924 1 : retval = mutex_lock_interruptible(&mousedev_mix->mutex);
925 2 : if (retval)
926 1 : return retval;
927 :
928 2 : if (mousedev_mix->open) {
929 3 : retval = mousedev_open_device(mousedev);
930 2 : if (retval)
931 1 : goto out;
932 :
933 1 : mousedev->mixdev_open = 1;
934 : }
935 :
936 2 : get_device(&mousedev->dev);
937 4 : list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
938 :
939 1 : out:
940 2 : mutex_unlock(&mousedev_mix->mutex);
941 2 : return retval;
942 : }
943 :
944 : static void mixdev_remove_device(struct mousedev *mousedev)
945 : {
946 1 : mutex_lock(&mousedev_mix->mutex);
947 :
948 2 : if (mousedev->mixdev_open) {
949 1 : mousedev->mixdev_open = 0;
950 3 : mousedev_close_device(mousedev);
951 : }
952 :
953 4 : list_del_init(&mousedev->mixdev_node);
954 1 : mutex_unlock(&mousedev_mix->mutex);
955 :
956 1 : put_device(&mousedev->dev);
957 1 : }
958 :
959 : static int mousedev_connect(struct input_handler *handler,
960 : struct input_dev *dev,
961 : const struct input_device_id *id)
962 1 : {
963 1 : struct mousedev *mousedev;
964 1 : int minor;
965 1 : int error;
966 1 :
967 5 : for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
968 4 : if (!mousedev_table[minor])
969 2 : break;
970 :
971 2 : if (minor == MOUSEDEV_MINORS) {
972 1 : printk(KERN_ERR "mousedev: no more free mousedev devices\n");
973 2 : return -ENFILE;
974 : }
975 :
976 3 : mousedev = mousedev_create(dev, handler, minor);
977 4 : if (IS_ERR(mousedev))
978 3 : return PTR_ERR(mousedev);
979 :
980 4 : error = mixdev_add_device(mousedev);
981 2 : if (error) {
982 2 : mousedev_destroy(mousedev);
983 1 : return error;
984 : }
985 :
986 1 : return 0;
987 : }
988 :
989 : static void mousedev_disconnect(struct input_handle *handle)
990 : {
991 3 : struct mousedev *mousedev = handle->private;
992 :
993 2 : mixdev_remove_device(mousedev);
994 2 : mousedev_destroy(mousedev);
995 1 : }
996 :
997 1 : static const struct input_device_id mousedev_ids[] = {
998 : {
999 : .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
1000 : INPUT_DEVICE_ID_MATCH_KEYBIT |
1001 : INPUT_DEVICE_ID_MATCH_RELBIT,
1002 : .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
1003 : .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
1004 : .relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },
1005 : }, /* A mouse like device, at least one button,
1006 : two relative axes */
1007 : {
1008 : .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
1009 : INPUT_DEVICE_ID_MATCH_RELBIT,
1010 : .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
1011 : .relbit = { BIT_MASK(REL_WHEEL) },
1012 : }, /* A separate scrollwheel */
1013 : {
1014 : .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
1015 : INPUT_DEVICE_ID_MATCH_KEYBIT |
1016 : INPUT_DEVICE_ID_MATCH_ABSBIT,
1017 : .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
1018 : .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
1019 : .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
1020 : }, /* A tablet like device, at least touch detection,
1021 : two absolute axes */
1022 : {
1023 : .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
1024 : INPUT_DEVICE_ID_MATCH_KEYBIT |
1025 : INPUT_DEVICE_ID_MATCH_ABSBIT,
1026 : .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
1027 : .keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =
1028 : BIT_MASK(BTN_TOOL_FINGER) },
1029 : .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
1030 : BIT_MASK(ABS_PRESSURE) |
1031 : BIT_MASK(ABS_TOOL_WIDTH) },
1032 : }, /* A touchpad */
1033 : {
1034 : .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
1035 : INPUT_DEVICE_ID_MATCH_KEYBIT |
1036 : INPUT_DEVICE_ID_MATCH_ABSBIT,
1037 : .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
1038 : .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
1039 : .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
1040 : }, /* Mouse-like device with absolute X and Y but ordinary
1041 : clicks, like hp ILO2 High Performance mouse */
1042 :
1043 : { }, /* Terminating entry */
1044 : };
1045 :
1046 : MODULE_DEVICE_TABLE(input, mousedev_ids);
1047 :
1048 1 : static struct input_handler mousedev_handler = {
1049 : .event = mousedev_event,
1050 : .connect = mousedev_connect,
1051 : .disconnect = mousedev_disconnect,
1052 : .fops = &mousedev_fops,
1053 : .minor = MOUSEDEV_MINOR_BASE,
1054 : .name = "mousedev",
1055 : .id_table = mousedev_ids,
1056 : };
1057 :
1058 : #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
1059 1 : static struct miscdevice psaux_mouse = {
1060 : PSMOUSE_MINOR, "psaux", &mousedev_fops
1061 : };
1062 1 : static int psaux_registered;
1063 : #endif
1064 :
1065 : static int __init mousedev_init(void)
1066 : {
1067 1 : int error;
1068 1 :
1069 4 : mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
1070 4 : if (IS_ERR(mousedev_mix))
1071 3 : return PTR_ERR(mousedev_mix);
1072 :
1073 1 : error = input_register_handler(&mousedev_handler);
1074 2 : if (error) {
1075 2 : mousedev_destroy(mousedev_mix);
1076 1 : return error;
1077 : }
1078 :
1079 : #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
1080 2 : error = misc_register(&psaux_mouse);
1081 2 : if (error)
1082 1 : printk(KERN_WARNING "mice: could not register psaux device, "
1083 : "error: %d\n", error);
1084 : else
1085 1 : psaux_registered = 1;
1086 : #endif
1087 :
1088 1 : printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
1089 :
1090 1 : return 0;
1091 : }
1092 :
1093 : static void __exit mousedev_exit(void)
1094 : {
1095 : #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
1096 4 : if (psaux_registered)
1097 4 : misc_deregister(&psaux_mouse);
1098 : #endif
1099 4 : input_unregister_handler(&mousedev_handler);
1100 8 : mousedev_destroy(mousedev_mix);
1101 2 : }
1102 :
1103 : module_init(mousedev_init);
1104 : module_exit(mousedev_exit);
|