linux驱动程序之增加按键异步通知机制

来源:互联网 发布:少儿编程用什么软件 编辑:程序博客网 时间:2024/05/16 18:29

目的:按下按键时驱动程序通知应用程序


1、大体框架:

1、应用程序:注册信号处理函数

2、驱动程序发送信号

3、应用程序通知驱动 PID

4、驱动程序发送如何发送信号


2、需要的操作:

为了使设备获得异步通知机制,驱动程序中涉及如下操作:

  1. 支持F_SETOWN 命令,能在这个命令处理中设置filp->f_owner为对应进程ID,这个工作已经由内核完成了。
  2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行,驱动中应该实现fasync()函数
  3. 在设备获得资源时,调用kill_fasync()函数激发相应的信号。

3、驱动程序编写:

1、在file_operations结构中添加:

    .fasync        = button_dev_fasync,

2、完成这个异步通知函数:

static int button_dev_fasync(int fd,struct file *filp,int on){printk("button_dev_fasync  \n");return fasync_helper(fd,filp,on,&button_async);}

初始化 button_async

3、驱动程序发送信号:

kill_fasync(&button_async,SIGIO,POLL_IN);

button_async的定义如下:

static struct fasync_struct *button_async;

4、驱动程序编写:

    fcntl(fd, F_SETOWN,getpid());//告诉内核发给谁    /*改变FASYNC标志,最终会调用驱动的button_dev_fasync函数*/    Oflags = fcntl(fd,F_GETFL);//    fcntl(fd,F_SETFL,Oflags|FASYNC);//  

    Oflags = fcntl(fd,F_GETFL);//
    fcntl(fd,F_SETFL,Oflags|FASYNC);//

这两个函数会调用驱动的button_dev_fasync函数,从而调用fasync_helper函数,初始化或者释放button_async结构体


5、完整驱动代码:

#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <asm/io.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/irq.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <mach/regs-gpio.h>#include <mach/irqs.h>//这个在/opt/EmbedSky/linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach 路径#include <linux/interrupt.h>#include <linux/poll.h>MODULE_LICENSE("Dual BSD/GPL");static struct class *buttondrv_class;static struct class_devices *buttondrv_class_dev;/*  */static DECLARE_WAIT_QUEUE_HEAD(button_wait_q);/*中断事件标志,中断服务程序将他置1,read函数将他置0*/static volatile int ev_press =0;volatile unsigned long *gpfcon = NULL;volatile unsigned long *gpfdat = NULL;static unsigned keyval;static struct fasync_struct *button_async;struct pin_desc{unsigned int pin;unsigned int key_value;};/*按键按下时是:0x01 0x02 0x03 0x04*//*按键松开时是:0x81 0x82 0x83 0x84*/struct pin_desc pins_desc[4] ={{S3C2410_GPF1,0x01},{S3C2410_GPF4,0x02},{S3C2410_GPF2,0x03},{S3C2410_GPF0,0x04},};/* * 确定按键值 */static irqreturn_t buttons_irq(int irq,void *dev_id){struct pin_desc * pindesc = (struct pin_desc *) dev_id;unsigned int pinval;pinval = s3c2410_gpio_getpin(pindesc -> pin);if(pinval)//松开{keyval = 0x80|pindesc->key_value;}else{keyval = pindesc->key_value;}ev_press =1;//中断发生wake_up_interruptible(&button_wait_q);kill_fasync(&button_async,SIGIO,POLL_IN);return IRQ_HANDLED;}static int button_dev_open(struct inode *inode ,struct file* file){//配置按键的引脚 GPF0,1,2,4为输入引脚request_irq(IRQ_EINT1,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key1",&pins_desc[0]);request_irq(IRQ_EINT4,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key2",&pins_desc[1]);request_irq(IRQ_EINT2,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key3",&pins_desc[2]);request_irq(IRQ_EINT0,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key4",&pins_desc[3]);return 0;}ssize_t button_dev_read(struct file *file,char __user *buf,size_t size,loff_t *ppos){if(size !=1){return -EINVAL;}/*如果没有按键动作发生  就休眠*/wait_event_interruptible(button_wait_q,ev_press);/*如果有按键动作发生,直接返回*/copy_to_user(buf,&keyval,1);ev_press = 0;return 0;}int button_dev_close(struct inode* inode ,struct file *file){free_irq(IRQ_EINT1,&pins_desc[0]);free_irq(IRQ_EINT4,&pins_desc[1]);free_irq(IRQ_EINT2,&pins_desc[2]);free_irq(IRQ_EINT0,&pins_desc[3]);return 0;}static int button_dev_fasync(int fd,struct file *filp,int on){printk("button_dev_fasync  \n");return fasync_helper(fd,filp,on,&button_async);}static struct file_operations button_sdv_fops ={.owner = THIS_MODULE,.open  = button_dev_open,.read = button_dev_read,.release = button_dev_close,.fasync= button_dev_fasync,};int major;static int button_dev_init(void)//入口函数{major = register_chrdev(0,"button_drv",&button_sdv_fops);buttondrv_class = class_create(THIS_MODULE,"button_drv");if(IS_ERR(buttondrv_class))return PTR_ERR(buttondrv_class);buttondrv_class_dev= device_create(buttondrv_class,NULL,MKDEV(major,0),NULL,"wq_button");if(unlikely(IS_ERR(buttondrv_class_dev)))return PTR_ERR(buttondrv_class_dev);/*映射物理地址*/gpfcon = (volatile unsigned long *) ioremap(0x56000050 ,16);gpfdat = gpfcon + 1;return 0;}static void button_dev_exit(void){unregister_chrdev(major,"button_drv");device_unregister(buttondrv_class_dev);class_destroy(buttondrv_class);iounmap(gpfcon);}module_init(button_dev_init);module_exit(button_dev_exit);

6、完整测试代码

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <poll.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>int fd;void my_signal_fun(int signum){unsigned char key_val;read(fd,&key_val,1);printf("key_val: 0x%x\n",key_val);}int main(int argc, char **argv){int ret=0;int Oflags;unsigned char key_val;signal(SIGIO,my_signal_fun);fd = open("/dev/wq_button",O_RDWR);if(fd<0){printf("can't open \n");}fcntl(fd, F_SETOWN,getpid());//告诉内核发给谁/*改变FASYNC标志,最终会调用驱动的button_dev_fasync函数*/Oflags = fcntl(fd,F_GETFL);//fcntl(fd,F_SETFL,Oflags|FASYNC);//while(1){sleep(1000);}return 0;}


0 0
原创粉丝点击