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");  
    
    
  • 相关阅读:
    第二十一章流 1流的操作 简单
    第二十章友元类与嵌套类 1友元类 简单
    第十九章 19 利用私有继承来实现代码重用 简单
    第二十章友元类与嵌套类 2嵌套类 简单
    第十九章 8链表类Node 简单
    第二十一章流 3用cin输入 简单
    第十九章 10 图书 药品管理系统 简单
    第十九章 11图书 药品管理系统 简单
    第二十一章流 4文件的输入和输出 简单
    第十九章 12 什么时候使用私有继承,什么时候使用包含 简单
  • 原文地址:https://www.cnblogs.com/standardzero/p/12550994.html
Copyright © 2011-2022 走看看