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/slab.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 blocking 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 
busmouse_add_movementbuttons(int mousedev,int dx,int dy,int buttons)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 
busmouse_add_movement(int mousedev,int dx,int dy)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 
busmouse_add_buttons(int mousedev,int clear,int eor)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 
busmouse_fasync(int fd,struct file * filp,int on)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 
busmouse_release(struct inode * inode,struct file * file)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 
busmouse_open(struct inode * inode,struct file * file)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 
busmouse_write(struct file * file,const char * buffer,size_t count,loff_t * ppos)233 static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
234 {
235 	return -EINVAL;
236 }
237 
busmouse_read(struct file * file,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)
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 */
busmouse_poll(struct file * file,poll_table * wait)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 
register_busmouse(struct busmouse * ops)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 
unregister_busmouse(int mousedev)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 
448 MODULE_LICENSE("GPL");
449