Device 与 platform device 在注册方法上有所不同。 Device 注册有两步,platform device注册也有两步,它们第一步相同,都是initialize设备, 但第二步有所不同,Device是直接调用device_add()函数来add设备,而platform device则调用platform_device_add()函数。 实际上,platform_device_add()里面也嵌套了device_add()函数(红色部分),不过在device_add()被调用之前,platform device要先注册它的resources。 就是下面蓝色的部分。
>>>>>>>>>>>>>>>>>>>> device的注册 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> void device_register(struct device *dev) { device_initialize(dev); return device_add(dev); } >>>>>>>>>>>>>>>>>>>>>>device_register的第一步, 初始化device>>>>>>>>>>>>>>>>>>>> void device_initialize(struct device *dev) { dev->kobj.kset = device_kset; kboject_init(&dev->kobj, &device_ktype); INIT_LIST_HEAD(&dev->dma_pools); mutex_init(&dev->mutex); lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock); INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); } >>>>>>>>备注: struct device_private *p;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> struct device_private { //hold the private to the driver core portions of the device structure struct klist klist_children; //containing all children of this device struct klist_node knode_parent; //node in sibling list struct klist_node knode_driver; //node in driver list struct klist_node knode_bus; //node in bus list void *driver_data; //private pointer for driver specific info. struct device *device; //pointer back to the struct class that this structure is associated with }; // Nothing outside of the driver core should ever touch these fields.
>>>>>>>>>>>>>>>>> device_register的第二步, 添加device>>>>>>>>>>>>>>>>>>>>>>>>> int device_add(struct device *dev) { struct device *parent =NULL; struct class_interface *class_intf; int error = -EINVAL; dev =get_device(dev); if(!dev) goto done; if(!dev->p){ error = device_private_init(dev); if(error) goto done; } /* for statically allocated devices, which should all be converted some day, we need to initialize the name. We prevent reading back the name, and force the use of dev_name() */ if(dev->init_name){ dev_set_name(dev, "%s", dev->init_name); dev->init_name =NULL; } if(!dev_name(dev)){ error = - EINVAL; goto name_error; } pr_debug("device: '%s' : %s\n", dev_name(dev), __func__); parent = getdevce(dev->parent); setup_parent(dev, parent); /*use paent numa_node*/ if(parent) set_dev_node(dev, dev_to_node(parent)); //first, register with generic layer, we require the name to be set before, and pass NULL error = kboject_add(&dev->kobj, dev->kobj.parent, NULL); if(error) goto Error; //notify platform of device entry if(platform_notify) platform_notify(dev); erro = device_create_file(dev, &uevent_attr); if(error) goto attrError; if(MAJOR(dev->devt)){ error = device_create_file(dev, &devt_attr); if(error) goto ueventattrError; error = device_create_sys_dev_entry(dev); if(error) goto devtattrError; devtmpfs_create_node(dev); } error = device_add_class_symlinks(dev); if(error) goto SymlinkError; error = device_add_attrs(dev); if(error) goto AttrsError; error = bus_add_device(dev); if(error) goto BusError; error = dpm_sysfs_add(dev); if(error) goto DPMError; device_pm_add(dev); / /Notify clients of device addtion. This call must come after dpm_sysf_add() and before kobject_uevent(). if(dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_ADD); bus_probe_device(dev); if(parent) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); if(dev->class){ mutex_lock(&dev->class->p->class_mutex); //tie the class to the device klist_add_tail(&dev->knode_class, &dev->class->p->class_devices); list_for_each_entry(class_intf, &dev->class->p->class_interfaces, node); if(class_intf->add_dev) class_intf->add_dev(dev, class_intf); mutex_unlock(&dev->class->class_mutex); }
done: put_device(dev); return error; DPMError: bus_remove_device(dev); BusError: device_remove_attrs(dev); AttrsError: device_remove_class_syslinks(dev); SymlinkError: if(MAJOR(dev->devt)) devtmpfs_delete_node(dev); if(MAJOR(dev->devt)) device_remover_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); name_error: kfree(dev->p); dev-> = NULL; goto done; } >>>>>>>>>>>>>>> platform_device 的注册>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // platform_device_register - add a platform-level device @pdev: platform device we're adding int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); //第一步与device完全相同 return platform_device_add(pdev); }
>>>>>>>>>>>>>>>>>>>platform_device_add()>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> int platform_device_add(struct platform_device *pdev) { int i, ret = 0; if(!pdev) return -EINVAL; if(!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; if(pdev->id != -1) dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); else dev_set_name(&pdev->dev, "%s", pdev->name); for( i = -; i < pdev->num_resources; i++){ struct resource *p, *r = &pdev->resource[i]; if( r->name == NULL ) r->name = dev_name(&pdev->dev); r->name = dev_name(&pdev->dev); p = r->parent; if(!p){ if(resource_type(r) == IORESOURCE_MEM) p = &iomem_resource; else if (resource_type(r) == IORESOURCE_IO) p = &ioport_resource; } if( p && insert_resource(p, r)){ printk(KERN_ERR "%s: failed to claim resource %d\n", dev_name(&pdev->dev), i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); if(ret == 0) return ret; failed: while( --i>=0){ struct resource *r = &pdev->resource[i]; unsigned long type = resouce_type(r); if(type==IORESOURCE_MEM)||type==IORESOURCE_IO) release_resource(r); } return ret; } }
|
|
来自: barry525 > 《linux api》