?? at91_key.c
字號:
/*****************************************************************************
;Copyright (C) 2005 Hyesco Technology Co.,Ltd
;Institue of Automation, Chinese Academy of Sciences
;
;WebSite: www.hyesco.com
;Description: Keyboard driver on Linux
;Date: 2006-11-15
;Author: Hyesco
;E_mail: Lijg@hyesco.com
*****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/AT91RM9200_SYS.h>
#include <asm/arch/hardware.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/devfs_fs_kernel.h>
//全局變量,常量;
static int major=0;
static char s_name[]="key";
#define U8 unsigned char
#define U16 unsigned short
#define U32 unsigned int
#define key_buffer_len 10 //定義鍵盤緩沖區長度
#define KBD_JITTER 2 //ms
#define QUERY_FREQ 10 //jiffer=10ms
struct kbd_info{
U8 bKeyBuff[key_buffer_len]; //retunr key code
U8 bCount; //Key count in buffer
U8 bStart; //start location of key
wait_queue_head_t key_wait;
spinlock_t lock;
};
//*********************************************************
//定義鍵值表,4X4矩陣鍵盤
//*********************************************************
static U8 keytable1[4][4] = {
{0x11,0x12,0x13,0x14},
{0x21,0x22,0x23,0x24},
{0x31,0x32,0x33,0x34},
{0x41,0x42,0x43,0x44},
};
//*********************************************************
//函數原型
//*********************************************************
void Init_Keyboard(void);
int key_open(struct inode * inode, struct file * filp);
int key_release(struct inode * inode, struct file * filp);
unsigned int key_poll(struct file * filp, struct poll_table_struct * wait);
ssize_t key_read(struct file * filp, char * buf, size_t count, loff_t * l);
void key_run_timer(void);
static struct kbd_info ownkbd_info;
static struct timer_list key_timer;
struct file_operations key_fops = {
owner: THIS_MODULE,
open: key_open,
release: key_release,
read: key_read,
poll: key_poll,
};
//*********************************************************
//初始化模塊函數;
//*********************************************************
static devfs_handle_t devfs_handle;
int __init KEY1_at91_init(void)
{
//unsigned int result = 0;
int ret;
//初始化鍵盤端口;
Init_Keyboard();
//注冊模塊;
if ((ret=devfs_register_chrdev(major,s_name,&key_fops)) < 0)
{
printk("\r\n<1>Keyboard Register Fail!\r\n");
return ret;
}
//動態分配主設備號;
if(major == 0)
major = ret;
//建立設備文件,文件名為:key;
devfs_handle = devfs_register(NULL, "key",DEVFS_FL_DEFAULT,
major, 0, S_IFCHR | S_IRUSR | S_IWUSR,&key_fops, NULL);
init_waitqueue_head(&ownkbd_info.key_wait);
ownkbd_info.bCount=0;
ownkbd_info.bStart=0;
spin_lock_init(&ownkbd_info.lock);
key_run_timer();
return 0;
}
//*********************************************************
//鍵盤模塊打開函數;
//*********************************************************
int key_open(struct inode * inode, struct file * filp)
{
MOD_INC_USE_COUNT;
return 0;
}
//*********************************************************
//鍵盤模塊釋放函數;
//*********************************************************
int key_release(struct inode * inode,struct file * filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
//*********************************************************
//鍵值設置函數;
//*********************************************************
static int KEY_DATA(U8 x)
{
int status=-1;
switch(x)
{
case 0:
//第一行輸出高電平
status = AT91_SYS->PIOB_PDSR & (0x1 <<0);
break;
case 1:
//第二行輸出高電平
status = AT91_SYS->PIOB_PDSR & (0x1 <<1);
break;
case 2:
//第三行輸出高電平
status = AT91_SYS->PIOB_PDSR & (0x1 <<2);
break;
case 3:
//第四行輸出高電平
status = AT91_SYS->PIOB_PDSR & (0x1 <<3);
break;
default:
break;
}
return status;
}
//*********************************************************
//讀鍵函數;
//*********************************************************
ssize_t key_read(struct file * filp, char * buf, size_t count, loff_t * l)
{
//Get count keys from keyboard
U8 bTrueCount=0;
U8 bTmp=0;
if ((buf!=NULL) && (count>0) && (ownkbd_info.bCount>0))
{
spin_lock(&ownkbd_info.lock);
bTrueCount=(count>ownkbd_info.bCount) ? ownkbd_info.bCount : count;
bTmp=ownkbd_info.bStart+bTrueCount;
if (bTmp<=key_buffer_len)
copy_to_user(buf, ownkbd_info.bKeyBuff+ownkbd_info.bStart, bTrueCount);
else
{
copy_to_user(buf, ownkbd_info.bKeyBuff+ownkbd_info.bStart, key_buffer_len-ownkbd_info.bStart);
copy_to_user(buf+key_buffer_len-ownkbd_info.bStart, ownkbd_info.bKeyBuff, bTmp-key_buffer_len);
}
ownkbd_info.bCount-=bTrueCount;
ownkbd_info.bStart+=bTrueCount;
ownkbd_info.bStart=(ownkbd_info.bStart<key_buffer_len)?ownkbd_info.bStart : (ownkbd_info.bStart-key_buffer_len);
spin_unlock(&ownkbd_info.lock);
return bTrueCount;
}
return -1;
}
//*********************************************************
// 鍵盤輪詢函數;
//*********************************************************
unsigned int key_poll(struct file * filp, struct poll_table_struct * wait)
{
//Support select/poll
spin_lock(&ownkbd_info.lock);
poll_wait(filp,&ownkbd_info.key_wait,wait);
if (ownkbd_info.bCount>0)
{
spin_unlock(&ownkbd_info.lock);
return POLLIN |POLLRDNORM;
}
else
{
spin_unlock(&ownkbd_info.lock);
return 0;
}
}
//*********************************************************
// 鍵掃描函數;
//*********************************************************
int Scan_Keyboard(void)
{
//keyboard scan main function
//scan key board to detect if a key down or up
//the result is stored in ownkbd_info
unsigned char row=0,col=0;
unsigned int iScanCode1=0,iScanCode2=0;
U8 bKeyLocation=0;
int i;
spin_lock(&ownkbd_info.lock);
if (ownkbd_info.bCount<key_buffer_len)
{
//There are remains in Key buffer, so we continue scaning
//get the location of the key buffer if a key down/up
bKeyLocation= ownkbd_info.bStart+ownkbd_info.bCount;
bKeyLocation=(bKeyLocation<key_buffer_len) ? bKeyLocation : (bKeyLocation-key_buffer_len);
//check key down
if (KEY_DATA(0)==0)
row=0x0;
else if (KEY_DATA(1)==0)
row=0x1;
else if (KEY_DATA(2)==0)
row=0x2;
else if (KEY_DATA(3)==0)
row=0x3;
else
goto end;
//列線全送高電平
AT91_SYS->PIOB_SODR |= 0xf0; //0xfc0;
for(i=0;i<4;i++)
{
//PB4~PB7依次送出低電平
AT91_SYS->PIOB_CODR |= (0x10 << i);
if (KEY_DATA(row) == 0)
{
//列值在行值的基礎上加10,便于區別;
col = i+0xa;
iScanCode1 = row | (col<<4) ;
break ;
}
else if(i == 3)
goto end ;
else
AT91_SYS->PIOB_SODR |= (0x10 << i);
}
mdelay(KBD_JITTER);
AT91_SYS->PIOB_CODR |=0xf0;
//check key down again
if (KEY_DATA(0)==0)
row=0;
else if (KEY_DATA(1)==0)
row=1;
else if (KEY_DATA(2)==0)
row=2;
else if (KEY_DATA(3)==0)
row=3;
else
goto end;
AT91_SYS->PIOB_SODR |= 0xf0;
for(i=0;i<4;i++)
{
//AT91_SYS->PIOB_SODR |= (0x1 << i);
AT91_SYS->PIOB_CODR |= (0x10 << i);
if (KEY_DATA(row) == 0)
{
col = i+0xa;
iScanCode2 = row | (col<<4) ;
break ;
}
else if(i == 3)
goto end ;
else
AT91_SYS->PIOB_CODR |= (0x10 << i);
}
//鍵確認
if(iScanCode1 != iScanCode2)
goto end;
//AT91_SYS->PIOB_CODR |= 0xf;
AT91_SYS->PIOB_CODR |= 0xf0;
//鍵up
while(KEY_DATA(row)==0);
*(ownkbd_info.bKeyBuff+bKeyLocation)=keytable1[row][col-0xa];
ownkbd_info.bCount++;
//DPRINTK("Key up %d\n", *(ownkbd_info.bKeyBuff+bKeyLocation));
}
end:
spin_unlock(&ownkbd_info.lock);
AT91_SYS->PIOB_CODR |= 0xf0;
return 0;
}/*end of scan*/
void key_timeout(unsigned long ptr)
{
Scan_Keyboard();
key_run_timer();
}
void key_run_timer(void)
{
init_timer(&key_timer);
key_timer.function = key_timeout;
key_timer.data = (unsigned long)0;
key_timer.expires = jiffies + QUERY_FREQ;
add_timer(&key_timer);
}
//*********************************************************
// 鍵盤端口初始化函數;
//*********************************************************
void Init_Keyboard(void)
{
//PB7~PB0用作鍵盤端口,PB0~PB3作為行,PB4~PB7作為列;
//使能PB7~PB0的GPIO功能
// PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
// 1 1 1 1 1 1 1 1
AT91_SYS->PIOB_PER |=0xff;
// PB0~PB3 輸入功能設置;
// PB0~PB3 enable input;
AT91_SYS->PIOB_ODR |=0xf;
// PB0~PB3 enable input filter;
AT91_SYS->PIOB_IFER |=0xf;
// PB0~PB3 enable Pull up;
AT91_SYS->PIOB_PPUER |=0xf;
// PB4~PB7 輸出功能設置;
// PB4~PB7 enable output;
AT91_SYS->PIOB_OER |=0xf0;
/* set PB4-7 are 0 */
AT91_SYS->PIOB_CODR |=0xf0;
/* enable piob clock */
AT91_SYS->PMC_PCER =0x1<< AT91C_ID_PIOB;
}
//*********************************************************
//注銷模塊函數;
//*********************************************************
void __exit KEY1_at91_cleanup(void)
{
int retv;
del_timer_sync(&key_timer);
//注銷模塊;
retv=devfs_unregister_chrdev(major,s_name);
return;
}
module_init(KEY1_at91_init);
module_exit(KEY1_at91_cleanup);
MODULE_AUTHOR("www.hyesco.com");
MODULE_DESCRIPTION("AT91 KEY Driver (AT91_KEY)");
MODULE_LICENSE("GPL");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -