当前位置:   article > 正文

linux驱动-设备驱动模型(class类)_struct class驱动

struct class驱动

该系列文章阅读顺序:

  1. linux驱动-设备驱动模型(属性文件 kobject )
  2. linux驱动-设备驱动模型(kset)
  3. linux驱动-设备驱动模型(bus总线)
  4. linux驱动-设备驱动模型(device设备)
  5. linux驱动-设备驱动模型(driver驱动)
  6. linux驱动-设备驱动模型(class类)
  7. linux驱动-设备驱动模型(platform设备)

class 用于管理同类的设备,常常被我们用来给上层开辟一个属性节点,多用于查看,修改对应的设备信息。

作者: baron

1、数据结构

1) class

struct class {
    const char      *name;                           // class名称,用来初始化 subsys_private->susbus.kobj
    struct module       *owner;

    struct class_attribute      *class_attrs;       // 默然属性文件指针

    // 默认的设备属性文件,当注册设备到该 class 上时,会自动在改设备下创建,即该 class 下的所有设备都会注册这个属性文件。
    const struct attribute_group    **dev_groups;   

    // 表示class下的设备在 /sys/dev 下的哪个目录,现在有两个目录 char 和 block 默认选择 char。
    struct kobject          *dev_kobj;              

    // 当class下的设备发生变化时,会调用class的uevent函数
    int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
    char *(*devnode)(struct device *dev, umode_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);
    int (*shutdown)(struct device *dev);

    const struct kobj_ns_type_operations *ns_type;
    const void *(*namespace)(struct device *dev);

    const struct dev_pm_ops *pm;

    struct subsys_private *p;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

2) subsys_private

struct subsys_private {
    struct kset subsys;	 	  // 该 class 在sysfs中的目录
    struct kset *devices_kset;
    struct list_head interfaces;  
    struct mutex mutex;

    struct kset *drivers_kset;	
    struct klist klist_devices;
    struct klist klist_drivers;
    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus; 

    struct kset glue_dirs;
    struct class *class;	// 保存上层的class
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2、函数接口

1) classes_init

int __init classes_init(void)
{
    class_kset = kset_create_and_add("class", NULL, NULL); //创建 /sys/class 节点
    if (!class_kset)
        return -ENOMEM;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2)class_create

用于在内核中创建一个 class

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

struct class *__class_create(struct module *owner, const char *name,
                 struct lock_class_key *key)
{
    struct class *cls;
    int retval;

    //动态创建 class 结构
    cls = kzalloc(sizeof(*cls), GFP_KERNEL);
    if (!cls) {
        retval = -ENOMEM;
        goto error;
    }

    cls->name = name; //初始化 name
    cls->owner = owner; //初始化 owner
    cls->class_release = class_create_release; //初始化 默认release函数

    retval = __class_register(cls, key); //注册class
    if (retval)
        goto error;

    return cls;

error:
    kfree(cls);
    return ERR_PTR(retval);
}
EXPORT_SYMBOL_GPL(__class_create);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
a. __class_register
int __class_register(struct class *cls, struct lock_class_key *key)
{
    struct subsys_private *cp;
    int error;

    pr_debug("device class '%s': registering\n", cls->name);
    //动态创建一个 subsys_private 结构
    cp = kzalloc(sizeof(*cp), GFP_KERNEL);
    if (!cp)
        return -ENOMEM;
    klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
    INIT_LIST_HEAD(&cp->interfaces);
    kset_init(&cp->glue_dirs);
    __mutex_init(&cp->mutex, "subsys mutex", key);
    error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); //初始化 class 目录名
    if (error) {
        kfree(cp);
        return error;
    }

    /* set the default /sys/dev directory for devices of this class */
    if (!cls->dev_kobj)
        cls->dev_kobj = sysfs_dev_char_kobj; //设置子设备的默认类型为char

#if defined(CONFIG_BLOCK)
    /* let the block class directory show up in the root of sysfs */
    if (!sysfs_deprecated || cls != &block_class)
        cp->subsys.kobj.kset = class_kset;
#else
    cp->subsys.kobj.kset = class_kset; //设置kset为class_kset 即出现在 /sys/class/目录下 (一般是不会设置class的父kobj的,因此默认使用kset作为父kobj)
#endif
    cp->subsys.kobj.ktype = &class_ktype; //初始化class的默认ktype
    cp->class = cls; 
    cls->p = cp;

    error = kset_register(&cp->subsys); //注册kset创建对应的class节点,/sys/class/xxx
    if (error) {
        kfree(cp);
        return error;
    }
    error = add_class_attrs(class_get(cls)); //增加引用计数,创建默认属性文件
    class_put(cls);
    return error;
}
EXPORT_SYMBOL_GPL(__class_register);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
b. device_create

在 class 下创建对应的设备,返回创建的设备结构。

struct device *device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
{
    va_list vargs;
    struct device *dev;

    va_start(vargs, fmt);
    dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
    va_end(vargs);
    return dev;
}
EXPORT_SYMBOL_GPL(device_create);

struct device *device_create_vargs(struct class *class, struct device *parent,
                   dev_t devt, void *drvdata, const char *fmt,
                   va_list args)
{
    return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
                      fmt, args);
}
EXPORT_SYMBOL_GPL(device_create_vargs);


static struct device *
device_create_groups_vargs(struct class *class, struct device *parent,
               dev_t devt, void *drvdata,
               const struct attribute_group **groups,
               const char *fmt, va_list args)
{
    struct device *dev = NULL;
    int retval = -ENODEV;

    if (class == NULL || IS_ERR(class))
        goto error;

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev) {
        retval = -ENOMEM;
        goto error;
    }

    device_initialize(dev);
    dev->devt = devt; //设置设备号
    dev->class = class; //设置设备所属的类
    dev->parent = parent; //设备的父节点
    dev->groups = groups; //设置设备的默认
    dev->release = device_create_release;
    dev_set_drvdata(dev, drvdata); //设置设备的私有数据

    retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
    if (retval)
        goto error;

    retval = device_add(dev); //注册设备 
    if (retval)
        goto error;

    return dev;

error:
    put_device(dev);
    return ERR_PTR(retval);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

device_add 函数在前面已经有很详细的分析,这里不赘述,不过这里再补充说明一点,device_create 会在 /dev/ 目录下创建设备节点是因为设备有设备号,只要是调用 device_add 注册的设备,同时有设备号就会在 /dev/ 下创建设备节点

3) 属性操作接口

属性文件是 class 重点内容,我们多用 class 来给上层提供接口,属性文件创建接口如下。

//快速创建 class_attribute

#define CLASS_ATTR(_name, _mode, _show, _store) \
    struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define CLASS_ATTR_RW(_name) \
    struct class_attribute class_attr_##_name = __ATTR_RW(_name)
#define CLASS_ATTR_RO(_name) \
    struct class_attribute class_attr_##_name = __ATTR_RO(_name)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
static inline int __must_check class_create_file(struct class *class, const struct class_attribute *attr)
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/246940
推荐阅读
相关标签
  

闽ICP备14008679号