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

📄 qpmouse.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
字号:
/* * linux/drivers/char/qpmouse.c * * Driver for a 82C710 C&T mouse interface chip. * * Based on the PS/2 driver by Johan Myreen. * * Corrections in device setup for some laptop mice & trackballs. * 02Feb93  (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) * * Modified by Johan Myreen (jem@iki.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@iki.fi * * Added support for SIGIO. 28Jul95 jem@iki.fi * * Rearranged SIGIO support to use code from tty_io.  9Sept95 ctm@ardi.com * * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk> */#include <linux/module.h> #include <linux/sched.h>#include <linux/kernel.h>#include <linux/interrupt.h>#include <linux/fcntl.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/malloc.h>#include <linux/miscdevice.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/init.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/semaphore.h>#include "pc_keyb.h"		/* mouse enable command.. *//* * We use the same minor number as the PS/2 mouse for (bad) historical * reasons.. */#define PSMOUSE_MINOR      1	       		/* Minor device # for this mouse */#define QP_BUF_SIZE	2048struct qp_queue {	unsigned long head;	unsigned long tail;	struct wait_queue *proc_list;	struct fasync_struct *fasync;	unsigned char buf[QP_BUF_SIZE];};static struct qp_queue *queue;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) & (QP_BUF_SIZE-1);	restore_flags(flags);	return result;}static inline int queue_empty(void){	return queue->head == queue->tail;}static int fasync_qp(int fd, struct file *filp, int on){	int retval;	retval = fasync_helper(fd, filp, on, &queue->fasync);	if (retval < 0)		return retval;	return 0;}/* *	82C710 Interface */#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          12static int qp_present = 0;static int qp_count = 0;static int qp_data = QP_DATA;static int qp_status = QP_STATUS;static int poll_qp_status(void);static int probe_qp(void);/* * Interrupt handler for the 82C710 mouse port. A character * is waiting in the 82C710. */static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs){	int head = queue->head;	int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1);	add_mouse_randomness(queue->buf[head] = inb(qp_data));	if (head != maxhead) {		head++;		head &= QP_BUF_SIZE-1;	}	queue->head = head;	if (queue->fasync)		kill_fasync(queue->fasync, SIGIO);	wake_up_interruptible(&queue->proc_list);}static int release_qp(struct inode * inode, struct file * file){	unsigned char status;	fasync_qp(-1, file, 0);	if (!--qp_count) {		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, NULL);		MOD_DEC_USE_COUNT;	}	return 0;}/* * Install interrupt handler. * Enable the device, enable interrupts.  */static int open_qp(struct inode * inode, struct file * file){	unsigned char status;	if (!qp_present)		return -EINVAL;	if (qp_count++)		return 0;	if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {		qp_count--;		return -EBUSY;	}	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");		qp_count--;		status &= ~(QP_ENABLE|QP_INTS_ON);		outb_p(status, qp_status);		free_irq(QP_IRQ, NULL);		return -EBUSY;	}	outb_p(AUX_ENABLE_DEV, qp_data);	/* Wake up mouse */	MOD_INC_USE_COUNT;	return 0;}/* * Write to the 82C710 mouse device. */static ssize_t write_qp(struct file * file, const char * buffer,			size_t count, loff_t *ppos){	ssize_t i = count;	while (i--) {		char c;		if (!poll_qp_status())			return -EIO;		get_user(c, buffer++);		outb_p(c, qp_data);	}	file->f_dentry->d_inode->i_mtime = CURRENT_TIME;	return count;}static unsigned int poll_qp(struct file *file, poll_table * wait){	poll_wait(file, &queue->proc_list, wait);	if (!queue_empty())		return POLLIN | POLLRDNORM;	return 0;}/* * Wait for device to send output char and flush any input char. */#define MAX_RETRIES (60)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;		schedule_timeout((5*HZ + 99) / 100);		retries++;	}	return !(retries==MAX_RETRIES);}/* * Put bytes from input queue to buffer. */static ssize_t read_qp(struct file * file, char * buffer,			size_t count, loff_t *ppos){	struct wait_queue wait = { current, NULL };	ssize_t 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() && !signal_pending(current)) {			schedule();			goto repeat;		}		current->state = TASK_RUNNING;		remove_wait_queue(&queue->proc_list, &wait);	}	while (i > 0 && !queue_empty()) {		c = get_from_queue();		put_user(c, buffer++);		i--;	}	if (count-i) {		file->f_dentry->d_inode->i_atime = CURRENT_TIME;		return count-i;	}	if (signal_pending(current))		return -ERESTARTSYS;	return 0;}struct file_operations qp_fops = {	NULL,		/* seek */	read_qp,	write_qp,	NULL, 		/* readdir */	poll_qp,	NULL, 		/* ioctl */	NULL,		/* mmap */	open_qp,	NULL,		/* flush */	release_qp,	NULL,	fasync_qp,};/* * Initialize driver. */static struct miscdevice qp_mouse = {	PSMOUSE_MINOR, "QPmouse", &qp_fops};/* * 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 __init 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;}int __init qpmouse_init(void){	if (!probe_qp())		return -EIO;	printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");/*	printk("82C710 address = %x (should be 0x310)\n", qp_data); */	qp_present = 1;	misc_register(&qp_mouse);	queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);	memset(queue, 0, sizeof(*queue));	queue->head = queue->tail = 0;	queue->proc_list = NULL;	return 0;}#ifdef MODULEint init_module(void){	return qpmouse_init();}void cleanup_module(void){	misc_deregister(&qp_mouse);	kfree(queue);}#endif

⌨️ 快捷键说明

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