前部分设备模型初始化
为了便于阅读,删掉部分代码,只留关键的过程:
static int initf_dm(void)
{
int ret;
ret = dm_init_and_scan(true);
if (ret)
return ret;
return 0;
}
该函数调用了 dm_init_and_scan();并且传入的参数为true,uboot中对该函数的注释如下:
/**
* dm_init_and_scan() - Initialise Driver Model structures and scan for devices
*
* This function initialises the roots of the driver tree and uclass trees,
* then scans and binds available devices from platform data and the FDT.
* This calls dm_init() to set up Driver Model structures.
*
* @pre_reloc_only: If true, bind only nodes with special devicetree properties,
* or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
* @return 0 if OK, -ve on error
*/
下面看具体的执行过程,删除参数检查等相关代码,如下图:
int dm_init_and_scan(bool pre_reloc_only)
{
ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE));
ret = dm_scan_platdata(pre_reloc_only);
ret = dm_extended_scan_fdt(gd->fdt_blob, pre_reloc_only);
ret = dm_scan_other(pre_reloc_only);
}
该函数一共调用了四个函数,首先看第一个函数 dm_init(),该函数中涉及到关键的结构体struct global_data,该结构体的具体作用此处不做展开,只看结构体中和DM相关的部分
struct udevice *dm_root; /* Root instance for Driver Model */
struct udevice *dm_root_f; /* Pre-relocation root instance */
struct list_head uclass_root; /* Head of core tree */
#define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root)
#define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root)
删除参数检查和返回值检查等代码,注释和实现过程如下:
/**
* dm_init() - Initialise Driver Model structures
* This function will initialize roots of driver tree and class tree.
* This needs to be called before anything uses the DM
* @of_live: Enable live device tree
* @return 0 if OK, -ve on error
*/
int dm_init(bool of_live)
{
int ret;
if (gd->dm_root) {
dm_warn("Virtual root driver already exists!\n");
return -EINVAL;
}
INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
#if CONFIG_IS_ENABLED(OF_CONTROL)
DM_ROOT_NON_CONST->node = offset_to_ofnode(0);
#endif
ret = device_probe(DM_ROOT_NON_CONST);
return 0;
}
该函数又调用了device_bind_by_name()函数
/**
* device_bind_by_name: Create a device and bind it to a driver
*
* This is a helper function used to bind devices which do not use device
* tree.
*
* @parent: Pointer to device's parent
* @pre_reloc_only: If true, bind the driver only if its DM_FLAG_PRE_RELOC flag
* is set. If false bind the driver always.
* @info: Name and platdata for this device
* @devp: if non-NULL, returns a pointer to the bound device
* @return 0 if OK, -ve on error
*/
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
const struct driver_info *info, struct udevice **devp)
{
struct driver *drv;
uint platdata_size = 0;
drv = lists_driver_lookup_name(info->name);
if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
return -EPERM;
#if CONFIG_IS_ENABLED(OF_PLATDATA)
platdata_size = info->platdata_size;
#endif
return device_bind_common(parent, drv, info->name,
(void *)info->platdata, 0, ofnode_null(), platdata_size,
devp);
}
该函数最终调用了device_bind_common()函数
static int device_bind_common(struct udevice *parent