zoukankan      html  css  js  c++  java
  • 7. linux 驱动异步编程

    TOC

    1. 相关接口和结构体

    接口

    //初始化接口
    int fasync _ helper(int fd, struct file *filp, int mode, struct
    fasync _ struct **fa);
    
    
    //释放信号接口
    void kill _ fasync(struct fasync _ struct **fa, int sig, int band);

    结构体

    
    //文件操作结构体
    static const struct file_operations fops = 
    {
        .owner = THIS_MODULE,
        .open = hello_open,
        .release = hello_release,
        //.read = hello_read,
        //.write = hello_write,
        .fasync = hello_fasync,
        .release = hello_release,
       // .unlocked_ioctl = hello_ioctl,
    };
    
    

    需要编写接口 int hello_fasync(int fd, struct file *flip, int mode)int hello_release(struct inode *pnode, struct file *pfile) 并注册到上述结构体中。

    2. 驱动代码示例

    使用定时器定时发送SIGIO信号给应用层

    #include <linux/module.h>  
    #include <linux/kernel.h>  
    #include <linux/fs.h>  
    #include <linux/init.h>  
    #include <linux/delay.h>  
    #include <linux/irq.h>  
    #include <linux/cdev.h>  
    #include <linux/device.h>
    #include <linux/timer.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/kdev_t.h>
    #include <linux/cdev.h>
    #include <linux/string.h>
    #include <asm/uaccess.h>
    #include <linux/sched.h> 
    
    
    
    
    #define HELLO_CNT   1  
    
    
    //主设备号为0,表示动态分配设备号 
    dev_t dev = 0;
    static int major = 0;   
    static int minor = 0;
    
    static struct cdev *hello_cdev[HELLO_CNT];
    static struct class *hello_class = NULL;
    static struct class_device * hello_class_dev[HELLO_CNT];
    
    
    static struct timer_list tm;
    static struct fasync_struct *async = NULL;
    
    
    int hello_open(struct inode * pnode, struct file * pfile)
    {
        printk("open file..
    ");
        int num = MINOR(pnode->i_rdev);
        if(num >= HELLO_CNT)
        {
            return -ENODEV;
        }
    
        pfile->private_data = hello_cdev[num];
    
        return 0;
    }
    
    
    
    
    int hello_fasync(int fd, struct file *flip, int mode)
    {
        printk("set fasync..");
        return fasync_helper(fd, flip, mode, &async);
    }
    
    
    int hello_release(struct inode *pnode, struct file *pfile)
    {
        printk("release file ..
    ");
    
    
        return hello_fasync(-1, filp, 0);
    }
    
    
    
    
    //文件操作结构体
    static const struct file_operations fops = 
    {
        .owner = THIS_MODULE,
        .open = hello_open,
        .release = hello_release,
        //.read = hello_read,
        //.write = hello_write,
        .fasync = hello_fasync,
        .release = hello_release,
       // .unlocked_ioctl = hello_ioctl,
    };
    
    
    static void setup_cdev(int index)
    {
        int err, devno = MKDEV(major, index);
    
        cdev_init(hello_cdev[index], &fops);
        hello_cdev[index]->owner = THIS_MODULE;
        hello_cdev[index]->ops = &fops;
        err = cdev_add(hello_cdev[index], devno, 1);
        if(err)
        {
            printk(KERN_NOTICE "Error %d adding hello%d", err, index);
        }
    }
    
    
    
    
    void call_back(unsigned long val)
    {
        printk("timer is out!!
    ");
        //使用信号通知上层应用
        if (async)
        {
            kill_fasync(&async, SIGIO, POLL_IN);
            printk("send SIGIO to app!!
    ");
        }
    
    
        //重新注册定时器
        tm.expires = jiffies + 2 * HZ;
        add_timer(&tm);
    }
    
    
    
    static int __init hello_init(void)
    {
        //申请设备号,动态or静态
        int ret = 0;
        if(major)
        {
            //为字符设备静态申请第一个设备号
            dev = MKDEV(major, minor);
            ret = register_chrdev_region(dev, HELLO_CNT, "hello");
        }
        else
        {
            //为字符设备动态申请一个设备号
            ret = alloc_chrdev_region(&dev, minor, HELLO_CNT, "hello");
            major = MAJOR(dev);
        }
    
    
        //构造cdev设备对象
        int i = 0;
        for(i = 0; i < HELLO_CNT; ++i)
        {
            hello_cdev[i] = cdev_alloc();
    
    
        }
    
    
        //初始化设备对象    
        for(minor = 0; minor < HELLO_CNT; ++minor)
        {
            setup_cdev(minor);
        }
    
        hello_class = class_create(THIS_MODULE, "hello");
        for(minor = 0; minor < HELLO_CNT; ++minor)
        {
            hello_class_dev[minor] = device_create(hello_class, NULL, MKDEV(major, minor), NULL, "hello%d",minor);
        }
    
    
        //初始化定时器
        init_timer(&tm);
        tm.function = call_back;
        tm.expires = jiffies + 2 * HZ;
        add_timer(&tm);
    
        return 0;
    }
    
    
    
    
    static void __exit hello_exit(void)
    {
        for(minor = 0; minor < HELLO_CNT; ++minor)
        {
            device_destroy(hello_class, MKDEV(major, minor));
        }
        class_destroy(hello_class);
    
    
        //从内核注销cdev设备对象
        cdev_del(hello_cdev);
    
        //回收设备号
        unregister_chrdev_region(dev, HELLO_CNT);
    
    
        //注销定时器
        del_timer(&tm);
    }
    
    
    module_init(hello_init);  
    module_exit(hello_exit);  
    
    
    MODULE_LICENSE("GPL"); 
    
    

    3. 应用层测试代码

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <unistd.h>
    
    
    #define DEV_NAME ("/dev/hello0")
    
    
    void signal_handle(int num)
    {
         printf("Get SIGIO Signal from kernel!
    ");
         printf("I need to do something!!
    ");
    }
    
    
    int main(int argc, char **argv)
    {
        int fd = -1;
        int flags = -1;
    
    
        //注册信号捕获函数
        signal(SIGIO, signal_handle);
    
    
        fd = open(DEV_NAME, O_RDWR);
        if(fd < 0)
        {
            printf("can't find dev:%s
    ", DEV_NAME);
            return -1;
        }
    
        //将驱动发出的异步信号绑定到本进程
        fcntl(fd, F_SETOWN, getpid());
        flags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, flags | FASYNC);
    
    
        while(1)
        {
            sleep(1);
        }
    
    
        return 0;
    }
    
    
  • 相关阅读:
    Java 进制转换
    k-近邻算法实例
    Java JTS & 空间数据模型
    Java中 &&与&,||与|的区别
    http https 区别
    四种DCOM错误的区别,0x80080005 0x800706be 0x80010105 0x
    OPC测试常用的OPCClient和OPCServer软件推荐
    关于TFS2010 远程无法创建团队项目的若干问题总结
    我对NHibernate的感受(4):令人欣喜的Interceptor机制
    我对NHibernate的感受(3):有些尴尬的集合支持
  • 原文地址:https://www.cnblogs.com/standardzero/p/12551079.html
Copyright © 2011-2022 走看看