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/malloc.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>
23 #include <asm/uaccess.h>
24 #include <asm/system.h>
29 /* Uncomment this if your mouse drivers expect the kernel to
30 * return with EAGAIN if the mouse does not have any events
31 * available, even if the mouse is opened in nonblocking mode.
32 * Please report use of this "feature" to the author using the
35 /*#define BROKEN_MOUSE*/
37 struct busmouse_data
{
38 struct miscdevice miscdev
;
42 wait_queue_head_t wait
;
43 struct fasync_struct
*fasyncptr
;
53 #define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev))
54 #define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
57 * List of mice and guarding semaphore. You must take the semaphore
58 * before you take the misc device semaphore if you need both
61 static struct busmouse_data
*busmouse_data
[NR_MICE
];
62 static DECLARE_MUTEX(mouse_sem
);
65 * busmouse_add_movement - notification of a change of mouse position
66 * @mousedev: mouse number
67 * @dx: delta X movement
68 * @dy: delta Y movement
69 * @buttons: new button state
71 * Updates the mouse position and button information. The mousedev
72 * parameter is the value returned from register_busmouse. The
73 * movement information is updated, and the new button state is
74 * saved. A waiting user thread is woken.
77 void busmouse_add_movementbuttons(int mousedev
, int dx
, int dy
, int buttons
)
79 struct busmouse_data
*mse
= busmouse_data
[mousedev
];
82 spin_lock(&mse
->lock
);
83 changed
= (dx
!= 0 || dy
!= 0 || mse
->buttons
!= buttons
);
86 add_mouse_randomness((buttons
<< 16) + (dy
<< 8) + dx
);
88 mse
->buttons
= buttons
;
94 * keep dx/dy reasonable, but still able to track when X (or
95 * whatever) must page or is busy (i.e. long waits between
98 if (mse
->dxpos
< -2048)
100 if (mse
->dxpos
> 2048)
102 if (mse
->dypos
< -2048)
104 if (mse
->dypos
> 2048)
108 spin_unlock(&mse
->lock
);
113 kill_fasync(&mse
->fasyncptr
, SIGIO
, POLL_IN
);
118 * busmouse_add_movement - notification of a change of mouse position
119 * @mousedev: mouse number
120 * @dx: delta X movement
121 * @dy: delta Y movement
123 * Updates the mouse position. The mousedev parameter is the value
124 * returned from register_busmouse. The movement information is
125 * updated, and a waiting user thread is woken.
128 void busmouse_add_movement(int mousedev
, int dx
, int dy
)
130 struct busmouse_data
*mse
= busmouse_data
[mousedev
];
132 busmouse_add_movementbuttons(mousedev
, dx
, dy
, mse
->buttons
);
136 * busmouse_add_buttons - notification of a change of button state
137 * @mousedev: mouse number
138 * @clear: mask of buttons to clear
139 * @eor: mask of buttons to change
141 * Updates the button state. The mousedev parameter is the value
142 * returned from register_busmouse. The buttons are updated by:
143 * new_state = (old_state & ~clear) ^ eor
144 * A waiting user thread is woken up.
147 void busmouse_add_buttons(int mousedev
, int clear
, int eor
)
149 struct busmouse_data
*mse
= busmouse_data
[mousedev
];
151 busmouse_add_movementbuttons(mousedev
, 0, 0, (mse
->buttons
& ~clear
) ^ eor
);
154 static int busmouse_fasync(int fd
, struct file
*filp
, int on
)
156 struct busmouse_data
*mse
= (struct busmouse_data
*)filp
->private_data
;
159 retval
= fasync_helper(fd
, filp
, on
, &mse
->fasyncptr
);
165 static int busmouse_release(struct inode
*inode
, struct file
*file
)
167 struct busmouse_data
*mse
= (struct busmouse_data
*)file
->private_data
;
170 busmouse_fasync(-1, file
, 0);
172 if (--mse
->active
== 0) {
174 if (mse
->ops
->release
)
175 ret
= mse
->ops
->release(inode
, file
);
177 __MOD_DEC_USE_COUNT(mse
->ops
->owner
);
185 static int busmouse_open(struct inode
*inode
, struct file
*file
)
187 struct busmouse_data
*mse
;
188 unsigned int mousedev
;
191 mousedev
= DEV_TO_MOUSE(inode
->i_rdev
);
192 if (mousedev
>= NR_MICE
)
196 mse
= busmouse_data
[mousedev
];
198 /* shouldn't happen, but... */
201 if (mse
->ops
&& mse
->ops
->owner
)
202 __MOD_INC_USE_COUNT(mse
->ops
->owner
);
203 if (mse
->ops
&& mse
->ops
->open
) {
204 ret
= mse
->ops
->open(inode
, file
);
205 if (ret
&& mse
->ops
->owner
)
206 __MOD_DEC_USE_COUNT(mse
->ops
->owner
);
212 file
->private_data
= mse
;
217 spin_lock_irq(&mse
->lock
);
223 mse
->buttons
= mse
->ops
->init_button_state
;
227 spin_unlock_irq(&mse
->lock
);
233 static ssize_t
busmouse_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*ppos
)
238 static ssize_t
busmouse_read(struct file
*file
, char *buffer
, size_t count
, loff_t
*ppos
)
240 struct busmouse_data
*mse
= (struct busmouse_data
*)file
->private_data
;
241 DECLARE_WAITQUEUE(wait
, current
);
242 int dxpos
, dypos
, buttons
;
247 spin_lock_irq(&mse
->lock
);
251 spin_unlock_irq(&mse
->lock
);
254 if (file
->f_flags
& O_NONBLOCK
) {
255 spin_unlock_irq(&mse
->lock
);
259 add_wait_queue(&mse
->wait
, &wait
);
261 set_current_state(TASK_INTERRUPTIBLE
);
262 if (!mse
->ready
&& !signal_pending(current
)) {
263 spin_unlock_irq(&mse
->lock
);
265 spin_lock_irq(&mse
->lock
);
269 current
->state
= TASK_RUNNING
;
270 remove_wait_queue(&mse
->wait
, &wait
);
272 if (signal_pending(current
)) {
273 spin_unlock_irq(&mse
->lock
);
281 buttons
= mse
->buttons
;
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
300 mse
->ready
= mse
->dxpos
|| mse
->dypos
;
302 spin_unlock_irq(&mse
->lock
);
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
309 if (put_user((char)buttons
| 128, buffer
) ||
310 put_user((char)dxpos
, buffer
+ 1) ||
311 put_user((char)dypos
, buffer
+ 2))
314 if (count
> 3 && clear_user(buffer
+ 3, count
- 3))
317 file
->f_dentry
->d_inode
->i_atime
= CURRENT_TIME
;
322 /* No kernel lock held - fine */
323 static unsigned int busmouse_poll(struct file
*file
, poll_table
*wait
)
325 struct busmouse_data
*mse
= (struct busmouse_data
*)file
->private_data
;
327 poll_wait(file
, &mse
->wait
, wait
);
330 return POLLIN
| POLLRDNORM
;
335 struct file_operations busmouse_fops
=
339 write
: busmouse_write
,
342 release
: busmouse_release
,
343 fasync
: busmouse_fasync
,
347 * register_busmouse - register a bus mouse interface
348 * @ops: busmouse structure for the mouse
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
355 int register_busmouse(struct busmouse
*ops
)
357 unsigned int msedev
= MINOR_TO_MOUSE(ops
->minor
);
358 struct busmouse_data
*mse
;
361 if (msedev
>= NR_MICE
) {
362 printk(KERN_ERR
"busmouse: trying to allocate mouse on minor %d\n",
367 mse
= kmalloc(sizeof(*mse
), GFP_KERNEL
);
372 if (busmouse_data
[msedev
])
379 memset(mse
, 0, sizeof(*mse
));
381 mse
->miscdev
.minor
= ops
->minor
;
382 mse
->miscdev
.name
= ops
->name
;
383 mse
->miscdev
.fops
= &busmouse_fops
;
385 mse
->lock
= (spinlock_t
)SPIN_LOCK_UNLOCKED
;
386 init_waitqueue_head(&mse
->wait
);
388 busmouse_data
[msedev
] = mse
;
390 ret
= misc_register(&mse
->miscdev
);
399 * unregister_busmouse - unregister a bus mouse interface
400 * @mousedev: Mouse number to release
402 * Unregister a previously installed mouse handler. The mousedev
403 * passed is the return code from a previous call to register_busmouse
407 int unregister_busmouse(int mousedev
)
413 if (mousedev
>= NR_MICE
) {
414 printk(KERN_ERR
"busmouse: trying to free mouse on"
415 " mousedev %d\n", mousedev
);
421 if (!busmouse_data
[mousedev
]) {
422 printk(KERN_WARNING
"busmouse: trying to free free mouse"
423 " on mousedev %d\n", mousedev
);
427 if (busmouse_data
[mousedev
]->active
) {
428 printk(KERN_ERR
"busmouse: trying to free active mouse"
429 " on mousedev %d\n", mousedev
);
433 err
= misc_deregister(&busmouse_data
[mousedev
]->miscdev
);
435 kfree(busmouse_data
[mousedev
]);
436 busmouse_data
[mousedev
] = NULL
;
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
);