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