linux 内核按键抖动,linux2.6内核下的一个按键中断驱动程序示例

本程序是基于三星s3c2410ARM平台下的按键驱动例程,程序中两个按键分别占用了ARM芯片上的外部中断16和17,程序中设定外部中断为下降沿响应中断.本程序是在2.6.16内核版本下编译测试通过,交叉编译器采用3.4.1版本的arm-linux-gcc.

1.驱动程序文件名为button.c,其源码如下示:

/**********************start*******************************/

#i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #i nclude #define BUTTON_IRQ1IRQ_EINT16

#define BUTTON_IRQ2IRQ_EINT17

#defineDEVICE_NAME"button"

static int buttonMajor=0;

#define BUTTONMINOR0

#define MAX_BUTTON_BUF16

#define BUTTONSTATUS_116

#define BUTTONSTATUS_217

static unsigned char buttonRead(void);

static int flag=0;

typedef struct {

unsigned int buttonStatus;//按键状态unsigned char buf[MAX_BUTTON_BUF]; //按键缓冲区unsigned int head,tail;//按键缓冲区头和尾wait_queue_head_t wq;//等待队列} BUTTON_DEV;

static BUTTON_DEV buttondev;

#define BUF_HEAD(buttondev.buf[buttondev.head])//缓冲区头#define BUF_TAIL(buttondev.buf[buttondev.tail])//缓冲区尾#define INCBUF(x,mod)((++(x)) & ((mod)-1))//移动缓冲区指针static void (*buttonEvent)(void);

static void buttonEvent_dummy(void) {}

static void buttonEvent_1(void)

{

if(buttondev.buttonStatus==BUTTONSTATUS_2) {

BUF_HEAD=BUTTONSTATUS_2;

}

else {

BUF_HEAD=BUTTONSTATUS_1;

}

buttondev.head=INCBUF(buttondev.head,MAX_BUTTON_BUF);

flag=1;

wake_up_interruptible(&(buttondev.wq));

printk("buttonEvent_1\n");

}

static irqreturn_t isr_button(int irq,void *dev_id,struct pt_regs *regs)

{

printk("Occured key board Inetrrupt,irq=%d\n",irq-44);

switch (irq) {

case BUTTON_IRQ1:buttondev.buttonStatus=BUTTONSTATUS_1;

break;

case BUTTON_IRQ2:buttondev.buttonStatus=BUTTONSTATUS_2;

break;

default:break;

}

buttonEvent();

return 0;

}

static int button_open(struct inode *inode,struct file *filp)

{

int ret;

buttondev.head=buttondev.tail=0;

buttonEvent=buttonEvent_1;

ret=request_irq(BUTTON_IRQ1,isr_button,SA_INTERRUPT,DEVICE_NAME,NULL);

if(ret){

printk("BUTTON_IRQ1: could not register interrupt\n");

return ret;

}

ret=request_irq(BUTTON_IRQ2,isr_button,SA_INTERRUPT,DEVICE_NAME,NULL);

if(ret){

printk("BUTTON_IRQ2: could not register interrupt\n");

return ret;

}

return 0;

}

static int button_release(struct inode *inode,struct file *filp)

{

buttonEvent=buttonEvent_dummy;

free_irq(BUTTON_IRQ1,NULL);

free_irq(BUTTON_IRQ2,NULL);

return 0;

}

static ssize_t button_read(struct file *filp,char *buffer,size_t count,loff_t *ppos)

{

static unsigned char button_ret;

retry:

printk("retry start\n");

if(buttondev.head!=buttondev.tail) {

button_ret=buttonRead();

copy_to_user(buffer,(char *)&button_ret,sizeof(unsigned char));

printk("the button_ret is 0x%x\n",button_ret);

return sizeof(unsigned char);

}

else {

if(filp->f_flags & O_NONBLOCK)

return -EAGAIN;

printk("sleep\n");

//interruptible_sleep_on(&(buttondev.wq));//为安全起见,最好不要调用该睡眠函数

wait_event_interruptible(buttondev.wq,flag);

flag=0;

printk("sleep_after\n");

if(signal_pending(current))

{

printk("rturn -ERESTARTSYS\n");

return -ERESTARTSYS;

}

goto retry;

}

return sizeof(unsigned char);

}

static struct file_operations button_fops= {

.owner=THIS_MODULE,

.open=button_open,

.read=button_read,

.release=button_release,

};

static int __init s3c2410_button_init(void)

{

int ret;

set_irq_type(BUTTON_IRQ1,IRQT_FALLING);

set_irq_type(BUTTON_IRQ2,IRQT_FALLING);

buttonEvent=buttonEvent_dummy;

ret=register_chrdev(0,DEVICE_NAME,&button_fops);

if(ret<0) {

printk("button: can't get major number\n");

return ret;

}

buttonMajor=ret;

#ifdefCONFIG_DEVFS_FS

devfs_mk_cdev(MKDEV(buttonMajor,BUTTONMINOR),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);

#endif

//buttondev.head=buttondev.tail=0;

buttondev.buttonStatus=BUTTONSTATUS_1;

init_waitqueue_head(&(buttondev.wq));

printk(DEVICE_NAME"initialized\n");

return 0;

}

static unsigned char buttonRead(void)

{

unsigned char button_ret;

button_ret=BUF_TAIL;

buttondev.tail=INCBUF(buttondev.tail,MAX_BUTTON_BUF);

return button_ret;

}

static void __exit s3c2410_button_eixt(void)

{

#ifdef CONFIG_DEVFS_FS

devfs_remove(DEVICE_NAME);

#endif

unregister_chrdev(buttonMajor,DEVICE_NAME);

}

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Kision");

MODULE_DEscrīptION ("the first char device driver");

module_init(s3c2410_button_init);

module_exit(s3c2410_button_eixt);

/*************************end***************************/

2.   当然在编写2.6内核驱动程序之前应该已经自己建立好一个2.6的内核源码树(我这里是基于s3c2410移植的源码树,本处该源码是放在宿主机的 /home/src/linux-2.6.16目录下的),如果没有的话,那么需要自己去建立好这个源码树.自己编写的模块化驱动程序可以不放在内核源码之内,但是此外还需要一个自己编写一个Makefile文件(该文件和上面的button.c文件应放在同一个目录下),其内容如下示:

ifneq ($(KERNELRELEASE),)

obj-m :=button.o

else

KERNELDIR ?= /home/src/linux-2.6.16

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

endif

3.在宿主机的终端下,进入驱动程序目录内,敲入命令:

#make

就会在该目录下生成button.ko文件,这就是2.6内核下生成的驱动加载模块,注意是.ko文件,不同于2.4内核下的.o文件.

把该button.ko文件拷贝到目标板上,在minicom终端下进入该文件目录,敲入:

#insmod button.ko

如果终端显示有buttoninitialized则表示加载成功.

这时可以用命令lsmod查看动态加载模块:

#lsmod

当然,可以用如下命令查看devfs文件系统信息:

#cat /proc/devices

如果用卸载该模块,敲入命令:

#rmmod button

4.加载驱动程序后,可以自己再编写一个简单的测试程序,如下:

/**************************start***********************/#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

#i nclude

main()

{

int retval;

int fileno;

int ts, maxfd;

intret= 0,i,j;

int number;

fileno = open("/dev/button",O_RDWR);

if (fileno == -1) {

printf("open device led errr!\n");

return 0;

}

while(1) {

read(fileno,&number,1);

printf("key=0x%x\n",number);

}

close(fileno);

return 0;

}/**************************end***********************/

命名为test.c,并交叉编译该文件:

#arm-linux-gcc test.c -o test

将二进制文件同样拷贝到目标板上,运行:

#./test &

即可看到实验效果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值