谨以此文纪念过往的岁月 一.前言 在前面学习过如何去注册新的bus,那仅仅是应用,在该文中我们将深入去理解bus是如何注册,如何使用的。在该文中不再讲述kset,kobject等的关系,如何去理解这两者的关系,google或baidu一下。 二.bus的parent 所有的bus类型均会在linux的sysfs中留下痕迹,均会在/sys/bus中留下关于自己总线的信息。 2.1 /sys/bus文件夹得创建 在bus.c文件中buses_init函数会创建/sys/bus文件夹,该函数在系统初始化时被调用,那来看一下这个函数。 int __init buses_init(void) { bus_kset = kset_create_and_add('bus', &bus_uevent_ops, NULL); if (!bus_kset) return -ENOMEM; return 0; } 函数很简单,其会调用kset_create_and_add来实现创建文件夹。 参数说明: name : 在/sys下创建文件夹的名称 uevent_ops : 这个参数比较难理解,其实就是一些事件处理函数。以上面的bus_uevent_ops为例。 static int bus_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); if (ktype == &bus_ktype) return 1; return 0; } static struct kset_uevent_ops bus_uevent_ops = { .filter = bus_uevent_filter, }; 其就提供了一种事件处理方法,即过滤事件处理。 parent_kobj : 这个参数为kset所指向的父kobj。 struct kset *kset_create_and_add(const char *name,struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj) { struct kset *kset; int error; kset = kset_create(name, uevent_ops, parent_kobj); if (!kset) return NULL; error = kset_register(kset); if (error) { kfree(kset); return NULL; } return kset; } kset只是kobject的容器,而kobject才是真正的实体,而每一个kobject则会对应一个文件夹,以/sys/bus为例。 static struct kset *kset_create(const char *name,struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj) { struct kset *kset; kset = kzalloc(sizeof(*kset), GFP_KERNEL); if (!kset) return NULL; kobject_set_name(&kobj, name); --设置kobject名称,也可以认为是文件夹的名称 kset->uevent_ops = uevent_ops; kset->kobj.parent = parent_kobj; kset->kobj.ktype = &kset_ktype; --设置实体类型,现在创建的kset为所有bus的父kset,所以该kset的父实体为NULL,而其kset类型为通用kset类型,而非bus_ktype。 kset->kobj.kset = NULL; return kset; --返回新的kset,该kset为所有bus的父kset。 } 上述函数为create kset,创建完成后需要注册kset。 int kset_register(struct kset *k) { int err; if (!k) return -EINVAL; kset_init(k); -- kset_init -> kobject_init_internal err = kobject_add_internal(kobj); if (err) return err; kobject_uevent(kobj, KOBJ_ADD); return 0; } void kset_init(struct kset *k) { kobject_init_internal(kobj); --初始化实体 INIT_LIST_HEAD(list); --初始化kset链表 spin_lock_init(list_lock); --初始自旋锁 } static void kobject_init_internal(struct kobject *kobj) { if (!kobj) return; kref_init(&kref); --初始化kobject计数器 INIT_LIST_HEAD(&entry); --初始化链表,用于将该kobj挂载到kset的链表中。 kobj->state_in_sysfs = 0; --下面的几个flag用于标示kobject初始化程度。 kobj->state_add_uevent_sent = 0; kobj->state_remove_uevent_sent = 0; kobj->state_initialized = 1; } 在kset init complete后,就是创建/sysfs中了,说白了就是创建一文件夹。仍以/sys/bus为例。 static int kobject_add_internal(struct kobject *kobj) { int error = 0; struct kobject *parent; parent = kobject_get(kobj->parent); --记住这里的实体的父实体为空,而对于某一个类型的bus而言,其父实体即为bus kobject。下面在针对某一bus再说。 if (kobj->kset) { --如果kobj->kset存在则将该kobject加入到kset链表中 if (!parent) --如果该实体的parent kobject不存在,则设置该kobject的parnet为其容器的实体。 parent = kobject_get(&kset->kobj); kobj_kset_join(kobj); kobj->parent = parent; } error = create_dir(kobj); --创建文件夹,以实体名命名的文件夹 kobj->state_in_sysfs = 1; return error; } static void kobj_kset_join(struct kobject *kobj) { if (!kobj->kset) return; kset_get(kobj->kset); spin_lock(&kset->list_lock); list_add_tail(&entry, &kset->list); spin_unlock(&kset->list_lock); } 到此dir被创建了。其文件夹的创建于kobject和kset息息相关。其实kobject以及kset存在都是为了更好的去管理设备。 2.2 注册bus 在前文中bus注册,对bus_register这个函数稍稍讲了一下,现在再回过头去仔细看这个函数。 以前对这个结构体没有仔细看,现在在看一下。 struct bus_type_private { struct kset subsys; --即该bus的kset,其parent会指向bus_kset struct kset *drivers_kset; --该kset亦如总bus创建一样,为该bus下的driver创建文件夹以及父实体容器。 struct kset *devices_kset; --类似上面 struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus; --该bus_type_private指向的bus }; int bus_register(struct bus_type *bus) { int retval; struct bus_type_private *priv; priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); if (!priv) return -ENOMEM; priv->bus = bus; bus->p = priv; BLOCKING_INIT_NOTIFIER_HEAD(&bus_notifier); retval = kobject_set_name(&subsys.kobj, '%s', bus->name); --设置kobject name,也是在/sys/bus/ 下创建文件夹的名称。 if (retval) goto out; priv->subsys.kobj.kset = bus_kset; --指向bus_kset priv->subsys.kobj.ktype = &bus_ktype; --实体类型 priv->drivers_autoprobe = 1; --自动探测。 retval = kset_register(&subsys); --注册kset,这里的实体的parent是存在的,会将该实体的链表头添加如父容器的链表中。 if (retval) goto out; retval = bus_create_file(bus, &bus_attr_uevent); --创建属性文件,在该总线文件夹下会有一个名为uevent的文件。 if (retval) goto bus_uevent_fail; priv->devices_kset = kset_create_and_add('devices', NULL,&subsys.kobj); --drvier和device的父实体均为该总线的实体。 if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; } priv->drivers_kset = kset_create_and_add('drivers', NULL,&subsys.kobj); if (!priv->drivers_kset) { retval = -ENOMEM; goto bus_drivers_fail; } klist_init(&klist_devices, klist_devices_get, klist_devices_put); klist_init(&klist_drivers, NULL, NULL); retval = add_probe_files(bus); --添加probe的属性文件 if (retval) goto bus_probe_files_fail; retval = bus_add_attrs(bus); --添加额外的属性文件 if (retval) goto bus_attrs_fail; pr_debug('bus: '%s': registered\n', bus->name); return 0; bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: kset_unregister(bus->p->drivers_kset); bus_drivers_fail: kset_unregister(bus->p->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: kset_unregister(p->subsys); kfree(bus->p); out: return retval; } 为bus创建属性文件。 int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) { int error; if (bus_get(bus)) { error = sysfs_create_file(p->subsys.kobj, &attr); bus_put(bus); } else error = -EINVAL; return error; } 三.总结 与以前的学习相互印证,好懂很多。 阅读(614) | 评论(0) | 转发(1) |
|
|