bus_register

上面分析了 kobject.kset,ktype.这三个结构联合起来一起构成了 整个设备模型的基石.而 bus.device.device_driver.则是基于 kobject.kset.ktype之上的架构.在这里,总线,设备,驱动被有序的组和在一起.
Bus.device.device_driver三者之间的关系如下图所示:
 
如上图所示 .struct bus_typep->drivers_kset(struct kset)指向注册在上面的驱动程序 .它的 p->device_kset(struct kset)上挂着注册在上面的设备 .每次有一个新的设备注册到上面 ,都会去匹配右边的驱动 ,看是否能匹配上 .如果匹配成功 ,则将设备结构的 is_registerd域置为 0.然后将设备添加到驱动的 p->klist_devices.同理 ,每注册一个驱动 ,都会去匹配左边的设备 ,.如果匹配成功 ,将则设备加到驱动的 p->klist_devices.再将设备的 is_registerd置为 0/
这就是 linux设备模型用来管理设备和驱动的基本架构 . 我们来跟踪一下代码来看下详细的操作 .
 
注册一个总线的接口为bus_register().我们照例分段分析:
 
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(&priv->bus_notifier);
 
     retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
     if (retval)
         goto out;
 
     priv->subsys.kobj.kset = bus_kset;                    
     priv->subsys.kobj.ktype = & bus_ktype;
     priv->drivers_autoprobe = 1;
 
     retval = kset_register(&priv->subsys);
     if (retval)
         goto out;
首先,先为struct bus_type的私有区分配空间,然后将其和struct bus_type关联起来. 由于struct bus_type也要在sysfs文件中表示一个节点,因此,它也内嵌也一个kset的结构.这就是priv->subsys.
首先,它为这个kset的名称赋值为 bus的名称,然后将priv->subsys.kobj.kset指向bus_kset. priv->subsys.kobj.ktype指向bus_ktype;然后调用kset_reqister()将priv->subsys注册.这里涉及到的接口都在之前分析过.注册过后,应该会在bus_kset所表示的目录下创建一个总线名称的目录.并且用户空间的hotplug应该会检测到一个add事件.我们来看一下 bus_kset到底指向的是什么:
     bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
从此可以看出.这个 bus_kset在sysfs中的结点就是/sys/bus.在这里注册的struct bus_types就会在/sys/bus/下面出现.
 
     retval = bus_create_file(bus, &bus_attr_uevent);
     if (retval)
         goto bus_uevent_fail;
bus_create_file()就是在priv->subsys.kobj的这个kobject上建立一个普通属性的文件.这个文件的属性对应在bus_attr_uevent. 读写操作对应在priv->subsys.kobj.ktype中.我们到后面才统一分析bus注册时候的文件创建
 
     priv->devices_kset = kset_create_and_add("devices", NULL,
                             &priv->subsys.kobj);
     if (!priv->devices_kset) {
         retval = -ENOMEM;
         goto bus_devices_fail;
     }
 
     priv->drivers_kset = kset_create_and_add("drivers", NULL,
                             &priv->subsys.kobj);
     if (!priv->drivers_kset) {
         retval = -ENOMEM;
         goto bus_drivers_fail;
     }
 
     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
     klist_init(&priv->klist_drivers, NULL, NULL);
这段代码会在bus所在的目录下建立两个目录,分别为devices和drivers.并初始化挂载设备和驱动的链表
 
     retval = add_probe_files(bus);
     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_attr_drivers_probe, bus_attr_drivers_autoprobe.注册bus_type中的属性建立文件
 
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(&bus->p->subsys);
     kfree(bus->p);
out:
     return retval;
}
这段代码为出错处理;
 
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 = kset_create(name, uevent_ops, parent_kobj);
     if (!kset)
         return NULL;
     //注册kset
     error = kset_register(kset);
     if (error)
     {
         //如果注册失败,释放kset
         kfree(kset);
         return NULL;
     }
     return kset;
}
 
Kset_create()用来创建一个struct kset结构.代码如下:
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(&kset->kobj, name);
     kset->uevent_ops = uevent_ops;
     kset->kobj.parent = parent_kobj;
 
     kset->kobj.ktype = & kset_ktype;
     kset->kobj.kset = NULL;
 
     return kset;
}
我们注意,在这里创建kset时.为其内嵌的kobject指定其struct kobj_type ktype结构为 kset_ktype.这个结构的定义如下:
static struct kobj_type kset_ktype = {
     .sysfs_ops    = & kobj_sysfs_ops,
     .release = kset_release,
};
属性文件的读写操作全部都包含在sysfs_ops成员里.kobj_sysfs_ops的定义如下:
struct sysfs_ops kobj_sysfs_ops = {
     .show    = kobj_attr_show,
     .store   = kobj_attr_store,
};
 
创建好了kset之后,会调用kset_register().这个函数就是kset操作的核心代码了.如下:
int kset_register(struct kset *k)
{
     int err;
 
     if (!k)
         return -EINVAL;
 
     kset_init(k);
     err = kobject_add_internal(&k->kobj);
     if (err)
         return err;
     kobject_uevent(&k->kobj, KOBJ_ADD);
     return 0;
}
 
void kset_init(struct kset *k)
{
    kobject_init_internal(&k->kobj);             //只是对kobj中的成员变量做一些赋值的初始化
    INIT_LIST_HEAD(&k->list);
    spin_lock_init(&k->list_lock);
}
 
 
static int kobject_add_internal(struct kobject *kobj)
{
     int error = 0;
     struct kobject *parent;
 
     if (!kobj)
         return -ENOENT;
     //如果kobject的名字为空.退出
     if (!kobj->name || !kobj->name[0]) {
         pr_debug("kobject: (%p): attempted to be registered with empty "
               "name!/n", kobj);
         WARN_ON(1);
         return -EINVAL;
     }
 
     //取kobject的父结点
     parent = kobject_get(kobj->parent);
     //如果kobject的父结点没有指定,就将kset->kobject做为它的父结点
     /* join kset if set, use it as parent if we do not already have one */
     if (kobj->kset) {
         if (!parent)
              parent = kobject_get(&kobj->kset->kobj);
         kobj_kset_join(kobj);
         kobj->parent = parent;
     }
     //调试用
     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",
          kobject_name(kobj), kobj, __FUNCTION__,
          parent ? kobject_name(parent) : "<NULL>",
          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
 
     //在sysfs中创建kobject的相关元素
     error = create_dir(kobj);                        
     if (error) {
         //v如果创建失败。减少相关的引用计数
         kobj_kset_leave(kobj);
         kobject_put(parent);
         kobj->parent = NULL;
 
         /* be noisy on error issues */
         if (error == -EEXIST)
              printk(KERN_ERR "%s failed for %s with "
                     "-EEXIST, don't try to register things with "
                     "the same name in the same directory./n",
                     __FUNCTION__, kobject_name(kobj));
         else
              printk(KERN_ERR "%s failed for %s (%d)/n",
                     __FUNCTION__, kobject_name(kobj), error);
         dump_stack();
     } else
         //如果创建成功。将state_in_sysfs建为1。表示该object已经在sysfs中了
         kobj->state_in_sysfs = 1;
 
     return error;
}
 
这段代码比较简单,它主要完成kobject父结点的判断和选定,然后再调用create_dir()在sysfs创建相关信息。该函数代码如下:
static int create_dir(struct kobject *kobj)
{
     int error = 0;
     if (kobject_name(kobj)) {
          //为kobject创建目录
         error = sysfs_create_dir(kobj);
         if (!error) {
              //为kobject->ktype中的属性创建文件
              error = populate_dir(kobj);
              if (error)
                   sysfs_remove_dir(kobj);
         }
     }
     return error;
}
 
int sysfs_create_dir(struct kobject * kobj)
{
     struct sysfs_dirent *parent_sd, *sd;
     int error = 0;
 
     BUG_ON(!kobj);
     /*如果kobject的parnet存在。就 在目录点的目录下创建这个目录。如果没有父结点不存在,就在/sys下面创建结点。*/
     if (kobj->parent)
         parent_sd = kobj->parent->sd;
     else
         parent_sd = &sysfs_root;
 
     //在sysfs中创建目录
     //create_dir()就是在sysfs中创建目录的接口,在之前已经详细分析过了
     error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
     if (!error)
         kobj->sd = sd;
     return error;
}
接着看为kobject->ktype中的属性创建文件。这是在populate_dir()中完成的。代码如下:
static int populate_dir(struct kobject *kobj)
{
     struct kobj_type *t = get_ktype(kobj);
     struct attribute *attr;
     int error = 0;
     int i;
 
     if (t && t->default_attrs) {
         for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
              error = sysfs_create_file(kobj, attr);
              if (error)
                   break;
         }
     }
     return error;
}
这段代码比较简单。它遍历ktype中的属性。然后为其建立文件。请注意:文件的操作最后都会回溯到ktype->sysfs_ops的show和store这两个函数中.
假如对于上面的bus_register()函数传入的参数为:
struct bus_type ldd_bus_type = {
        .name = "ldd",
        .match = ldd_match,
        .hotplug  = ldd_hotplug,
};
则通过bus_register()函数调用后,在/sys/bus/目录下出现的框图大概是这样的:
。。。。
在kset_init()里会初始化kset中的其它字段.然后调用kobject_add_internal()为其内嵌的kobject结构建立空间层次结构.之后因为添加了kset.会产生一个事件.这个事件是通过用户空间的hotplug程序处理的.这就是kset明显不同于kobject的地方.
 
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值