kobject,kset,子系統層次結構 、platform_device platform_driver
阿新 • • 發佈:2019-01-05
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的模型