一个类是一个设备的高层视图,它抽象掉了底层的实现细节。例如,在驱动层面时,你可能会见到SCSI磁盘或者ATA磁盘;但在类层面时,它们都是磁盘。类允许用户空间基于它们做什么来使用设备,而不是它们如何被连接或者它们如何工作。
在《
GSC3280的ADC子系统驱动模型(一)》的3.1,程序adc_class
= class_create
(THIS_MODULE
, "adc");产生一个class,class_create()函数如下:
-
struct class {
-
const char *name;
-
struct module *owner;
-
-
struct class_attribute *class_attrs;
-
struct device_attribute *dev_attrs;
-
struct bin_attribute *dev_bin_attrs;
-
struct kobject *dev_kobj;
-
-
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
-
char *(*devnode)(struct device *dev, mode_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);
-
-
const struct kobj_ns_type_operations *ns_type;
-
const void *(*namespace)(struct device *dev);
-
-
const struct dev_pm_ops *pm;
-
-
struct subsys_private *p;
-
};
-
#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;
-
-
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);
-
}
-
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);
-
-
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->class_interfaces);
-
kset_init(&cp->glue_dirs);
-
__mutex_init(&cp->class_mutex, "struct class mutex", key);
-
error = kobject_set_name(&cp->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_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;
-
#endif
-
cp->subsys.kobj.ktype = &class_ktype;
-
cp->class = cls;
-
cls->p = cp;
-
-
error = kset_register(&cp->subsys);
-
if (error) {
-
kfree(cp);
-
return error;
-
}
-
error = add_class_attrs(class_get(cls));
-
class_put(cls);
-
return error;
-
}
说明:
1) class_create()函数是一个宏定义,具体调用了__class_create()函数。
2) __class_create()函数首先申请了一个class结构体内存,然后对其结构体成员变量赋值,最后调用__class_register
()函数注册类。
3) __class_register
()函数中,首先申请了结构体subsys_private内存,从class结构体成员可以看到,subsys_private是其一个成员指针。
4) 然后就是对subsys_private的成员变量初始化,注册
subsys
的kset,增加类属性等。
在《
GSC3280的ADC子系统驱动模型(二)》的2.1中,介绍了sysfs的初始化,程序如下:
-
void __init adc_sysfs_init(struct class *adc_class)
-
{
-
adc_class->dev_attrs = adc_attrs;
-
}
说明:
1) 此处的类即是上面我们使用class_creat()创建的类。
2) 对类中的设备属性赋值,下面会讲述。
在《
GSC3280的ADC子系统驱动模型(一)》的3.2中,首先使用程序adc
->dev
.class = adc_class
;将我们上面定义的类赋值给dev中的类,然后程序
err = device_register
(&adc
->dev
);注册这个设备,在这里的设备注册函数中,我们主要关注设备结构体中类的注册。device_register()函数如下:
-
int device_register(struct device *dev)
-
{
-
device_initialize(dev);
-
return device_add(dev);
-
}
-
void device_initialize(struct device *dev)
-
{
-
dev->kobj.kset = devices_kset;
-
kobject_init(&dev->kobj, &device_ktype);
-
INIT_LIST_HEAD(&dev->dma_pools);
-
mutex_init(&dev->mutex);
-
lockdep_set_novalidate_class(&dev->mutex);
-
spin_lock_init(&dev->devres_lock);
-
INIT_LIST_HEAD(&dev->devres_head);
-
device_pm_init(dev);
-
set_dev_node(dev, -1);
-
}
-
int device_add(struct device *dev)
-
{
-
struct device *parent = NULL;
-
struct class_interface *class_intf;
-
int error = -EINVAL;
-
-
dev = get_device(dev);
-
if (!dev)
-
goto done;
-
-
if (!dev->p) {
-
error = device_private_init(dev);
-
if (error)
-
goto done;
-
}
-
-
/*
-
* for statically allocated devices, which should all be converted
-
* some day, we need to initialize the name. We prevent reading back
-
* the name, and force the use of dev_name()
-
*/
-
if (dev->init_name) {
-
dev_set_name(dev, "%s", dev->init_name);
-
dev->init_name = NULL;
-
}
-
-
if (!dev_name(dev)) {
-
error = -EINVAL;
-
goto name_error;
-
}
-
-
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
-
-
parent = get_device(dev->parent);
-
setup_parent(dev, parent);
-
-
/* use parent numa_node */
-
if (parent)
-
set_dev_node(dev, dev_to_node(parent));
-
-
/* first, register with generic layer. */
-
/* we require the name to be set before, and pass NULL */
-
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
-
if (error)
-
goto Error;
-
-
/* notify platform of device entry */
-
if (platform_notify)
-
platform_notify(dev);
-
-
error = device_create_file(dev, &uevent_attr);
-
if (error)
-
goto attrError;
-
-
if (MAJOR(dev->devt)) {
-
error = device_create_file(dev, &devt_attr);
-
if (error)
-
goto ueventattrError;
-
-
error = device_create_sys_dev_entry(dev);
-
if (error)
-
goto devtattrError;
-
-
devtmpfs_create_node(dev);
-
}
-
-
error = device_add_class_symlinks(dev);
-
if (error)
-
goto SymlinkError;
-
error = device_add_attrs(dev);
-
if (error)
-
goto AttrsError;
-
error = bus_add_device(dev);
-
if (error)
-
goto BusError;
-
error = dpm_sysfs_add(dev);
-
if (error)
-
goto DPMError;
-
device_pm_add(dev);
-
-
/* Notify clients of device addition. This call must come
-
* after dpm_sysf_add() and before kobject_uevent().
-
*/
-
if (dev->bus)
-
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
-
BUS_NOTIFY_ADD_DEVICE, dev);
-
-
kobject_uevent(&dev->kobj, KOBJ_ADD);
-
bus_probe_device(dev);
-
if (parent)
-
klist_add_tail(&dev->p->knode_parent,
-
&parent->p->klist_children);
-
-
if (dev->class) {
-
mutex_lock(&dev->class->p->class_mutex);
-
/* tie the class to the device */
-
klist_add_tail(&dev->knode_class,
-
&dev->class->p->klist_devices);
-
-
/* notify any interfaces that the device is here */
-
list_for_each_entry(class_intf,
-
&dev->class->p->class_interfaces, node)
-
if (class_intf->add_dev)
-
class_intf->add_dev(dev, class_intf);
-
mutex_unlock(&dev->class->p->class_mutex);
-
}
-
done:
-
put_device(dev);
-
return error;
-
DPMError:
-
bus_remove_device(dev);
-
BusError:
-
device_remove_attrs(dev);
-
AttrsError:
-
device_remove_class_symlinks(dev);
-
SymlinkError:
-
if (MAJOR(dev->devt))
-
devtmpfs_delete_node(dev);
-
if (MAJOR(dev->devt))
-
device_remove_sys_dev_entry(dev);
-
devtattrError:
-
if (MAJOR(dev->devt))
-
device_remove_file(dev, &devt_attr);
-
ueventattrError:
-
device_remove_file(dev, &uevent_attr);
-
attrError:
-
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
-
kobject_del(&dev->kobj);
-
Error:
-
cleanup_device_parent(dev);
-
if (parent)
-
put_device(parent);
-
name_error:
-
kfree(dev->p);
-
dev->p = NULL;
-
goto done;
-
}
说明:
1) device_register()函数首先调用device_initialize
(dev
);对dev成员初始化。
2) 然后调用device_add()函数增加设备。
其中的device_add_attrs(dev)函数完成对类成员中的设备属性初始化,具体程序如下:
-
static int device_add_attrs(struct device *dev)
-
{
-
struct class *class = dev->class;
-
const struct device_type *type = dev->type;
-
int error;
-
-
if (class) {
-
error = device_add_attributes(dev, class->dev_attrs);
-
if (error)
-
return error;
-
error = device_add_bin_attributes(dev, class->dev_bin_attrs);
-
if (error)
-
goto err_remove_class_attrs;
-
}
-
-
if (type) {
-
error = device_add_groups(dev, type->groups);
-
if (error)
-
goto err_remove_class_bin_attrs;
-
}
-
-
error = device_add_groups(dev, dev->groups);
-
if (error)
-
goto err_remove_type_groups;
-
-
return 0;
-
-
err_remove_type_groups:
-
if (type)
-
device_remove_groups(dev, type->groups);
-
err_remove_class_bin_attrs:
-
if (class)
-
device_remove_bin_attributes(dev, class->dev_bin_attrs);
-
err_remove_class_attrs:
-
if (class)
-
device_remove_attributes(dev, class->dev_attrs);
-
-
return error;
-
}
说明:
1) 由上面可知,dev成员中有class成员,但是class中只有对dev_attrs赋值了,dev成员中没有groups成员,所以此处执行的函数为device_add_attributes
(dev
, class->dev_attrs
),程序如下:
-
static int device_add_attributes(struct device *dev,
-
struct device_attribute *attrs)
-
{
-
int error = 0;
-
int i;
-
-
if (attrs) {
-
for (i = 0; attr_name(attrs[i]); i++) {
-
error = device_create_file(dev, &attrs[i]);
-
if (error)
-
break;
-
}
-
if (error)
-
while (--i >= 0)
-
device_remove_file(dev, &attrs[i]);
-
}
-
return error;
-
}
说明:
1) 最后是调用device_create_file
(dev
, &attrs
[i
]);产生文件的。此函数在其他文章中会介绍。
阅读(890) | 评论(0) | 转发(0) |