File: /usr/src/linux/drivers/char/busmouse.c

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      
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     
448     MODULE_LICENSE("GPL");
449