Chinaunix首页 | 论坛 | 博客
  • 博客访问: 98168
  • 博文数量: 38
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 384
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-06 16:52
文章分类

全部博文(38)

文章存档

2014年(38)

我的朋友

分类: 嵌入式

2014-05-06 13:05:58

异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上"中断"地概念,比较准确的称谓是"信号驱动(SIGIO)的异步I/O"。

异步通知的功能需要应用和驱动完成一些步骤。
1. 应用程序应做的工作
     (1)注册信号处理函数。  
            通过signal 或sigaction()实现。
     (2)使进程成为该文件的的属主进程。  
            通过fcntl 的F_SETOWN命令来实现。如fcntl(fd, F_SETOWN, getpid());
     (3)启用异步通知功能。  
            通过fcntl 的F_SETFL命令设置FASYNC标记。 
    应用程序代码如下

点击(此处)折叠或打开

  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. #include <unistd.h>

  8. int fd;

  9. void my_signal_fun(int signum)
  10. {
  11.     unsigned char key_val;
  12.     read(fd, &key_val, 1);
  13.     printf("key_val: 0x%x\n", key_val);
  14. }

  15. int main(int argc, char **argv)
  16. {
  17.     unsigned char key_val;
  18.     int ret;
  19.     int Oflags;

  20.     signal(SIGIO, my_signal_fun);
  21.     
  22.     fd = open("/dev/button_signal", O_RDWR);
  23.     if (fd < 0)
  24.     {
  25.         printf("can't open!\n");
  26.         return 0;
  27.     }

  28.     fcntl(fd, F_SETOWN, getpid());//告诉内核发给谁
  29.     
  30.     Oflags = fcntl(fd, F_GETFL); // 读出Oflags 
  31.     
  32.     fcntl(fd, F_SETFL, Oflags | FASYNC);//改变fasync标记,最终会调用到驱动的fasync里的fasync_helper:初始化/释放fasync_struct

  33.     while (1)
  34.     {
  35.         sleep(1000);
  36.     }
  37.     
  38.     return 0;
  39. }

2. 驱动应做的工作 
    在内核里异步通知是通过,异步通知队列struct fasync_struct来实现的。在这里,我们只需要用到内核提供的两个有关异步通知队列的函数就可以了。fasync_helper 和 kill_fasync。 
    fasync_helper 用于把文件指针加到(或移除,当参数on = 0)异步通知队列
    kill_fasync用于发送信号给应用程序。

    具体的字符设备驱动通过下面这几个步骤来实现:
    (1) 实现struct file_operations的.fasync函数。 
            这个函数,会在应用程序里,设置/删除FASYNC文件标记时会调用。该函数指针的原型为: 
            int (*fasync)(int fd, struct file *filp, int mode) ; 在函数实现时,我们只需要调用: 
            int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) ; 
    (2)在数据就绪时,调用kill_fasync通知应用程序 
   
    驱动程序代码如下

点击(此处)折叠或打开

  1. //moudle.h 包含了大量加载模块需要的函数和符号的定义
  2. #include <linux/module.h>
  3. //kernel.h以便使用printk()等函数
  4. #include <linux/kernel.h>
  5. //fs.h包含常用的数据结构,如struct file等
  6. #include <linux/fs.h>
  7. //uaccess.h 包含copy_to_user(),copy_from_user()等函数
  8. #include <linux/uaccess.h>
  9. //io.h 包含inl(),outl(),readl(),writel()等IO口操作函数
  10. #include <linux/io.h>
  11. #include <linux/miscdevice.h>
  12. #include <linux/pci.h>
  13. //init.h来指定你的初始化和清理函数,例如:module_init(init_function)、module_exit(cleanup_function)
  14. #include <linux/init.h>
  15. #include <linux/delay.h>
  16. #include <linux/device.h>
  17. #include <linux/cdev.h>
  18. #include <linux/gpio.h>
  19. #include <linux/irq.h>
  20. #include <linux/sched.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/poll.h>
  23. //irq.h中断与并发请求事件
  24. #include <asm/irq.h>
  25. //下面这些头文件是IO口在内核的虚拟映射地址,涉及IO口的操作所必须包含
  26. //#include <mach/gpio.h>
  27. #include <mach/regs-gpio.h>
  28. #include <plat/gpio-cfg.h>
  29. #include <mach/hardware.h>
  30. #include <mach/map.h>


  31. static struct class *button_signal_class;
  32. static int major;

  33. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
  34. /* 中断事件标志, 中断服务程序将它置1,button_signal_read将它清0 */
  35. static volatile int ev_press = 0;

  36. static struct fasync_struct *button_async;

  37. struct pin_desc {
  38.     unsigned int pin;
  39.     unsigned int button_val;
  40. };

  41. static unsigned char button_val;

  42. static struct pin_desc pins_desc[6] = {
  43.     {S3C64XX_GPN(0), 0x01},
  44.     {S3C64XX_GPN(1), 0x02},
  45.     {S3C64XX_GPN(2), 0x03},
  46.     {S3C64XX_GPN(3), 0x04},
  47.     {S3C64XX_GPN(4), 0x05},
  48.     {S3C64XX_GPN(5), 0x06},
  49. };

  50. /*中断服务函数*/
  51. /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 ...*/
  52. /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 ...*/
  53. static irqreturn_t button_signal_irq(int irq, void *dev_id)
  54. {
  55.     struct pin_desc *pindesc = (struct pin_desc *)dev_id;
  56.     unsigned char pinval;
  57.     
  58.     pinval = gpio_get_value(pindesc->pin);
  59.     
  60.     if(pinval == 1)
  61.         button_val = 0x80 | pindesc->button_val;
  62.     else
  63.         button_val = pindesc->button_val;
  64.     
  65.     ev_press = 1; /* 表示中断发生了 */
  66.     wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
  67.     
  68.     kill_fasync (&button_async, SIGIO, POLL_IN);//通过这个函数去发送信号给应用程序
  69.     
  70.     return IRQ_HANDLED;
  71. }

  72. static int button_signal_open(struct inode *inode, struct file *file)
  73. {    
  74.     int ret;
  75.     
  76.     /*request_irq注册中断
  77.      *第一个参数是中断号,也是中断处理函数button_signal的第一个参数
  78.      *第二个参数是中断处理函数
  79.      *第三个参数是中断触发方式
  80.      *第四个参数是设备名称
  81.      *第五个参数是设备ID,也是中断处理函数button_signal的第二个参数
  82.      */
  83.     ret = request_irq(IRQ_EINT(0), button_signal_irq, IRQ_TYPE_EDGE_BOTH, "k1", &pins_desc[0]);
  84.     if (ret){
  85.         printk("request IRQ_EINT(0) error!\n");
  86.         free_irq(IRQ_EINT(0), &pins_desc[0]);
  87.     }    
  88.     ret = request_irq(IRQ_EINT(1), button_signal_irq, IRQ_TYPE_EDGE_BOTH, "k2", &pins_desc[1]);
  89.     if (ret){
  90.         printk("request IRQ_EINT(1) error!\n");
  91.         free_irq(IRQ_EINT(1), &pins_desc[1]);
  92.     }
  93.         
  94.     ret = request_irq(IRQ_EINT(2), button_signal_irq, IRQ_TYPE_EDGE_BOTH, "k3", &pins_desc[2]);
  95.     if (ret){
  96.         printk("request IRQ_EINT(2) error!\n");
  97.         free_irq(IRQ_EINT(2), &pins_desc[2]);
  98.     }
  99.         
  100.     ret = request_irq(IRQ_EINT(3), button_signal_irq, IRQ_TYPE_EDGE_BOTH, "k4", &pins_desc[3]);
  101.     if (ret){
  102.         printk("request IRQ_EINT(3) error!\n");
  103.         free_irq(IRQ_EINT(3), &pins_desc[3]);
  104.     }
  105.         
  106.     ret = request_irq(IRQ_EINT(4), button_signal_irq, IRQ_TYPE_EDGE_BOTH, "k5", &pins_desc[4]);
  107.     if (ret){
  108.         printk("request IRQ_EINT(4) error!\n");
  109.         free_irq(IRQ_EINT(4), &pins_desc[4]);
  110.     }
  111.         
  112.     ret = request_irq(IRQ_EINT(5), button_signal_irq, IRQ_TYPE_EDGE_BOTH, "k6", &pins_desc[5]);
  113.     if (ret){
  114.         printk("request IRQ_EINT(5) error!\n");
  115.         free_irq(IRQ_EINT(5), &pins_desc[5]);
  116.     }
  117.     return 0;
  118. }

  119. static ssize_t button_signal_read(struct file *file, char __user *buf, size_t size, loff_t * ppos)
  120. {
  121.     if (size != 1)
  122.         return -EINVAL;
  123.         
  124.     /* 如果没有按键动作, 休眠 */
  125.     /*ev_press=0时休眠,ev_press=1时继续向下执行程序*/
  126.     wait_event_interruptible(button_waitq, ev_press);
  127.         
  128.     /* 如果有按键动作, 返回键值 */
  129.     if( copy_to_user(buf, &button_val, 1) ){
  130.         printk("error in function ‘copy_to_user’ !\n");
  131.             return -EFAULT;
  132.     }
  133.     
  134.     ev_press = 0;
  135.     return 0;
  136. }

  137. static ssize_t button_signal_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
  138. {
  139.     return 0;
  140. }

  141. static int button_signal_release(struct inode *inode, struct file *file)
  142. {    
  143.     free_irq(IRQ_EINT(0), &pins_desc[0]);    
  144.     free_irq(IRQ_EINT(1), &pins_desc[1]);
  145.     free_irq(IRQ_EINT(2), &pins_desc[2]);
  146.     free_irq(IRQ_EINT(3), &pins_desc[3]);
  147.     free_irq(IRQ_EINT(4), &pins_desc[4]);
  148.     free_irq(IRQ_EINT(5), &pins_desc[5]);

  149.     return 0;
  150. }

  151. static unsigned button_signal_poll(struct file *file, poll_table *wait)
  152. {
  153.     unsigned int mask = 0;
  154.     poll_wait(file, &button_waitq, wait); // 不会立即休眠

  155.     if (ev_press)
  156.         mask |= POLLIN | POLLRDNORM;

  157.     return mask;
  158. }

  159. static int button_signal_fasync (int fd, struct file *filp, int on)
  160. {
  161.     printk("driver: button_signal_fasync\n");
  162.     return fasync_helper (fd, filp, on, &button_async);
  163. }

  164. static struct file_operations button_signal_fops = {
  165.     .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  166.     .open = button_signal_open,
  167.     .read = button_signal_read,
  168.     .write = button_signal_write,
  169.     .release = button_signal_release,
  170.     .poll = button_signal_poll,
  171.     .fasync     = button_signal_fasync,    
  172. };

  173. static int button_signal_init(void)
  174. {
  175.     major = register_chrdev(0, "button_signal_dev", &button_signal_fops);//注册,告诉内核
  176.     button_signal_class = class_create(THIS_MODULE, "button_signal_cls");
  177.     device_create(button_signal_class, NULL, MKDEV(major, 0), NULL, "button_signal");/* /dev/button_signal */
  178.     
  179.     return 0;
  180. }

  181. static void button_signal_exit(void)
  182. {
  183.     unregister_chrdev(major, "button_signal_cls");
  184.     device_destroy(button_signal_class, MKDEV(major, 0));
  185.     class_destroy(button_signal_class);
  186. }

  187. module_init(button_signal_init);
  188. module_exit(button_signal_exit);

  189. MODULE_LICENSE("GPL");


阅读(867) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~