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

📄 psaux.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
字号:
/* * linux/kernel/chr_drv/psaux.c * * Driver for PS/2 type mouse by Johan Myreen. * * Supports pointing devices attached to a PS/2 type * Keyboard and Auxiliary Device Controller. * * Corrections in device setup for some laptop mice & trackballs. * 02Feb93  (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) * * Changed to prevent keyboard lockups on AST Power Exec. * 28Jul93  Brad Bosch - brad@lachman.com * * Modified by Johan Myreen (jem@cs.hut.fi) 04Aug93 *   to include support for QuickPort mouse. * * Changed references to "QuickPort" with "82C710" since "QuickPort" * is not what this driver is all about -- QuickPort is just a * connector type, and this driver is for the mouse port on the Chips * & Technologies 82C710 interface chip. 15Nov93 jem@cs.hut.fi *//* Uncomment the following line if your mouse needs initialization. *//* #define INITIALIZE_DEVICE */#include <linux/timer.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/fcntl.h>#include <linux/errno.h>#include <asm/io.h>#include <asm/segment.h>#include <asm/system.h>#include <linux/config.h>/* aux controller ports */#define AUX_INPUT_PORT	0x60		/* Aux device output buffer */#define AUX_OUTPUT_PORT	0x60		/* Aux device input buffer */#define AUX_COMMAND	0x64		/* Aux device command buffer */#define AUX_STATUS	0x64		/* Aux device status reg *//* aux controller status bits */#define AUX_OBUF_FULL	0x21		/* output buffer (from device) full */#define AUX_IBUF_FULL	0x02		/* input buffer (to device) full *//* aux controller commands */#define AUX_CMD_WRITE	0x60		/* value to write to controller */#define AUX_MAGIC_WRITE	0xd4		/* value to send aux device data */#define AUX_INTS_ON	0x47		/* enable controller interrupts */#define AUX_INTS_OFF	0x65		/* disable controller interrupts */#define AUX_DISABLE	0xa7		/* disable aux */#define AUX_ENABLE	0xa8		/* enable aux *//* aux device commands */#define AUX_SET_RES	0xe8		/* set resolution */#define AUX_SET_SCALE11	0xe6		/* set 1:1 scaling */#define AUX_SET_SCALE21	0xe7		/* set 2:1 scaling */#define AUX_GET_SCALE	0xe9		/* get scaling factor */#define AUX_SET_STREAM	0xea		/* set stream mode */#define AUX_SET_SAMPLE	0xf3		/* set sample rate */#define AUX_ENABLE_DEV	0xf4		/* enable aux device */#define AUX_DISABLE_DEV	0xf5		/* disable aux device */#define AUX_RESET	0xff		/* reset aux device */#define MAX_RETRIES	60		/* some aux operations take long time*/#define AUX_IRQ		12#define AUX_BUF_SIZE	2048/* 82C710 definitions */#define QP_DATA         0x310		/* Data Port I/O Address */#define QP_STATUS       0x311		/* Status Port I/O Address */#define QP_DEV_IDLE     0x01	        /* Device Idle */#define QP_RX_FULL      0x02		/* Device Char received */#define QP_TX_IDLE      0x04		/* Device XMIT Idle */#define QP_RESET        0x08		/* Device Reset */#define QP_INTS_ON      0x10		/* Device Interrupt On */#define QP_ERROR_FLAG   0x20		/* Device Error */#define QP_CLEAR        0x40		/* Device Clear */#define QP_ENABLE       0x80		/* Device Enable */#define QP_IRQ          12extern unsigned char aux_device_present;extern unsigned char kbd_read_mask;	/* from keyboard.c */struct aux_queue {	unsigned long head;	unsigned long tail;	struct wait_queue *proc_list;	unsigned char buf[AUX_BUF_SIZE];};static struct aux_queue *queue;static int aux_ready = 0;static int aux_busy = 0;static int aux_present = 0;static int poll_aux_status(void);#ifdef CONFIG_82C710_MOUSEstatic int qp_present = 0;static int qp_busy = 0;static int qp_data = QP_DATA;static int qp_status = QP_STATUS;static int poll_qp_status(void);static int probe_qp(void);#endif/* * Write to aux device */static void aux_write_dev(int val){	poll_aux_status();	outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);	/* write magic cookie */	poll_aux_status();	outb_p(val,AUX_OUTPUT_PORT);		/* write data */}/* * Write to device & handle returned ack */ #if defined INITIALIZE_DEVICEstatic int aux_write_ack(int val){        int retries = 0;	aux_write_dev(val);		/* write the value to the device */	while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL	            && retries < MAX_RETRIES) {          /* wait for ack */       		current->state = TASK_INTERRUPTIBLE;		current->timeout = jiffies + 5;		schedule();		retries++;        }	if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)	{		return (inb(AUX_INPUT_PORT));	}	return 0;}#endif /* INITIALIZE_DEVICE *//* * Write aux device command */static void aux_write_cmd(int val){	poll_aux_status();	outb_p(AUX_CMD_WRITE,AUX_COMMAND);	poll_aux_status();	outb_p(val,AUX_OUTPUT_PORT);}static unsigned int get_from_queue(void){	unsigned int result;	unsigned long flags;	save_flags(flags);	cli();	result = queue->buf[queue->tail];	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);	restore_flags(flags);	return result;}static inline int queue_empty(void){	return queue->head == queue->tail;}/* * Interrupt from the auxiliary device: a character * is waiting in the keyboard/aux controller. */static void aux_interrupt(int cpl){	int head = queue->head;	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);	queue->buf[head] = inb(AUX_INPUT_PORT);	if (head != maxhead) {		head++;		head &= AUX_BUF_SIZE-1;	}	queue->head = head;	aux_ready = 1;	wake_up_interruptible(&queue->proc_list);}/* * Interrupt handler for the 82C710 mouse port. A character * is waiting in the 82C710. */#ifdef CONFIG_82C710_MOUSEstatic void qp_interrupt(int cpl){	int head = queue->head;	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);	queue->buf[head] = inb(qp_data);	if (head != maxhead) {		head++;		head &= AUX_BUF_SIZE-1;	}	queue->head = head;	aux_ready = 1;	wake_up_interruptible(&queue->proc_list);}#endifstatic void release_aux(struct inode * inode, struct file * file){	aux_write_dev(AUX_DISABLE_DEV);		/* disable aux device */	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */	poll_aux_status();	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */	poll_aux_status();	free_irq(AUX_IRQ);	aux_busy = 0;}#ifdef CONFIG_82C710_MOUSEstatic void release_qp(struct inode * inode, struct file * file){	unsigned char status;	if (!poll_qp_status())	        printk("Warning: Mouse device busy in release_qp()\n");	status = inb_p(qp_status);	outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);	if (!poll_qp_status())	        printk("Warning: Mouse device busy in release_qp()\n");	free_irq(QP_IRQ);	qp_busy = 0;}#endif/* * Install interrupt handler. * Enable auxiliary device. */static int open_aux(struct inode * inode, struct file * file){	if (!aux_present)		return -EINVAL;	if (aux_busy)		return -EBUSY;	if (!poll_aux_status())		return -EBUSY;	aux_busy = 1;	queue->head = queue->tail = 0;	        /* Flush input queue */	if (request_irq(AUX_IRQ, aux_interrupt)) {		aux_busy = 0;		return -EBUSY;	}	poll_aux_status();	outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */	aux_write_dev(AUX_ENABLE_DEV);		/* enable aux device */	aux_write_cmd(AUX_INTS_ON);		/* enable controller ints */	poll_aux_status();	aux_ready = 0;	return 0;}#ifdef CONFIG_82C710_MOUSE/* * Install interrupt handler. * Enable the device, enable interrupts. Set qp_busy * (allow only one opener at a time.) */static int open_qp(struct inode * inode, struct file * file){        unsigned char status;	if (!qp_present)		return -EINVAL;	if (qp_busy)		return -EBUSY;	if (request_irq(QP_IRQ, qp_interrupt))		return -EBUSY;	qp_busy = 1;	status = inb_p(qp_status);	status |= (QP_ENABLE|QP_RESET);	outb_p(status, qp_status);	status &= ~(QP_RESET);	outb_p(status, qp_status);	queue->head = queue->tail = 0;          /* Flush input queue */	status |= QP_INTS_ON;	outb_p(status, qp_status);              /* Enable interrupts */	while (!poll_qp_status()) {	        printk("Error: Mouse device busy in open_qp()\n");		return -EBUSY;        }	outb_p(AUX_ENABLE_DEV, qp_data);	/* Wake up mouse */	return 0;}#endif/* * Write to the aux device. */static int write_aux(struct inode * inode, struct file * file, char * buffer, int count){	int i = count;	while (i--) {		if (!poll_aux_status())			return -EIO;		outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);		if (!poll_aux_status())			return -EIO;		outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT);	}	inode->i_mtime = CURRENT_TIME;	return count;}#ifdef CONFIG_82C710_MOUSE/* * Write to the 82C710 mouse device. */static int write_qp(struct inode * inode, struct file * file, char * buffer, int count){	int i = count;	while (i--) {		if (!poll_qp_status())			return -EIO;		outb_p(get_fs_byte(buffer++), qp_data);	}	inode->i_mtime = CURRENT_TIME;	return count;}#endif/* * Put bytes from input queue to buffer. */static int read_aux(struct inode * inode, struct file * file, char * buffer, int count){	struct wait_queue wait = { current, NULL };	int i = count;	unsigned char c;	if (queue_empty()) {		if (file->f_flags & O_NONBLOCK)			return -EAGAIN;		add_wait_queue(&queue->proc_list, &wait);repeat:		current->state = TASK_INTERRUPTIBLE;		if (queue_empty() && !(current->signal & ~current->blocked)) {			schedule();			goto repeat;		}		current->state = TASK_RUNNING;		remove_wait_queue(&queue->proc_list, &wait);				}			while (i > 0 && !queue_empty()) {		c = get_from_queue();		put_fs_byte(c, buffer++);		i--;	}	aux_ready = !queue_empty();	if (count-i) {		inode->i_atime = CURRENT_TIME;		return count-i;	}	if (current->signal & ~current->blocked)		return -ERESTARTSYS;	return 0;}static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait){	if (sel_type != SEL_IN)		return 0;	if (aux_ready)		return 1;	select_wait(&queue->proc_list, wait);	return 0;}struct file_operations psaux_fops = {	NULL,		/* seek */	read_aux,	write_aux,	NULL, 		/* readdir */	aux_select,	NULL, 		/* ioctl */	NULL,		/* mmap */	open_aux,	release_aux,};/* * Initialize driver. First check for a 82C710 chip; if found * forget about the Aux port and use the *_qp functions. */unsigned long psaux_init(unsigned long kmem_start){        int qp_found = 0;#ifdef CONFIG_82C710_MOUSE        if ((qp_found = probe_qp())) {	        printk("82C710 type pointing device detected -- driver installed.\n");/*		printk("82C710 address = %x (should be 0x310)\n", qp_data); */		qp_present = 1;		psaux_fops.write = write_qp;		psaux_fops.open = open_qp;		psaux_fops.release = release_qp;		poll_qp_status();	} else#endif	if (aux_device_present == 0xaa) {	        printk("PS/2 auxiliary pointing device detected -- driver installed.\n");         	aux_present = 1;		kbd_read_mask = AUX_OBUF_FULL;	        poll_aux_status();	} else {		return kmem_start;              /* No mouse at all */	}	queue = (struct aux_queue *) kmem_start;	kmem_start += sizeof (struct aux_queue);	queue->head = queue->tail = 0;	queue->proc_list = NULL;	if (!qp_found) {#if defined INITIALIZE_DEVICE                outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */	        aux_write_ack(AUX_SET_SAMPLE);	        aux_write_ack(100);			/* 100 samples/sec */	        aux_write_ack(AUX_SET_RES);	        aux_write_ack(3);			/* 8 counts per mm */	        aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */	        poll_aux_status();#endif /* INITIALIZE_DEVICE */        	outb_p(AUX_DISABLE,AUX_COMMAND);   /* Disable Aux device */	        aux_write_cmd(AUX_INTS_OFF);    /* disable controller ints */		poll_aux_status();	}	return kmem_start;}static int poll_aux_status(void){	int retries=0;	while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) { 		if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)			inb_p(AUX_INPUT_PORT);		current->state = TASK_INTERRUPTIBLE;		current->timeout = jiffies + 5;		schedule();		retries++;	}	return !(retries==MAX_RETRIES);}#ifdef CONFIG_82C710_MOUSE/* * Wait for device to send output char and flush any input char. */static int poll_qp_status(void){	int retries=0;	while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))	               != (QP_DEV_IDLE|QP_TX_IDLE)	               && retries < MAX_RETRIES) {	        if (inb_p(qp_status)&(QP_RX_FULL))		        inb_p(qp_data);		current->state = TASK_INTERRUPTIBLE;		current->timeout = jiffies + 5;		schedule();		retries++;	}	return !(retries==MAX_RETRIES);}/* * Function to read register in 82C710. */static inline unsigned char read_710(unsigned char index){        outb_p(index, 0x390);			/* Write index */	return inb_p(0x391);			/* Read the data */}/* * See if we can find a 82C710 device. Read mouse address. */static int probe_qp(void){        outb_p(0x55, 0x2fa);			/* Any value except 9, ff or 36 */	outb_p(0xaa, 0x3fa);			/* Inverse of 55 */	outb_p(0x36, 0x3fa);			/* Address the chip */	outb_p(0xe4, 0x3fa);			/* 390/4; 390 = config address */	outb_p(0x1b, 0x2fa);			/* Inverse of e4 */	if (read_710(0x0f) != 0xe4)		/* Config address found? */	  return 0;				/* No: no 82C710 here */	qp_data = read_710(0x0d)*4;		/* Get mouse I/O address */	qp_status = qp_data+1;	outb_p(0x0f, 0x390);	outb_p(0x0f, 0x391);			/* Close config mode */	return 1;}#endif

⌨️ 快捷键说明

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