zoukankan      html  css  js  c++  java
  • 驱动对应用的异步通知机制

                    驱动对应用的异步通知机制

    1.应用程序需要完成如下三个步骤:

    (1)signal(SIGIO, sig_handler);

    调用signal函数,让指定的信号SIGIO与处理函数sig_handler对应。

    (2)fcntl(fd, F_SET_OWNER, getpid());

    指定一个进程作为文件的“属主(filp->owner)”,这样内核才知道信号要发给哪个进程。

    (3)f_flags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, f_flags | FASYNC);

    在设备文件中添加FASYNC标志,驱动中就会调用将要实现的test_fasync函数。

    三个步骤执行后,一旦有信号产生,相应的进程就会收到。


    2.驱动需要完成下面四个步骤:

    (1)定义结构体fasync_struct。

    struct fasync_struct *async_queue;

    (2)实现test_fasync,把函数fasync_helper将fd,filp和定义的结构体传给内核。

    int test_fasync (int fd, struct file *filp, int mode)
    {
        struct _test_t *dev = filp->private_data;

        return fasync_helper(fd, filp, mode, &dev->async_queue);
    }

    (3)当设备可写时,调用函数kill_fasync发送信号SIGIO给内核。

    if (dev->async_queue){
        kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
    }

    3.驱动代码

    #include <linux/types.h>
    #include <linux/module.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/gpio.h>
    #include <linux/irq.h>
    #include <linux/interrupt.h>
    #include <linux/sched.h> 
    #include <linux/wait.h>
    #include <linux/uaccess.h>
    #include <mach/gpio.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    
    struct key_desc{
        unsigned int  pin;
        unsigned char value;
    };
    
    static dev_t devno;
    static struct cdev cdev;
    static struct class* buttons_class;
    static struct device* buttons_device;
    
    static wait_queue_head_t button_waitq;
    static struct timer_list buttons_timer;
    
    static volatile int pressed = 0;
    static unsigned int key_val;
    
    static struct fasync_struct *button_async;
    
    static struct key_desc *irq_pd;
    
    static volatile unsigned long *gph3con;
    static volatile unsigned long *gph3dat;
    
    
    static struct key_desc key_descs[8] = {
        [0] = {
            .pin = S5PV210_GPH2(3),
            .value = 0x00,
        },
        [1] = {
            .pin = S5PV210_GPH2(4),
            .value = 0x01,
        },
        [2] = {
            .pin = S5PV210_GPH2(5),
            .value = 0x02,
        },
        [3] = {
            .pin = S5PV210_GPH2(6),
            .value = 0x03,
        },
        [4] = {
            .pin = S5PV210_GPH2(7),
            .value = 0x04,
        },
    };
    
    static void buttons_timer_function(unsigned long data)
    {
        struct key_desc * pindesc = irq_pd;
        unsigned int pinval;
        if (!pindesc)
            return;
        pinval = gpio_get_value(pindesc->pin);
    
        if (pinval)
        {
            /* 松开 */
            key_val = 0x80 | pindesc->value;
        }
        else
        {
            /* 按下 */
            key_val = pindesc->value;
        }
        pressed = 1;
        wake_up_interruptible(&button_waitq);
        
        kill_fasync (&button_async, SIGIO, POLL_IN);
    }
    
    static irqreturn_t buttons_irq(int irq, void *dev_id){
        printk("buttons_irq happen
    ");
        /* 10ms后启动定时器 */
        irq_pd = (struct key_desc *)dev_id;
        mod_timer(&buttons_timer, jiffies+HZ/100);
        return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    static int buttons_open(struct inode *inode, struct file *file){
        int ret;
    
        ret = request_irq(IRQ_EINT(19),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key1", &key_descs[0]);
        if(ret)
            return ret;
        ret = request_irq(IRQ_EINT(20),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key2", &key_descs[1]);
        if(ret)
            return ret;
         ret = request_irq(IRQ_EINT(21),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key3", &key_descs[2]);
        if(ret)
            return ret;
         ret = request_irq(IRQ_EINT(22),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key4", &key_descs[3]);
        if(ret)
            return ret;
        ret = request_irq(IRQ_EINT(23),   buttons_irq, IRQ_TYPE_EDGE_BOTH, "key5", &key_descs[4]);
        if(ret)
            return ret;
        return 0;
    }
    
    static ssize_t buttons_read(struct file * file, char __user *data, size_t count, loff_t *loff){
        
        if (count != 1)
            return -EINVAL;
    
        if (file->f_flags & O_NONBLOCK)
        {
            if (!pressed)
                return -EAGAIN;
        }
    
        wait_event_interruptible(button_waitq, pressed);
        pressed = 0;
    
        if(copy_to_user(data, &key_val, 1)){
            printk(KERN_ERR "The driver can not copy the data to user area!
    ");
            return -ENOMEM;
        }
        
        return 0;
    }
    
    static int buttons_close(struct inode *inode, struct file *file){
        free_irq(IRQ_EINT(19),  &key_descs[0]);
        free_irq(IRQ_EINT(20),  &key_descs[1]);    
        free_irq(IRQ_EINT(21),  &key_descs[2]);
        free_irq(IRQ_EINT(22),  &key_descs[3]);
        free_irq(IRQ_EINT(23),  &key_descs[4]);
        return 0;
    }
    
    static int buttons_fasync (int fd, struct file *filp, int on)
    {
        printk("driver: buttons_fasync
    ");
        return fasync_helper (fd, filp, on, &button_async);
    }
    
    struct file_operations buttons_ops = {
        .open    = buttons_open,
        .read    = buttons_read,
        .release = buttons_close,
        .fasync     = buttons_fasync,
    };
    
    int buttons_init(void){
        int ret;
    
        init_timer(&buttons_timer);
        buttons_timer.function = buttons_timer_function;
        //buttons_timer.expires  = 0;
        add_timer(&buttons_timer); 
        
        cdev_init(&cdev, &buttons_ops);
        cdev.owner = THIS_MODULE;
    
        ret = alloc_chrdev_region(&devno, 0, 1, "buttons");
        if(ret){
            printk(KERN_ERR "alloc char device region faild!
    ");
            return ret;
        }
    
        ret = cdev_add(&cdev, devno, 1);
        if(ret){
            printk(KERN_ERR "add char device faild!
    ");
            goto add_error;
        }
    
        buttons_class = class_create(THIS_MODULE, "buttonsdrv");
        if(IS_ERR(buttons_class)){
            printk(KERN_ERR "create class error!
    ");
            goto class_error;
        }
    
        buttons_device = device_create(buttons_class, NULL, devno, NULL, "buttons");
        if(IS_ERR(buttons_device)){
            printk(KERN_ERR "create buttons device error!
    ");
            goto device_error;
        }
    
        init_waitqueue_head(&button_waitq);
    
        gph3con = (volatile unsigned long *)ioremap(0xE0200C60, 16);
        gph3dat = gph3con + 1;
    
        *gph3con &= (~0x000000ff);
        *gph3con |=0x11;
        *gph3dat &= ~0x03;    
    
        
        printk("buttons init
    ");
        return 0;
    
    device_error:
        class_destroy(buttons_class);
    class_error:
        cdev_del(&cdev);
    add_error:
        unregister_chrdev_region(devno,1);
    
        return -ENODEV;
    }
    
    void buttons_exit(void){
        printk("buttons exit
    ");
        device_destroy(buttons_class, devno);
        class_destroy(buttons_class);
        cdev_del(&cdev);
        unregister_chrdev_region(devno, 1);
    }
    
    module_init(buttons_init);
    module_exit(buttons_exit);
    MODULE_LICENSE("GPL");

    4.用户空间代码:

    #include <fcntl.h>
    #include <stdio.h>
    #include <poll.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    
    int fd; 
    
    void sig_handler(int signum)
    {
        unsigned char key_val;
        read(fd, &key_val, 1); 
        printf("key_val: 0x%x
    ", key_val);
    }
    
    int main(int argc, char **argv)
    {
        unsigned char key_val;
        int ret;
        int Oflags;
    
        signal(SIGIO, sig_handler);
    
        fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);
        if (fd < 0){ 
            printf("can't open!
    ");
            return -1; 
        }   
    
        fcntl(fd, F_SETOWN, getpid());
        Oflags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, Oflags | FASYNC);
    
        while(1);
    
        return 0;
    }

    5.测试结果:

    [210_Liujia]#insmod buttons.ko
    [210_Liujia]#./buttons_test
    key_val: 0x1
    key_val: 0x81
    key_val: 0x0
    key_val: 0x80
    key_val: 0x2
    key_val: 0x82
    key_val: 0x3
    key_val: 0x83
    key_val: 0x4
    key_val: 0x84
    key_val: 0x1
    key_val: 0x81
    key_val: 0x2
    key_val: 0x82
    key_val: 0x4
    key_val: 0x84
    key_val: 0x3
    key_val: 0x83

    转载: 

  • 相关阅读:
    IOS之Block的应用-textFeild的回调应用
    KVC与KVO的不同
    git
    perl读取excel
    Linux用户管理
    Linux软件包的管理
    linux系统学习(二)
    linux系统学习(一)
    js模版渲染
    Discuz核心函数的解析
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/9074631.html
Copyright © 2011-2022 走看看