设备Class

    技术2026-05-02  3

    class是设备的高层的视图,他抽象出了底层的实现细节。

    类允许用户空间使用设备所提供的功能,而不需要关系设备是如何连接的,以及他们是如何工作的。

    几乎所有的类都是显示在 sys/class,但是有一个例外,就是block,其出现在 sys/block下。

    系统导出了两个不同接口来供用户来使用一个是class_simple和正规的接口。

    class_simple接口:

    第一步:创建类本身。         class_simple_create()         class_simple_destroy()         class_simple_device_add()         class_simple_device_remove()

    此类函数在比较新的版本上已经不存在了,2.6.13之前存在,2.6.13之后就需要把中间的_simple去掉了。

    /*         * device classes         */         struct class {                 const    char              * name;                 struct    module        * owner;

            struct    kset                     subsys;                 struct    list_head            children;                 struct    list_head            devices;                 struct    list_head            interfaces;                 struct    kset                     class_dirs;                 struct    semaphore        sem;        /* locks both the children and interfaces lists */

            struct    class_attribute                          * class_attrs;                 struct    class_device_attribute            * class_dev_attrs;                 struct    device_attribute                        * dev_attrs;

            /* 以下两个函数跟热插拔相关的函数 */                 int         (*uevent)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size);                 int         (*dev_uevent)(struct device *dev, char **envp, int num_envp,char *buffer, int buffer_size);

            void        (*release)(struct class_device *dev);         /* 删掉类里面的设备 */                 void         (*class_release)(struct class *class);        /* 删掉类本身 */                 void         (*dev_release)(struct device *dev);        /* 删掉设备本身 */

            int         (*suspend)(struct device *, pm_message_t state);         /* 设备暂停 */                 int        (*resume)(struct device *);        /* 设备启动 */         };

    /* 类的注册函数 */

    int class_register(struct class * cls)         {                 int error;

            pr_debug("device class '%s': registering/n", cls->name);

            INIT_LIST_HEAD(&cls->children);                 INIT_LIST_HEAD(&cls->devices);                 INIT_LIST_HEAD(&cls->interfaces);                 kset_init(&cls->class_dirs);                 init_MUTEX(&cls->sem);                 error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name);                 if (error)                         return error;

            subsys_set_kset(cls, class_subsys);

            error = subsystem_register(&cls->subsys);                 if (!error) {                         error = add_class_attrs(class_get(cls));                         class_put(cls);                 }                 return error;         }

    struct class_attribute {                 struct attribute attr;                 ssize_t (*show)(struct class *, char * buf);                 ssize_t (*store)(struct class *, const char * buf, size_t count);         };

    int class_create_file(struct class * cls, const struct class_attribute * attr)         {                 int error;                 if (cls) {                         error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);                 } else                         error = -EINVAL;                 return error;         }

    void class_remove_file(struct class * cls, const struct class_attribute * attr)         {                 if (cls)                         sysfs_remove_file(&cls->subsys.kobj, &attr->attr);         }

    类的主要目的就是为类成员提供容器。         用class_device结构来表示类的成员。

    struct class_device {                 struct list_head        node;

            struct kobject                    kobj;                 struct class                      * class;                          /* required */                 dev_t                                   devt;                              /* dev_t, creates the sysfs "dev" */                 struct class_device_attribute *devt_attr;                 struct class_device_attribute uevent_attr;                 struct device                      * dev;                           /* not necessary, but nice to have */                 void                                     * class_data;              /* class-specific data */                 struct class_device         *parent;                        /* parent of this child device, if there is one */                 struct attribute_group        ** groups;                 /* optional groups */

            void        (*release)(struct class_device *dev);                 int         (*uevent)(struct class_device *dev, char **envp,                                                 int         num_envp, char *buffer, int buffer_size);                 char         class_id[BUS_ID_SIZE]; /* unique to this class */         };

    /* 为类里面添加具体的设备,来让udev使用创建具体的设备文件。 */         struct class_device *class_device_create(struct class *cls,struct class_device *parent,dev_t devt,struct device *device,const char *fmt, ...)         {                 va_list args;                 struct class_device *class_dev = NULL;                 int         retval = -ENODEV;

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

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

            class_dev->devt = devt;                 class_dev->dev = device;                 class_dev->class = cls;                 class_dev->parent = parent;                 class_dev->release = class_device_create_release;                 class_dev->uevent = class_device_create_uevent;

            va_start(args, fmt);                 vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);                 va_end(args);                 retval = class_device_register(class_dev);                 if (retval)                         goto error;

            return class_dev;

    error:                 kfree(class_dev);                 return ERR_PTR(retval);         }

    具体的应用例子:

    struct class *test_class = class_create(THIS_MODULE, “test_device_driver”);         class_device_create(test_class, NULL, MKDEV(major_num, 0), NULL, “test_device”);

    一个类是一个设备的高层视图,它抽象掉了底层的实现细节。例如,在驱动层面时,你可能会见到SCSI磁盘或者ATA磁盘;但在类层面时,它们都是磁盘。类允许用户空间基于它们做什么来使用设备,而不是它们如何被连接或者它们如何工作。

    class表示一类设备,所有class都属于class_subsys(class子系统),即出现在/sys/class目录下,除了块设备(可能出现在/sys/block/或/sys/class/block,上面讲过了)。

    其实,class在/sys/class下生成的目录也就是上面提到subsystem。这样第1点就有了。         /* class结构体 */         struct class {                 const char        * name;         /* class的名称 */                 struct module        * owner;        /* 拥有该class的模块 */

            struct kset        subsys;         /* 该class对应的子系统 */                 struct list_head        children;          /* 该class的class_device列表 */                 struct list_head        devices;                 struct list_head        interfaces;                 struct kset                class_dirs;                 struct semaphore        sem;          /* locks both the children and interfaces lists */

            struct class_attribute                * class_attrs; /* 该class的默认属性,以NULL结尾 */                 struct class_device_attribute        * class_dev_attrs; /* 添加到class的class_device所拥有的默认属性 */                 struct device_attribute                 * dev_attrs;

            /* 该函数提供在产生热插拔class_device事件时,添加环境变量的能力 */                 int        (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);                 /* 该函数提供在产生热插拔device(物理设备)事件时,添加环境变量的能力 */                 int        (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

            /* 添加到class的class_device移除时,调用该函数进行必要的清理工作 */                 void (*release)(struct class_device *dev);                 /* class被移除时,调用该函数进行必要的清理工作 */                 void (*class_release)(struct class *class);                 void (*dev_release)(struct device *dev);

            int        (*suspend)(struct device *, pm_message_t state);                 int        (*resume)(struct device *);         };

    /* class注册函数 */         int __must_check class_register(struct class *);         void class_unregister(struct class *);

    建立一个class有两种方法         a、根据需要,填充一个struct class,然后再调用class_register注册该class就ok了(此法比较灵活,可以自己定制很多东西)         b、就是通过下面的class_create来创建一个class,该函数会返回一个指向刚建立的class的指针(创建class的最简单方法)         /* class_create用于创建一个名为name的class,其owner参数一般为THIS_MODULE。class_create内部调用了class_register */         struct class *class_create(struct module *owner, const char *name);         /* class_destroy用于删除一个class,实际上其内部只是简单调用了class_unregister(cls)来注销cls */         void class_destroy(struct class *cls);

    一个class属性对应于/sys/class/class.name(class.name就是该class的名称)目录里的一个文件。通过这些文件,可以向用户空间输出一些关于该class的信息,也可从用户空间获取到一些信息。         /* class属性结构体 */         struct class_attribute {                 struct attribute        attr;                 /* 当用户空间读取该属性时,调用show函数输出一个"属性值"给用户空间 */                 ssize_t (*show)(struct class *, char * buf);                 /* 当用户空间写该属性时,调用store函数保存用户写入的"属性值" */                 ssize_t (*store)(struct class *, const char * buf, size_t count);         };

    struct attribute {                 const char        * name;                 struct module        * owner;                 mode_t                mode;         };

    /* CLASS_ATTR可以在编译时创建一个class属性,该属性的名称为class_attr_name */         #define CLASS_ATTR(_name,_mode,_show,_store) /         struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store)

    /* class_create_file与class_remove_file用于创建与删除class默认属性外的属性 */         int __must_check class_create_file(struct class *,const struct class_attribute *);         void class_remove_file(struct class *, const struct class_attribute *);

    最新回复(0)