📄 key.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 + -