zoukankan      html  css  js  c++  java
  • linux 内核事件通知驱动编程

    1. eventfd 事件通知

    eventfd 事件通知不仅可以用于线程间的事件通知,还可以用于内核和用户空间的事件通知。

    2. eventfd 用户空间API

    #include <sys/eventfd.h>
    
    
    //创建事件通知句柄,可以被read 和 write 函数使用
    int eventfd(unsigned int initval, int flags);

    Linux shell下 输入 man eventfd 命令查看,里面有详细的使用说明和例子

    3. eventfd 内核空间API

    #include <linux/eventfd.h>
    
    
    //将fd 转换为 struct eventfd_ctx
    struct eventfd_ctx *eventfd_ctx_fdget(int fd);
    
    
    //移除 struct eventfd_ctx
    void eventfd_ctx_put(struct eventfd_ctx *ctx);
    
    
    //相当于用户层的write
    __u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n);
    //相当于用户层的read
    ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt);

    4. 驱动例程

    command.h

    #ifndef INCLUDE_COMMAND_H
    #define INCLUDE_COMMAND_H
    
    
    #include <linux/ioctl.h>
    
    
    //幻数
    #define IOCTL_MAGIC 'x'
    
    
    //定义命令
    #define HELLO_RESET _IO(IOCTL_MAGIC, 1)
    #define HELLO_READ _IOR(IOCTL_MAGIC, 2, int)
    #define HELLO_WRITE _IOW(IOCTL_MAGIC, 3, int)
    #define HELLO_NOTIFICATION _IOW(IOCTL_MAGIC, 4, int)
    
    
    #endif
    
    

    hello.c

    #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/poll.h>  
    #include <linux/cdev.h>  
    #include <linux/device.h>
    #include <linux/eventfd.h>
    #include <linux/timer.h>
    
    
    #include "command.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 int s_val = 0;
    static int s_EventFd = -1;
    static struct eventfd_ctx * eve_ctx = NULL;
    static struct timer_list tm;
    
    
    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_release(struct inode *pnode, struct file *pfile)
    {
        printk("release file ..
    ");
    
    
        return 0;
    }
    
    
    
    
    long hello_ioctl(struct file *pfile, unsigned int cmd, unsigned long val)
    {
        int ret = 0;
    
        switch(cmd)
        {
            case HELLO_RESET:
            {
                printk("Rev HELLO_RESET cmd
    ");
                break;
            }
            case HELLO_READ:
            {
                printk("Rec HELLO_READ cmd
    ");
    
                ret = copy_to_user(val, &s_val, sizeof(int));
                break;
            }
            case HELLO_WRITE:
            {
                printk("Rec HELLO_WRITE cmd
    ");
    
                ret = copy_from_user(&s_val, val, sizeof(int));
                break;
            }
            case HELLO_NOTIFICATION:
            {
                printk("Rec HELLO_NOTIFICATION cmd..
    ");
                ret = copy_from_user(&s_EventFd, val, sizeof(int));
                eve_ctx = eventfd_ctx_fdget(s_EventFd);
                break;
            }
            default:
            {
                printk("unkownd cmd...
    ");
                return -EINVAL;
            }
        }
    
        return ret;
    }
    
    
    //文件操作结构体
    static const struct file_operations fops = 
    {
        .owner = THIS_MODULE,
        .open = hello_open,
        .release = hello_release,
        //.read = hello_read,
        //.write = hello_write,
        .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(eve_ctx)
        {
           eventfd_signal(eve_ctx, 1);
        }
    
    
        tm.expires = jiffies + 2 * HZ;
        add_timer(&tm);
    }
    
    static void __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);
    
    
    }
    
    
    
    
    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);
    
    
        //回收eventfd context
        if(eve_ctx)
        {
            eventfd_ctx_put(eve_ctx);
            eve_ctx = NULL;
        }
    
    
        //注销定时器
        del_timer(&tm);
    }
    
    
    module_init(hello_init);  
    module_exit(hello_exit);  
    
    
    MODULE_LICENSE("GPL");  
    
    

    5. 用户空间

    test_ioctl.c

    /*
     * =====================================================================================
     *
     *       Filename:  ioctl.c
     *
     *    Description:  
     *
     *        Version:  1.0
     *        Created:  08/27/17 14:18:42
     *       Revision:  none
     *       Compiler:  gcc
     *
     *         Author:  linsheng.pan (), life_is_legend@163.com
     *   Organization:  
     *
     * =====================================================================================
     */
    #include <stdlib.h>
    #include <stdio.h>
    #include <fcntl.h>
    
    
    #include "command.h"
    
    
    int main(int argc, char *argv[])
    {
        int fd = open("/dev/hello0", O_RDWR);
        if(fd < 0)
        {
            perror("open error:");
            return -1;
        }
    
    
        if(ioctl(fd, HELLO_RESET) < 0)
        {
            perror("error:");
            return -1;
        }
    
    
        int val = 1;
    
        if(ioctl(fd, HELLO_WRITE, &val) < 0)
        {
            perror("write error:");
            return -1;
        }
    
    
        val = 2;
        if(ioctl(fd, HELLO_READ, &val) < 0)
        {
            perror("read error");
            return -1;
        }
    
    
        printf("val = %d
    ", val);
    
    
        return 0;
    }
    

     

  • 相关阅读:
    IOS数组
    caffe-fasterrcnn程序理解
    pytorch官网上两个例程
    python:批量修改文件名批量修改图片尺寸
    faster rcnn报错:TypeError: slice indices must be integers or None or have an __index__ method
    faster-rcnn原理讲解
    caffe + ssd网络训练过程
    运行Keras版本的Faster R-CNN(1)
    Ubuntu16.04 faster-rcnn+caffe+gpu运行环境配置以及解决各种bug
    ubuntu16+caffe fast-rcnnCPU运行步骤
  • 原文地址:https://www.cnblogs.com/dream397/p/13937847.html
Copyright © 2011-2022 走看看