• linux驱动学习(四)自创建设备文件节点


    ---恢复内容开始---

    1: 首先回顾一下之前的学习内容:

      1:register_chrdev来注册字符设备驱动,用这种方法的好处是简单,只需要一个函数就可以注册字符设备驱动了,缺点是无法设置次设备号;

      2:register_chrdev_region/allco_chrdev_region、cdev_XXX这些函数来配合注册设备驱动,单纯使用这些函数存在一个问题就是无法自动在/dev目录下面创建

    驱动设备文件,我们在嵌入式设备中一般使用busybox中的mdev来实现驱动设备文件的自动创建,但是驱动设备文件的创建需要一个uevent文件;

      3:uevent文件是有kobject_uevent函数来实现的;所以我们为了设备文件的自动生成,首先使用class_create函数来创建一个设备类,在用device_create函数

    把子目录创建了,这时候就会有一个uevent文件,然后mdev会自动的根据uevent创建/dev/目录下面的设备文件;

      4:所以我们在module_init的时候要把sys目录下的类创建了,以及把device也创建了;

    下面是详细分析:

    class_create函数:

    class_create

      __class_create      

        __class_register

          kset_register  

            kobject_uevent

    class是创建了一个类即结构体struct class,对应的是在sysfs目录下面创建了一个关于这个类的文件夹

    owner:THIS_MODULE  name : leds   然后是用device_create在创建相应的设备文件;  

    #define class_create(owner, name) ({ static struct lock_class_key __key; __class_create(owner, name, &__key); })

    class_create其实是一个宏,调用的是__class_create这个函数

    struct class *__class_create(struct module *owner, const char *name,
                     struct lock_class_key *key)
    {
        struct class *cls;
        int retval;
    
        cls = kzalloc(sizeof(*cls), GFP_KERNEL);
        if (!cls) {
            retval = -ENOMEM;
            goto error;
        }
    
        cls->name = name;
        cls->owner = owner;
        cls->class_release = class_create_release;
    
        retval = __class_register(cls, key);
        if (retval)
            goto error;
    
        return cls;
    
    error:
        kfree(cls);
        return ERR_PTR(retval);
    }
    struct class {
        const char        *name;
        struct module        *owner;
    
        struct class_attribute        *class_attrs;
        struct device_attribute        *dev_attrs;
        struct kobject            *dev_kobj;
    
        int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
        char *(*devnode)(struct device *dev, mode_t *mode);
    
        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);
    
        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
    
        const struct kobj_ns_type_operations *ns_type;
        const void *(*namespace)(struct device *dev);
    
        const struct dev_pm_ops *pm;
    
        struct class_private *p;
    };

    device_create

    struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)

    例子:device_create(batman_class, NULL, MKDEV(tmp_major, 0), NULL, "batman-adv");

    struct device {
        struct device        *parent;
    
        struct device_private    *p;
    
        struct kobject kobj;
        const char        *init_name; /* initial name of the device */
        struct device_type    *type;
    
        struct mutex        mutex;    /* mutex to synchronize calls to
                         * its driver.
                         */
    
        struct bus_type    *bus;        /* type of bus device is on */
        struct device_driver *driver;    /* which driver has allocated this
                           device */
        void        *platform_data;    /* Platform specific data, device
                           core doesn't touch it */
        struct dev_pm_info    power;
    
    #ifdef CONFIG_NUMA
        int        numa_node;    /* NUMA node this device is close to */
    #endif
        u64        *dma_mask;    /* dma mask (if dma'able device) */
        u64        coherent_dma_mask;/* Like dma_mask, but for
                             alloc_coherent mappings as
                             not all hardware supports
                             64 bit addresses for consistent
                             allocations such descriptors. */
    
        struct device_dma_parameters *dma_parms;
    
        struct list_head    dma_pools;    /* dma pools (if dma'ble) */
    
        struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
                             override */
        /* arch specific additions */
        struct dev_archdata    archdata;
    #ifdef CONFIG_OF
        struct device_node    *of_node;
    #endif
    
        dev_t            devt;    /* dev_t, creates the sysfs "dev" */
    
        spinlock_t        devres_lock;
        struct list_head    devres_head;
    
        struct klist_node    knode_class;
        struct class        *class;
        const struct attribute_group **groups;    /* optional groups */
    
        void    (*release)(struct device *dev);
    };

    device_create

      device_create_vargs:对device类中的变量赋值,devt name release等初始化这个结构体中的变量

         device_register : 对设备的初始化,就是把这个结构体,插入到链表中;

           device_add :创建设备文件

            device_create_file

            device_create_sys_dev_entry

            device_add_class_symlinks

            device_add_attrs

            bus_add_device

            dpm_sysfs_add

            kobject_uevent

    类似的还有DRIVER_ATTR,BUS_ATTR,CLASS_ATTR。这几个东东的区别就是,DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下面。
    而其他几个分别在driver,bus,class中对应的目录下。这次主要介绍DEVICE_ATTR,其他几个类似。

    struct device_attribute {
        struct attribute    attr;
        ssize_t (*show)(struct device *dev, struct device_attribute *attr,
                char *buf);
        ssize_t (*store)(struct device *dev, struct device_attribute *attr,
                 const char *buf, size_t count);
    };
    struct attribute {
        const char        *name;
        struct module        *owner;
        mode_t            mode;
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
        struct lock_class_key    *key;
        struct lock_class_key    skey;
    #endif
    };

    http://blog.csdn.net/wujiangguizhen/article/details/37929963

    device_attribute的主要是由 name、owner、show、store四个元素组成;

    先看看DEVICE_ATTR的原型:
    DEVICE_ATTR(_name, _mode, _show, _store)
    _name:名称,也就是将在sys fs中生成的文件名称。
    _mode:上述文件的访问权限,与普通文件相同,UGO的格式。
    _show:显示函数,cat该文件时,此函数被调用。
    _store:写函数,echo内容到该文件时,此函数被调用。

    这就是真正创建class目录下的文件的函数:

    我们看一下在i2c-0目录下有6个文件,这些文件就是用上面的那些函数生成的,有了uevent文件以后我们在安装驱动模块的时候mdev会自动生成/dev/ 下的设备文件节点

    注意:在删除模块的时候记得使用

    device_destroy
    class_destroy

    这两个函数把创建的文件删除;

    下面写代码来测试一下:

     

    struct class这个结构体在include/linux/device.h头文件中定义的;

    ---恢复内容结束---

  • 相关阅读:
    powershell网络钓鱼获取用户密码
    js 倒计时(转)
    TFS如何设置在客户端独占签出
    TFS 2010 配置的时候,提示TF255466错误
    浅谈Dynamic 关键字系列之一:dynamic 就是Object(转)
    js替换字符串中全部“-”
    苹果safari浏览器登陆时Cookie无法保存的问题
    IIS发布网站出现“未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。”的解决方法
    Aspose.Cells单元格转换为数字格式
    SQL Server中GO的使用方法(转)
  • 原文地址:https://www.cnblogs.com/biaohc/p/6628457.html
Copyright © 2020-2023  润新知