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

  • 相关阅读:
    Windows Mobile开发资源列表
    Windows Mobile获取SIM卡上的所有电话号码
    Windows Mobile手机软件安装卸载方法
    Windows CE跨进程内存注入之原理
    推荐几篇关于Windows Mobile程序安装包制作的文章
    C#智能设备中程序的调用
    Windows Mobile 获得 MAC,IP,IMEI,IMSI
    为什么要使用Base64?
    如何选择正确的SQL Server Compact安装包
    [Drupal] Using the Administrator theme whenever you want.
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/7017125.html
Copyright © 2011-2022 走看看