前面的按键驱动方式都是应用程序通过主动查询的方式获得按键值的:

1、查询方式

2、中断方式

3、poll机制

下面介绍第四种按键驱动的方式

4、异步通知:它可以做到应用程序不用随时去查询按键的状态,而等待有按键被按下后,驱动程序主动发消息给应用程序,应用程序再去处理。

比如说:kill -9 pid即是一种发信号的过程:其中9就是信号值,pid就是被发送的进程的进程号

a、一个简单的异步通知的例子

b、编写测试程序实现异步通知

c、更改按键驱动实现异步通知

1、一个简单的异步通知的例子

直接看到程序源码,可以看到这个程序在主程序里面什么事情也没有做,一直处于睡眠状态。

  1. #include <signal.h>
  2.  
  3. void my_signal_test(int signum)
  4. {
  5. static int cnt = ;
  6. printf("signal = %d,%d times\n",signum,++cnt);
  7. }
  8.  
  9. int main(int argc,char **argv)
  10. {
  11. signal(SIGUSR1, my_signal_test);//建立一个信号函数,接收的信号是SIGUSR1表示用户可用的信号值
  12.  
  13. while()
  14. {
  15. sleep();
  16. }
  17. return ;
  18. }

首先这个程序调用了signal这个C库中的函数,在linux下查询它的用法输入man 2 signal

  1. #include <signal.h> //需要包含的头文件
  2.  
  3. typedef void (*sighandler_t)(int);//信号函数原型,它的参数是信号值
  4.  
  5. sighandler_t signal(int signum, sighandler_t handler);//函数,其中signum代表发送的信号值,handler表示信号函数

编译这个程序,然后在命令行输入kill -USR1 2333,my_signal函数被运行。

 2、更改测试程序实现异步通知

直接看代码,从代码可以看出,实现异步通知在应用层需要如下几步:

1、利用signal(SIGIO, fifth_testsignal)函数注册一个信号,信号处理的函数为fifth_testsignal。SISGIO说明是IO信号量,因为按键驱动属于IO型的。

2、利用fcntl(fd, F_SETOWN, getpid())函数将本应用程序的进程号告诉给内核,最终使得驱动程序可以成功发送信号给应用程序。

3、利用fcntl(fd, F_SETFL, oflags | FASYNC)函数改变fasync标记,最终会调用到驱动的faync > fasync_helper。

4、signal、与fcntl的系统调用过程比较复杂,后面再去分析。这里只能记住是怎么使用它们来是实现异步通知的功能。

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <poll.h>
  6. #include <signal.h>
  7.  
  8. static int fd;
  9.  
  10. static void fifth_testsignal(int signum)
  11. {
  12. unsigned char key_val;
  13.  
  14. printf("signal = %d\n",signum);
  15.  
  16. read(fd, &key_val, );//读取按键数据,只有收到按键数据驱动层才会发送消息给应用层。
  17. printf("signumkey_val: 0x%x\n\n",key_val);
  18. }
  19.  
  20. /*
  21. *usage ./buttonstest
  22. */
  23. int main(int argc, char **argv)
  24. {
  25. char* filename="dev/buttons";
  26. int oflags;
  27.  
  28. fd = open(filename, O_RDWR);//打开dev/firstdrv设备文件
  29. if (fd < )//小于0说明没有成功
  30. {
  31. printf("error, can't open %s\n", filename);
  32. return ;
  33. }
  34.  
  35. if(argc !=)
  36. {
  37. printf("Usage : %s ",argv[]);
  38. return ;
  39. }
  40. signal(SIGIO, fifth_testsignal);//注册一个信号,函数为fifth_testsignal
  41.  
  42. fcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁
  43.  
  44. oflags = fcntl(fd, F_GETFL); //取得当前的状态
  45.  
  46. fcntl(fd, F_SETFL, oflags | FASYNC); // 改变fasync标记,最终会调用到驱动的faync > fasync_helper:初始化/释放fasync_struct
  47.  
  48. while()
  49. {
  50. sleep();
  51. }
  52.  
  53. return ;
  54. }

 3、更改按键驱动实现异步通知功能

与原先的按键驱动程序相比:

1、定义fasync_struct结构

  1. struct fasync_struct *fifth_fasync;//定义fasync_struct结构

2、在fifth_drv_ops 结构体中增加fifth_drv_fasync异步通知处理函数

  1. static struct file_operations fifth_drv_ops =
  2. {
  3. .owner = THIS_MODULE,
  4. .open = fifth_drv_open,
  5. .read = fifth_drv_read,
  6. .release = fifth_drv_close,
  7. .poll = fifth_drv_poll,
  8. .fasync = fifth_drv_fasync,//增加异步通知处理的函数
  9.  
  10. };

3、编写fifth_drv_fasync异步通知处理函数,这个函数会在C库函数fcntl设置FASYNC时被调用

  1. static int fifth_drv_fasync(int fd, struct file * file, int on)
  2. {
  3. int err;
  4. printk("fansync_helper\n");
  5. err = fasync_helper(fd, file, on, &fifth_fasync);//利用fasync_helper初始化fifth_fasync
  6. if (err < )
  7. return err;
  8. return ;
  9. }

下面是完整的代码

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <asm/io.h> //含有iomap函数iounmap函数
  6. #include <asm/uaccess.h>//含有copy_from_user函数
  7. #include <linux/device.h>//含有类相关的处理函数
  8. #include <asm/arch/regs-gpio.h>//含有S3C2410_GPF0等相关的
  9. #include <linux/irq.h> //含有IRQ_HANDLED\IRQ_TYPE_EDGE_RISING
  10. #include <asm-arm/irq.h> //含有IRQT_BOTHEDGE触发类型
  11. #include <linux/interrupt.h> //含有request_irq、free_irq函数
  12. #include <linux/poll.h>
  13. //#include <asm-arm\arch-s3c2410\irqs.h>
  14.  
  15. static struct class *fifth_drv_class;//类
  16. static struct class_device *fifth_drv_class_dev;//类下面的设备
  17. static int fifthmajor;
  18.  
  19. static unsigned long *gpfcon = NULL;
  20. static unsigned long *gpfdat = NULL;
  21. static unsigned long *gpgcon = NULL;
  22. static unsigned long *gpgdat = NULL;
  23.  
  24. struct fasync_struct *fifth_fasync;//定义fasync_struct结构
  25.  
  26. static unsigned int key_val;
  27.  
  28. struct pin_desc
  29. {
  30. unsigned int pin;
  31. unsigned int key_val;
  32. };
  33.  
  34. static struct pin_desc pins_desc[] =
  35. {
  36. {S3C2410_GPF0,0x01},
  37. {S3C2410_GPF2,0x02},
  38. {S3C2410_GPG3,0x03},
  39. {S3C2410_GPG11,0x04}
  40. };
  41.  
  42. unsigned int ev_press;
  43. DECLARE_WAIT_QUEUE_HEAD(button_waitq);//注册一个等待队列button_waitq
  44.  
  45. /*
  46. *0x01、0x02、0x03、0x04表示按键被按下
  47. */
  48.  
  49. /*
  50. *0x81、0x82、0x83、0x84表示按键被松开
  51. */
  52.  
  53. /*
  54. *利用dev_id的值为pins_desc来判断是哪一个按键被按下或松开
  55. */
  56. static irqreturn_t buttons_irq(int irq, void *dev_id)
  57. {
  58. unsigned int pin_val;
  59. struct pin_desc * pin_desc = (struct pin_desc *)dev_id;//取得哪个按键被按下的状态
  60.  
  61. pin_val = s3c2410_gpio_getpin(pin_desc->pin);
  62.  
  63. if(pin_val) //按键松开
  64. key_val = 0x80 | pin_desc->key_val;
  65. else
  66. key_val = pin_desc->key_val;
  67.  
  68. wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
  69. ev_press = ;
  70.  
  71. kill_fasync(&fifth_fasync, SIGIO, POLL_IN);//发生信号给进程
  72.  
  73. return IRQ_HANDLED;
  74. }
  75.  
  76. static int fifth_drv_open (struct inode * inode, struct file * file)
  77. {
  78. int ret;
  79. ret = request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "s1", (void * )&pins_desc[]);
  80. if(ret)
  81. {
  82. printk("open failed 1\n");
  83. return -;
  84. }
  85. ret = request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "s2", (void * )& pins_desc[]);
  86. if(ret)
  87. {
  88. printk("open failed 2\n");
  89. return -;
  90. }
  91. ret = request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "s3", (void * )&pins_desc[]);
  92. if(ret)
  93. {
  94. printk("open failed 3\n");
  95. return -;
  96. }
  97. ret = request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "s4", (void * )&pins_desc[]);
  98. if(ret)
  99. {
  100. printk("open failed 4\n");
  101. return -;
  102. }
  103.  
  104. return ;
  105. }
  106.  
  107. static int fifth_drv_close(struct inode * inode, struct file * file)
  108. {
  109. free_irq(IRQ_EINT0 ,(void * )&pins_desc[]);
  110.  
  111. free_irq(IRQ_EINT2 ,(void * )& pins_desc[]);
  112.  
  113. free_irq(IRQ_EINT11 ,(void * )&pins_desc[]);
  114.  
  115. free_irq(IRQ_EINT19 ,(void * )&pins_desc[]);
  116.  
  117. return ;
  118. }
  119.  
  120. static ssize_t fifth_drv_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
  121. {
  122. int ret;
  123.  
  124. if(count != )
  125. {
  126. printk("read error\n");
  127. return -;
  128. }
  129.  
  130. // wait_event_interruptible(button_waitq, ev_press);//将当前进程放入等待队列button_waitq中
  131.  
  132. ret = copy_to_user(userbuf, &key_val, );
  133. ev_press = ;//按键已经处理可以继续睡眠
  134.  
  135. if(ret)
  136. {
  137. printk("copy error\n");
  138. return -;
  139. }
  140.  
  141. return ;
  142. }
  143.  
  144. static unsigned int fifth_drv_poll(struct file *file, poll_table *wait)
  145. {
  146. unsigned int ret = ;
  147. poll_wait(file, &button_waitq, wait);//将当前进程放到button_waitq列表
  148.  
  149. if(ev_press)
  150. ret |=POLLIN;//说明有数据被取到了
  151.  
  152. return ret;
  153. }
  154.  
  155. static int fifth_drv_fasync(int fd, struct file * file, int on)
  156. {
  157. int err;
  158. printk("fansync_helper\n");
  159. err = fasync_helper(fd, file, on, &fifth_fasync);//利用fasync_helper初始化fifth_fasync
  160. if (err < )
  161. return err;
  162. return ;
  163. }
  164.  
  165. static struct file_operations fifth_drv_ops =
  166. {
  167. .owner = THIS_MODULE,
  168. .open = fifth_drv_open,
  169. .read = fifth_drv_read,
  170. .release = fifth_drv_close,
  171. .poll = fifth_drv_poll,
  172. .fasync = fifth_drv_fasync,//增加异步通知处理的函数
  173.  
  174. };
  175.  
  176. static int fifth_drv_init(void)
  177. {
  178. fifthmajor = register_chrdev(, "buttons", &fifth_drv_ops);//注册驱动程序
  179.  
  180. if(fifthmajor < )
  181. printk("failes 1 buttons_drv register\n");
  182.  
  183. fifth_drv_class = class_create(THIS_MODULE, "buttons");//创建类
  184. if(fifth_drv_class < )
  185. printk("failes 2 buttons_drv register\n");
  186. fifth_drv_class_dev = class_device_create(fifth_drv_class, NULL, MKDEV(fifthmajor,), NULL,"buttons");//创建设备节点
  187. if(fifth_drv_class_dev < )
  188. printk("failes 3 buttons_drv register\n");
  189.  
  190. gpfcon = ioremap(0x56000050, );//重映射
  191. gpfdat = gpfcon + ;
  192. gpgcon = ioremap(0x56000060, );//重映射
  193. gpgdat = gpgcon + ;
  194.  
  195. printk("register buttons_drv\n");
  196. return ;
  197. }
  198.  
  199. static void fifth_drv_exit(void)
  200. {
  201. unregister_chrdev(fifthmajor,"buttons");
  202.  
  203. class_device_unregister(fifth_drv_class_dev);
  204. class_destroy(fifth_drv_class);
  205.  
  206. iounmap(gpfcon);
  207. iounmap(gpgcon);
  208.  
  209. printk("unregister buttons_drv\n");
  210. }
  211.  
  212. module_init(fifth_drv_init);
  213. module_exit(fifth_drv_exit);
  214.  
  215. MODULE_LICENSE("GPL");

将测试程序与驱动程序编译后测试成功。以上就是异步通知的应用实现。

Linux驱动之异步通知的应用的更多相关文章

  1. linux驱动的异步通知(kill_fasync,fasync)---- 驱动程序向应用程序发送信号

    应用程序 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include < ...

  2. 蜕变成蝶~Linux设备驱动之异步通知和异步I/O

    在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似“中断”的异步通知所取代.异步通知类 ...

  3. linux下使用异步通知

    阻塞式I/O是一直等待直到设备可以访问,非阻塞式I/O是定期轮询设备是否可以访问. 异步通知则是当设备可以访问时才主动通知应用程序,有点像设备的硬中断. 并不是所有的设备都支持异步通知,应用程序通常假 ...

  4. Linux通信之异步通知模式

    [参考]韦东山 教学笔记 为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID. 不过此项工 ...

  5. Linux驱动之异步OR同步,阻塞OR非阻塞概念介绍

    链接:https://www.zhihu.com/question/19732473/answer/20851256 1.同步与异步同步和异步关注的是消息通信机制 (synchronous commu ...

  6. Linux学习 :按键信号 之 异步通知

    一.异步通知概念: 异步通知是指:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态,类似于中断的概念,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是异步的,一个进 ...

  7. linux异步通知

    简述 linux下异步方式有两种:异步通知和异步IO(AIO),aio请参考:linux异步IO--aio 异步通知的含义是:一旦设备就绪,则主动通知应用程序,这样应用程序就不需要查询设备状态,准确称 ...

  8. Linux内核开发之异步通知与异步I/O(一)

    “小王,听说过锦上添花吧..”我拍拍下王的头说. “还锦上添花你,为你上次提的几个东东,我是头上长包..”小王气愤地瞪着我. “啊,为啥这样呢,本来还特意拒绝了MM的月份,抽出时间打算给你说点高级的东 ...

  9. Smart20学习记录----异步通知

    异步通知: 阻塞与非阻塞访问.poll()函数提供了较好地解决设备访问的机制(应用程序主动访问) 异步通知:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件 ...

随机推荐

  1. kafka原理和实践(五)spring-kafka配置详解

    系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...

  2. Bootstrap Tooltip 显示换行

    <a class="pink" href="#" data-toggle="tooltip" data-placement=" ...

  3. string formating字符串格式化,function函数,group组,recursion递归,练习

    # -*- coding: UTF-8 -*- msg = 'i am {} my hobby is {}'.format('lhf',18) print(msg) msg1 = 'i am %s m ...

  4. 枚举、反射等 GetEnumName GetEnumDescription

    /// <summary> /// Retrieves the name of the constant in the specified enumeration that has the ...

  5. Python图形开发之PIL

    1.背景介绍 PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了.PIL功能非常强大,但API却非常简单易用. 2.安装 Windows平台:PIL官 ...

  6. springboot+mockito 异常解决方案

    系统启动的异常日志如下 javax.net.ssl.* java.lang.IllegalStateException: Failed to load ApplicationContext at or ...

  7. git之sourceTree操作流程

    1x.sourceTree的使用流程  12.Git管理工具对比(GitBash.EGit.SourceTree)  11.SourceTree使用SSH克隆码云项目 ====== 1x.source ...

  8. 知识点:spring 完全手册

    什么是spring spring是一个开源框架,为简化企业级开发而生,使用spring可以使简单的java bean 实现以前只有EJG才能实现的功能. Spring是一个轻量级的控制反转(IoC)和 ...

  9. 用kettle从mysql中使用存储过程读取数据写入到sqlserver数据库

    1.mysql存储过程,可以实现动态表读取,满足较为复杂的业务逻辑 DROP PROCEDURE if exists p_get_car_trace; delimiter // CREATE PROC ...

  10. 关于连接oracle工具plsql的一些使用

    上面图片是打开客户端PL\SQL devepoper的连接内容 进入页面后就可以进行相关的sql语句编写了 将几个结果放入一个表中 select 30+30 as 结果 from dual union ...