个人对kobject的一点研究[2]

来源:互联网 发布:c 语言的socket 编辑:程序博客网 时间:2024/06/03 02:26
现在到bus_register了

注册的参数platform_bus_type如下所示
struct bus_type platform_bus_type = {
        .name                = "platform",
        .dev_attrs        = platform_dev_attrs,
        .match                = platform_match,
        .uevent                = platform_uevent,
        .suspend                = platform_suspend,
        .suspend_late        = platform_suspend_late,
        .resume_early        = platform_resume_early,
        .resume                = platform_resume,
};


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);

        //设置私有数据中kobj对象的名字
        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
        if (retval)
                goto out;

        //设置父容器为bus_kset,操作集为bus_ktype
        priv->subsys.kobj.kset = bus_kset;
        priv->subsys.kobj.ktype = &bus_ktype;
        priv->drivers_autoprobe = 1;

        //注册bus容器
        retval = kset_register(&priv->subsys);
        if (retval)
                goto out;

        //建立uevent属性文件
        retval = bus_create_file(bus, &bus_attr_uevent);
        if (retval)
                goto bus_uevent_fail;

        //建立devices目录
        priv->devices_kset = kset_create_and_add("devices", NULL,
                                                 &priv->subsys.kobj);
        if (!priv->devices_kset) {
                retval = -ENOMEM;
                goto bus_devices_fail;
        }

        //建立drivers目录
        priv->drivers_kset = kset_create_and_add("drivers", NULL,
                                                 &priv->subsys.kobj);
        if (!priv->drivers_kset) {
                retval = -ENOMEM;
                goto bus_drivers_fail;
        }

        //初始化klist_devices和klist_drivers链表
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
        klist_init(&priv->klist_drivers, NULL, NULL);

        //增加probe属性文件
        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_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;
}

在kset_register-> kobject_add_internal中

//提取父对象,因为没有设置父对象,所以为空
parent = kobject_get(kobj->parent);

//父容器存在则设置父对象,在上文中设置了父容器priv->subsys.kobj.kset = bus_kset
if (kobj->kset) {

        //检测是否已经设置父对象
        if (!parent)
                //无则使用父容器为父对象
                parent = kobject_get(&kobj->kset->kobj);

        //添加该kobj到父容器的链表中
        kobj_kset_join(kobj);

        //设置父对象
        kobj->parent = parent;
}

在retval = kset_register(&priv->subsys)完成之后platform在bus下的模型如下图

platform_bus.png
2009-01-19 01:31 上传
下载附件(84.78 KB)


有印象的话大家还记得在platform下面有两个目录devices和drivers吧~
现在就到这两个目录的注册了
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
注意这两条语句的头部
priv->devices_kset = kset_create_and_add
priv->drivers_kset = kset_create_and_add
可以清楚的看到bus_type_private下的devices_kset, drivers_kset分别连接到了devices,drivers的kset上

现在来看kset_create_and_add("devices", NULL,&priv->subsys.kobj);
struct kset *kset_create_and_add(const char *name,
                                 struct kset_uevent_ops *uevent_ops,
                                 struct kobject *parent_kobj)
//参数为"devices", NULL,&priv->subsys.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) {
                kfree(kset);
                return NULL;
        }
        return kset;
}
在kset_create 中比较重要的操作为
kset->kobj.ktype = &kset_ktype //设置了ktype,为kset_ktype
kset->kobj.parent = parent_kobj; //设置了父对象,为priv->subsys.kobj,也就是platform_bus_type->p->subsys.kobj
kset->kobj.kset = NULL;    //设置父容器为空
在kset_register中

//提取父对象
parent = kobject_get(kobj->parent); //在之前设置为了

//父容器存在则设置父对象,由于父容器为空,不执行以下代码
if (kobj->kset) {

        //检测是否已经设置父对象
        if (!parent)
                //无则使用父容器为父对象
                parent = kobject_get(&kobj->kset->kobj);

        //添加该kobj到父容器的链表中
        kobj_kset_join(kobj);

        //设置父对象
        kobj->parent = parent;
}

至此, devices的模型就建立好了,drivers模型的建立和devices是一致的,只是名字不同而已,我就不复述了,建立好的模型如下

platform_devices_drivers.png
2009-01-19 01:31 上传
下载附件(111.97 KB)


好了~  到了这里,bus,devices和platform的基础模型就就建立好了,就等设备来注册了
在platform模型设备的建立中,需要2个部分的注册,驱动的注册和设备的注册
platform_device_register(&test_device);        
platform_driver_register(&test_driver);
首先看platform_device_register
注册参数为test_device,结构如下
static struct platform_device test_device = {
        .name = "test_ts",
        .id = -1,
        //. resource
        //.dev
};
这个结构主要描述了设备的名字,ID和资源和私有数据,其中资源和私有数据我们在这里不使用,将在别的文章中进行讲解

int platform_device_register(struct platform_device *pdev)
{
        //设备属性的初始化
        device_initialize(&pdev->dev);
        //将设备添加进platform里
        return platform_device_add(pdev);
}

void device_initialize(struct device *dev)
{
        dev->kobj.kset = devices_kset;                   //设置kset为devices_kset,则将设备挂接上了devices目录
        kobject_init(&dev->kobj, &device_ktype);                    //初始化kobeject,置ktype为device_ktype
        klist_init(&dev->klist_children, klist_children_get,
                   klist_children_put);
        INIT_LIST_HEAD(&dev->dma_pools);
        INIT_LIST_HEAD(&dev->node);
        init_MUTEX(&dev->sem);
        spin_lock_init(&dev->devres_lock);
        INIT_LIST_HEAD(&dev->devres_head);
        device_init_wakeup(dev, 0);
        set_dev_node(dev, -1);
}

int platform_device_add(struct platform_device *pdev)
{
        int i, ret = 0;

        if (!pdev)
                return -EINVAL;

        //检测是否设置了dev中的parent,无则赋为platform_bus
        if (!pdev->dev.parent)
                pdev->dev.parent = &platform_bus;

        //设置dev中的bus为platform_bus_type
        pdev->dev.bus = &platform_bus_type;

        //检测id,id为-1表明该设备只有一个,用设备名为bus_id
        //不为1则表明该设备有数个,需要用序号标明bus_id
        if (pdev->id != -1)
                snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
                         pdev->id);
        else
                strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

        //增加资源到资源树中
        for (i = 0; i < pdev->num_resources; i++) {
                struct resource *p, *r = &pdev->resource;

                if (r->name == NULL)
                        r->name = pdev->dev.bus_id;

                p = r->parent;
                if (!p) {
                        if (r->flags & IORESOURCE_MEM)
                                p = &iomem_resource;
                        else if (r->flags & IORESOURCE_IO)
                                p = &ioport_resource;
                }

                if (p && insert_resource(p, r)) {
                        printk(KERN_ERR "%s: failed to claim resource %d\n",pdev->dev.bus_id, i);
                        ret = -EBUSY;
                        goto failed;
                }
        }

        pr_debug("Registering platform device '%s'. Parent at %s\n",pdev->dev.bus_id, pdev->dev.parent->bus_id);

        //添加设备到设备层次中
        ret = device_add(&pdev->dev);
        if (ret == 0)
                return ret;

failed:
        while (--i >= 0)
                if (pdev->resource.flags & (IORESOURCE_MEM|IORESOURCE_IO))
                        release_resource(&pdev->resource);
        return ret;
}



int device_add(struct device *dev)
{
        struct device *parent = NULL;
        struct class_interface *class_intf;
        int error;

        dev = get_device(dev);
        if (!dev || !strlen(dev->bus_id)) {
                error = -EINVAL;
                goto Done;
        }

        pr_debug("device: '%s': %s\n", dev->bus_id, __func__);

        //取得上层device,而dev->parent的赋值是在platform_device_add中的pdev->dev.parent = &platform_bus完成的
        parent = get_device(dev->parent);

        //以上层devices为准重设dev->kobj.parent
        setup_parent(dev, parent);

        if (parent)
                set_dev_node(dev, dev_to_node(parent));

        //设置dev->kobj的名字和父对象,并建立相应目录
        error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
        if (error)
                goto Error;

        if (platform_notify)
                platform_notify(dev);

        //一种新型的通知机制,但是platform中没有设置相应的结构,所以在这里跳过
        /* notify clients of device entry (new way) */
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);

        //建立uevent文件
        error = device_create_file(dev, &uevent_attr);
        if (error)
                goto attrError;

        //设备有设备号则建立dev文件
        if (MAJOR(dev->devt)) {
                error = device_create_file(dev, &devt_attr);
                if (error)
                        goto ueventattrError;
        }
        //建立subsystem连接文件连接到所属class
        error = device_add_class_symlinks(dev);
        if (error)
                goto SymlinkError;
        //添加dev的描述文件
        error = device_add_attrs(dev);
        if (error)
                goto AttrsError;
        //添加链接文件至所属bus
        error = bus_add_device(dev);
        if (error)
                goto BusError;
        //添加power文件
        error = device_pm_add(dev);
        if (error)
                goto PMError;
        kobject_uevent(&dev->kobj, KOBJ_ADD);

        //检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,所以不会进行匹配
        bus_attach_device(dev);
        if (parent)
                klist_add_tail(&dev->knode_parent, &parent->klist_children);

        if (dev->class) {
                down(&dev->class->sem);
                list_add_tail(&dev->node, &dev->class->devices);

                list_for_each_entry(class_intf, &dev->class->interfaces, node)
                        if (class_intf->add_dev)
                                class_intf->add_dev(dev, class_intf);
                up(&dev->class->sem);
        }
Done:
        put_device(dev);
        return error;
PMError:
        bus_remove_device(dev);
BusError:
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_attrs(dev);
AttrsError:
        device_remove_class_symlinks(dev);
SymlinkError:
        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);
        goto Done;
}

static void setup_parent(struct device *dev, struct device *parent)
{
        struct kobject *kobj;
        //取得上层device的kobj
        kobj = get_device_parent(dev, parent);
        //kobj不为空则重设dev->kobj.parent
        if (kobj)
                dev->kobj.parent = kobj;
}


static struct kobject *get_device_parent(struct device *dev,
                                         struct device *parent)
{
        int retval;

        //因为dev->class为空,所以跳过这段代码
        if (dev->class) {
                struct kobject *kobj = NULL;
                struct kobject *parent_kobj;
                struct kobject *k;

                if (parent == NULL)
                        parent_kobj = virtual_device_parent(dev);
                else if (parent->class)
                        return &parent->kobj;
                else
                        parent_kobj = &parent->kobj;

                spin_lock(&dev->class->class_dirs.list_lock);
                list_for_each_entry(k, &dev->class->class_dirs.list, entry)
                        if (k->parent == parent_kobj) {
                                kobj = kobject_get(k);
                                break;
                        }
                spin_unlock(&dev->class->class_dirs.list_lock);
                if (kobj)
                        return kobj;

                k = kobject_create();
                if (!k)
                        return NULL;
                k->kset = &dev->class->class_dirs;
                retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
                if (retval < 0) {
                        kobject_put(k);
                        return NULL;
                }
                return k;
        }

        if (parent)
                //返回上层device的kobj
                return &parent->kobj;
        return NULL;
}

在bus_attach_device中虽然没有成功进行匹配,但是有很重要的一步为之后正确的匹配打下基础
void bus_attach_device(struct device *dev)
{
        struct bus_type *bus = dev->bus;
        int ret = 0;

        if (bus) {
                if (bus->p->drivers_autoprobe)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
                        klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
        }
}

klist_add_tail(&dev->knode_bus, &bus->p->klist_devices)就是这一行
在这一行代码中将设备挂载到了bus下的devices链表下,这样,当驱动请求匹配的时候,platform总线就会历遍devices链表为驱动寻找合适的设备


现在来看一下test_device的模型
test_device.png
2009-01-19 01:31 上传
下载附件(141.22 KB)



然后platform_driver_unregister,他的参数 test_driver的结构如下
static struct platform_driver test_driver = {
        .probe                = test_probe,
        .remove                = test_remove,
        .driver                = {
                .name        = "test_ts",
                .owner        = THIS_MODULE,
        },
};

int platform_driver_register(struct platform_driver *drv)
{
        drv->driver.bus = &platform_bus_type;
        if (drv->probe)
                drv->driver.probe = platform_drv_probe;
        if (drv->remove)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;
        if (drv->suspend)
                drv->driver.suspend = platform_drv_suspend;
        if (drv->resume)
                drv->driver.resume = platform_drv_resume;
        return driver_register(&drv->driver);
}

从上面代码可以看出,在platform_driver中设置了probe, remove, shutdown, suspend或resume函数的话
则drv->driver也会设置成platform对应的函数

int driver_register(struct device_driver *drv)
{
        int ret;
        struct device_driver *other;
        
        //检测总线的操作函数和驱动的操作函数是否同时存在,同时存在则提示使用总线提供的操作函数
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown))
                printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);

        //检测是否已经注册过
        other = driver_find(drv->name, drv->bus);
        if (other) {
                put_driver(other);
                printk(KERN_ERR "Error: Driver '%s' is already registered, “"aborting...\n", drv->name);
                return -EEXIST;
        }

        //添加驱动到总线上
        ret = bus_add_driver(drv);
        if (ret)
                return ret;

        
        ret = driver_add_groups(drv, drv->groups);
        if (ret)
                bus_remove_driver(drv);
        return ret;
}



int bus_add_driver(struct device_driver *drv)
{
        struct bus_type *bus;
        struct driver_private *priv;
        int error = 0;

        //取bus结构
        bus = bus_get(drv->bus);
        if (!bus)
                return -EINVAL;

        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

        //分配驱动私有数据
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                error = -ENOMEM;
                goto out_put_bus;
        }

        //初始化klist_devices链表
        klist_init(&priv->klist_devices, NULL, NULL);

        //互相关联
        priv->driver = drv;
        drv->p = priv;

        //设置私有数据的父容器,在这一步中,设置了kset为platform下的drivers_kset结构,也就是drivers呢个目录
        priv->kobj.kset = bus->p->drivers_kset;

        //初始化kobj对象,设置容器操作集并建立相应的目录,这里由于没有提供parent,所以会使用父容器中的kobj为父对象
        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                                     "%s", drv->name);
        if (error)
                goto out_unregister;

        //检测所属总线的drivers_autoprobe属性是否为真
        //为真则进行与设备的匹配,到这里,就会与我们之前注册的test_device连接上了,至于如何连接,进行了什么操作,将在别的文章中详细描述
        if (drv->bus->p->drivers_autoprobe) {
                error = driver_attach(drv);
                if (error)
                        goto out_unregister;
        }

        //挂载到所属总线驱动链表上
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        module_add_driver(drv->owner, drv);

        //建立uevent属性文件
        error = driver_create_file(drv, &driver_attr_uevent);
        if (error) {
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",
                        __func__, drv->name);
        }

        //建立设备属性文件
        error = driver_add_attrs(bus, drv);
        if (error) {
                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);
        }
        error = add_bind_files(drv);
        if (error) {
                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);
        }

        kobject_uevent(&priv->kobj, KOBJ_ADD);
        return error;
out_unregister:
        kobject_put(&priv->kobj);
out_put_bus:
        bus_put(bus);
        return error;
}

到这里test_driver的模型就建立好了,图就是最上面的层次图,我就不再贴了

到这里一个基本的框架就建立起来了~
原创粉丝点击