📄 s3c2440_kb.c
字号:
/********************************************************** * s3c2440-ts.c * * keyboard driver for S3C2440 based PDA * * * History: * * ***********************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <asm/irq.h>#include <asm/arch/irq.h>#include <asm/arch/irqs.h>#include <asm/arch/clocks.h>#include <asm/hardware.h>#include <asm/arch/S3C2440.h>#define DEVICE_NAME "s3c2440-kb" //键盘设备名static int kbMajor = 0; //默认的主设备号#define MAX_KB_BUF 10 //循环队列的尺寸 typedef struct { unsigned int keyStatus; int irq;// int timeCount; u_short buf[MAX_KB_BUF]; /* 循环队列*/ unsigned int head, tail; /* 循环队列的读写指针*/ spinlock_t lock; /*锁*/} KB_DEV;static KB_DEV kbdev;#define KEY_UP 0 //按键弹起#define KEY_DOWN 1 //按键按下#define NO_KEY_DOWN 2 //没有键按下#define EINT1_DOWN 0#define EINT3_DOWN 1#define EINT8_DOWN 2#define NO_EINT_DOWN 3/*循环队列操作*/#define BUF_HEAD (kbdev.buf[kbdev.head])#define BUF_TAIL (kbdev.buf[kbdev.tail])#define INCBUF(x) if((++x)==MAX_KB_BUF) x=0/*定时器设置*/#define KB_TIMER_DELAY (HZ/50) /*HZ表示每秒产生的时钟滴答数,定时器超时为20ms*/#define REPEAT_START_DELAY (HZ) /* 自动重复开始延时:1秒*/#define REPEAT_DELAY (HZ/2) /*自动重复延时:0.5秒*/static struct timer_list kb_timer;static struct timer_list repeat_timer;spinlock_t repeat_lock;static int timeCount =1;static int TIME_OUT =5;/*键盘矩阵*/static u_short keyboard_code_map[4][3]={ {1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 9 }, {10, 11, 12} }; //每个按键对应的键盘码static u_short pre_keyboard_code = 0; //上次扫描得到的按键值static u_short curr_keyboard_code = 0;//当前扫描得到的按键值static u_short snap_keyboard_code[4][3]={ {0 , 0 , 0 }, {0 , 0 , 0 }, {0 , 0 , 0 }, {0, 0, 0} }; //临时按键值#define DETECTION_THROLD 3static int requestIrq();static int s3c2440_kb_release(struct inode *inode, struct file *filp);/*----------------------------------------------------* func: 初始化GPJCON寄存器,将GPJ9,GPJ10,GPJ11,GPJ12* 配置成output管腿* ------------------------------------------------------*/static void init_gpjcon(){ //GPJ9,GPJ10,GPJ11,GPJ12------>output GPJCON &= 0xFC03FFFF; GPJCON |= 0x01540000;}/*----------------------------------------------------* func: 向GPJ9,GPJ10,GPJ11,GPJ12输出value* param: * value: 输出值* ------------------------------------------------------*///static inline void output_giop(int value ) //往所有行输出{ value &= 0x0000000F; value <<= 9; GPJDAT &= 0xE1FF; GPJDAT |= value; udelay(2);}/*----------------------------------------------------* func: 判断eint当前是否是低电平* param: * irq: 当前引发中断的eint的irq号* return: * EINT1_DOWN: eint1上是低电平* EINT3_DOWN: eint3上是低电平* EINT8_DOWN: eint8上是低电平* NO_EINT_DOWN:eint上不是低电平------------------------------------------------------*/int get_eint_value(int irq){ u_int IOValue; IOValue = GPFDAT ; if( (irq == 1) && (( IOValue & 0x00000002)==0) ) { return EINT1_DOWN; } if((irq ==3 ) && (( IOValue & 0x00000008)==0) ) { return EINT3_DOWN; } IOValue = GPGDAT ; if((irq ==36) && (( IOValue & 0x0000001)==0) ) { return EINT8_DOWN; } return NO_EINT_DOWN;}/*----------------------------------------------------* func: 扫描键盘,判断哪一个键被按下* param: * x: 得到按键的行号* y: 得到按键的列号* return: * KEY_DOWN: 键盘上有键被按下* NO_KEY_DOWN: 键盘上没有键被按下------------------------------------------------------*/static inline int scan_keyboard(int* x,int* y){ int matrix_row,matrix_col,matrix_col_status; output_giop(0xF); //往所有行输出1 //判断按键在哪一行 matrix_row=matrix_col=-1; output_giop(0xE);//在第1行上输出1,其余行输出0 matrix_col_status = get_eint_value(kbdev.irq); if(matrix_col_status != NO_EINT_DOWN) { matrix_row = 0; matrix_col = matrix_col_status; goto scanend; } output_giop(0xD);//在第2行上输出1,其余行输出0 matrix_col_status = get_eint_value(kbdev.irq); if(matrix_col_status != NO_EINT_DOWN) { matrix_row=1; matrix_col = matrix_col_status; goto scanend; } output_giop(0xB);//在第3行上输出1,其余行输出0 matrix_col_status =get_eint_value(kbdev.irq); if(matrix_col_status != NO_EINT_DOWN) { matrix_row=2; matrix_col = matrix_col_status; goto scanend; } output_giop(0x7);//在第4行上输出1,其余行输出0 matrix_col_status =get_eint_value(kbdev.irq); if(matrix_col_status != NO_EINT_DOWN) { matrix_row=3; matrix_col = matrix_col_status; goto scanend; }scanend: output_giop(0); if(matrix_row >=0 ) { snap_keyboard_code[matrix_row][matrix_col_status]= snap_keyboard_code[matrix_row][matrix_col_status] + 1; if(snap_keyboard_code[matrix_row][matrix_col]>=DETECTION_THROLD) { *x=matrix_row; *y=matrix_col; curr_keyboard_code = keyboard_code_map[matrix_row][matrix_col]; return KEY_DOWN; } } return NO_KEY_DOWN;}/*----------------------------------------------------* func: 判断本次按键是否与上次按键相同* param: * * return: * 0: 相同* 1: 不同------------------------------------------------------*/static inline int key_changed(){ return (pre_keyboard_code == curr_keyboard_code)? 0 : 1;}/*----------------------------------------------------* func: 将按键对应的键盘码保存到循环队列中* param: * keyValue: 按键的对应的键盘码* return: * ------------------------------------------------------*/static inline void save_key_to_queue(u_short keyValue){ if (kbdev.keyStatus == KEY_DOWN) { BUF_HEAD = keyValue; INCBUF(kbdev.head); //wake_up_interruptible(&(kbdev.wq)); }}/*----------------------------------------------------* func: 重复按键定时器处理程序,如果一直按住某键, 则将该键的键盘码定时存到循环队列中* param: * data: 无参数* return: * ------------------------------------------------------*/static inline void repeat_timer_handler(unsigned long data){ spin_lock_irq(&(repeat_lock)); if(kbdev.keyStatus ==KEY_DOWN) { repeat_timer.expires = jiffies + REPEAT_DELAY;//设置自动重复延时 add_timer(&repeat_timer);//将定时器加入队列 if(pre_keyboard_code != 0) { //printk("repeat save keyvalue\n %d",pre_keyboard_code); save_key_to_queue(pre_keyboard_code);//将按键值存入循环队列 } } else//如果按键弹起 { //del_timer(&repeat_timer); // printk("del repeat timer\n"); } spin_unlock_irq(&(repeat_lock));}/*----------------------------------------------------* func: 使能中断* param: * return: * ------------------------------------------------------*///使能中断static inline void enableIrq(){ //清除SRCPND寄存器中eint1 eint2 eint8相应位 SRCPND = 0x0000002A; //使能中断 enable_irq(IRQ_EINT1); enable_irq(IRQ_EINT3); enable_irq(IRQ_EINT8);}/*----------------------------------------------------* func: 键盘定时扫描程序,如果得到稳定键码,将键码存* 入循环队列;如果没有,则延时20ms后继续扫描* param: * data: 无参数* return: * ------------------------------------------------------*/static inline void kb_timer_handler(unsigned long data){ int x,y; spin_lock_irq(&(kbdev.lock)); x = y = 0; if(scan_keyboard(&x,&y) == KEY_DOWN) { // printk("snap_keyboard_code=%d, %d, %d, %d\n", snap_keyboard_code[0][1],snap_keyboard_code[1][1],snap_keyboard_code[2][1],snap_keyboard_code[3][1]); kbdev.keyStatus =KEY_DOWN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -