⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 busmouse.c

📁 讲述linux的初始化过程
💻 C
字号:
/* * linux/drivers/char/busmouse.c * * Copyright (C) 1995 - 1998 Russell King <linux@arm.linux.org.uk> *  Protocol taken from original busmouse.c *  read() waiting taken from psaux.c * * Medium-level interface for quadrature or bus mice. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/malloc.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/random.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/io.h>#include "busmouse.h"/* Uncomment this if your mouse drivers expect the kernel to * return with EAGAIN if the mouse does not have any events * available, even if the mouse is opened in nonblocking mode. * Please report use of this "feature" to the author using the * above address. *//*#define BROKEN_MOUSE*/struct busmouse_data {	struct miscdevice	miscdev;	struct busmouse		*ops;	spinlock_t		lock;	wait_queue_head_t	wait;	struct fasync_struct	*fasyncptr;	char			active;	char			buttons;	char			ready;	int			dxpos;	int			dypos;};#define NR_MICE			15#define FIRST_MOUSE		0#define DEV_TO_MOUSE(dev)	MINOR_TO_MOUSE(MINOR(dev))#define MINOR_TO_MOUSE(minor)	((minor) - FIRST_MOUSE)/* *	List of mice and guarding semaphore. You must take the semaphore *	before you take the misc device semaphore if you need both */ static struct busmouse_data *busmouse_data[NR_MICE];static DECLARE_MUTEX(mouse_sem);/** *	busmouse_add_movement - notification of a change of mouse position *	@mousedev: mouse number *	@dx: delta X movement *	@dy: delta Y movement *	@buttons: new button state * *	Updates the mouse position and button information. The mousedev *	parameter is the value returned from register_busmouse. The *	movement information is updated, and the new button state is *	saved.  A waiting user thread is woken. */ void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons){	struct busmouse_data *mse = busmouse_data[mousedev];	int changed;	spin_lock(&mse->lock);	changed = (dx != 0 || dy != 0 || mse->buttons != buttons);	if (changed) {		add_mouse_randomness((buttons << 16) + (dy << 8) + dx);		mse->buttons = buttons;		mse->dxpos += dx;		mse->dypos += dy;		mse->ready = 1;		/*		 * keep dx/dy reasonable, but still able to track when X (or		 * whatever) must page or is busy (i.e. long waits between		 * reads)		 */		if (mse->dxpos < -2048)			mse->dxpos = -2048;		if (mse->dxpos > 2048)			mse->dxpos = 2048;		if (mse->dypos < -2048)			mse->dypos = -2048;		if (mse->dypos > 2048)			mse->dypos = 2048;	}	spin_unlock(&mse->lock);	if (changed) {		wake_up(&mse->wait);		kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN);	}}/** *	busmouse_add_movement - notification of a change of mouse position *	@mousedev: mouse number *	@dx: delta X movement *	@dy: delta Y movement * *	Updates the mouse position. The mousedev parameter is the value *	returned from register_busmouse. The movement information is *	updated, and a waiting user thread is woken. */ void busmouse_add_movement(int mousedev, int dx, int dy){	struct busmouse_data *mse = busmouse_data[mousedev];	busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);}/** *	busmouse_add_buttons - notification of a change of button state *	@mousedev: mouse number *	@clear: mask of buttons to clear *	@eor: mask of buttons to change * *	Updates the button state. The mousedev parameter is the value *	returned from register_busmouse. The buttons are updated by: *		new_state = (old_state & ~clear) ^ eor *	A waiting user thread is woken up. */ void busmouse_add_buttons(int mousedev, int clear, int eor){	struct busmouse_data *mse = busmouse_data[mousedev];	busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);}static int busmouse_fasync(int fd, struct file *filp, int on){	struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;	int retval;	retval = fasync_helper(fd, filp, on, &mse->fasyncptr);	if (retval < 0)		return retval;	return 0;}static int busmouse_release(struct inode *inode, struct file *file){	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;	int ret = 0;	lock_kernel();	busmouse_fasync(-1, file, 0);	if (--mse->active == 0) {		if (mse->ops->release)			ret = mse->ops->release(inode, file);	   	if (mse->ops->owner)			__MOD_DEC_USE_COUNT(mse->ops->owner);		mse->ready = 0;	}	unlock_kernel();	return ret;}static int busmouse_open(struct inode *inode, struct file *file){	struct busmouse_data *mse;	unsigned int mousedev;	int ret;	mousedev = DEV_TO_MOUSE(inode->i_rdev);	if (mousedev >= NR_MICE)		return -EINVAL;	down(&mouse_sem);	mse = busmouse_data[mousedev];	ret = -ENODEV;	if (!mse || !mse->ops)	/* shouldn't happen, but... */		goto end;	if (mse->ops->owner && !try_inc_mod_count(mse->ops->owner))		goto end;	ret = 0;	if (mse->ops->open) {		ret = mse->ops->open(inode, file);		if (ret && mse->ops->owner)			__MOD_DEC_USE_COUNT(mse->ops->owner);	}	if (ret)		goto end;	file->private_data = mse;	if (mse->active++)		goto end;	spin_lock_irq(&mse->lock);	mse->ready   = 0;	mse->dxpos   = 0;	mse->dypos   = 0;	mse->buttons = mse->ops->init_button_state;	spin_unlock_irq(&mse->lock);end:	up(&mouse_sem);	return ret;}static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){	return -EINVAL;}static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;	DECLARE_WAITQUEUE(wait, current);	int dxpos, dypos, buttons;	if (count < 3)		return -EINVAL;	spin_lock_irq(&mse->lock);	if (!mse->ready) {#ifdef BROKEN_MOUSE		spin_unlock_irq(&mse->lock);		return -EAGAIN;#else		if (file->f_flags & O_NONBLOCK) {			spin_unlock_irq(&mse->lock);			return -EAGAIN;		}		add_wait_queue(&mse->wait, &wait);repeat:		set_current_state(TASK_INTERRUPTIBLE);		if (!mse->ready && !signal_pending(current)) {			spin_unlock_irq(&mse->lock);			schedule();			spin_lock_irq(&mse->lock);			goto repeat;		}		current->state = TASK_RUNNING;		remove_wait_queue(&mse->wait, &wait);		if (signal_pending(current)) {			spin_unlock_irq(&mse->lock);			return -ERESTARTSYS;		}#endif	}	dxpos = mse->dxpos;	dypos = mse->dypos;	buttons = mse->buttons;	if (dxpos < -127)		dxpos =- 127;	if (dxpos > 127)		dxpos = 127;	if (dypos < -127)		dypos =- 127;	if (dypos > 127)		dypos = 127;	mse->dxpos -= dxpos;	mse->dypos -= dypos;	/* This is something that many drivers have apparantly	 * forgotten...  If the X and Y positions still contain	 * information, we still have some info ready for the	 * user program...	 */	mse->ready = mse->dxpos || mse->dypos;	spin_unlock_irq(&mse->lock);	/* Write out data to the user.  Format is:	 *   byte 0 - identifer (0x80) and (inverted) mouse buttons	 *   byte 1 - X delta position +/- 127	 *   byte 2 - Y delta position +/- 127	 */	if (put_user((char)buttons | 128, buffer) ||	    put_user((char)dxpos, buffer + 1) ||	    put_user((char)dypos, buffer + 2))		return -EFAULT;	if (count > 3 && clear_user(buffer + 3, count - 3))		return -EFAULT;	file->f_dentry->d_inode->i_atime = CURRENT_TIME;	return count;}/* No kernel lock held - fine */static unsigned int busmouse_poll(struct file *file, poll_table *wait){	struct busmouse_data *mse = (struct busmouse_data *)file->private_data;	poll_wait(file, &mse->wait, wait);	if (mse->ready)		return POLLIN | POLLRDNORM;	return 0;}struct file_operations busmouse_fops={	owner:		THIS_MODULE,	read:		busmouse_read,	write:		busmouse_write,	poll:		busmouse_poll,	open:		busmouse_open,	release:	busmouse_release,	fasync:		busmouse_fasync,};/** *	register_busmouse - register a bus mouse interface *	@ops: busmouse structure for the mouse * *	Registers a mouse with the driver. The return is mouse number on *	success and a negative errno code on an error. The passed ops *	structure most not be freed until the mouser is unregistered */ int register_busmouse(struct busmouse *ops){	unsigned int msedev = MINOR_TO_MOUSE(ops->minor);	struct busmouse_data *mse;	int ret;	if (msedev >= NR_MICE) {		printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",		       ops->minor);		return -EINVAL;	}	mse = kmalloc(sizeof(*mse), GFP_KERNEL);	if (!mse)		return -ENOMEM;	down(&mouse_sem);	if (busmouse_data[msedev])	{		up(&mouse_sem);		kfree(mse);		return -EBUSY;	}	memset(mse, 0, sizeof(*mse));	mse->miscdev.minor = ops->minor;	mse->miscdev.name = ops->name;	mse->miscdev.fops = &busmouse_fops;	mse->ops = ops;	mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;	init_waitqueue_head(&mse->wait);	busmouse_data[msedev] = mse;	ret = misc_register(&mse->miscdev);	if (!ret)		ret = msedev;	up(&mouse_sem);		return ret;}/** *	unregister_busmouse - unregister a bus mouse interface *	@mousedev: Mouse number to release * *	Unregister a previously installed mouse handler. The mousedev *	passed is the return code from a previous call to register_busmouse */ int unregister_busmouse(int mousedev){	int err = -EINVAL;	if (mousedev < 0)		return 0;	if (mousedev >= NR_MICE) {		printk(KERN_ERR "busmouse: trying to free mouse on"		       " mousedev %d\n", mousedev);		return -EINVAL;	}	down(&mouse_sem);		if (!busmouse_data[mousedev]) {		printk(KERN_WARNING "busmouse: trying to free free mouse"		       " on mousedev %d\n", mousedev);		goto fail;	}	if (busmouse_data[mousedev]->active) {		printk(KERN_ERR "busmouse: trying to free active mouse"		       " on mousedev %d\n", mousedev);		goto fail;	}	err = misc_deregister(&busmouse_data[mousedev]->miscdev);	kfree(busmouse_data[mousedev]);	busmouse_data[mousedev] = NULL;fail:	up(&mouse_sem);	return err;}EXPORT_SYMBOL(busmouse_add_movementbuttons);EXPORT_SYMBOL(busmouse_add_movement);EXPORT_SYMBOL(busmouse_add_buttons);EXPORT_SYMBOL(register_busmouse);EXPORT_SYMBOL(unregister_busmouse);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -