【linux】class设备

转:
https://emb.hqyj.com/Column/Column299.htm

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 *);

你可能感兴趣的:(linux,运维,服务器)