zoukankan      html  css  js  c++  java
  • 3. linux 字符设备驱动框架

    TOC

    1.主设备号码和次设备号

    dev_t

    dev_t 类型是定义在中定义用来保存设备编号(前12位用来表示主设备号,后20位表示次设备号)

    注意:我们获取主设备号和次设备号应该使用内核提供的宏
    MAJOR(dev_t):获取主设备号
    MINOR(dev_t):获取次设备号
    MKDEV(int major, int minor):将主设备号和次设备号转换为dev_t类型

    • 分配和释放设备编号

    在建立一个字符设备之前,首先需要分别一个或多个字符设备。

    静态分配设备号

    /*
    first: 要分配的设备编号范围的初始值,次设备号为0
    count: 连续编号范围
    name:编号相关联的设备名称(/proc/devices)
    
    
    */
    int register_chrdev_region(dev_t first, unsigned int count, char *name);
    
    

    动态分配设备号

    /*
    dev:分配到的设备号
    firstminor:被请求的第一个次设备号,通常为0
    count:请求的连续设备号数
    name:设备名
    */
    int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

    释放

    void unregist_chrdev_region(dev_t first,unsigned int count);

    2.字符设备的注册

    static void __init chrdev_init(void)
    {
        //构造cdev设备对象
        struct cdev *my_cdev = cdev_alloc();
        my_cdev->ops = &my_fops;
    
    
        //初始化cdev设备对象
        cdev_init(my_cdev, &my_fops);
        my_cdev->owner = THIS_MODULE;
    
    
        //申请设备号,动态or静态
        dev_t dev;
        int ret = 0;
        if(major)
        {
            //为字符设备静态申请第一个设备号
            dev = MKDEV(major, minor);
            ret = register_chrdev_region(dev, 1, "mydev");
        }
        else
        {
            //为字符设备动态申请一个设备号
            ret = alloc_chrdev_region(&dev, minor, 1, "mydev");
            major = MAJOR(dev);
        }
    
    
        //将字符设备对象注册到内核
        ret = cdev_add(my_cdev, dev, 1);
    
    
    }
    
    
    
    
    static void __exit chrdev_exit(void)
    {
        //从内核注销cdev设备对象
        cdev_del(my_dev);
    
    
        //回收设备号
        unregister_chrdev_region(dev, 1);
    }
    
    
    
    

    3.字符设备驱动程序样例

    #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>
    
    
    #define HELLO_CNT   2  
    
    
    //主设备号为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 const struct file_operations fops = 
    {
        .owner = THIS_MODULE,
        //.open = hello_open,
        //.release = hello_release,
        //.read = hello_read,
        //.write = hello_write,
    };
    
    
    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);
        }
    }
    
    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);
        }
    
    
    }
    
    
    
    
    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);
    }
    
    
    module_init(hello_init);  
    module_exit(hello_exit);  
    
    
    MODULE_LICENSE("GPL");  
    
    
  • 相关阅读:
    终于把5GB的Cygwin安装完成了
    JavaApplet-Application Blocked..Your security setting have blocked an untrusted application from running..
    C++程序运行时间测定
    WAV MP3 Converter-强大的音频转换软件-特别版
    搞ACM的你伤不起[转载] 原作者:RoBa
    邮件中的CC和BCC含义
    MESS-配置
    ShareRepository
    利用DB Link两步搞定Oracle两个数据库间的表同步
    使用ASP .NET (C#) 產生PDF檔的好幫手—iTextSharp library (上)
  • 原文地址:https://www.cnblogs.com/standardzero/p/12550994.html
Copyright © 2011-2022 走看看