linux驱动程序之增加按键异步通知机制
来源:互联网 发布:少儿编程用什么软件 编辑:程序博客网 时间:2024/05/16 18:29
目的:按下按键时驱动程序通知应用程序
1、大体框架:
1、应用程序:注册信号处理函数
2、驱动程序发送信号
3、应用程序通知驱动 PID
4、驱动程序发送如何发送信号
2、需要的操作:
为了使设备获得异步通知机制,驱动程序中涉及如下操作:
- 支持F_SETOWN 命令,能在这个命令处理中设置filp->f_owner为对应进程ID,这个工作已经由内核完成了。
- 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行,驱动中应该实现fasync()函数
- 在设备获得资源时,调用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
- linux驱动程序之增加按键异步通知机制
- linux 驱动程序中异步通知机制
- 异步通知的按键驱动程序
- 按键驱动程序(异步通知)
- 嵌入式linux之按键驱动,异步通知
- Linux驱动开发之八-----按键驱动(异步通知机制)
- 字符设备驱动程序之按键——异步通信机制
- TQ2440 按键驱动程序 异步通知(发送信号)
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- linux字符驱动之异步通知按键驱动
- linux字符驱动之异步通知按键驱动
- linux字符驱动之异步通知按键驱动
- linux字符驱动之异步通知按键驱动
- linux字符驱动之异步通知按键驱动
- Linux设备驱动之六----异步通知的驱动程序
- 按键驱动深化-异步通知机制
- 基于异步通知机制的按键驱动
- Linux驱动开发七:按键中断+poll机制+异步通知机制
- CSS深入研究:display的恐怖故事解密(2) - table-cell
- hdu4508湫湫系列故事——减肥记I
- 大话设计模式C++实现-第19章-组合模式
- Delphi XE之路(5)让应用程序禁止竖屏(只显示横屏)
- 第17周 项目5-玩日期时间
- linux驱动程序之增加按键异步通知机制
- Eclipse安装颜色主题,个性化你的IDE
- 【C语言】[库函数]:printf 函数 和 scanf 函数 对float 和double 类型打印和读取
- leetcode 152: Compare Version Numbers
- 第十七周项目6-学生成绩统计(4 已初始化)
- 数字证书、公钥和私钥这三者之间的关系是什么
- 控件开发中的设计期包和运行期包
- WDM ioctl 缓冲区读写
- Android 项目下每个文件夹的作用