2 * linux/drivers/char/busmouse.c
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
8 * Medium-level interface for quadrature or bus mice.
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/signal.h>
15 #include <linux/slab.h>
16 #include <linux/errno.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>
24 #include <asm/uaccess.h>
25 #include <asm/system.h>
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 blocking mode.
33 * Please report use of this "feature" to the author using the
36 /*#define BROKEN_MOUSE*/
38 struct busmouse_data {
39 struct miscdevice miscdev;
43 wait_queue_head_t wait;
44 struct fasync_struct *fasyncptr;
54 #define DEV_TO_MOUSE(inode) MINOR_TO_MOUSE(iminor(inode))
55 #define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
58 * List of mice and guarding semaphore. You must take the semaphore
59 * before you take the misc device semaphore if you need both
62 static struct busmouse_data *busmouse_data[NR_MICE];
63 static DECLARE_MUTEX(mouse_sem);
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
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.
78 void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
80 struct busmouse_data *mse = busmouse_data[mousedev];
83 spin_lock(&mse->lock);
84 changed = (dx != 0 || dy != 0 || mse->buttons != buttons);
87 add_mouse_randomness((buttons << 16) + (dy << 8) + dx);
89 mse->buttons = buttons;
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
99 if (mse->dxpos < -2048)
101 if (mse->dxpos > 2048)
103 if (mse->dypos < -2048)
105 if (mse->dypos > 2048)
109 spin_unlock(&mse->lock);
114 kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN);
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
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.
129 void busmouse_add_movement(int mousedev, int dx, int dy)
131 struct busmouse_data *mse = busmouse_data[mousedev];
133 busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
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
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.
148 void busmouse_add_buttons(int mousedev, int clear, int eor)
150 struct busmouse_data *mse = busmouse_data[mousedev];
152 busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
155 static int busmouse_fasync(int fd, struct file *filp, int on)
157 struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
160 retval = fasync_helper(fd, filp, on, &mse->fasyncptr);
166 static int busmouse_release(struct inode *inode, struct file *file)
168 struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
172 busmouse_fasync(-1, file, 0);
174 down(&mouse_sem); /* to protect mse->active */
175 if (--mse->active == 0) {
176 if (mse->ops->release)
177 ret = mse->ops->release(inode, file);
178 module_put(mse->ops->owner);
187 static int busmouse_open(struct inode *inode, struct file *file)
189 struct busmouse_data *mse;
190 unsigned int mousedev;
193 mousedev = DEV_TO_MOUSE(inode);
194 if (mousedev >= NR_MICE)
198 mse = busmouse_data[mousedev];
200 if (!mse || !mse->ops) /* shouldn't happen, but... */
203 if (!try_module_get(mse->ops->owner))
207 if (mse->ops->open) {
208 ret = mse->ops->open(inode, file);
210 module_put(mse->ops->owner);
216 file->private_data = mse;
221 spin_lock_irq(&mse->lock);
226 mse->buttons = mse->ops->init_button_state;
228 spin_unlock_irq(&mse->lock);
234 static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
239 static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
241 struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
242 DECLARE_WAITQUEUE(wait, current);
243 int dxpos, dypos, buttons;
248 spin_lock_irq(&mse->lock);
252 spin_unlock_irq(&mse->lock);
255 if (file->f_flags & O_NONBLOCK) {
256 spin_unlock_irq(&mse->lock);
260 add_wait_queue(&mse->wait, &wait);
262 set_current_state(TASK_INTERRUPTIBLE);
263 if (!mse->ready && !signal_pending(current)) {
264 spin_unlock_irq(&mse->lock);
266 spin_lock_irq(&mse->lock);
270 current->state = TASK_RUNNING;
271 remove_wait_queue(&mse->wait, &wait);
273 if (signal_pending(current)) {
274 spin_unlock_irq(&mse->lock);
282 buttons = mse->buttons;
296 /* This is something that many drivers have apparantly
297 * forgotten... If the X and Y positions still contain
298 * information, we still have some info ready for the
301 mse->ready = mse->dxpos || mse->dypos;
303 spin_unlock_irq(&mse->lock);
305 /* Write out data to the user. Format is:
306 * byte 0 - identifer (0x80) and (inverted) mouse buttons
307 * byte 1 - X delta position +/- 127
308 * byte 2 - Y delta position +/- 127
310 if (put_user((char)buttons | 128, buffer) ||
311 put_user((char)dxpos, buffer + 1) ||
312 put_user((char)dypos, buffer + 2))
315 if (count > 3 && clear_user(buffer + 3, count - 3))
318 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
323 /* No kernel lock held - fine */
324 static unsigned int busmouse_poll(struct file *file, poll_table *wait)
326 struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
328 poll_wait(file, &mse->wait, wait);
331 return POLLIN | POLLRDNORM;
336 struct file_operations busmouse_fops=
338 .owner = THIS_MODULE,
339 .read = busmouse_read,
340 .write = busmouse_write,
341 .poll = busmouse_poll,
342 .open = busmouse_open,
343 .release = busmouse_release,
344 .fasync = busmouse_fasync,
348 * register_busmouse - register a bus mouse interface
349 * @ops: busmouse structure for the mouse
351 * Registers a mouse with the driver. The return is mouse number on
352 * success and a negative errno code on an error. The passed ops
353 * structure most not be freed until the mouser is unregistered
356 int register_busmouse(struct busmouse *ops)
358 unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
359 struct busmouse_data *mse;
362 if (msedev >= NR_MICE) {
363 printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",
369 mse = kmalloc(sizeof(*mse), GFP_KERNEL);
375 if (busmouse_data[msedev])
378 memset(mse, 0, sizeof(*mse));
380 mse->miscdev.minor = ops->minor;
381 mse->miscdev.name = ops->name;
382 mse->miscdev.fops = &busmouse_fops;
384 mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
385 init_waitqueue_head(&mse->wait);
388 ret = misc_register(&mse->miscdev);
393 busmouse_data[msedev] = mse;
406 * unregister_busmouse - unregister a bus mouse interface
407 * @mousedev: Mouse number to release
409 * Unregister a previously installed mouse handler. The mousedev
410 * passed is the return code from a previous call to register_busmouse
414 int unregister_busmouse(int mousedev)
420 if (mousedev >= NR_MICE) {
421 printk(KERN_ERR "busmouse: trying to free mouse on"
422 " mousedev %d\n", mousedev);
428 if (!busmouse_data[mousedev]) {
429 printk(KERN_WARNING "busmouse: trying to free free mouse"
430 " on mousedev %d\n", mousedev);
434 if (busmouse_data[mousedev]->active) {
435 printk(KERN_ERR "busmouse: trying to free active mouse"
436 " on mousedev %d\n", mousedev);
440 err = misc_deregister(&busmouse_data[mousedev]->miscdev);
442 kfree(busmouse_data[mousedev]);
443 busmouse_data[mousedev] = NULL;
449 EXPORT_SYMBOL(busmouse_add_movementbuttons);
450 EXPORT_SYMBOL(busmouse_add_movement);
451 EXPORT_SYMBOL(busmouse_add_buttons);
452 EXPORT_SYMBOL(register_busmouse);
453 EXPORT_SYMBOL(unregister_busmouse);
455 MODULE_ALIAS_MISCDEV(BUSMOUSE_MINOR);
456 MODULE_LICENSE("GPL");