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