按键扫描驱动--linux2.6系统下
以下是我写的驱动代码,贴出来,以备继续改善或参考之用。感兴趣的朋友联系:QQ:26451602
/****************************************************************
Copyright(c) 2009-2010,zmf
模块名称(Filename): kbd_s3c2410.c
项目名称(Projectname):
版本号(Version): 1.0.0
创建日期(Date): 2009-8-18
作者(Author): ZMF(Zheng meifu)
功能描述(Description): key button driver for linux2.6.14.1
其他说明(Others):
修改记录(History):
2009-10-26: 依据要求,改为刚按下/按住/释放都要给应用层信号。
修改标志:ZMF091026_KEYPROCESS
2009-11-2:读键盘,采用非阻塞读时改为返回0,不返回-EAGAIN.
2009-12-4:想增加fasync异步通知信号给应用程序。经调试ok!不用send_sig函数。
修改标志:ZMF091204_FASYNC
****************************************************************/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/hardware.h>
#include <linux/devfs_fs_kernel.h>
/*
RPM按键共6个。
GPC0 GPC1 GPC2 GPC3 GPC4 GPC5
K1 K2 K3 K4 K5 K6
*/
#define CONFIG_TARGET_RPM
// 注释掉则开发板按键驱动程序为外部中断方式触发,RPM板则为定时扫描。
// 此参数已在内核配置里定义了,此处为调试目的
#define FOR_YL2410BORD
// 次参数定义为在开发板调试按键,注释掉为实际RPM目标板
// 实际运行以上两个参数都要注释掉。驱动为定时器扫描键盘。
#define ZMF091026_KEYPROCESS 1
#define ZMF091204_FASYNC 1
#define DEVICE_NAME "keybutton"
#define MAX_KEY_BUF 32 //KEY BUFFER SIZE
#ifdef CONFIG_TARGET_RPM
#ifdef FOR_YL2410BORD
#define KEY_NUM 8 //key num
#else
#define KEY_NUM 6 //key num
#endif
#else
#define KEY_NUM 4 //key num
#endif
#define INCBUF(x,mod) ((++(x))&((mod)-1))
#define KEY_DELAYMS(X) (HZ/(1000/(X)))
#define KEY_S_UP 0x1000
#define KEY_S_HOLD 0x2000
#define KEY_MAJOR 222
static dev_t key_major = KEY_MAJOR;
#define KEY_FIRST_DOWN 0
#define KEY_SECOND_DOWN 1
#define KEY_STATUS_UP 2
typedef unsigned int KEY_RET;
struct key_dev_t{
struct cdev cdev;
unsigned int keystatus[KEY_NUM];
KEY_RET buf[MAX_KEY_BUF];
unsigned int head,tail;
wait_queue_head_t wq;
#ifdef CONFIG_TARGET_RPM
unsigned int key_pressed; // =1 key is pressed =0 release
#endif
int wait_cond;
#ifdef ZMF091204_FASYNC
struct fasync_struct * async_queue;
#endif
// struct semaphore sam;
};
struct key_dev_t key_dev;
#define BUF_HEAD (key_dev.buf[key_dev.head])
#define BUF_TAIL (key_dev.buf[key_dev.tail])
#ifdef CONFIG_TARGET_RPM
struct timer_list key_timer;
#else
struct timer_list key_timer[KEY_NUM];
#endif
//static int wait_cond=0;
static struct key_info {
#ifdef CONFIG_TARGET_RPM
unsigned int pin;//gpio port
unsigned int pin_setting;
int key_code;//key value
#else
int irq;//中断号
unsigned int pin;//gpio port
unsigned int pin_setting;
int key_code;//key value
char *name;
#endif
}key_info_tab[] = {
#ifdef CONFIG_TARGET_RPM
#ifdef FOR_YL2410BORD
{ S3C2410_GPF0,S3C2410_GPF0_INP,1 },
{ S3C2410_GPB6,S3C2410_GPB6_OUTP,2 },
{ S3C2410_GPG5,S3C2410_GPG5_INP,3 },
{ S3C2410_GPB7,S3C2410_GPB7_OUTP,4 },
{ S3C2410_GPG3,S3C2410_GPG3_INP,5 },
{ S3C2410_GPB6,S3C2410_GPB6_OUTP,6 },
{ S3C2410_GPG11,S3C2410_GPG11_INP,7 },
{ S3C2410_GPB7,S3C2410_GPB7_OUTP,8 },
#else
{ S3C2410_GPC0,S3C2410_GPC0_INP,1 },
{ S3C2410_GPC1,S3C2410_GPC1_INP,2 },
{ S3C2410_GPC2,S3C2410_GPC2_INP,3 },
{ S3C2410_GPC3,S3C2410_GPC3_INP,4 },
{ S3C2410_GPC4,S3C2410_GPC4_INP,5 },
{ S3C2410_GPC5,S3C2410_GPC5_INP,6 },
#endif
#else
{ IRQ_EINT0,S3C2410_GPF0,S3C2410_GPF0_EINT0,KEY_UP,"Key Up" },
/* { IRQ_EINT1,S3C2410_GPF1,S3C2410_GPF1_EINT1,KEY_DOWN,"Key Down" },
{ IRQ_EINT2,S3C2410_GPF2,S3C2410_GPF2_EINT2,KEY_LEFT,"Key Left" }, */
{ IRQ_EINT13,S3C2410_GPG5,S3C2410_GPG5_EINT13,KEY_RIGHT,"Key Right" },
{ IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG3_EINT11,KEY_ENTER,"Key Enter" },
{ IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG11_EINT19,KEY_EXIT,"Key Exit" },
#endif
};
#define ISKEY_DOWN(key) (s3c2410_gpio_getpin(key_info_tab[key].pin) == 0)
static void key_timer_handler(unsigned long data);
#if !defined(CONFIG_TARGET_RPM)
static irqreturn_t key_eint_hander(int irq, void *dev_id, struct pt_regs *reg);
static int request_irqs(void);
#endif
static int key_open(struct inode *inode, struct file *filp);
static int key_release(struct inode *inode, struct file *filp);
static ssize_t key_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos);
static ssize_t key_read(struct file *file,char __user *buffer, size_t count, loff_t *ppos);
#ifdef ZMF091204_FASYNC
static int key_fasync(int fd, struct file *filp, int mode);
#endif
static const struct file_operations key_fops ={
.owner = THIS_MODULE,
.read = key_read,
.write = key_write,
.open = key_open,
.release = key_release,
#ifdef ZMF091204_FASYNC
.fasync = key_fasync,
#endif
};
static int key_open(struct inode *inode, struct file *filp){
filp->private_data = &key_dev;
key_dev.head=key_dev.tail=0;
memset(key_dev.buf, 0, MAX_KEY_BUF);
key_dev.wait_cond = 1;
return 0;
}
#ifdef ZMF091204_FASYNC
static int key_fasync(int fd, struct file *filp, int mode){
struct key_dev_t *dev = (struct key_dev_t *)filp->private_data;
return fasync_helper(fd,filp, mode, &dev->async_queue);
}
#endif
static int key_release(struct inode *inode, struct file *filp){
#ifdef ZMF091204_FASYNC
key_fasync(-1,filp,0);
#endif
return 0;
}
static ssize_t key_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos){
return 0;
}
static ssize_t key_read(struct file *filp,char __user *buffer, size_t count, loff_t *ppos){
KEY_RET key_ret[MAX_KEY_BUF],xi;
struct key_dev_t *dev;
dev = (struct key_dev_t*)filp->private_data;
retry:
if (key_dev.head != key_dev.tail) {
for(xi=0; key_dev.head != key_dev.tail; xi++){
key_ret[xi] = BUF_TAIL;
BUF_TAIL=0;
dev->tail = INCBUF(dev->tail,MAX_KEY_BUF);
}
copy_to_user(buffer,(char*)&key_ret,xi*sizeof(KEY_RET));
return xi;//sizeof(KEY_RET);
}else {
if (filp->f_flags & O_NONBLOCK) {
return 0;//-EAGAIN;
}
/*interruptible_sleep_on(&(dev->wq)); //为安全起见,最好不要调用该睡眠函数*/
/*用户采用阻塞方式读取,调用该函数使进程睡眠*/
wait_event_interruptible(dev->wq,key_dev.wait_cond);
key_dev.wait_cond = 0;
if (signal_pending(current)) {
return -ERESTARTSYS;
}
goto retry;
}
return sizeof(KEY_RET);
}
#if !defined(CONFIG_TARGET_RPM)
static irqreturn_t key_eint_hander(int irq, void *dev_id, struct pt_regs *reg){
int key =(int)dev_id;
int i;
int found = 0;
for (i=0; i<ARRAY_SIZE(key_info_tab); i++) {
if (key_info_tab[i].irq == irq) {
found = 1;
break;
}
}
if (!found) {
printk(KERN_NOTICE"bad irq %d in button\n", irq);
return IRQ_NONE;
}
//printk(KERN_NOTICE "key_eint_hander:key:%d\n",key);
disable_irq(key_info_tab[key].irq);
key_dev.keystatus[key] = KEY_FIRST_DOWN;
key_timer[key].expires = jiffies + KEY_DELAYMS(10);
add_timer(&key_timer[key]);
return IRQ_HANDLED;
}
#endif
static void keyevent_intimerhandler(KEY_RET key){
#ifdef CONFIG_TARGET_RPM
#ifdef ZMF091026_KEYPROCESS
if (key_dev.keystatus[key] == KEY_FIRST_DOWN) {/*刚按下*/
BUF_HEAD = key_info_tab[key].key_code;
key_dev.key_pressed=1;
key_dev.keystatus[key] = KEY_SECOND_DOWN;
key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
}else if (key_dev.keystatus[key] == KEY_SECOND_DOWN){//一直按下
if(BUF_HEAD == (key_info_tab[key].key_code | KEY_S_HOLD)){
(key_dev.buf[((key_dev.head+1)&(MAX_KEY_BUF-1))])++;
}else{
BUF_HEAD = key_info_tab[key].key_code | KEY_S_HOLD;
// key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
}
}else if (key_dev.keystatus[key] == KEY_STATUS_UP){
if(key_dev.key_pressed == 1) return; // second press other key,not do anything
key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
BUF_HEAD = key_info_tab[key].key_code | KEY_S_UP;
key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
#ifdef ZMF091204_FASYNC
kill_fasync(&key_dev.async_queue, SIGIO, POLL_IN);
#else
send_sig(SIGUSR2, current, 1);
#endif
}
wake_up_interruptible(&(key_dev.wq));
key_dev.wait_cond = 1;
#else
int i;
if (key_dev.key_pressed==0){ // 若之前未按下则为有效键
if (key_dev.keystatus[key] == KEY_FIRST_DOWN) {/*刚按下*/
BUF_HEAD = key_info_tab[key].key_code;
key_dev.key_pressed=1;
key_timer.data=0;
key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
wake_up_interruptible(&(key_dev.wq));
key_dev.wait_cond = 1;
}else if (key_dev.keystatus[key] == KEY_STATUS_UP){ /*抬起*/
key_dev.keystatus[key] = KEY_FIRST_DOWN;
for (i=0; i<KEY_NUM; i++) // 为防止第二次扫到其他键
if (i != key) key_dev.keystatus[i] = KEY_STATUS_UP;
}
}
// 若一直按着则不处理
#endif
#else
if (key_dev.keystatus[key] == KEY_FIRST_DOWN)//刚按下
BUF_HEAD = key_info_tab[key].key_code;
else if (key_dev.keystatus[key] == KEY_SECOND_DOWN)//一直按下
BUF_HEAD = key_info_tab[key].key_code | KEY_S_HOLD;
else if (key_dev.keystatus[key] == KEY_STATUS_UP)//抬起
BUF_HEAD = key_info_tab[key].key_code | KEY_S_UP;
key_dev.head = INCBUF(key_dev.head,MAX_KEY_BUF);
wake_up_interruptible(&(key_dev.wq));
// 以上程序刚按键和按键保持及释放都会产生键值
key_dev.wait_cond = 1;
// 若key_read()里使用了wait_event_interruptible()函数,则此条件要打开
#endif
}
static void key_timer_handler(unsigned long data){
#ifdef CONFIG_TARGET_RPM
#ifdef FOR_YL2410BORD
#ifdef ZMF091026_KEYPROCESS
u32 temp_read;
mod_timer(&key_timer, jiffies+ KEY_DELAYMS(50));
s3c2410_gpio_setpin(S3C2410_GPB6, 0);
s3c2410_gpio_setpin(S3C2410_GPB7, 0);
if ((ISKEY_DOWN(1-1)||ISKEY_DOWN(3-1)||ISKEY_DOWN(5-1)||ISKEY_DOWN(7-1))
&&(key_dev.key_pressed==1) )
goto scan_line;
if (key_dev.key_pressed==1) {
key_dev.key_pressed=0;
for (temp_read=0; temp_read<KEY_NUM; temp_read++){
if (key_dev.keystatus[temp_read] == KEY_SECOND_DOWN){
key_dev.keystatus[temp_read] = KEY_STATUS_UP;
keyevent_intimerhandler(temp_read);
}
key_dev.keystatus[temp_read] = KEY_STATUS_UP; // release to KEY_STATUS_UP
}
goto scan_comp;
}
scan_line:
s3c2410_gpio_setpin(S3C2410_GPB6, 0);
s3c2410_gpio_setpin(S3C2410_GPB7, 1);
if (ISKEY_DOWN(1-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[1-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(1-1);goto scan_comp;}
else if (ISKEY_DOWN(3-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[3-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(3-1); goto scan_comp;}
else if (ISKEY_DOWN(5-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[5-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(5-1); goto scan_comp;}
else if (ISKEY_DOWN(7-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[7-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(7-1); goto scan_comp;}
s3c2410_gpio_setpin(S3C2410_GPB6, 1);
s3c2410_gpio_setpin(S3C2410_GPB7, 0);
if (ISKEY_DOWN(1-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[2-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(2-1); goto scan_comp;}
else if (ISKEY_DOWN(3-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[4-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(4-1); goto scan_comp;}
else if (ISKEY_DOWN(5-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[6-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(6-1); goto scan_comp;}
else if (ISKEY_DOWN(7-1)){
if(key_dev.key_pressed==0) key_dev.keystatus[8-1] = KEY_FIRST_DOWN;
keyevent_intimerhandler(8-1); goto scan_comp;}
scan_comp:
s3c2410_gpio_setpin(S3C2410_GPB6, 1);
s3c2410_gpio_setpin(S3C2410_GPB7, 1);
#else // is not ZMF091026_KEYPROCESS & yes for FOR_YL2410BORD
u32 temp_read;
/* if(down_trylock(&key_dev.sam)){
mod_timer(&key_timer, jiffies+ KEY_DELAYMS(50));
return ;
} */
mod_timer(&key_timer, jiffies+ KEY_DELAYMS(50));
s3c2410_gpio_setpin(S3C2410_GPB6, 0);
s3c2410_gpio_setpin(S3C2410_GPB7, 0);
if ((ISKEY_DOWN(1-1)||ISKEY_DOWN(3-1)||ISKEY_DOWN(5-1)||ISKEY_DOWN(7-1))
&&(key_dev.key_pressed==1) )
return;
if (key_dev.key_pressed==1) {
for (temp_read=0; temp_read<KEY_NUM; temp_read++)
if (key_dev.keystatus[temp_read] != KEY_STATUS_UP)
key_dev.keystatus[temp_read] = KEY_STATUS_UP;
key_dev.key_pressed=0;
}
s3c2410_gpio_setpin(S3C2410_GPB6, 0);
s3c2410_gpio_setpin(S3C2410_GPB7, 1);
if (ISKEY_DOWN(1-1)){keyevent_intimerhandler(1-1);goto scan_comp;}
else if (ISKEY_DOWN(3-1)){keyevent_intimerhandler(3-1); goto scan_comp;}
else if (ISKEY_DOWN(5-1)){keyevent_intimerhandler(5-1); goto scan_comp;}
else if (ISKEY_DOWN(7-1)){keyevent_intimerhandler(7-1); goto scan_comp;}
s3c2410_gpio_setpin(S3C2410_GPB6, 1);
s3c2410_gpio_setpin(S3C2410_GPB7, 0);
if (ISKEY_DOWN(1-1)){keyevent_intimerhandler(2-1); goto scan_comp;}
else if (ISKEY_DOWN(3-1)){keyevent_intimerhandler(4-1); goto scan_comp;}
else if (ISKEY_DOWN(5-1)){keyevent_intimerhandler(6-1); goto scan_comp;}
else if (ISKEY_DOWN(7-1)){keyevent_intimerhandler(8-1); goto scan_comp;}
scan_comp:
s3c2410_gpio_setpin(S3C2410_GPB6, 1);
s3c2410_gpio_setpin(S3C2410_GPB7, 1);
// up(&key_dev.sam);
#endif // end ZMF091026_KEYPROCESS
#else // not for yl-2410 devp board
#ifdef ZMF091026_KEYPROCESS
int keyscan_hist = data;
int keyscan_read_io;
u32 temp_read;
temp_read=__raw_readl(S3C2410_GPCDAT);
keyscan_read_io = temp_read & 0x3f;
if ( keyscan_read_io != 0x3f){
switch(keyscan_read_io){
case 0x3e: temp_read=0; break;
case 0x3d: temp_read=1; break;
case 0x3b: temp_read=2; break;
case 0x37: temp_read=3; break;
case 0x2f: temp_read=4; break;
case 0x1f: temp_read=5; break;
default: temp_read=0xff; break;
}
if(temp_read != 0xff){
if ( key_dev.key_pressed==0)
key_dev.keystatus[temp_read] = KEY_FIRST_DOWN;
keyevent_intimerhandler(temp_read);
} /*else{
for (temp_read=0; temp_read<KEY_NUM; temp_read++)
key_dev.keystatus[temp_read] = KEY_STATUS_UP;
key_dev.key_pressed=0;
}*/ // press double key error!! Not do anything
key_timer.data=0;
}else if ( key_dev.key_pressed==1) {
if (++keyscan_hist >=2) {
key_dev.key_pressed=0;
for (temp_read=0; temp_read<KEY_NUM; temp_read++){
if(key_dev.keystatus[temp_read] == KEY_SECOND_DOWN){
key_dev.keystatus[temp_read] = KEY_STATUS_UP;
keyevent_intimerhandler(temp_read);
}
key_dev.keystatus[temp_read] = KEY_STATUS_UP; // release to KEY_STATUS_UP
}
key_timer.data=0;
}else key_timer.data=keyscan_hist;
}
mod_timer(&key_timer, jiffies+ KEY_DELAYMS(50));
#else // not for yl2410, not modify on ZMF091026_KEYPROCESS
int keyscan_hist = data;
int keyscan_read_io;
u32 temp_read;
temp_read=__raw_readl(S3C2410_GPCDAT);
keyscan_read_io = temp_read & 0x3f;
if ( keyscan_read_io != 0x3f) {
switch(keyscan_read_io) {
case 0x3e: keyevent_intimerhandler(0); break;
case 0x3d: keyevent_intimerhandler(1); break;
case 0x3b: keyevent_intimerhandler(2); break;
case 0x37: keyevent_intimerhandler(3); break;
case 0x2f: keyevent_intimerhandler(4); break;
case 0x1f: keyevent_intimerhandler(5); break;
default: break;
}
}else if ( key_dev.key_pressed==1) {
for (temp_read=0; temp_read<KEY_NUM; temp_read++)
if (key_dev.keystatus[temp_read] != KEY_STATUS_UP)
key_dev.keystatus[temp_read] = KEY_STATUS_UP;
if (++keyscan_hist >=2) {
key_dev.key_pressed=0;
key_timer.data=0;
}else key_timer.data=keyscan_hist;
}
mod_timer(&key_timer, jiffies+ KEY_DELAYMS(50));
#endif // end ZMF091026_KEYPROCESS
#endif // end FOR_YL2410BORD
#else // is not CONFIG_TARGET_RPM
int key = data;
if (ISKEY_DOWN(key)) {
//printk(KERN_NOTICE"key_dev.keystatus[key]:%d\n",key);
if (key_dev.keystatus[key] == KEY_FIRST_DOWN)//从中断进入
{
keyevent_intimerhandler(key);
key_dev.keystatus[key] = KEY_SECOND_DOWN;
key_timer[key].expires = jiffies + KEY_DELAYMS(200);
add_timer(&key_timer[key]);
}else {
keyevent_intimerhandler(key);
key_timer[key].expires = jiffies + KEY_DELAYMS(200);//HOLD key,每隔200MS发送一次
add_timer(&key_timer[key]);
}
}else {
key_dev.keystatus[key] = KEY_STATUS_UP;
keyevent_intimerhandler(key);
enable_irq(key_info_tab[key].irq);
}
#endif // end CONFIG_TARGET_RPM
}
#if !defined(CONFIG_TARGET_RPM)
//申请irq中断
static int request_irqs(void){
int i;
for (i=0; i<ARRAY_SIZE(key_info_tab); i++) {
s3c2410_gpio_cfgpin(key_info_tab[i].pin, key_info_tab[i].pin_setting);
set_irq_type(key_info_tab[i].irq, IRQT_FALLING);//下降沿触发
if (request_irq(key_info_tab[i].irq, key_eint_hander, SA_INTERRUPT, DEVICE_NAME, (void *)i))
{
return -1;
}
}
return 0;
}
//释放irq中断
static void free_irqs(void){
int i;
for (i=0; i<ARRAY_SIZE(key_info_tab); i++) {
free_irq(key_info_tab[i].irq, (void *)i);
}
}
#endif
static void key_init_cdev(void){
int i;
int err,devno = MKDEV(key_major,0);
cdev_init((struct cdev *)&(key_dev.cdev),(struct file_operations *)&key_fops);
key_dev.cdev.owner = THIS_MODULE;
key_dev.cdev.ops = (struct file_operations *)&key_fops;
key_dev.wait_cond = 0;
err = cdev_add(&key_dev.cdev, devno, 1);
if (err) {
printk(KERN_NOTICE "Error %d adding key",err);
}
key_dev.head = key_dev.tail = 0;
for(i=0; i<KEY_NUM; i++) {
key_dev.keystatus[i] = KEY_STATUS_UP;
}
init_waitqueue_head(&(key_dev.wq));
#ifdef CONFIG_TARGET_RPM
key_dev.key_pressed=0;
init_timer(&key_timer);
key_timer.expires = jiffies + KEY_DELAYMS(50);
key_timer.function = key_timer_handler;
key_timer.data = 0x00;
add_timer(&key_timer);
#else
request_irqs();
for(i=0; i<KEY_NUM; i++) {
key_timer[i].function = key_timer_handler;
key_timer[i].data = i;
init_timer(&key_timer[i]);
}
#endif
}
static int __init key_init(void){
int result;
dev_t devno = MKDEV(key_major,0);
if (key_major) {
result = register_chrdev_region(devno, 1, DEVICE_NAME);
}else {
result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
key_major = MAJOR(devno);
}
if (result < 0) {
return result;
}
// init_MUTEX(&key_dev.sam);
#ifdef CONFIG_TARGET_RPM
for (result=0; result<KEY_NUM; result++)
s3c2410_gpio_cfgpin(key_info_tab[result].pin, key_info_tab[result].pin_setting);
#else
s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPB6_OUTP);
s3c2410_gpio_cfgpin(S3C2410_GPB7, S3C2410_GPB7_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB6, 0);
s3c2410_gpio_setpin(S3C2410_GPB7, 1);
#endif
key_init_cdev();
#ifdef CONFIG_DEVFS_FS
devfs_mk_cdev(MKDEV(key_major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVICE_NAME);
#endif
printk(KERN_NOTICE "/dev/keybutton inited: zhengmeifu@sina.com\n");
return 0;
}
static void __exit key_exit(void){
#if !defined(CONFIG_TARGET_RPM)
int i;
#endif
cdev_del(&key_dev.cdev);
unregister_chrdev_region(MKDEV(key_major,0),1);
#ifdef CONFIG_DEVFS_FS
devfs_remove(DEVICE_NAME);
#endif
#ifdef CONFIG_TARGET_RPM
del_timer(&key_timer);
#else
for(i=0; i<KEY_NUM; i++) {
del_timer(&key_timer[i]);
}
free_irqs();
#endif
}
module_init(key_init);
module_exit(key_exit);
MODULE_AUTHOR("zhengmeifu@sina.com");
MODULE_DESCRIPTION("RPM or (yls3c2410 devlp board) keyboard driver");
MODULE_LICENSE("Dual BSD/GPL");
/*linux驱动开发之key
今天做了key的驱动,程序测试ok。
key的驱动牵涉的内核知识很多,有中断,内核定时器,阻塞。
后续有时间我会再写一个详细的分析。
测试如下:
先通过cat /proc/devices 插看keybutton的主号为222.
mknod /dev/keybutton c 222 0
测试程序如下:
*/
/*
* Buttons Example for linux s3c2410 rpm
*/
/*
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
int main(void)
{
int buttons_fd;
int key_value;
buttons_fd = open("/dev/keybutton", 0);
if (buttons_fd < 0) {
perror("cann't open device /dev/keybutton");
exit(1);
}
for (;;) {
int ret = read(buttons_fd, &key_value, sizeof key_value);
printf("You pressed buttons %d\n", key_value);
}
close(buttons_fd);
return 0;
}
驱动程序如上:
*/
posted on 2010-03-11 10:27 zhengmeifu 阅读(2118) 评论(0) 编辑 收藏 举报