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

📄 hp_psaux.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
字号:
/* *      LASI PS/2 keyboard/psaux driver for HP-PARISC workstations *       *      (c) Copyright 1999 The Puffin Group Inc. *      by Alex deVries <adevries@thepuffingroup.com> *	Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org> * *	2000/10/26	Debacker Xavier (debackex@esiee.fr) *			Marteau Thomas (marteaut@esiee.fr) * 			Djoudi Malek (djoudim@esiee.fr) *	fixed leds control *	implemented the psaux and controlled the mouse scancode based on pc_keyb.c */#include <linux/config.h>#include <asm/hardware.h>#include <asm/keyboard.h>#include <asm/gsc.h>#include <linux/types.h>#include <linux/ptrace.h>	/* interrupt.h wants struct pt_regs defined */#include <linux/interrupt.h>#include <linux/sched.h>	/* for request_irq/free_irq */#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/wait.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/pc_keyb.h>#include <linux/kbd_kern.h>/* mouse includes */#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/random.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <linux/poll.h>/* HP specific LASI PS/2 keyboard and psaux constants */#define	AUX_REPLY_ACK	0xFA	/* Command byte ACK. */#define	AUX_RECONNECT	0xAA	/* scancode when ps2 device is plugged (back) in */#define	LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */#define	LASI_ID		0x00	/* ID and reset port offsets */#define	LASI_RESET	0x00#define	LASI_RCVDATA	0x04	/* receive and transmit port offsets */#define	LASI_XMTDATA	0x04#define	LASI_CONTROL	0x08	/* see: control register bits */#define	LASI_STATUS	0x0C	/* see: status register bits *//* control register bits */#define LASI_CTRL_ENBL	0x01	/* enable interface */#define LASI_CTRL_LPBXR	0x02	/* loopback operation */#define LASI_CTRL_DIAG	0x20	/* directly control clock/data line */#define LASI_CTRL_DATDIR 0x40	/* data line direct control */#define LASI_CTRL_CLKDIR 0x80	/* clock line direct control *//* status register bits */#define LASI_STAT_RBNE	0x01#define LASI_STAT_TBNE	0x02#define LASI_STAT_TERR	0x04#define LASI_STAT_PERR	0x08#define LASI_STAT_CMPINTR 0x10#define LASI_STAT_DATSHD 0x40#define LASI_STAT_CLKSHD 0x80static void *lasikbd_hpa;static void *lasips2_hpa;static inline u8 read_input(void *hpa){	return gsc_readb(hpa+LASI_RCVDATA);}static inline u8 read_control(void *hpa){        return gsc_readb(hpa+LASI_CONTROL);}static inline void write_control(u8 val, void *hpa){	gsc_writeb(val, hpa+LASI_CONTROL);}static inline u8 read_status(void *hpa){        return gsc_readb(hpa+LASI_STATUS);}static int write_output(u8 val, void *hpa){	int wait = 0;	while (read_status(hpa) & LASI_STAT_TBNE) {		wait++;		if (wait>10000) {			/* printk(KERN_WARNING "Lasi PS/2 transmit buffer timeout\n"); */			return 0;		}	}	if (wait)		printk(KERN_DEBUG "Lasi PS/2 wait %d\n", wait);		gsc_writeb(val, hpa+LASI_XMTDATA);	return 1;}/* This function is the PA-RISC adaptation of i386 source */static inline int aux_write_ack(u8 val){      return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET);}static void lasikbd_leds(unsigned char leds){	write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);	write_output(leds, lasikbd_hpa);	write_output(KBD_CMD_ENABLE, lasikbd_hpa);}#if 0/* this might become useful again at some point.  not now  -prumpf */int lasi_ps2_test(void *hpa){	u8 control,c;	int i, ret = 0;	control = read_control(hpa);	write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa);	for (i=0; i<256; i++) {		write_output(i, hpa);		while (!(read_status(hpa) & LASI_STAT_RBNE))		    /* just wait */;		    		c = read_input(hpa);		if (c != i)			ret--;	}	write_control(control, hpa);	return ret;}#endif static int __init lasi_ps2_reset(void *hpa, int id){	u8 control;	int ret = 1;	/* reset the interface */	gsc_writeb(0xff, hpa+LASI_RESET);	gsc_writeb(0x0 , hpa+LASI_RESET);			/* enable it */	control = read_control(hpa);	write_control(control | LASI_CTRL_ENBL, hpa);        /* initializes the leds at the default state */        if (id==0) {           write_output(KBD_CMD_SET_LEDS, hpa);	   write_output(0, hpa);	   ret = write_output(KBD_CMD_ENABLE, hpa);	}	return ret;}static int inited;static void lasi_ps2_init_hw(void){	++inited;}/* Greatly inspired by pc_keyb.c *//* * Wait for keyboard controller input buffer to drain. * * Don't use 'jiffies' so that we don't depend on * interrupts.. * * Quote from PS/2 System Reference Manual: * * "Address hex 0060 and address hex 0064 should be written only when * the input-buffer-full bit and output-buffer-full bit in the * Controller Status register are set 0." */#ifdef CONFIG_PSMOUSEstatic struct aux_queue	*queue;static spinlock_t	kbd_controller_lock = SPIN_LOCK_UNLOCKED;static unsigned char	mouse_reply_expected;static int 		aux_count;static int fasync_aux(int fd, struct file *filp, int on){	int retval;		retval = fasync_helper(fd, filp, on, &queue->fasync);	if (retval < 0)		return retval;		return 0;}static inline void handle_mouse_scancode(unsigned char scancode){	if (mouse_reply_expected) {		if (scancode == AUX_REPLY_ACK) {			mouse_reply_expected--;			return;		}		mouse_reply_expected = 0;	}	else if (scancode == AUX_RECONNECT) {		queue->head = queue->tail = 0;  /* Flush input queue */		return;	}	add_mouse_randomness(scancode);	if (aux_count) {		int head = queue->head;						queue->buf[head] = scancode;		head = (head + 1) & (AUX_BUF_SIZE-1);				if (head != queue->tail) {			queue->head = head;			kill_fasync(&queue->fasync, SIGIO, POLL_IN);			wake_up_interruptible(&queue->proc_list);		}	}}static inline int queue_empty(void){	return queue->head == queue->tail;}static unsigned char get_from_queue(void){	unsigned char result;	unsigned long flags;	spin_lock_irqsave(&kbd_controller_lock, flags);	result = queue->buf[queue->tail];	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);	spin_unlock_irqrestore(&kbd_controller_lock, flags);	return result;}/* * Write to the aux device. */static ssize_t write_aux(struct file * file, const char * buffer,			 size_t count, loff_t *ppos){	ssize_t retval = 0;	if (count) {		ssize_t written = 0;		if (count > 32)			count = 32; /* Limit to 32 bytes. */		do {			char c;			get_user(c, buffer++);			written++;		} while (--count);		retval = -EIO;		if (written) {			retval = written;			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;		}	}	return retval;}static ssize_t read_aux(struct file * file, char * buffer,			size_t count, loff_t *ppos){	DECLARE_WAITQUEUE(wait, current);	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:		set_current_state(TASK_INTERRUPTIBLE);		if (queue_empty() && !signal_pending(current)) {			schedule();			goto repeat;		}		set_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;}static int open_aux(struct inode * inode, struct file * file){	if (aux_count++) 		return 0;	queue->head = queue->tail = 0;	/* Flush input queue */	aux_count = 1;	aux_write_ack(AUX_ENABLE_DEV);	/* Enable aux device */		return 0;}/* No kernel lock held - fine */static unsigned int aux_poll(struct file *file, poll_table * wait){	poll_wait(file, &queue->proc_list, wait);	if (!queue_empty())		return POLLIN | POLLRDNORM;	return 0;}static int release_aux(struct inode * inode, struct file * file){	lock_kernel();	fasync_aux(-1, file, 0);	if (--aux_count) {	   unlock_kernel();		return 0;	}	unlock_kernel();	return 0;}static struct file_operations psaux_fops = {	read:		read_aux,	write:		write_aux,	poll:		aux_poll,	open:		open_aux,	release:	release_aux,	fasync:		fasync_aux,};static struct miscdevice psaux_mouse = {	minor:		PSMOUSE_MINOR,	name:		"psaux",	fops:		&psaux_fops,};#endif /* CONFIG_PSMOUSE *//* This function is looking at the PS2 controller and empty the two buffers */static u8 handle_lasikbd_event(void *hpa){        u8 status_keyb,status_mouse,scancode,id;        extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */                /* Mask to get the base address of the PS/2 controller */        id = gsc_readb(hpa+LASI_ID) & 0x0f;                if (id==1)            hpa -= LASI_PSAUX_OFFSET;         lasikbd_hpa = hpa;                status_keyb = read_status(hpa);        status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);        while ((status_keyb|status_mouse) & LASI_STAT_RBNE){                      while (status_keyb & LASI_STAT_RBNE) {	                    scancode = read_input(hpa);	      /* XXX don't know if this is a valid fix, but filtering	       * 0xfa avoids 'unknown scancode' errors on, eg, capslock	       * on some keyboards.	       */	      if (inited && scancode != 0xfa)		 handle_at_scancode(scancode); 	      	      status_keyb =read_status(hpa);           }	   #ifdef CONFIG_PSMOUSE           while (status_mouse & LASI_STAT_RBNE) {	      scancode = read_input(hpa+LASI_PSAUX_OFFSET);	      handle_mouse_scancode(scancode);              status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);	   }           status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);#endif /* CONFIG_PSMOUSE */           status_keyb = read_status(hpa);        }        tasklet_schedule(&keyboard_tasklet);        return (status_keyb|status_mouse);}	extern struct pt_regs *kbd_pt_regs;static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs){	lasips2_hpa = dev; /* save "hpa" for lasikbd_leds() */	kbd_pt_regs = regs;	handle_lasikbd_event(lasips2_hpa);}extern int pckbd_translate(unsigned char, unsigned char *, char);static struct kbd_ops gsc_ps2_kbd_ops = {	translate:	pckbd_translate,	init_hw:	lasi_ps2_init_hw,	leds:		lasikbd_leds,#ifdef CONFIG_MAGIC_SYSRQ	sysrq_key:	0x54,	sysrq_xlate:	hp_ps2kbd_sysrq_xlate,#endif};static int __initlasi_ps2_register(struct hp_device *d, struct pa_iodc_driver *dri){	void *hpa = (void *) d->hpa;	unsigned int irq;	char *name;	int device_found;	u8 id;	id = gsc_readb(hpa+LASI_ID) & 0x0f;	switch (id) {	case 0:		name = "keyboard";		lasikbd_hpa = hpa;		break;	case 1:		name = "psaux";		break;	default:		printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n",			__FUNCTION__, id );		return 0;	}		/* reset the PS/2 port */	device_found = lasi_ps2_reset(hpa,id);	/* allocate the irq and memory region for that device */	if (!(irq = busdevice_alloc_irq(d)))		return -ENODEV;		    	if (request_irq(irq, lasikbd_interrupt, 0, name, hpa))		return -ENODEV;		if (!request_mem_region((unsigned long)hpa, LASI_STATUS + 4, name))		return -ENODEV;	switch (id) {	case 0:			register_kbd_ops(&gsc_ps2_kbd_ops);		break;	case 1:#ifdef CONFIG_PSMOUSE		queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);		if (!queue)			return -ENOMEM;		memset(queue, 0, sizeof(*queue));		queue->head = queue->tail = 0;		init_waitqueue_head(&queue->proc_list);				misc_register(&psaux_mouse);		aux_write_ack(AUX_ENABLE_DEV);		/* try it a second time, this will give status if the device is		 * available */		device_found = aux_write_ack(AUX_ENABLE_DEV);		break;#else		/* return without printing any unnecessary and misleading info */		return 0;	#endif	} /* of case */		printk(KERN_INFO "PS/2 %s controller at 0x%08lx (irq %d) found, "			 "%sdevice attached.\n",			name, (unsigned long)hpa, irq,			device_found ? "":"no ");	return 0;}static struct pa_iodc_driver lasi_psaux_drivers_for[] __initdata = {	{HPHW_FIO, 0x0, 0,0x00084, 0, 0,		DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION,		"Lasi psaux", "generic", (void *) lasi_ps2_register},	{ 0, }};static int __init gsc_ps2_init(void) {	return pdc_register_driver(lasi_psaux_drivers_for);}module_init(gsc_ps2_init);

⌨️ 快捷键说明

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