本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记
一. class结构体描述
struct class{
const char *name; //class的名称,会在“/sys/class/”目录下体现
struct module *owner;
struct class_attribute *class_attrs; //该class的默认attribute
struct device_attribute *dev_attrs; //该class下每个设备的attribute
struct kobject *dev_kobj; //表示该class下的设备在/sys/dev/下的目录,现在一般有char和block两个,如果dev_kobj为NULL,则默认选择char
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); //当该class下有设备发生变化时,会调用class的uevent回调函数
char *(*devnode)(struct device *dev, mode_t *mode);
void (*class_release)(struct class *class); //用于release自身的回调函数
void (*dev_release)(struct device *dev); //用于release class内设备的回调函数
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
struct class_private *p; //class的私有数据
}
二. class模块初始化
创建一个class_kset,parent = NULL, kset->kobj.kset = NULL,相当于新建文件夹/sys/class
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
return 0;
}
class_kset .uevent_ops = NULL;
三. class的创建函数class_create
dca_class = class_create(THIS_MODULE, "dca");
__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;
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);
}
调用class_create接口创建一个class,class_create调用的是__class_create。
__class_create接口里面分配了一个struct class类型的内存,然后调用__class_register接口。
int __class_register(struct class *cls, struct lock_class_key *key)
{
struct class_private *cp;
int error;
pr_debug("device class '%s': registering\n", cls->name);
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp)
return -ENOMEM;
klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
INIT_LIST_HEAD(&cp->class_interfaces);
kset_init(&cp->class_dirs);
__mutex_init(&cp->class_mutex, "struct class mutex", key);
error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
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;
#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
/* let the block class directory show up in the root of sysfs */
if (cls != &block_class)
cp->class_subsys.kobj.kset = class_kset;
#else
cp->class_subsys.kobj.kset = class_kset;
#endif
cp->class_subsys.kobj.ktype = &class_ktype;
cp->class = cls;
cls->p = cp;
error = kset_register(&cp->class_subsys);
if (error) {
kfree(cp);
return error;
}
error = add_class_attrs(class_get(cls));
class_put(cls);
return error;
}
1.申请class的私有数据cp
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
2.cp->class_subsys的初始化
kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
cp->class_subsys.kobj.kset = class_kset;
cp->class_subsys.kobj.ktype = &class_ktype;
class_subsys.kobj.kset = class_kset,相当于在/sys/class目录下创建一个名称为 cls->name的文件夹。
static struct kobj_type class_ktype = {
.sysfs_ops = &class_sysfs_ops,
.release = class_release,
};
展开得到:
static struct kobj_type class_ktype = {
.sysfs_ops =
{
.show = class_attr_show,
.store = class_attr_store,
}
.release = class_release,
};
3.上面的注册没有给cls->dev_kobj赋值,因此cls->dev_kobj = sysfs_dev_char_kobj。
sysfs_dev_char_kobj在devices_init函数中注册,这个kobj的目录是/sys/dev/char。
if (!cls->dev_kobj)
cls->dev_kobj = sysfs_dev_char_kobj;
4.注册class kset,相当于在/sys/class目录下新建一个文件夹
error = kset_register(&cp->class_subsys);
5.创建class的属性文件
error = add_class_attrs(class_get(cls));
static int add_class_attrs(struct class *cls)
{
int i;
int error = 0;
if (cls->class_attrs) {
for (i = 0; attr_name(cls->class_attrs[i]); i++) {
error = class_create_file(cls, &cls->class_attrs[i]);
if (error)
goto error;
}
}
done:
return error;
error:
while (--i >= 0)
class_remove_file(cls, &cls->class_attrs[i]);
goto done;
}
int class_create_file(struct class *cls, const struct class_attribute *attr)
{
int error;
if (cls)
error = sysfs_create_file(&cls->p->class_subsys.kobj,
&attr->attr);
else
error = -EINVAL;
return error;
}
由上面可以得到:
error = add_class_attrs(class_get(cls));
error = class_create_file(cls, &cls->class_attrs[i]);
error = sysfs_create_file(&cls->p->class_subsys.kobj, &attr->attr);
add_class_attrs函数在class目录创建了class的默认attribute文件。
找一个gpio_class的例子,如下所示:
static struct class gpio_class = {
.name = "gpio",
.owner = THIS_MODULE,
.class_attrs = gpio_class_attrs,
};
static struct class_attribute gpio_class_attrs[] = {
__ATTR(export, 0200, NULL, export_store),
__ATTR(unexport, 0200, NULL, unexport_store),
__ATTR_NULL,
};
展开gpio_class ,得到:
static struct class gpio_class = {
.name = "gpio",
.owner = THIS_MODULE,
.class_attrs =
{
.attr = {.name = “export”, .mode = 0200},
.show = NULL,
.store = export_store,
},
{
.attr = {.name = “unexport”, .mode = 0200},
.show = NULL,
.store = unexport_store,
},
};
结果是在gpio这个class目录下创建了export文件,这个文件的写函数为export_store;
在gpio这个class目录下创建了unexport文件,这个文件的写函数是unexport_store;
上面的class_ktype 展开得到:
static struct kobj_type class_ktype = {
.sysfs_ops =
{
.show = class_attr_show,
.store = class_attr_store,
}
.release = class_release,
};
static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct class_attribute *class_attr = to_class_attr(attr);
struct class_private *cp = to_class(kobj);
ssize_t ret = -EIO;
if (class_attr->show)
ret = class_attr->show(cp->class, buf);
return ret;
}
static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
{
struct class_attribute *class_attr = to_class_attr(attr);
struct class_private *cp = to_class(kobj);
ssize_t ret = -EIO;
if (class_attr->store)
ret = class_attr->store(cp->class, buf, count);
return ret;
}
那么相当于写gpio_class目录下的export和unexport文件,最终调用的函数是export_store和unexport_store。
四. class的注册函数class_register
#define class_register(class) \
({ \
static struct lock_class_key __key; \
__class_register(class, &__key); \
})
class_register注册一个已经定义好了的class,直接调用__class_register函数,不用申请class内存。
__class_register函数在上面已经分析过了。
五. class_create和class_register
class_create是创建一个原先不存在的class,class_register是注册一个已经定义的class到内核。
class_create注册的class需要内核主动释放申请的class内存,而class_register注册的class一般在driver里面定义成了全局变量,不用去主动释放内存。