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

📄 scan_smallkbd.c

📁 基于PXA255+ARM-linux的扫描按键驱动
💻 C
字号:
#include <linux/module.h>#include <linux/config.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/ioport.h>#include <linux/tqueue.h>#include <linux/wait.h>#include <asm/hardware.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/io.h>#include <linux/pc_keyb.h>#include <asm/keyboard.h>#include <asm/hardware/sa1111.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/param.h>#include <linux/timer.h>#include <asm/arch/hardware.h>#define SMALLKBD_MAJOR 51#define MAX_SMALLKBD_BUFFER	1024static struct timer_list tmlist;static wait_queue_head_t smallkbd_wait;static spinlock_t smallkbd_lock = SPIN_LOCK_UNLOCKED;static int scan_interval = 200;		static unsigned char smallkbd_buf[MAX_SMALLKBD_BUFFER];static int buf_head,buf_tail,key_count;#ifdef CONFIG_MAGIC_SYSRQstatic unsigned char sa1111_sysrq_xlate[128] = "\000\0331234567890-=\177\t"	    "qwertyuiop[]\r\000as"	    "dfghjkl;'`\000\\zxcv"	    "bnm,./\000*\000 \000\201\202\203\204\205"	    "\206\207\210\211\212\000\000789-456+1"	    "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000"	    "\r\000/";			#endif#define E0_KPENTER 96#define E0_RCTRL   97#define E0_KPSLASH 98#define E0_PRSCR   99#define E0_RALT    100#define E0_BREAK   101		#define E0_HOME    102#define E0_UP      103#define E0_PGUP    104#define E0_LEFT    105#define E0_RIGHT   106#define E0_END     107#define E0_DOWN    108#define E0_PGDN    109#define E0_INS     110#define E0_DEL     111#define E0_YEN         124#define E0_BACKSLASH   89#define E1_PAUSE   119/* */#define SC_LIM 89#define FOCUS_PF1 85		#define FOCUS_PF2 89#define FOCUS_PF3 90#define FOCUS_PF4 91#define FOCUS_PF5 92#define FOCUS_PF6 93#define FOCUS_PF7 94#define FOCUS_PF8 95#define FOCUS_PF9 120#define FOCUS_PF10 121#define FOCUS_PF11 122#define FOCUS_PF12 123#define JAP_86     124#define RGN1 124#define RGN2 125#define RGN3 126#define RGN4 127static unsigned char high_keys[128 - SC_LIM] = {	RGN1, RGN2, RGN3, RGN4, 0, 0, 0,		0, 0, 0, 0, 0, 0, 0, 0,		0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,		0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,		FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,		FOCUS_PF8, JAP_86, FOCUS_PF10, 0	};#define E0_MACRO   112#define E0_F13     113#define E0_F14     114#define E0_HELP    115#define E0_DO      116#define E0_F17     117#define E0_KPMINPLUS 118/* */#define E0_OK  124/* */#define E0_MSLW        125#define E0_MSRW        126#define E0_MSTM        127static unsigned char e0_keys[128] = {	0, 0, 0, 0, 0, 0, 0, 0,	/*  */	0, 0, 0, 0, 0, 0, 0, 0,	/*  */	0, 0, 0, 0, 0, 0, 0, 0,	/*  */	0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	/*  */	0, 0, 0, 0, 0, 0, 0, 0,	/*  */	0, 0, 0, 0, 0, 0, 0, 0,	/*  */	0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	/*  */	E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	/*  */	E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	/*  */	E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,	/*  */	E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	/*  */	0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	/*  */	0, 0, 0, 0, 0, 0, 0, 0,	/*  */	0, 0, 0, 0, 0, 0, 0, E0_MACRO,	/*  */	//0, 0, 0, 0, 0, 0, 0, 0,                          /*  */	0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0,	/*  */	0, 0, 0, E0_YEN, 0, 0, 0, 0	/*  */};int smallkbd_setkeycode(unsigned int scancode, unsigned int keycode){	if (scancode < SC_LIM || scancode > 255 || keycode > 127)		return -EINVAL;	if (scancode < 128)		high_keys[scancode - SC_LIM] = keycode;	else		e0_keys[scancode - 128] = keycode;	return 0;}int smallkbd_getkeycode(unsigned int scancode){	return	    (scancode < SC_LIM || scancode > 255) ? -EINVAL :	    (scancode <	     128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128];}int smallkbd_translate(unsigned char scancode, unsigned char *keycode,char raw_mode){	static int prev_scancode = 0;		if (scancode == 0xe0 || scancode == 0xe1) {		prev_scancode = scancode;		return 0;	}	if (scancode == 0x00 || scancode == 0xff) {		prev_scancode = 0;		return 0;	}	scancode &= 0x7f;	if (prev_scancode) {		/*		 */		if (prev_scancode != 0xe0) {			if (prev_scancode == 0xe1 && scancode == 0x1d) {				prev_scancode = 0x100;				return 0;			}				else if (prev_scancode == 0x100					 && scancode == 0x45) {				*keycode = E1_PAUSE;				prev_scancode = 0;			} else {#ifdef KBD_REPORT_UNKN				if (!raw_mode)					printk(KERN_INFO					       "keyboard: unknown e1 escape sequence\n");#endif				prev_scancode = 0;				return 0;			}		} else {			prev_scancode = 0;			/*			 */			/*			 */			if (scancode == 0x2a || scancode == 0x36)				return 0;			if (e0_keys[scancode])				*keycode = e0_keys[scancode];			else {#ifdef KBD_REPORT_UNKN				if (!raw_mode)					printk(KERN_INFO					       "keyboard: unknown scancode e0 %02x\n",					       scancode);#endif				return 0;			}		}	} else if (scancode >= SC_LIM) {		*keycode = high_keys[scancode - SC_LIM];		if (!*keycode) {			if (!raw_mode) {#ifdef KBD_REPORT_UNKN				printk(KERN_INFO				       "keyboard: unrecognized scancode (%02x)"				       " - ignored\n", scancode);#endif			}			return 0;		}	} else		*keycode = scancode;	return 1;}char smallkbd_unexpected_up(unsigned char keycode){	if (keycode >= SC_LIM || keycode == 85)		return 0;	else		return 0200;}void smallkbd_leds(unsigned char leds){	return; }static ssize_t smallkbd_read(struct file *fp,char *buf, size_t count,loff_t *l_t){	if (verify_area(VERIFY_WRITE, buf, 1) == -EFAULT)			return  -1;		if (key_count == 0)		return 0;		copy_to_user(buf, &smallkbd_buf[buf_head], 1);	key_count--;	buf_head++;		if (buf_head == MAX_SMALLKBD_BUFFER)		buf_head = 0;	return 1;}static int smallkbd_open(struct inode *node,struct file *fp){	buf_head = buf_tail = key_count = 0;	return 0;}static int smallkbd_release(struct inode *node,struct file *fp){	return 0;}static ssize_t smallkbd_write(struct file *fp,const char *buf,size_t count,loff_t *l_t){	return 0;}static unsigned int smallkbd_poll(struct file *file,poll_table *table){	if (key_count)		return 1;	poll_wait(file,&smallkbd_wait,table);	return 0;}static int smallkbd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg){	switch (cmd)	{		case 1: 			if (50 > arg)				arg = 50;			else if (500 < arg)				arg = 500;			scan_interval = (int)arg;			break;		case 2:			break;		default:			break;	}	return 0;}struct file_operations smallkbd_fops = {	read:	smallkbd_read,	write:	smallkbd_write,	poll:	smallkbd_poll,	ioctl:	smallkbd_ioctl,	open:	smallkbd_open,	release:	smallkbd_release,};unsigned char read_scancode(const unsigned char nScanCode){	unsigned char c;	switch(nScanCode & 0x1f)	{		case 0x0f: 			GPCR0 = 0x40000000;			break;		case 0x17:			GPCR0 = 0xa0000000;			break;		case 0x1b:			GPCR1 = 0x01000000;			break;		case 0x1d:			GPCR0 = 0x02000000;			break;		case 0x1e: 			GPCR0 = 0x01000000;			break;		default:			return 0;			break;	}	c = (GPLR0 >> 19) & 0x1f;	switch(nScanCode & 0x1f)	{		case 0x0f: 			GPSR0 = 0x40000000;			break;		case 0x17: 			GPSR0 = 0xa0000000;			break;		case 0x1b: 			GPSR1 = 0x01000000;			break;		case 0x1d:			GPSR0 = 0x02000000;			break;		case 0x1e:			GPSR0 = 0x01000000;			break;		default:			return 0;			break;	}	return c;}static void handle_smallkbd_event(unsigned char scancode,unsigned char keycode,int flag){	unsigned long flags;		spin_lock_irqsave(&smallkbd_lock,flags);	handle_scancode(scancode,flag);	tasklet_schedule(&keyboard_tasklet);	spin_unlock_irqrestore(&smallkbd_lock,flags);	if ((1 == flag) && (key_count < MAX_SMALLKBD_BUFFER))	{		smallkbd_buf[buf_tail++] = keycode;		key_count++;		if (buf_tail >= MAX_SMALLKBD_BUFFER)			buf_tail = 0;	}	wake_up(&smallkbd_wait);	return;}static unsigned char _byOldScanCode1 = 0x00,_byOldScanCode2 = 0x00,_byOldScanCode3 = 0x00;static unsigned char _byOldScanCode4 = 0x00,_byOldScanCode5 = 0x00;static short _bKeyDownFlag1 = 0,_bKeyDownFlag2 = 0,_bKeyDownFlag3 = 0;static short _bKeyDownFlag4 = 0,_bKeyDownFlag5 = 0;static void smallkbd_timer(void){	unsigned char byScanCode1,byScanCode2,byScanCode3;	unsigned char byScanCode4,byScanCode5;	byScanCode1 = read_scancode(0x0f);//	if ((_byOldScanCode1 == byScanCode1) && (0 == _bKeyDownFlag1))	{		_bKeyDownFlag1 = 1;		switch (byScanCode1)		{			case 0x0f:  				handle_smallkbd_event(0x15,21,1);				handle_smallkbd_event(0x15,21,0);				break;			case 0x17: 				handle_smallkbd_event(0x2d,45,1);				handle_smallkbd_event(0x2d,45,0);				break;			case 0x1b: 				handle_smallkbd_event(0x11,17,1);				handle_smallkbd_event(0x11,17,0);				break;			case 0x1d: 				handle_smallkbd_event(0x2f,47,1);				handle_smallkbd_event(0x2f,47,0);				break;			case 0x1e: 				handle_smallkbd_event(0x16,22,1);				handle_smallkbd_event(0x16,22,0);				break;			default: 				break;		}	}//	else if (_byOldScanCode1 != byScanCode1)	{		_bKeyDownFlag1 = 0;		_byOldScanCode1 = byScanCode1;	}	byScanCode2 = read_scancode(0x17);//	if ((_byOldScanCode2 == byScanCode2) && (0 == _bKeyDownFlag2))	{		_bKeyDownFlag2 = 1;		switch (byScanCode2)		{			case 0x0f:  				handle_smallkbd_event(0x14,20,1);				handle_smallkbd_event(0x14,20,0);				break;			case 0x17:  				handle_smallkbd_event(0x1f,31,1);				handle_smallkbd_event(0x1f,31,0);				break;			case 0x1b:				handle_smallkbd_event(0x13,19,1);				handle_smallkbd_event(0x13,19,0);				break;			case 0x1d:				handle_smallkbd_event(0x10,16,1);				handle_smallkbd_event(0x10,16,0);				break;			case 0x1e: 				handle_smallkbd_event(0x19,25,1);				handle_smallkbd_event(0x19,25,0);				break;			default: 				break;		}	}//	else if (_byOldScanCode2 != byScanCode2)	{		_bKeyDownFlag2 = 0;		_byOldScanCode2 = byScanCode2;	}	byScanCode3 = read_scancode(0x1b);//	if ((_byOldScanCode3 == byScanCode3) && (0 == _bKeyDownFlag3))	{		_bKeyDownFlag3 = 1;		switch (byScanCode3)		{			case 0x0f:				handle_smallkbd_event(0x18,24,1);				handle_smallkbd_event(0x18,24,0);				break;			case 0x17:				handle_smallkbd_event(0x31,49,1);				handle_smallkbd_event(0x31,49,0);				break;			case 0x1b: 				handle_smallkbd_event(0x32,50,1);				handle_smallkbd_event(0x32,50,0);				break;			case 0x1d:				handle_smallkbd_event(0x26,38,1);				handle_smallkbd_event(0x26,38,0);				break;			case 0x1e:				handle_smallkbd_event(0x25,37,1);				handle_smallkbd_event(0x25,37,0);				break;			default: 				break;		}	}//	else if (_byOldScanCode3 != byScanCode3)	{		_bKeyDownFlag3 = 0;		_byOldScanCode3 = byScanCode3;		}	byScanCode4 = read_scancode(0x1d);//	if ((_byOldScanCode4 == byScanCode4) && (0 == _bKeyDownFlag4))	{		_bKeyDownFlag4 = 1;		switch (byScanCode4)		{			case 0x0f:				handle_smallkbd_event(0x24,36,1);				handle_smallkbd_event(0x24,36,0);				break;			case 0x17:				handle_smallkbd_event(0x17,23,1);				handle_smallkbd_event(0x17,23,0);				break;			case 0x1b:				handle_smallkbd_event(0x23,35,1);				handle_smallkbd_event(0x23,35,0);				break;			case 0x1d: 				handle_smallkbd_event(0x22,34,1);				handle_smallkbd_event(0x22,34,0);				break;			case 0x1e:  				handle_smallkbd_event(0x21,33,1);				handle_smallkbd_event(0x21,33,0);				break;			default: 				break;		}	}//	else if (_byOldScanCode4 != byScanCode4)	{		_bKeyDownFlag4 = 0;		_byOldScanCode4 = byScanCode4;		}	byScanCode5 = read_scancode(0x1e);//	if ((_byOldScanCode5 == byScanCode5) && (0 == _bKeyDownFlag5))	{		_bKeyDownFlag5 = 1;		switch (byScanCode5)		{			case 0x0f:  				handle_smallkbd_event(0x12,18,1);				handle_smallkbd_event(0x12,18,0);				break;			case 0x17:  				handle_smallkbd_event(0x20,32,1);				handle_smallkbd_event(0x20,32,0);				break;			case 0x1b: 				handle_smallkbd_event(0x2e,46,1);				handle_smallkbd_event(0x2e,46,0);				break;			case 0x1d:  				handle_smallkbd_event(0x30,48,1);				handle_smallkbd_event(0x30,48,0);				break;			case 0x1e:  				handle_smallkbd_event(0x1e,30,1);				handle_smallkbd_event(0x1e,30,0);				break;			default: 				break;		}	}//	else if (_byOldScanCode5 != byScanCode5)	{		_bKeyDownFlag5 = 0;		_byOldScanCode5 = byScanCode5;		}	if ( (0 == byScanCode1) && (0 == byScanCode2) && (0 == byScanCode3) &&	(0 == byScanCode4) && (0 == byScanCode5) )		_byOldScanCode1 = _byOldScanCode2 = _byOldScanCode3 = _byOldScanCode4 = _byOldScanCode5 = 0x00;	init_timer(&tmlist);	tmlist.expires = jiffies + scan_interval*HZ/1000;	tmlist.function = (void*)smallkbd_timer;	add_timer(&tmlist);}int init_module(void){	int result;	GAFR0_U &= 0x03f0003f;	GAFR1_U &= 0xfffcffff;	GPDR0 |= 0xe3000000;	GPDR1 |= 0x01000000;	GPDR0 &= 0xff07ffff;		buf_head = buf_tail = key_count = 0;	result = register_chrdev(SMALLKBD_MAJOR,"smallkbd",&smallkbd_fops);	if (0 > result)	{		printk("smallkbd:can't get major %d.\n",SMALLKBD_MAJOR);		return result;	}#ifdef CONFIG_MAGIC_SYSRQ	k_sysrq_xlate	= smallkbd_sysrq_xlate;	k_sysrq_key	= 0x54;#endif		init_waitqueue_head(&smallkbd_wait);		init_timer(&tmlist);	tmlist.expires = jiffies + HZ;	tmlist.function = (void*)smallkbd_timer;	add_timer(&tmlist);	printk("Init smallkbd success.\n");	return 0;}void cleanup_module(void){	del_timer(&tmlist);	unregister_chrdev(SMALLKBD_MAJOR,"smallkbd");	printk("Clean up smallkbd success.\n");	return;}EXPORT_SYMBOL(smallkbd_setkeycode);EXPORT_SYMBOL(smallkbd_getkeycode);EXPORT_SYMBOL(smallkbd_translate);EXPORT_SYMBOL(smallkbd_unexpected_up);EXPORT_SYMBOL(smallkbd_leds);

⌨️ 快捷键说明

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