~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/input/mousedev.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * $Id: mousedev.c,v 1.15 2000/08/14 21:05:26 vojtech Exp $
  3  *
  4  *  Copyright (c) 1999-2000 Vojtech Pavlik
  5  *
  6  *  Input driver to PS/2 or ImPS/2 device driver module.
  7  *
  8  *  Sponsored by SuSE
  9  */
 10 
 11 /*
 12  * This program is free software; you can redistribute it and/or modify
 13  * it under the terms of the GNU General Public License as published by
 14  * the Free Software Foundation; either version 2 of the License, or 
 15  * (at your option) any later version.
 16  * 
 17  * This program is distributed in the hope that it will be useful,
 18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20  * GNU General Public License for more details.
 21  * 
 22  * You should have received a copy of the GNU General Public License
 23  * along with this program; if not, write to the Free Software
 24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 25  * 
 26  * Should you need to contact me, the author, you can do so either by
 27  * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 28  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 29  */
 30 
 31 #define MOUSEDEV_MINOR_BASE     32
 32 #define MOUSEDEV_MINORS         32
 33 #define MOUSEDEV_MIX            31
 34 
 35 #include <linux/malloc.h>
 36 #include <linux/poll.h>
 37 #include <linux/module.h>
 38 #include <linux/init.h>
 39 #include <linux/input.h>
 40 #include <linux/config.h>
 41 #include <linux/smp_lock.h>
 42 #include <linux/random.h>
 43 
 44 #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
 45 #define CONFIG_INPUT_MOUSEDEV_SCREEN_X  1024
 46 #endif
 47 #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
 48 #define CONFIG_INPUT_MOUSEDEV_SCREEN_Y  768
 49 #endif
 50 
 51 struct mousedev {
 52         int exist;
 53         int open;
 54         int minor;
 55         wait_queue_head_t wait;
 56         struct mousedev_list *list;
 57         struct input_handle handle;
 58         devfs_handle_t devfs;
 59 };
 60 
 61 struct mousedev_list {
 62         struct fasync_struct *fasync;
 63         struct mousedev *mousedev;
 64         struct mousedev_list *next;
 65         int dx, dy, dz, oldx, oldy;
 66         signed char ps2[6];
 67         unsigned long buttons;
 68         unsigned char ready, buffer, bufsiz;
 69         unsigned char mode, genseq, impseq;
 70 };
 71 
 72 #define MOUSEDEV_GENIUS_LEN     5
 73 #define MOUSEDEV_IMPS_LEN       6
 74 
 75 static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
 76 static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
 77 
 78 static struct input_handler mousedev_handler;
 79 
 80 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 81 static struct mousedev mousedev_mix;
 82 
 83 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 84 {
 85         struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
 86         struct mousedev **mousedev = mousedevs;
 87         struct mousedev_list *list;
 88         int index, size;
 89 
 90         add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
 91 
 92         while (*mousedev) {
 93                 list = (*mousedev)->list;
 94                 while (list) {
 95                         switch (type) {
 96                                 case EV_ABS:
 97                                         if (test_bit(BTN_TRIGGER, handle->dev->keybit))
 98                                                 break;
 99                                         switch (code) {
100                                                 case ABS_X:     
101                                                         size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
102                                                         list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
103                                                         list->oldx += list->dx * size;
104                                                         break;
105                                                 case ABS_Y:
106                                                         size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
107                                                         list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
108                                                         list->oldy -= list->dy * size;
109                                                         break;
110                                         }
111                                         break;
112 
113                                 case EV_REL:
114                                         switch (code) {
115                                                 case REL_X:     list->dx += value; break;
116                                                 case REL_Y:     list->dy -= value; break;
117                                                 case REL_WHEEL: if (list->mode) list->dz -= value; break;
118                                         }
119                                         break;
120 
121                                 case EV_KEY:
122                                         switch (code) {
123                                                 case BTN_0:
124                                                 case BTN_TOUCH:
125                                                 case BTN_LEFT:   index = 0; break;
126                                                 case BTN_4:
127                                                 case BTN_EXTRA:  if (list->mode > 1) { index = 4; break; }
128                                                 case BTN_STYLUS:
129                                                 case BTN_1:
130                                                 case BTN_RIGHT:  index = 1; break;
131                                                 case BTN_3:
132                                                 case BTN_SIDE:   if (list->mode > 1) { index = 3; break; }
133                                                 case BTN_2:
134                                                 case BTN_STYLUS2:
135                                                 case BTN_MIDDLE: index = 2; break;      
136                                                 default: return;
137                                         }
138                                         switch (value) {
139                                                 case 0: clear_bit(index, &list->buttons); break;
140                                                 case 1: set_bit(index, &list->buttons); break;
141                                                 case 2: return;
142                                         }
143                                         break;
144                         }
145                                         
146                         list->ready = 1;
147 
148                         kill_fasync(&list->fasync, SIGIO, POLL_IN);
149 
150                         list = list->next;
151                 }
152 
153                 wake_up_interruptible(&((*mousedev)->wait));
154                 mousedev++;
155         }
156 }
157 
158 static int mousedev_fasync(int fd, struct file *file, int on)
159 {
160         int retval;
161         struct mousedev_list *list = file->private_data;
162         retval = fasync_helper(fd, file, on, &list->fasync);
163         return retval < 0 ? retval : 0;
164 }
165 
166 static int mousedev_release(struct inode * inode, struct file * file)
167 {
168         struct mousedev_list *list = file->private_data;
169         struct mousedev_list **listptr;
170 
171         lock_kernel();
172         listptr = &list->mousedev->list;
173         mousedev_fasync(-1, file, 0);
174 
175         while (*listptr && (*listptr != list))
176                 listptr = &((*listptr)->next);
177         *listptr = (*listptr)->next;
178 
179         if (!--list->mousedev->open) {
180                 if (list->mousedev->minor == MOUSEDEV_MIX) {
181                         struct input_handle *handle = mousedev_handler.handle;
182                         while (handle) {
183                                 struct mousedev *mousedev = handle->private;
184                                 if (!mousedev->open) {
185                                         if (mousedev->exist) {
186                                                 input_close_device(&mousedev->handle);
187                                         } else {
188                                                 input_unregister_minor(mousedev->devfs);
189                                                 mousedev_table[mousedev->minor] = NULL;
190                                                 kfree(mousedev);
191                                         }
192                                 }
193                                 handle = handle->hnext;
194                         }
195                 } else {
196                         if (!mousedev_mix.open) {
197                                 if (list->mousedev->exist) {
198                                         input_close_device(&list->mousedev->handle);
199                                 } else {
200                                         input_unregister_minor(list->mousedev->devfs);
201                                         mousedev_table[list->mousedev->minor] = NULL;
202                                         kfree(list->mousedev);
203                                 }
204                         }
205                 }
206         }
207         
208         kfree(list);
209         unlock_kernel();
210 
211         return 0;
212 }
213 
214 static int mousedev_open(struct inode * inode, struct file * file)
215 {
216         struct mousedev_list *list;
217         int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
218 
219         if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
220                 return -ENODEV;
221 
222         if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
223                 return -ENOMEM;
224         memset(list, 0, sizeof(struct mousedev_list));
225 
226         list->mousedev = mousedev_table[i];
227         list->next = mousedev_table[i]->list;
228         mousedev_table[i]->list = list;
229         file->private_data = list;
230 
231         if (!list->mousedev->open++) {
232                 if (list->mousedev->minor == MOUSEDEV_MIX) {
233                         struct input_handle *handle = mousedev_handler.handle;
234                         while (handle) {
235                                 struct mousedev *mousedev = handle->private;
236                                 if (!mousedev->open)
237                                         if (mousedev->exist)    
238                                                 input_open_device(handle);
239                                 handle = handle->hnext;
240                         }
241                 } else {
242                         if (!mousedev_mix.open)
243                                 if (list->mousedev->exist)      
244                                         input_open_device(&list->mousedev->handle);
245                 }
246         }
247 
248         return 0;
249 }
250 
251 static void mousedev_packet(struct mousedev_list *list, unsigned char off)
252 {
253         list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
254         list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
255         list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
256         list->dx -= list->ps2[off + 1];
257         list->dy -= list->ps2[off + 2];
258         list->bufsiz = off + 3;
259 
260         if (list->mode > 1)
261                 list->ps2[off] |= ((list->buttons & 0x18) << 3);
262         
263         if (list->mode) {
264                 list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
265                 list->bufsiz++;
266                 list->dz -= list->ps2[off + 3];
267         }
268         if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
269         list->buffer = list->bufsiz;
270 }
271 
272 
273 static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
274 {
275         struct mousedev_list *list = file->private_data;
276         unsigned char c;
277         int i;
278 
279         for (i = 0; i < count; i++) {
280 
281                 c = buffer[i];
282 
283                 if (c == mousedev_genius_seq[list->genseq]) {
284                         if (++list->genseq == MOUSEDEV_GENIUS_LEN) {
285                                 list->genseq = 0;
286                                 list->ready = 1;
287                                 list->mode = 2;
288                         }
289                 } else list->genseq = 0;
290 
291                 if (c == mousedev_imps_seq[list->impseq]) {
292                         if (++list->impseq == MOUSEDEV_IMPS_LEN) {
293                                 list->impseq = 0;
294                                 list->ready = 1;
295                                 list->mode = 1;
296                         }
297                 } else list->impseq = 0;
298 
299                 list->ps2[0] = 0xfa;
300                 list->bufsiz = 1;
301 
302                 switch (c) {
303 
304                         case 0xeb: /* Poll */
305                                 mousedev_packet(list, 1);
306                                 break;
307 
308                         case 0xf2: /* Get ID */
309                                 list->ps2[1] = (list->mode == 1) ? 3 : 0;
310                                 list->bufsiz = 2;
311                                 break;
312 
313                         case 0xe9: /* Get info */
314                                 if (list->mode == 2) {
315                                         list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55;
316                                 } else {
317                                         list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
318                                 }
319                                 list->bufsiz = 4;
320                                 break;
321                 }
322 
323                 list->buffer = list->bufsiz;
324         }
325 
326         kill_fasync(&list->fasync, SIGIO, POLL_IN);
327 
328         wake_up_interruptible(&list->mousedev->wait);
329                 
330         return count;
331 }
332 
333 static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
334 {
335         DECLARE_WAITQUEUE(wait, current);
336         struct mousedev_list *list = file->private_data;
337         int retval = 0;
338 
339         if (!list->ready && !list->buffer) {
340 
341                 add_wait_queue(&list->mousedev->wait, &wait);
342                 current->state = TASK_INTERRUPTIBLE;
343 
344                 while (!list->ready) {
345 
346                         if (file->f_flags & O_NONBLOCK) {
347                                 retval = -EAGAIN;
348                                 break;
349                         }
350                         if (signal_pending(current)) {
351                                 retval = -ERESTARTSYS;
352                                 break;
353                         }
354 
355                         schedule();
356                 }
357 
358                 current->state = TASK_RUNNING;
359                 remove_wait_queue(&list->mousedev->wait, &wait);
360         }
361 
362         if (retval)
363                 return retval;
364 
365         if (!list->buffer)
366                 mousedev_packet(list, 0);
367 
368         if (count > list->buffer)
369                 count = list->buffer;
370 
371         if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count))
372                 return -EFAULT;
373         
374         list->buffer -= count;
375 
376         return count;   
377 }
378 
379 /* No kernel lock - fine */
380 static unsigned int mousedev_poll(struct file *file, poll_table *wait)
381 {
382         struct mousedev_list *list = file->private_data;
383         poll_wait(file, &list->mousedev->wait, wait);
384         if (list->ready || list->buffer)
385                 return POLLIN | POLLRDNORM;
386         return 0;
387 }
388 
389 struct file_operations mousedev_fops = {
390         owner:          THIS_MODULE,
391         read:           mousedev_read,
392         write:          mousedev_write,
393         poll:           mousedev_poll,
394         open:           mousedev_open,
395         release:        mousedev_release,
396         fasync:         mousedev_fasync,
397 };
398 
399 static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
400 {
401         struct mousedev *mousedev;
402         int minor = 0;
403 
404         if (!test_bit(EV_KEY, dev->evbit) ||
405            (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
406                 return NULL;
407 
408         if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
409             (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
410                 return NULL;
411 
412         for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
413         if (minor == MOUSEDEV_MINORS) {
414                 printk(KERN_ERR "mousedev: no more free mousedev devices\n");
415                 return NULL;
416         }
417 
418         if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
419                 return NULL;
420         memset(mousedev, 0, sizeof(struct mousedev));
421         init_waitqueue_head(&mousedev->wait);
422 
423         mousedev->exist = 1;
424         mousedev->minor = minor;
425         mousedev_table[minor] = mousedev;
426 
427         mousedev->handle.dev = dev;
428         mousedev->handle.handler = handler;
429         mousedev->handle.private = mousedev;
430 
431         mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
432 
433         if (mousedev_mix.open)
434                 input_open_device(&mousedev->handle);
435 
436         printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
437 
438         return &mousedev->handle;
439 }
440 
441 static void mousedev_disconnect(struct input_handle *handle)
442 {
443         struct mousedev *mousedev = handle->private;
444 
445         mousedev->exist = 0;
446 
447         if (mousedev->open) {
448                 input_close_device(handle);
449         } else {
450                 if (mousedev_mix.open)
451                         input_close_device(handle);
452                 input_unregister_minor(mousedev->devfs);
453                 mousedev_table[mousedev->minor] = NULL;
454                 kfree(mousedev);
455         }
456 }
457         
458 static struct input_handler mousedev_handler = {
459         event:          mousedev_event,
460         connect:        mousedev_connect,
461         disconnect:     mousedev_disconnect,
462         fops:           &mousedev_fops,
463         minor:          MOUSEDEV_MINOR_BASE,
464 };
465 
466 static int __init mousedev_init(void)
467 {
468         input_register_handler(&mousedev_handler);
469 
470         memset(&mousedev_mix, 0, sizeof(struct mousedev));
471         init_waitqueue_head(&mousedev_mix.wait);
472         mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
473         mousedev_mix.exist = 1;
474         mousedev_mix.minor = MOUSEDEV_MIX;
475         mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
476 
477         printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
478 
479         return 0;
480 }
481 
482 static void __exit mousedev_exit(void)
483 {
484         input_unregister_minor(mousedev_mix.devfs);
485         input_unregister_handler(&mousedev_handler);
486 }
487 
488 module_init(mousedev_init);
489 module_exit(mousedev_exit);
490 
491 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
492 MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
493 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.