📄 keydrv3.c
字号:
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#include <linux/interrupt.h>
//#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include "keydrv.h"
static KBD_DEV kbddev;
static void (*kbdEvent)(void);
static struct timer_list kbd_timer;
unsigned long last_down_time;
static int major=253;
char key_name[]="keydrv";
u_char key;
u_char last_raw_code = '1'; // for later extention.
u_char CAP_FLAG = CAP_OFF;
u_char index = 0;
static u_char table[4][16]={'1' ,'2' ,'3' ,'<',
'4' ,'5' ,'6' ,'>',
'7' ,'8' ,'9' ,'^',
'*' ,'0' ,'#' ,'$',
'a' ,'b' ,'c' ,'<',
'd' ,'e' ,'f' ,'>',
'g' ,'h' ,'i' ,'^',
'j' ,'k' ,'l' ,'$',
'm' ,'n' ,'o' ,'<',
'p' ,'q' ,'r' ,'>',
's' ,'t' ,'u' ,'^',
'v' ,'w' ,'x' ,'$',
'y' ,'z' ,',' ,'<',
'.' ,'!' ,'?' ,'>',
'(' ,')' ,'+' ,'^',
'-' ,'*' ,'/' ,'$' };
// f_ops mapping.
static struct file_operations key_fops=
{
// owner: THIS_MODULE,
read: (void(*))key_read,
open: (void(*))key_open,
release: (void(*))key_release,
};
// application specific function.
void kbdEvent_dummy(void)
{}
static u_char decode_key(void)
{
u_char i,raw_code,col_id=0 ,row_id=0 ,tmp,row_mask[4]={0xF7,0xFb,0xFd,0xfe}; //mask=0x0f ;
// scan coloums , here col to output : high 4 bits, raw to input : low 4 bits .
// printk("<1>start to decode the key..\n");
// tmp = KEY_PORT_COLS&0x0f;
tmp = readl(PIO_KEY_IN_BASE) & 0x0f ;
printk("<1>the col input data is 0x%x\n",tmp);
if(tmp==0x0e)
col_id=0;
else if(tmp==0x0d)
col_id=1;
else if(tmp==0x0b)
col_id=2;
else if(tmp==0x07)
col_id=3;
printk("<1>the col is %d\n",col_id);
for (i=0;i<4;i++)
{
writel(row_mask[3-i], PIO_KEY_OUT_BASE);
if(ISKBD_DOWN()){
printk("<1>get the row: %d\n",i); //(KEY_PORT_COLS&mask)!=0x0f){
row_id=i; // if the col input is also have signal, then get the col
break;
}
if(i==3)
printk("<1>scan error!\n");
}
printk("<1>the row is %d\n",row_id);
// printk("<1>again we set rows to low back.\n");
// KEY_PORT_ROWS = 0x00; // we must set alls rows to low in plain time.
writel(0, PIO_KEY_OUT_BASE);
raw_code=KEY_MAX_COLS*row_id+col_id; // raw_code is 0 -> 15
printk("<1>we get the raw_code: %d\n",raw_code);
// '>', '<' , to select the talbe .
//
// inserted to data buf.
printk("<1>now the s_talbe is: %d\n\n",s_table);
// to get the index of the talbe.
if(row_code==last_row_code && row_id <=3 && col_id<=3 && row_code!=1)
{
if(jiffies < (last_down_time + KBD_SWIFT_TIME))
{
if(index==3)
index = 0;
else
index++
}
}
else
index = 0;
last_row_code = row_code;
if(raw_code==12)
CAP_FLAG = ~CAP_FLAG ;
if(row_id <=3 && col_id<=3 && row_code!=1)
return (CAP_FLAG ? (table[index][raw_code]-32):table[index][raw_code]) ;
else
return table[index][raw_code];
}
static u_char readbuf(void)
{
u_char ret;
ret = BUF_TAIL;
kbddev.tail = INCBUF(kbddev.tail,MAX_KBD_BUF);
// printk("<1>tail increased! now the pos is:%d\n",kbddev.tail);
return ret;
}
static int __init keydrv_init_module(void)
{
int retv;
/* define a interrupt number here
such as in arm: set_external_irq(IRQ_KBD, EXT_LOWLEVEL,GPIO_PULLUP_EN);
*/
kbdEvent = kbdEvent_dummy;
retv=register_chrdev(major,key_name,&key_fops);
if(retv<0)
{
printk("<1>register fail!\n");
return retv;
}
if(major==0)
major=retv;
/*
// Enable interrupt
retv = request_irq(PIO_KEY_INT_IRQ,key_interrupt,SA_INTERRUPT,key_name,key_interrupt);
printk("request_irq done, you can use open to see the irq list ifo..\n");
*/
if(retv<0)
return retv;
kbddev.head = kbddev.tail = 0;
kbddev.kbdStatus = KEYSTATUS_UP;
init_waitqueue_head(&(kbddev.wq));
init_timer(&kbd_timer);
kbd_timer.function = kbd_timer_handler;
printk("<1>register keydrv seccuss major_key is : %d\n",major);
return 0;
}
static void __exit keydrv_cleanup(void)
{
int retv;
retv=unregister_chrdev(major,key_name);
if(retv<0)
{
printk("<1>unreginster fail!\n");
return;
}
printk("<1>keydrv:good_bye!\n");
}
static int key_open(struct inode *inode,struct file *filp)
{
writel(0, PIO_KEY_OUT_BASE);
// KEY_PORT_ROWS = 0x00; // we set all rows to low
// printk("<1>rows is set to 0x07,so should just a line effect\n");
// printk("<1>rows have set to ox00\n");
kbd_timer.expires = jiffies + KBD_TIMER_DELAY; // 100ms
add_timer(&kbd_timer);
kbddev.head = kbddev.tail = 0;
kbdEvent = kbdEvent_raw;
MOD_INC_USE_COUNT;
// printk("<1>open key dev\n");
return 0;
}
static int key_release(struct inode *inode,struct file *filp)
{
kbdEvent = kbdEvent_dummy;
MOD_DEC_USE_COUNT;
printk("<1>key dev released!\n");
return 0;
}
static ssize_t key_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)
{
u_char ret;
retry:
// printk("<1>IN DRIVER: now entering read...\n");
if(kbddev.head!=kbddev.tail){
// printk("<1>IN DRIVER: have data now read buffer..\n");
ret = readbuf();
copy_to_user(buffer,(char *)&ret,sizeof(char));
return sizeof(char);
}else{
// printk("<1>IN DRIVER: don't have data\n");
if(filp->f_flags & O_NONBLOCK)
return -EAGAIN;
// printk("IN DRIVER: now waiting...\n");
// printk("<1>begin to sleep_on.. ");
interruptible_sleep_on(&(kbddev.wq)); // if it is block mode.
// printk("<1>waked form interruptible_sleep_on() yet\n");
if(signal_pending(current))
return -ERESTARTSYS;
goto retry;
}
return sizeof(char); // actually this line is never have the chance to run.
}
static void kbd_timer_handler(unsigned long data)
{
switch(kbddev.kbdStatus)
{
case KEYSTATUS_UP:
if(ISKBD_DOWN()){
kbddev.kbdStatus = KEYSTATUS_DOWNX;
kbd_timer.expires = jiffies + KBD_TIMER_DELAY1; // 10ms
// printk("now KEYSTATUS_DOWNX, add a timer 10ms..");
}
else{
kbd_timer.expires = jiffies + KBD_TIMER_DELAY; // 100ms
// printk("idle time\n");
}
add_timer(&kbd_timer);
break;
case KEYSTATUS_DOWNX:
if(ISKBD_DOWN()){
kbddev.kbdStatus = KEYSTATUS_DOWN;
kbd_timer.expires = jiffies + KBD_TIMER_DELAY; // probe repeat key
last_down_time = jiffies; // record the key input time.
// printk("real input,now get the key\n");
get_kbd(); // get the key and write key buffer and wake up the interrupted exec.
// last_key = key; // for later extention
}
else{
printk("noise input\n");
kbd_timer.expires = jiffies + KBD_TIMER_DELAY;
kbddev.kbdStatus = KEYSTATUS_UP;
}
add_timer(&kbd_timer);
break;
case KEYSTATUS_DOWN:
if(ISKBD_DOWN()){
kbd_timer.expires = jiffies + KBD_TIMER_DELAY; // rep dalay time. just waiting button up.
printk("repeat input\n");
}
else{
kbddev.kbdStatus = KEYSTATUS_UP;
kbd_timer.expires = jiffies + KBD_TIMER_DELAY;
printk("released the key\n");
}
add_timer(&kbd_timer);
break;
default:
printk("error input state\n");
break;
}
}
static void get_kbd(void)
{
key = decode_key(); // we just get the key data one time, store in key.
// printk("<1>in get_kbd() we get the return key is :%c\n",key);
// printk("<1>now entering kebEvent()..\n");
kbdEvent(); // it is a function pointer , we have initialezed it by kbdEvent_raw() ;
}
static void kbdEvent_raw(void)
{
printk("<1>now we have got the decode_key is: %c\n",key);
if(kbddev.kbdStatus == KEYSTATUS_DOWN)
BUF_HEAD = key ; // here KEY_UP = 0X80 , as a identifier of KEY_DOWN code.
/* else
BUF_HEAD = key ; // here KEY_UP = 0X80 , as a identifier of KEY_DOWN code.
else
BUF_HEAD = key |KEY_UP ; // here is KEY_UP code.
*/
kbddev.head = INCBUF(kbddev.head,MAX_KBD_BUF);
// printk("<1> head increased!,now the pos is:%d\n",kbddev.head);
// printk("<1>now to wake_up_interruptible now.. ");
wake_up_interruptible(&(kbddev.wq));
// printk("<1>wake_up yet..\n");
}
module_init(keydrv_init_module);
module_exit(keydrv_cleanup);
//MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -