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

📄 qtronix.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
字号:
/* * * BRIEF MODULE DESCRIPTION *	Qtronix 990P infrared keyboard driver. * * * Copyright 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. *         	ppopov@mvista.com or source@mvista.com * * *  The bottom portion of this driver was take from  *  pc_keyb.c  Please see that file for copyrights. * *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  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., *  675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>/*  * NOTE:   * *	This driver has only been tested with the Consumer IR *	port of the ITE 8172 system controller. * *	You do not need this driver if you are using the ps/2 or *	USB adapter that the keyboard ships with.  You only need  *	this driver if your board has a IR port and the keyboard *	data is being sent directly to the IR.  In that case, *	you also need some low-level IR support. See it8172_cir.c. *	 */#ifdef CONFIG_QTRONIX_KEYBOARD#include <linux/types.h>#include <linux/pci.h>#include <linux/kernel.h>#include <asm/it8172/it8172.h>#include <asm/it8172/it8172_int.h>#include <asm/it8172/it8172_cir.h>#include <linux/spinlock.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/mm.h>#include <linux/signal.h>#include <linux/init.h>#include <linux/kbd_ll.h>#include <linux/delay.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/kbd_kern.h>#include <linux/smp_lock.h>#include <asm/io.h>#include <linux/pc_keyb.h>#include <asm/keyboard.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/system.h>#define leading1 0#define leading2 0xF#define KBD_CIR_PORT 0#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */static int data_index;struct cir_port *cir;static unsigned char kbdbytes[5];static unsigned char cir_data[32]; /* we only need 16 chars */static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);static int handle_data(unsigned char *p_data);static inline void handle_mouse_event(unsigned char scancode);static inline void handle_keyboard_event(unsigned char scancode, int down);static int __init psaux_init(void);static struct aux_queue *queue;	/* Mouse data buffer. */static int aux_count = 0;/* * Keys accessed through the 'Fn' key * The Fn key does not produce a key-up sequence. So, the first * time the user presses it, it will be key-down event. The key * stays down until the user presses it again. */#define NUM_FN_KEYS 56static unsigned char fn_keys[NUM_FN_KEYS] = {	0,0,0,0,0,0,0,0,        /* 0 7   */	8,9,10,93,0,0,0,0,      /* 8 15  */	0,0,0,0,0,0,0,5,        /* 16 23 */	6,7,91,0,0,0,0,0,       /* 24 31 */	0,0,0,0,0,2,3,4,        /* 32 39 */	92,0,0,0,0,0,0,0,       /* 40 47 */	0,0,0,0,11,0,94,95        /* 48 55 */};void init_qtronix_990P_kbd(void){	int retval;	cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);	if (!cir) {		printk("Unable to initialize Qtronix keyboard\n");		return;	}	/* 	 * revisit	 * this should be programmable, somehow by the, by the user.	 */	cir->port = KBD_CIR_PORT;	cir->baud_rate = 0x1d;	cir->rdwos = 0;	cir->rxdcr = 0x3;	cir->hcfs = 0;	cir->fifo_tl = 0;	cir->cfq = 0x1d;	cir_port_init(cir);	retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler, 			(unsigned long )(SA_INTERRUPT|SA_SHIRQ), 			(const char *)"Qtronix IR Keyboard", (void *)cir);	if (retval) {		printk("unable to allocate cir %d irq %d\n", 				cir->port, IT8172_CIR0_IRQ);	}#ifdef CONFIG_PSMOUSE	psaux_init();#endif}static inline unsigned char BitReverse(unsigned short key){	unsigned char rkey = 0;	rkey |= (key & 0x1) << 7;	rkey |= (key & 0x2) << 5;	rkey |= (key & 0x4) << 3;	rkey |= (key & 0x8) << 1;	rkey |= (key & 0x10) >> 1;	rkey |= (key & 0x20) >> 3;	rkey |= (key & 0x40) >> 5;	rkey |= (key & 0x80) >> 7;	return rkey;}static inline u_int8_t UpperByte(u_int8_t data){	return (data >> 4);}static inline u_int8_t LowerByte(u_int8_t data){	return (data & 0xF);}int CheckSumOk(u_int8_t byte1, u_int8_t byte2, 		u_int8_t byte3, u_int8_t byte4, u_int8_t byte5){	u_int8_t CheckSum;	CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;	if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )		return 0;	else		return 1;}static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs){	struct cir_port *cir;	int j;	unsigned char int_status;	cir = (struct cir_port *)dev_id;	int_status = get_int_status(cir);;	if (int_status & 0x4) {		clear_fifo(cir);		return;	}	while (cir_get_rx_count(cir)) {		cir_data[data_index] = cir_read_data(cir);		if (data_index == 0) {/* expecting first byte */			if (cir_data[data_index] != leading1) {				//printk("!leading byte %x\n", cir_data[data_index]);				set_rx_active(cir);				clear_fifo(cir);				continue;			}		}		if (data_index == 1) {			if ((cir_data[data_index] & 0xf) != leading2) {				set_rx_active(cir);				data_index = 0; /* start over */				clear_fifo(cir);				continue;			}		}		if ( (cir_data[data_index] == 0xff)) { /* last byte */			//printk("data_index %d\n", data_index);			set_rx_active(cir);#if 0			for (j=0; j<=data_index; j++) {				printk("rx_data %d:  %x\n", j, cir_data[j]);			}#endif			data_index = 0;			handle_data(cir_data);			return;		}		else if (data_index>16) {			set_rx_active(cir);#if 0			printk("warning: data_index %d\n", data_index);			for (j=0; j<=data_index; j++) {				printk("rx_data %d:  %x\n", j, cir_data[j]);			}#endif			data_index = 0;			clear_fifo(cir);			return;		}		data_index++;	}}#define NUM_KBD_BYTES 5static int handle_data(unsigned char *p_data){	u_int32_t bit_bucket;	u_int32_t i, j;	u_int32_t got_bits, next_byte;	int down = 0;	/* Reorganize the bit stream */	for (i=0; i<16; i++)		p_data[i] = BitReverse(~p_data[i]);	/* 	 * We've already previously checked that p_data[0]	 * is equal to leading1 and that (p_data[1] & 0xf)	 * is equal to leading2. These twelve bits are the	 * leader code.  We can now throw them away (the 12	 * bits) and continue parsing the stream.	 */	bit_bucket = p_data[1] << 12;	got_bits = 4;	next_byte = 2;	/* 	 * Process four bits at a time	 */	for (i=0; i<NUM_KBD_BYTES; i++) {		kbdbytes[i]=0;		for (j=0; j<8; j++) /* 8 bits per byte */		{			if (got_bits < 4) {				bit_bucket |= (p_data[next_byte++] << (8 - got_bits));				got_bits += 8;			}			if ((bit_bucket & 0xF000) == 0x8000) { 				/* Convert 1000b to 1 */				kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);				got_bits -= 4;				bit_bucket = bit_bucket << 4;			}			else if ((bit_bucket & 0xC000) == 0x8000) {				/* Convert 10b to 0 */				kbdbytes[i] =  kbdbytes[i] >> 1;				got_bits -= 2;				bit_bucket = bit_bucket << 2;			}			else {				/* bad serial stream */				return 1;			}			if (next_byte > 16) {				//printk("error: too many bytes\n");				return 1;			}		}	}	if (!CheckSumOk(kbdbytes[0], kbdbytes[1], 				kbdbytes[2], kbdbytes[3], kbdbytes[4])) {		//printk("checksum failed\n");		return 1;	}	if (kbdbytes[1] & 0x08) {		//printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);		handle_mouse_event(kbdbytes[1]);		handle_mouse_event(kbdbytes[2]);		handle_mouse_event(kbdbytes[3]);	}	else {		if (kbdbytes[2] == 0) down = 1;#if 0		if (down)			printk("down %d\n", kbdbytes[3]);		else			printk("up %d\n", kbdbytes[3]);#endif		handle_keyboard_event(kbdbytes[3], down);	}	return 0;}spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;static unsigned char handle_kbd_event(void);int kbd_setkeycode(unsigned int scancode, unsigned int keycode){	printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode);	return 0;}int kbd_getkeycode(unsigned int scancode){	return scancode;}int kbd_translate(unsigned char scancode, unsigned char *keycode,		    char raw_mode){	static int prev_scancode = 0;	if (scancode == 0x00 || scancode == 0xff) {		prev_scancode = 0;		return 0;	}	/* todo */	if (!prev_scancode && scancode == 160) { /* Fn key down */		//printk("Fn key down\n");		prev_scancode = 160;		return 0;	}	else if (prev_scancode && scancode == 160) { /* Fn key up */		//printk("Fn key up\n");		prev_scancode = 0;		return 0;	}	/* todo */	if (prev_scancode == 160) {		if (scancode <= NUM_FN_KEYS) {			*keycode = fn_keys[scancode];			//printk("fn keycode %d\n", *keycode);		}		else			return 0;	} 	else if (scancode <= 127) {		*keycode = scancode;	}	else		return 0; 	return 1;}char kbd_unexpected_up(unsigned char keycode){	//printk("kbd_unexpected_up\n");	return 0;}static unsigned char kbd_exists = 1;static inline void handle_keyboard_event(unsigned char scancode, int down){	kbd_exists = 1;	handle_scancode(scancode, down);	tasklet_schedule(&keyboard_tasklet);}	void kbd_leds(unsigned char leds){}/* dummy */void kbd_init_hw(void){}static inline void handle_mouse_event(unsigned char scancode){	if(scancode == AUX_RECONNECT){		queue->head = queue->tail = 0;  /* Flush input queue */	//	__aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */		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 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;}static inline int queue_empty(void){	return queue->head == queue->tail;}static int fasync_aux(int fd, struct file *filp, int on){	int retval;	//printk("fasync_aux\n");	retval = fasync_helper(fd, filp, on, &queue->fasync);	if (retval < 0)		return retval;	return 0;}/* * Random magic cookie for the aux device */#define AUX_DEV ((void *)queue)static int release_aux(struct inode * inode, struct file * file){	lock_kernel();	fasync_aux(-1, file, 0);	aux_count--;	unlock_kernel();	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 */	return 0;}/* * Put bytes from input queue to buffer. */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;		}		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;}/* * Write to the aux device. */static ssize_t write_aux(struct file * file, const char * buffer,			 size_t count, loff_t *ppos){	/*	 * The ITE boards this was tested on did not have the	 * transmit wires connected.	 */	return count;}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;}struct file_operations psaux_fops = {	read:		read_aux,	write:		write_aux,	poll:		aux_poll,	open:		open_aux,	release:	release_aux,	fasync:		fasync_aux,};/* * Initialize driver. */static struct miscdevice psaux_mouse = {	PSMOUSE_MINOR, "psaux", &psaux_fops};static int __init psaux_init(void){	misc_register(&psaux_mouse);	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);	memset(queue, 0, sizeof(*queue));	queue->head = queue->tail = 0;	init_waitqueue_head(&queue->proc_list);	return 0;}#endif

⌨️ 快捷键说明

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