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

📄 amba_kmi_keyb.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/char/amba_kmi_keyb.c * *  AMBA Keyboard and Mouse Interface Driver * *  Copyright (C) 2000 Deep Blue Solutions Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *  This keyboard driver drives a PS/2 keyboard and mouse connected *  to the KMI interfaces.  The KMI interfaces are nothing more than *  a uart; there is no inteligence in them to do keycode translation. *  We leave all that up to the keyboard itself. * *	   FIXES: *		 dirk.uffmann@nokia.com:  enabled PS/2 reconnection */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/interrupt.h>	/* for in_interrupt */#include <linux/timer.h>#include <linux/init.h>#include <linux/delay.h>	/* for udelay */#include <linux/kbd_kern.h>	/* for keyboard_tasklet */#include <linux/kbd_ll.h>#include <asm/io.h>#include <asm/hardware/amba_kmi.h>#include <asm/mach/amba_kmi.h>#include <asm/keyboard.h>//#define DEBUG(s) printk s#define DEBUG(s) do { } while (0)#define CONFIG_AMBA_PS2_RECONNECT#define KMI_BASE	(kmi->base)#define KMI_RESET		0x00#define KMI_RESET_POR		0x01#define KMI_RESET_DONE		0x02#define KMI_NO_ACK		0xffff#define PS2_O_RESET		0xff#define PS2_O_RESEND		0xfe#define PS2_O_DISABLE		0xf5#define PS2_O_ENABLE		0xf4#define PS2_O_ECHO		0xee/* * Keyboard */#define PS2_O_SET_DEFAULT	0xf6#define PS2_O_SET_RATE_DELAY	0xf3#define PS2_O_SET_SCANSET	0xf0#define PS2_O_INDICATORS	0xed/* * Mouse */#define PS2_O_SET_SAMPLE	0xf3#define PS2_O_SET_STREAM	0xea#define PS2_O_SET_RES		0xe8#define PS2_O_SET_SCALE21	0xe7#define PS2_O_SET_SCALE11	0xe6#define PS2_O_REQ_STATUS	0xe9/* * Responses */#define PS2_I_RESEND		0xfe#define PS2_I_DIAGFAIL		0xfc#define PS2_I_ACK		0xfa#define PS2_I_BREAK		0xf0#define PS2_I_ECHO		0xee#define PS2_I_BAT_OK		0xaastatic char *kmi_type[] = { "Keyboard", "Mouse" };static struct kmi_info *kmi_keyb;static struct kmi_info *kmi_mouse;static inline void __kmi_send(struct kmi_info *kmi, u_int val){	u_int status;	do {		status = __raw_readb(KMISTAT);	} while (!(status & KMISTAT_TXEMPTY));	kmi->resend_count += 1;	__raw_writeb(val, KMIDATA);}static void kmi_send(struct kmi_info *kmi, u_int val){	kmi->last_tx = val;	kmi->resend_count = -1;	__kmi_send(kmi, val);}static u_int kmi_send_and_wait(struct kmi_info *kmi, u_int val, u_int timeo){	DECLARE_WAITQUEUE(wait, current);	if (kmi->present == 0)		return KMI_NO_ACK;	kmi->res = KMI_NO_ACK;	kmi->last_tx = val;	kmi->resend_count = -1;	if (current->pid != 0 && !in_interrupt()) {		add_wait_queue(&kmi->wait_q, &wait);		set_current_state(TASK_UNINTERRUPTIBLE);		__kmi_send(kmi, val);		schedule_timeout(timeo);		current->state = TASK_RUNNING;		remove_wait_queue(&kmi->wait_q, &wait);	} else {		int i;		__kmi_send(kmi, val);		for (i = 0; i < 1000; i++) {			if (kmi->res != KMI_NO_ACK)				break;			udelay(100);		}	}	return kmi->res;}/* * This lot should probably be separated into a separate file... */#ifdef CONFIG_KMI_MOUSE#include <linux/fs.h>		/* for struct file_ops */#include <linux/poll.h> 	/* for poll_table */#include <linux/miscdevice.h>	/* for struct miscdev */#include <linux/random.h>	/* for add_mouse_randomness */#include <linux/slab.h> 	/* for kmalloc */#include <linux/smp_lock.h>	/* for {un,}lock_kernel */#include <linux/spinlock.h>#include <asm/uaccess.h>#define BUF_SZ	2048static spinlock_t kmi_mouse_lock;static int kmi_mouse_count;static struct queue {	u_int			head;	u_int			tail;	struct fasync_struct	*fasync;	unsigned char		buf[BUF_SZ];} *queue;#define queue_empty() (queue->head == queue->tail)static u_char get_from_queue(void){	unsigned long flags;	u_char res;	spin_lock_irqsave(&kmi_mouse_lock, flags);	res = queue->buf[queue->tail];	queue->tail = (queue->tail + 1) & (BUF_SZ-1);	spin_unlock_irqrestore(&kmi_mouse_lock, flags);	return res;}static ssize_tkmi_mouse_read(struct file *file, char *buf, size_t count, loff_t *ppos){	ssize_t i = count;	if (queue_empty()) {		int ret;		if (file->f_flags & O_NONBLOCK)			return -EAGAIN;		ret = wait_event_interruptible(kmi_mouse->wait_q, !queue_empty());		if (ret)			return ret;	}	while (i > 0 && !queue_empty()) {		u_char c;		c = get_from_queue();		put_user(c, buf++);		i--;	}	if (count - i)		file->f_dentry->d_inode->i_atime = CURRENT_TIME;	return count - i;}static ssize_tkmi_mouse_write(struct file *file, const char *buf, size_t count, loff_t *ppos){	ssize_t retval = 0;	if (count > 32)		count = 32;	do {		char c;		get_user(c, buf++);		kmi_send_and_wait(kmi_mouse, c, HZ);		retval++;	} while (--count);	if (retval)		file->f_dentry->d_inode->i_mtime = CURRENT_TIME;	return retval;}static unsigned intkmi_mouse_poll(struct file *file, poll_table *wait){	poll_wait(file, &kmi_mouse->wait_q, wait);	return (!queue_empty()) ? POLLIN | POLLRDNORM : 0;}static intkmi_mouse_release(struct inode *inode, struct file *file){	lock_kernel();	fasync_helper(-1, file, 0, &queue->fasync);	if (--kmi_mouse_count == 0)		kmi_send_and_wait(kmi_mouse, PS2_O_DISABLE, HZ);	unlock_kernel();	return 0;}static intkmi_mouse_open(struct inode *inode, struct file *file){	if (kmi_mouse_count++)		return 0;	queue->head = queue->tail = 0;	kmi_send_and_wait(kmi_mouse, PS2_O_ENABLE, HZ);	return 0;}static intkmi_mouse_fasync(int fd, struct file *filp, int on){	int retval = fasync_helper(fd, filp, on, &queue->fasync);	if (retval > 0)		retval = 0;	return retval;}static struct file_operations ps_fops = {	read:		kmi_mouse_read,	write:		kmi_mouse_write,	poll:		kmi_mouse_poll,	open:		kmi_mouse_open,	release:	kmi_mouse_release,	fasync: 	kmi_mouse_fasync,};static struct miscdevice ps_mouse = {	minor:		PSMOUSE_MINOR,	name:		"psaux",	fops:		&ps_fops,};static u_char kmi_mse_init_string[] = {	PS2_O_DISABLE,	PS2_O_SET_SAMPLE, 100,	PS2_O_SET_RES, 3,	PS2_O_SET_SCALE21};/* * The "normal" mouse scancode processing */static void kmi_mse_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs){	u_int head;	add_mouse_randomness(val);#ifdef CONFIG_AMBA_PS2_RECONNECT	/* Try to detect a hot-plug event on the PS/2 mouse port */	switch (kmi->hotplug_state) {	case 0:		/* Maybe we lost contact... */		if (val == PS2_I_BAT_OK) {			kmi->hotplug_state++;			DEBUG(("%s: Saw 0xAA. Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));		}		break;	case 1:		/* Again, maybe (but only maybe) we lost contact... */		if (val == 0) {			kmi->hotplug_state++;			kmi_send(kmi, PS2_O_REQ_STATUS);			DEBUG(("%s: Got 0xAA 0x00. Sent Status Request\n", kmi->name));		} else {			kmi->hotplug_state = 0;			DEBUG(("%s: No 0x00 followed 0xAA. No reconnect.\n", kmi->name));		}		break;	case 2:		/* Eat up acknowledge */		if (val == PS2_I_ACK)			kmi->hotplug_state++;		else {			kmi->hotplug_state = 0;			DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));		}		break;	case 3:		/* check if data reporting is still enabled, then no POR has happend */		kmi->reconnect = !(val & 1<<5);		DEBUG(("%s: Data reporting disabled?: (%d)\n", kmi->name, kmi->reconnect));		kmi->hotplug_state++;		DEBUG(("%s: Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));		break;	case 4:		/* Eat up one status byte */		kmi->hotplug_state++;		DEBUG(("%s: Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));		break;	case 5:		/* Eat up another status byte */		if (kmi->reconnect) {			kmi->config_num = 0;			kmi_send(kmi, kmi_mse_init_string[kmi->config_num]);			kmi->config_num++;			kmi->hotplug_state++;			DEBUG(("%s: Sending byte %d of PS/2 init string.\n", kmi->name, kmi->config_num));		} else {			kmi->hotplug_state = 0;			DEBUG(("%s: False Alarm...\n", kmi->name));		}		break;	case 6:		if (val == PS2_I_ACK && kmi->config_num < sizeof(kmi_mse_init_string)) {			kmi_send(kmi, kmi_mse_init_string[kmi->config_num]);			kmi->config_num++;			DEBUG(("%s: Sending byte %d of PS/2 init string.\n", kmi->name, kmi->config_num));		} else {			if (val == PS2_I_ACK) {				DEBUG(("%s: Now enable the mouse again...\n", kmi->name));				queue->head = queue->tail = 0;				kmi_send(kmi, PS2_O_ENABLE);				kmi->hotplug_state++;			} else {				kmi->hotplug_state = 0;				DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));			}		}		break;	case 7:		/* Eat up last acknowledge from enable */		if (val == PS2_I_ACK)			printk(KERN_ERR "%s: reconnected\n", kmi->name);		else			DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));		kmi->hotplug_state = 0;		break;	} /* switch (kmi->hotplug_state) */	/* while inside hotplug mechanism, don't misinterpret values */	if (kmi->hotplug_state > 2)		return;#endif	/* We are waiting for the mouse to respond to a kmi_send_and_wait() */	if (kmi->res == KMI_NO_ACK) {		if (val == PS2_I_RESEND) {			if (kmi->resend_count < 5)				__kmi_send(kmi, kmi->last_tx);			else {				printk(KERN_ERR "%s: too many resends\n", kmi->name);				return;			}		}		if (val == PS2_I_ACK) {			kmi->res = val;			wake_up(&kmi->wait_q);		}		return;	}	/* The mouse autonomously send new data, so wake up mouse_read() */	if (queue) {		head = queue->head;		queue->buf[head] = val;		head = (head + 1) & (BUF_SZ - 1);		if (head != queue->tail) {			queue->head = head;			kill_fasync(&queue->fasync, SIGIO, POLL_IN);			wake_up_interruptible(&kmi->wait_q);		}	}}static int kmi_init_mouse(struct kmi_info *kmi){	u_int ret, i;	if (kmi->present) {		kmi->rx = kmi_mse_intr;		for (i = 0; i < sizeof(kmi_mse_init_string); i++) {			ret = kmi_send_and_wait(kmi, kmi_mse_init_string[i], HZ);			if (ret != PS2_I_ACK)				printk("%s: didn't get ack (0x%2.2x)\n",					kmi->name, ret);		}	}	queue = kmalloc(sizeof(*queue), GFP_KERNEL);	if (queue) {		memset(queue, 0, sizeof(*queue));		misc_register(&ps_mouse);		ret = 0;	} else		ret = -ENOMEM;	return ret;}#endif /* CONFIG_KMI_MOUSE *//* * The "program" we send to the keyboard to set it up how we want it: *  - default typematic delays *  - scancode set 1 */static u_char kmi_kbd_init_string[] = {	PS2_O_DISABLE,	PS2_O_SET_DEFAULT,	PS2_O_SET_SCANSET, 0x01,	PS2_O_ENABLE};static void kmi_kbd_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs);static int __kmi_init_keyboard(struct kmi_info *kmi){	u_int ret, i;	if (!kmi->present)		return 0;	kmi->rx = kmi_kbd_intr;	for (i = 0; i < sizeof(kmi_kbd_init_string); i++) {		ret = kmi_send_and_wait(kmi, kmi_kbd_init_string[i], HZ);		if (ret != PS2_I_ACK)			printk("%s: didn't ack (0x%2.2x)\n",				kmi->name, ret);	}	return 0;}static void kmi_kbd_init_tasklet(unsigned long k){	struct kmi_info *kmi = (struct kmi_info *)k;	__kmi_init_keyboard(kmi);}static DECLARE_TASKLET_DISABLED(kmikbd_init_tasklet, kmi_kbd_init_tasklet, 0);/* * The "normal" keyboard scancode processing */

⌨️ 快捷键说明

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