zoukankan      html  css  js  c++  java
  • 按键驱动程序(异步通知)

    此驱动程序之前的按键驱动程序(中断方式)上加以优化。用到异步通知。对于内核来讲,既然用户想得到的是按键后的状态,那么自然不必时时都要read状态。当它检测到中断发生变主动通知用户,用户再来读。这样,用户空间、内核就可以着手干点其它的事情,而不必忙等按键按下或释放。那么就先从应用程序上面看。

    怎么设置相关联到“异步通知”呢?
    flag = fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, flag|FASYNC);
    这样的两句就可以将文件描述符fd与异步通知关联,到时候将会接到相关通知。
    怎么知道通知道本程序呢?
    fcntl(fd, F_SETOWN, getpid());
    将其与进程号关联,这样内核就知道要将通知发往本进程。
    得到通知后该怎么做呢?
    sighandler_t signal(int signum, sighandler_t handler);
    后面的handler是接到信号后的处理函数,而对于一般的IO操作,signum通常为SIGIO,这点在内核驱动中要保持一致。handler的定义为
    typedef void (*sighandler_t)(int); 在这个函数体内就可以去read数据了。


    驱动程序上面又是如何实现的呢?
    需要在file_operations结构体里设置.fasync = xxx_fasync,并定义xxx_fasync函数.
    static int xxx_fasync(int fd, struct file *filp, int on)
    当fcntl(fd, F_SETFL, flag|FASYNC);设置异步通知标志后,就会调用驱动里的xxx_fasync函数,我们需要在驱动程序里先定义一个fasync_struct结构体指针,然后通过xxx_fasync函数再调用int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)去初始化这个结构体。以便在中断服务程序里发送信号。当产生按键中断时,再不是像poll机制那样唤醒等待队列,而是用kill_fasync(struct fasync_struct **fp, int sig, int band)发送信号。应用程序收到信号后会调用自定义的handler做相关处理(本程序是read内核的按键状态)。

    详细的驱动程序为:

    [plain] view plain copy
     print?
    1. #include <linux/module.h>  
    2. #include <linux/kernel.h>  
    3. #include <linux/fs.h>  
    4. #include <linux/init.h>  
    5. #include <linux/delay.h>  
    6. #include <linux/irq.h>  
    7. #include <asm/uaccess.h>  
    8. #include <linux/cdev.h>  
    9. #include <linux/interrupt.h>  
    10. #include <linux/device.h>  
    11. #include <linux/sched.h>  
    12. #include <linux/gpio.h>  
    13. #include <linux/poll.h>  
    14.   
    15. #define FIFTHDEV MKDEV(250, 0)  
    16. struct cdev fifthdrv_cdev;  
    17.   
    18. static struct class *fifthdrv_class;  
    19.   
    20. struct button {  
    21.     int irq;  
    22.     char *name;  
    23.     int pin;  
    24.     int val;  
    25. };  
    26. //static volatile int pressed = 0;  
    27. static unsigned char key_val;  
    28.   
    29. struct fasync_struct *button_async;  
    30.   
    31. //DECLARE_WAIT_QUEUE_HEAD(button_wqh);  
    32.   
    33. /* 六个按键的相关定义整合到结构体 */  
    34. static struct button buttons[6] = {  
    35.         {IRQ_EINT8, "K1", S3C2410_GPG(0), 0x1},  
    36.         {IRQ_EINT11, "K2", S3C2410_GPG(3), 0x2},  
    37.         {IRQ_EINT13, "K3", S3C2410_GPG(5), 0x3},  
    38.         {IRQ_EINT14, "K4", S3C2410_GPG(6), 0x4},  
    39.         {IRQ_EINT15, "K5", S3C2410_GPG(7), 0x5},  
    40.         {IRQ_EINT19, "K6", S3C2410_GPG(11),0x6},  
    41. };  
    42.   
    43. /* 中断处理函数 */  
    44. static irqreturn_t fifthdrv_intr(int irq, void *data)  
    45. {  
    46.     struct button *buttonp;  
    47.     int val;  
    48.       
    49.     buttonp = (struct button*)data;  
    50.   
    51.     val = s3c2410_gpio_getpin(buttonp->pin);  
    52.   
    53.       
    54.     if (!val) {/* 按下按键*/  
    55.         key_val = buttonp->val;      
    56.     } else { /* 释放按键*/  
    57.         key_val = buttonp->val | 0x10; //将第4位置1,做标记  
    58.     }  
    59.   
    60.     //pressed = 1; //此处改变按下标志,以使队列不继续睡眠  
    61.     //wake_up_interruptible(&button_wqh);  
    62.     kill_fasync(&button_async, SIGIO, POLL_IN);  
    63.       
    64.     return IRQ_RETVAL(IRQ_HANDLED);  
    65. }  
    66.   
    67. static int fifthdrv_open(struct inode * inode, struct file * file)  
    68. {  
    69.     int i=6;  
    70.     while(i--){  
    71.         request_irq(buttons[i].irq, &fifthdrv_intr, IRQ_TYPE_EDGE_BOTH,  
    72.                     buttons[i].name, &buttons[i]);  
    73.     }  
    74.     return 0;  
    75.       
    76. }  
    77.   
    78. static ssize_t fifthdrv_read(struct file *file, char __user *user, size_t size,loff_t*o)  
    79. {  
    80.     int sz = sizeof(key_val) ;  
    81.       
    82.     if (sz != size) {  
    83.         return -EINVAL;  
    84.     }  
    85.       
    86.     /* 使用异步通知,此处不必休眠 */  
    87.     //wait_event_interruptible(button_wqh, pressed);  
    88.       
    89.     copy_to_user(user, &key_val, sz);  
    90.   
    91.     /* 重新清除按下标志 */  
    92.     //pressed = 0;  
    93.   
    94.     return sz;  
    95. }  
    96.   
    97. static int fifthdrv_close(struct inode *inode, struct file *file)  
    98. {  
    99.     int i=6;  
    100.       
    101.     while(i--) {  
    102.         free_irq(buttons[i].irq, &buttons[i]);  
    103.     }  
    104.     return 0;  
    105. }  
    106.   
    107. /*  
    108. static unsigned int fifthdrv_poll(struct file *file, poll_table *wait)  
    109. {  
    110.     unsigned int res=0;  
    111.       
    112.     poll_wait(file, &button_wqh, wait);  
    113.   
    114.     if (pressed) {  
    115.         res |= POLLIN | POLLRDNORM;  
    116.     }  
    117.     return res;  
    118. }  
    119. */  
    120. static int fifthdrv_fasync(int fd, struct file *filp, int on)  
    121. {  
    122.     return fasync_helper(fd, filp, on, &button_async);  
    123. }  
    124.   
    125.   
    126. static struct file_operations fifthdrv_ops = {  
    127.     .owner = THIS_MODULE,  
    128.     .open = fifthdrv_open,  
    129.     .read = fifthdrv_read,  
    130.     //.poll = fifthdrv_poll,  
    131.     .release = fifthdrv_close,  
    132.     .fasync = fifthdrv_fasync,  
    133. };  
    134. static int fifthdrv_init(void)  
    135. {  
    136.     int ret;  
    137.     int devt = FIFTHDEV;  
    138.       
    139.     ret = register_chrdev_region(devt, 1, "fifthdrv");  
    140.     if (ret) {  
    141.         printk(KERN_ERR "Unable to register minors for fifthdrv ");  
    142.         goto fail;  
    143.     }  
    144.     fifthdrv_class = class_create(THIS_MODULE, "fifthdrv_class");  
    145.     if (IS_ERR(fifthdrv_class)) {  
    146.         printk(KERN_ERR "can't register device class ");  
    147.         return PTR_ERR(fifthdrv_class);  
    148.     }  
    149.     device_create(fifthdrv_class, NULL, devt, NULL, "buttons");  
    150.     cdev_init(&fifthdrv_cdev, &fifthdrv_ops);  
    151.     ret = cdev_add(&fifthdrv_cdev, devt, 1);  
    152.     if (ret < 0)  
    153.         goto fail_cdev;  
    154.     return 0;  
    155.       
    156. fail_cdev:  
    157.     class_unregister(fifthdrv_class);  
    158.     device_destroy(fifthdrv_class, devt);  
    159.     cdev_del(&fifthdrv_cdev);  
    160. fail:  
    161.     unregister_chrdev_region(devt, 1);  
    162.       
    163.     return 0;  
    164. }  
    165.   
    166. static void fifthdrv_exit(void)  
    167. {  
    168.     class_unregister(fifthdrv_class);  
    169.     device_destroy(fifthdrv_class, FIFTHDEV);  
    170.     cdev_del(&fifthdrv_cdev);  
    171.     unregister_chrdev_region(FIFTHDEV, 1);  
    172. }  
    173.   
    174. module_init(fifthdrv_init);  
    175. module_exit(fifthdrv_exit);  
    176. MODULE_LICENSE("GPL");  


    应用程序为:

    1. #include <stdio.h>
    2. #include <signal.h>
    3. #include <unistd.h>
    4. #include <fcntl.h>
    5. #include <sys/types.h>
    6.  
    7. int fd;
    8. void signal_f(int signum)
    9. {
    10.     unsigned char val;
    11.     static unsigned int cnt = 1;
    12.     read(fd, &val, sizeof(val));
    13.     printf("cnt:%d, val:0x%x ", cnt++, val);
    14. }
    15. int main(int argc, char *argv[]) 
    16. {
    17.     int flag;
    18.     
    19.     fd = open("/dev/buttons", O_RDWR);
    20.     if (fd < 0)
    21.     {
    22.         printf("can't open! ");
    23.     }
    24.     signal(SIGIO, signal_f);
    25.     fcntl(fd, F_SETOWN, getpid());
    26.     flag = fcntl(fd, F_GETFL);
    27.     fcntl(fd, F_SETFL, flag|FASYNC);
    28.     while (1)
    29.     {
    30.         sleep(1000);
    31.     }
    32.     return 0;
    33. }

    运行状态:

    本文转自:http://blog.chinaunix.NET/uid-22609852-id-3153120.html

  • 相关阅读:
    NOIP201208同余方程
    NOIP模拟赛 最佳组合
    NOIP模拟赛 拓展
    CF1253E Antenna Coverage(DP)
    LOJ6033「雅礼集训 2017 Day2」棋盘游戏 (博弈论,二分图,匈牙利算法)
    CF582E Boolean Function(DP,状态压缩,FMT)
    CF750G New Year and Binary Tree Paths(DP)
    Codeforces Round 596 题解
    AGC008E Next or Nextnext(组合计数,神奇思路)
    ARC082E ConvexScore(神奇思路)
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/7017125.html
Copyright © 2011-2022 走看看