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

Linux Cross Reference
Linux/drivers/char/busmouse.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/drivers/char/busmouse.c
  3  *
  4  * Copyright (C) 1995 - 1998 Russell King <linux@arm.linux.org.uk>
  5  *  Protocol taken from original busmouse.c
  6  *  read() waiting taken from psaux.c
  7  *
  8  * Medium-level interface for quadrature or bus mice.
  9  */
 10 
 11 #include <linux/module.h>
 12 #include <linux/kernel.h>
 13 #include <linux/sched.h>
 14 #include <linux/signal.h>
 15 #include <linux/malloc.h>
 16 #include <linux/errno.h>
 17 #include <linux/mm.h>
 18 #include <linux/poll.h>
 19 #include <linux/miscdevice.h>
 20 #include <linux/random.h>
 21 #include <linux/init.h>
 22 #include <linux/smp_lock.h>
 23 
 24 #include <asm/uaccess.h>
 25 #include <asm/system.h>
 26 #include <asm/io.h>
 27 
 28 #include "busmouse.h"
 29 
 30 /* Uncomment this if your mouse drivers expect the kernel to
 31  * return with EAGAIN if the mouse does not have any events
 32  * available, even if the mouse is opened in nonblocking mode.
 33  * Please report use of this "feature" to the author using the
 34  * above address.
 35  */
 36 /*#define BROKEN_MOUSE*/
 37 
 38 struct busmouse_data {
 39         struct miscdevice       miscdev;
 40         struct busmouse         *ops;
 41         spinlock_t              lock;
 42 
 43         wait_queue_head_t       wait;
 44         struct fasync_struct    *fasyncptr;
 45         char                    active;
 46         char                    buttons;
 47         char                    ready;
 48         int                     dxpos;
 49         int                     dypos;
 50 };
 51 
 52 #define NR_MICE                 15
 53 #define FIRST_MOUSE             0
 54 #define DEV_TO_MOUSE(dev)       MINOR_TO_MOUSE(MINOR(dev))
 55 #define MINOR_TO_MOUSE(minor)   ((minor) - FIRST_MOUSE)
 56 
 57 /*
 58  *      List of mice and guarding semaphore. You must take the semaphore
 59  *      before you take the misc device semaphore if you need both
 60  */
 61  
 62 static struct busmouse_data *busmouse_data[NR_MICE];
 63 static DECLARE_MUTEX(mouse_sem);
 64 
 65 /**
 66  *      busmouse_add_movement - notification of a change of mouse position
 67  *      @mousedev: mouse number
 68  *      @dx: delta X movement
 69  *      @dy: delta Y movement
 70  *      @buttons: new button state
 71  *
 72  *      Updates the mouse position and button information. The mousedev
 73  *      parameter is the value returned from register_busmouse. The
 74  *      movement information is updated, and the new button state is
 75  *      saved.  A waiting user thread is woken.
 76  */
 77  
 78 void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
 79 {
 80         struct busmouse_data *mse = busmouse_data[mousedev];
 81         int changed;
 82 
 83         spin_lock(&mse->lock);
 84         changed = (dx != 0 || dy != 0 || mse->buttons != buttons);
 85 
 86         if (changed) {
 87                 add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
 88 
 89                 mse->buttons = buttons;
 90                 mse->dxpos += dx;
 91                 mse->dypos += dy;
 92                 mse->ready = 1;
 93 
 94                 /*
 95                  * keep dx/dy reasonable, but still able to track when X (or
 96                  * whatever) must page or is busy (i.e. long waits between
 97                  * reads)
 98                  */
 99                 if (mse->dxpos < -2048)
100                         mse->dxpos = -2048;
101                 if (mse->dxpos > 2048)
102                         mse->dxpos = 2048;
103                 if (mse->dypos < -2048)
104                         mse->dypos = -2048;
105                 if (mse->dypos > 2048)
106                         mse->dypos = 2048;
107         }
108 
109         spin_unlock(&mse->lock);
110 
111         if (changed) {
112                 wake_up(&mse->wait);
113 
114                 kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN);
115         }
116 }
117 
118 /**
119  *      busmouse_add_movement - notification of a change of mouse position
120  *      @mousedev: mouse number
121  *      @dx: delta X movement
122  *      @dy: delta Y movement
123  *
124  *      Updates the mouse position. The mousedev parameter is the value
125  *      returned from register_busmouse. The movement information is
126  *      updated, and a waiting user thread is woken.
127  */
128  
129 void busmouse_add_movement(int mousedev, int dx, int dy)
130 {
131         struct busmouse_data *mse = busmouse_data[mousedev];
132 
133         busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
134 }
135 
136 /**
137  *      busmouse_add_buttons - notification of a change of button state
138  *      @mousedev: mouse number
139  *      @clear: mask of buttons to clear
140  *      @eor: mask of buttons to change
141  *
142  *      Updates the button state. The mousedev parameter is the value
143  *      returned from register_busmouse. The buttons are updated by:
144  *              new_state = (old_state & ~clear) ^ eor
145  *      A waiting user thread is woken up.
146  */
147  
148 void busmouse_add_buttons(int mousedev, int clear, int eor)
149 {
150         struct busmouse_data *mse = busmouse_data[mousedev];
151 
152         busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
153 }
154 
155 static int busmouse_fasync(int fd, struct file *filp, int on)
156 {
157         struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
158         int retval;
159 
160         retval = fasync_helper(fd, filp, on, &mse->fasyncptr);
161         if (retval < 0)
162                 return retval;
163         return 0;
164 }
165 
166 static int busmouse_release(struct inode *inode, struct file *file)
167 {
168         struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
169         int ret = 0;
170 
171         lock_kernel();
172         busmouse_fasync(-1, file, 0);
173 
174         if (--mse->active == 0) {
175                 if (mse->ops->release)
176                         ret = mse->ops->release(inode, file);
177                 if (mse->ops->owner)
178                         __MOD_DEC_USE_COUNT(mse->ops->owner);
179                 mse->ready = 0;
180         }
181         unlock_kernel();
182 
183         return ret;
184 }
185 
186 static int busmouse_open(struct inode *inode, struct file *file)
187 {
188         struct busmouse_data *mse;
189         unsigned int mousedev;
190         int ret;
191 
192         mousedev = DEV_TO_MOUSE(inode->i_rdev);
193         if (mousedev >= NR_MICE)
194                 return -EINVAL;
195 
196         down(&mouse_sem);
197         mse = busmouse_data[mousedev];
198         ret = -ENODEV;
199         if (!mse || !mse->ops)  /* shouldn't happen, but... */
200                 goto end;
201 
202         if (mse->ops->owner && !try_inc_mod_count(mse->ops->owner))
203                 goto end;
204 
205         ret = 0;
206         if (mse->ops->open) {
207                 ret = mse->ops->open(inode, file);
208                 if (ret && mse->ops->owner)
209                         __MOD_DEC_USE_COUNT(mse->ops->owner);
210         }
211 
212         if (ret)
213                 goto end;
214 
215         file->private_data = mse;
216 
217         if (mse->active++)
218                 goto end;
219 
220         spin_lock_irq(&mse->lock);
221 
222         mse->ready   = 0;
223         mse->dxpos   = 0;
224         mse->dypos   = 0;
225         mse->buttons = mse->ops->init_button_state;
226 
227         spin_unlock_irq(&mse->lock);
228 end:
229         up(&mouse_sem);
230         return ret;
231 }
232 
233 static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
234 {
235         return -EINVAL;
236 }
237 
238 static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
239 {
240         struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
241         DECLARE_WAITQUEUE(wait, current);
242         int dxpos, dypos, buttons;
243 
244         if (count < 3)
245                 return -EINVAL;
246 
247         spin_lock_irq(&mse->lock);
248 
249         if (!mse->ready) {
250 #ifdef BROKEN_MOUSE
251                 spin_unlock_irq(&mse->lock);
252                 return -EAGAIN;
253 #else
254                 if (file->f_flags & O_NONBLOCK) {
255                         spin_unlock_irq(&mse->lock);
256                         return -EAGAIN;
257                 }
258 
259                 add_wait_queue(&mse->wait, &wait);
260 repeat:
261                 set_current_state(TASK_INTERRUPTIBLE);
262                 if (!mse->ready && !signal_pending(current)) {
263                         spin_unlock_irq(&mse->lock);
264                         schedule();
265                         spin_lock_irq(&mse->lock);
266                         goto repeat;
267                 }
268 
269                 current->state = TASK_RUNNING;
270                 remove_wait_queue(&mse->wait, &wait);
271 
272                 if (signal_pending(current)) {
273                         spin_unlock_irq(&mse->lock);
274                         return -ERESTARTSYS;
275                 }
276 #endif
277         }
278 
279         dxpos = mse->dxpos;
280         dypos = mse->dypos;
281         buttons = mse->buttons;
282 
283         if (dxpos < -127)
284                 dxpos =- 127;
285         if (dxpos > 127)
286                 dxpos = 127;
287         if (dypos < -127)
288                 dypos =- 127;
289         if (dypos > 127)
290                 dypos = 127;
291 
292         mse->dxpos -= dxpos;
293         mse->dypos -= dypos;
294 
295         /* This is something that many drivers have apparantly
296          * forgotten...  If the X and Y positions still contain
297          * information, we still have some info ready for the
298          * user program...
299          */
300         mse->ready = mse->dxpos || mse->dypos;
301 
302         spin_unlock_irq(&mse->lock);
303 
304         /* Write out data to the user.  Format is:
305          *   byte 0 - identifer (0x80) and (inverted) mouse buttons
306          *   byte 1 - X delta position +/- 127
307          *   byte 2 - Y delta position +/- 127
308          */
309         if (put_user((char)buttons | 128, buffer) ||
310             put_user((char)dxpos, buffer + 1) ||
311             put_user((char)dypos, buffer + 2))
312                 return -EFAULT;
313 
314         if (count > 3 && clear_user(buffer + 3, count - 3))
315                 return -EFAULT;
316 
317         file->f_dentry->d_inode->i_atime = CURRENT_TIME;
318 
319         return count;
320 }
321 
322 /* No kernel lock held - fine */
323 static unsigned int busmouse_poll(struct file *file, poll_table *wait)
324 {
325         struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
326 
327         poll_wait(file, &mse->wait, wait);
328 
329         if (mse->ready)
330                 return POLLIN | POLLRDNORM;
331 
332         return 0;
333 }
334 
335 struct file_operations busmouse_fops=
336 {
337         owner:          THIS_MODULE,
338         read:           busmouse_read,
339         write:          busmouse_write,
340         poll:           busmouse_poll,
341         open:           busmouse_open,
342         release:        busmouse_release,
343         fasync:         busmouse_fasync,
344 };
345 
346 /**
347  *      register_busmouse - register a bus mouse interface
348  *      @ops: busmouse structure for the mouse
349  *
350  *      Registers a mouse with the driver. The return is mouse number on
351  *      success and a negative errno code on an error. The passed ops
352  *      structure most not be freed until the mouser is unregistered
353  */
354  
355 int register_busmouse(struct busmouse *ops)
356 {
357         unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
358         struct busmouse_data *mse;
359         int ret;
360 
361         if (msedev >= NR_MICE) {
362                 printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",
363                        ops->minor);
364                 return -EINVAL;
365         }
366 
367         mse = kmalloc(sizeof(*mse), GFP_KERNEL);
368         if (!mse)
369                 return -ENOMEM;
370 
371         down(&mouse_sem);
372         if (busmouse_data[msedev])
373         {
374                 up(&mouse_sem);
375                 kfree(mse);
376                 return -EBUSY;
377         }
378 
379         memset(mse, 0, sizeof(*mse));
380 
381         mse->miscdev.minor = ops->minor;
382         mse->miscdev.name = ops->name;
383         mse->miscdev.fops = &busmouse_fops;
384         mse->ops = ops;
385         mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
386         init_waitqueue_head(&mse->wait);
387 
388         busmouse_data[msedev] = mse;
389 
390         ret = misc_register(&mse->miscdev);
391         if (!ret)
392                 ret = msedev;
393         up(&mouse_sem);
394         
395         return ret;
396 }
397 
398 /**
399  *      unregister_busmouse - unregister a bus mouse interface
400  *      @mousedev: Mouse number to release
401  *
402  *      Unregister a previously installed mouse handler. The mousedev
403  *      passed is the return code from a previous call to register_busmouse
404  */
405  
406 
407 int unregister_busmouse(int mousedev)
408 {
409         int err = -EINVAL;
410 
411         if (mousedev < 0)
412                 return 0;
413         if (mousedev >= NR_MICE) {
414                 printk(KERN_ERR "busmouse: trying to free mouse on"
415                        " mousedev %d\n", mousedev);
416                 return -EINVAL;
417         }
418 
419         down(&mouse_sem);
420         
421         if (!busmouse_data[mousedev]) {
422                 printk(KERN_WARNING "busmouse: trying to free free mouse"
423                        " on mousedev %d\n", mousedev);
424                 goto fail;
425         }
426 
427         if (busmouse_data[mousedev]->active) {
428                 printk(KERN_ERR "busmouse: trying to free active mouse"
429                        " on mousedev %d\n", mousedev);
430                 goto fail;
431         }
432 
433         err = misc_deregister(&busmouse_data[mousedev]->miscdev);
434 
435         kfree(busmouse_data[mousedev]);
436         busmouse_data[mousedev] = NULL;
437 fail:
438         up(&mouse_sem);
439         return err;
440 }
441 
442 EXPORT_SYMBOL(busmouse_add_movementbuttons);
443 EXPORT_SYMBOL(busmouse_add_movement);
444 EXPORT_SYMBOL(busmouse_add_buttons);
445 EXPORT_SYMBOL(register_busmouse);
446 EXPORT_SYMBOL(unregister_busmouse);
447 

~ [ 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.