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

📄 key.c

📁 linux的按键(键盘)驱动程序
💻 C
字号:
/*#ifndef __KERNEL__    #define __KERNEL__#endif#ifndef MODULE    #define MODULE#endif*/#include <linux/module.h>#include <linux/sched.h>#include <linux/config.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/iobuf.h>#include <linux/highmem.h>#include <linux/timer.h>#include <linux/wait.h>#include <asm/arch/hardware.h>#include <asm/delay.h>#include <asm/uaccess.h>#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endifstatic void (*kbdEvent)(void);void kbdEvent_dummy(void){}#define  DEVICE_NAME  "keyboard"#define  KBDRAW_MINOR  1static int   kbdMajor;#define  MAX_KBD_BUF  16typedef  unsigned char KBD_RET;typedef struct{	unsigned  int kbdStatus;	//按键状态	KBD_RET buf[MAX_KBD_BUF];	//按键缓冲区	unsigned int head,tail;		//按键缓冲区头和尾	wait_queue_head_t wq;		//等待队列	}KBD_DEV;static KBD_DEV kbddev;#define KEYSTATUS_UP		1 #define KEYSTATUS_DOWN		2#define KEYSTATUS_DOWNX		3#define KEYSTATUS_REPEAT	4#define BUF_HEAD (kbddev.buf[kbddev.head])	//缓冲区头#define BUF_TAIL (kbddev.buf[kbddev.tail])	//缓冲区尾#define INCBUF(x,mod)  ((++(x)) & ((mod) -1 ))	//移动缓冲区指针static KBD_RET  key;static struct timer_list kbd_timer;#define KBD_TIMER_DELAY   (HZ/10)	//100ms#define KBD_TIMER_DELAY1  (HZ/100)	//第一次按下后延时10ms#ifdef CONFIG_DEVFS_FSstatic 	devfs_handle_t devfs_kbd_dir=NULL;static  devfs_handle_t  devfs_kbdraw ;#endif#define KEY_DOWN 0#undef DEBUG//#define DEBUG #ifdef DEBUG #define DPRINTK(x...) printk(KERN_ALERT##"at91rm9200kbd:"##x);#else#define DPRINTK(x...)#endifstatic int  at91rm9200_kbd_open(struct inode * inode,struct file *filp);static int  at91rm9200_kbd_release(struct inode *inode,struct file * filp);static void at91_isr_kbd(int irq,void * dev_id,struct pt_regs * reg);static void kbd_timer_handler(unsigned long data);static KBD_RET Read_ExINT_Key(void);static void at91_get_kbd(void);static void kbdEvent_raw(void);static KBD_RET kbdRead(void);static ssize_t at91rm9200_kbd_read(struct file * filp,char *buffer,size_t conunt,loff_t * ppos);static AT91PS_SYS AT91_SYS = (AT91PS_SYS) AT91C_VA_BASE_SYS;/**************************************************************************************************************************************************************/static struct file_operations at91_key_fops = {	owner:	THIS_MODULE,	open:   at91rm9200_kbd_open,	read:	at91rm9200_kbd_read,	release: at91rm9200_kbd_release,};void  KBD_CLOSE_INT(void){	AT91_SYS->PIOB_IER  &=  ~( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );	AT91_SYS->PIOB_IDR  |=  ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );}  unsigned char  ISKBD_DOWN(void){    	unsigned int status  = AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12;	if( (AT91_SYS->PIOB_PDSR & status) !=  status)		return  1;	else		return  0;} 	void KBD_OPEN_INT(void){	AT91_SYS->PIOB_IER  |=  ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );	AT91_SYS->PIOB_IDR  &=  ~( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );}/**********************************************************************************************************************************************/static int __init at91_kbd_init(void){	int ret;	unsigned int status; 	AT91_SYS->PIOB_PER  |= ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );//使能IO口	AT91_SYS->PIOB_ODR  |= ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );//使能输入	AT91_SYS->PIOB_PPUDR &=  ~( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );//上拉电阻使能	AT91_SYS->PIOB_PPUER |= ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );	AT91_SYS->PIOB_IER  |=  ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );//中断使能	AT91_SYS->PIOB_IDR  &=   ~( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );       	status = AT91_SYS->PIOB_ISR & AT91_SYS->PIOB_IMR;	AT91_SYS->PMC_PCER |= (1 << AT91C_ID_PIOB);		kbdEvent = kbdEvent_dummy;	ret = register_chrdev(0,DEVICE_NAME,&at91_key_fops);	if( ret < 0)	{		printk(DEVICE_NAME "cant get major number\n");		return ret;	}	kbdMajor = ret;		#ifdef CONFIG_DEVFS_FS		devfs_kbd_dir = devfs_mk_dir(NULL,"keyboard",NULL);		devfs_kbdraw = devfs_register( devfs_kbd_dir,					       "0raw",					       DEVFS_FL_DEFAULT,					       kbdMajor,					       KBDRAW_MINOR,					       S_IFCHR | S_IRUSR | S_IWUSR,					       &at91_key_fops,					       NULL);	#endif 		//Enable interrupt	if( request_irq(AT91C_ID_PIOB,at91_isr_kbd,0,DEVICE_NAME,NULL) )		return -EBUSY;	kbddev.head = kbddev.tail = 0;	kbddev.kbdStatus = KEYSTATUS_UP;	init_waitqueue_head(&(kbddev.wq));	init_timer(&kbd_timer);	kbd_timer.function = kbd_timer_handler;	#ifdef DEBUG		at91rm9200_kbd_open(NULL,NULL);	#endif	printk(DEVICE_NAME " initialized\n");	return 0;}/**********************************************************************************************************************************/static  int at91rm9200_kbd_open(struct inode * inode,struct file *filp){	kbddev.head = kbddev.tail = 0;	kbdEvent = kbdEvent_raw;	MOD_INC_USE_COUNT;	return 0;}/*********************************************************************************************************************************************/static int at91rm9200_kbd_release(struct inode *inode,struct file * filp){	kbdEvent = kbdEvent_dummy;	MOD_DEC_USE_COUNT;	return 0;	}/************************************************************************************************************************************************/static void at91_isr_kbd(int irq,void * dev_id,struct pt_regs * reg){	unsigned int status;	DPRINTK("Occured key board Interrupt,irq = %d\n",irq);	status = AT91_SYS->PIOB_ISR & AT91_SYS->PIOB_IMR;		if((kbddev.kbdStatus == KEYSTATUS_UP))	{		KBD_CLOSE_INT();		if(ISKBD_DOWN())		{			kbddev.kbdStatus = KEYSTATUS_DOWNX;			kbd_timer.expires = jiffies + KBD_TIMER_DELAY1;			add_timer(&kbd_timer);		}		else		{			KBD_OPEN_INT();		}	}}/************************************************************************************************************************************************************************/static void kbd_timer_handler(unsigned long data){	if(ISKBD_DOWN())	{		if(kbddev.kbdStatus == KEYSTATUS_DOWNX)		{				kbddev.kbdStatus = KEYSTATUS_DOWN;			kbd_timer.expires = jiffies + KBD_TIMER_DELAY;			at91_get_kbd();					}		else		{			kbd_timer.expires = jiffies + KBD_TIMER_DELAY;		}			add_timer(&kbd_timer);	}	else	{		kbddev.kbdStatus = KEYSTATUS_UP;		del_timer(&kbd_timer);				DPRINTK("KEY UP,code=%x\n",key);	//	kbdEvent();		KBD_OPEN_INT();			}}static KBD_RET Read_ExINT_Key(void) //得到键盘码{	KBD_RET  temp = 0;	unsigned int reg;	reg = AT91_SYS->PIOB_PDSR;	if( (reg & AT91C_PIO_PB9) == 0 )        {		temp = 1;		}        else if( (reg & AT91C_PIO_PB10) == 0)	{		temp = 2;	}	else if( (reg & AT91C_PIO_PB11) == 0 )	{		temp = 3;	}	else if( (reg & AT91C_PIO_PB12) == 0 )	{		temp = 4;	}	return temp;}/*****************************************************************************************************************************************************************/static void at91_get_kbd(void){	key = Read_ExINT_Key();	kbdEvent();}/********************************************************************************************************************************************************************/static void kbdEvent_raw(void){	if(kbddev.kbdStatus == KEYSTATUS_DOWN)	{		BUF_HEAD = key | KEY_DOWN;/*	}	else 	{		BUF_HEAD = key;	}*/			kbddev.head = INCBUF(kbddev.head,MAX_KBD_BUF);		wake_up_interruptible(&(kbddev.wq));	}}/*************************************************************************************************************************************************************************/static  KBD_RET kbdRead(void){	KBD_RET  kbd_ret;	kbd_ret = BUF_TAIL;	kbddev.tail = INCBUF(kbddev.tail,MAX_KBD_BUF);	return kbd_ret;}/************************************************************************************************************************************************************************************************/static ssize_t at91rm9200_kbd_read(struct file * filp,char *buffer,size_t conunt,loff_t * ppos){	KBD_RET kbd_ret;	retry:	if(kbddev.head != kbddev.tail)	{		kbd_ret = kbdRead();		copy_to_user(buffer,(char *)&kbd_ret,sizeof(KBD_RET));		return sizeof(KBD_RET);	}	else	{		if(filp -> f_flags & O_NONBLOCK)			return -EAGAIN;		interruptible_sleep_on(&(kbddev.wq));		if(signal_pending(current))			return -ERESTARTSYS;		goto retry;	}		return sizeof(KBD_RET);}/**********************************************************************************************************************************************/static void  __exit at91_kbd_exit(void){//	printk(DEVICE_NAME " rmmod\n");	free_irq(AT91C_ID_PIOB,0);#ifdef CONFIG_DEVFS_FS	devfs_unregister(devfs_kbdraw);	devfs_unregister(devfs_kbd_dir);#else	unregister_chrdev(kbdMajor,DEVICE_NAME);#endif		 //KBD_CLOSE_INT();}module_init(at91_kbd_init);module_exit(at91_kbd_exit);EXPORT_NO_SYMBOLS;MODULE_AUTHOR("Rick Bronson");MODULE_DESCRIPTION("AT91 kbd driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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