1. 程式人生 > >kobject,kset,子系統層次結構 、platform_device platform_driver

kobject,kset,子系統層次結構 、platform_device platform_driver

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的模型