一个类是一个设备的高层视图,它抽象掉了底层的实现细节。例如,在驱动层面时,你可能会见到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
]
)
;产生文件的。此函数在其他文章中会介绍。