device node结构体转换成platform_device结构体
Posted 正在起飞的蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了device node结构体转换成platform_device结构体相关的知识,希望对你有一定的参考价值。
1、函数调用关系
of_platform_default_populate_init()
of_find_node_by_path() //根据路径查找device_node结构体
of_platform_default_populate() //实例化每个device_node结构体成platform_device结构体
of_platform_populate() //获取根节点的device_node结构体,遍历每个节点,都转换成platform_device结构体
of_platform_bus_create()
of_device_is_compatible() //检查节点的compatible属性是否和amba总线匹配
of_amba_device_create() //创建amba总线的struct amba_device
of_platform_device_create_pdata() //将device_node结构体转换成platform_device结构体
of_device_allocc() //示例化platform_device结构体,将device_node中的属性值转换成platform_device结构体里的resource资源
of_device_add() //注册构建好的platform_device结构体到platform总线
for_each_child_of_node() //遍历节点的子节点
of_platform_bus_create() //将device_node结构体转换成platform_device结构体
(1)
device_node结构体不止可以转换为platform总线的device,还可以转换成amba总线上的设备,具体转换为何种总线上的设备要根据节点的compatible属性,默认是转换成platform总线的devic
e;
(2)of_platform_bus_create()函数这里是递归调用,因为设备树的数据组织方式是树形的,很适合递归的方式去访问;
(3)设备树的数据组织方式参考博客:《设备树的树形结构到底是怎样体现的?》;
2、of_platform_default_populate_init()函数
static int __init of_platform_default_populate_init(void)
struct device_node *node;
//判断dtb是否已经转换成struct device_node结构体
if (!of_have_populated_dt())
return -ENODEV;
//解析reserved-memory节点,这个节点是告诉内核这部分内存保留,不要去使用
//一般这部分内存就是存放dtb数据本身
node = of_find_node_by_path("/reserved-memory");
if (node)
node = of_find_compatible_node(node, NULL, "ramoops");
if (node)
of_platform_device_create(node, NULL, NULL);
/* 实例化每个device_node结构体成platform_device结构体 */
of_platform_default_populate(NULL, NULL, NULL);
return 0;
arch_initcall_sync(of_platform_default_populate_init);
(1)函数本身没有做转换的工作,主要是做一些前期的判断,以及处理reserved-memory节点;
(2)arch_initcall_sync宏:将of_platform_default_populate_init函数赋予".initcall3s.init"段属性,结果就是of_platform_default_populate_init函数会在内核启动过程中被调用;
3、of_platform_populate()函数
/**
* of_platform_bus_create() - Create a device for a node and its children.
* @bus: device node of the bus to instantiate
* @matches: match table for bus nodes
* @lookup: auxdata table for matching id and platform_data with device nodes
* @parent: parent for new device, or NULL for top level.
* @strict: require compatible property
*
* Creates a platform_device for the provided device_node, and optionally
* recursively create devices for all the child nodes.
*/
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
/* 确保节点有compatible属性,这是用于和总线匹配的*/
if (strict && (!of_get_property(bus, "compatible", NULL)))
pr_debug("%s() - skipping %s, no compatible prop\\n",
__func__, bus->full_name);
return 0;
//检查该节点是否已经被实例化过
if (of_node_check_flag(bus, OF_POPULATED_BUS))
pr_debug("%s() - skipping %s, already populated\\n",
__func__, bus->full_name);
return 0;
//遍历节点,因为传进来lookup是NULL,实际这段代码没起作用
auxdata = of_dev_lookup(lookup, bus);
if (auxdata)
bus_id = auxdata->name;
platform_data = auxdata->platform_data;
//判断节点的compatible属性是否是"arm,primecell"
//如果compatible属性匹配上则表示该节点需要注册到amba总线上
if (of_device_is_compatible(bus, "arm,primecell"))
/*
* Don't return an error here to keep compatibility with older
* device tree files.
*/
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
//将device_node结构体转换成platform_device结构体
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;
//遍历节点的子节点,递归调用of_platform_bus_create()函数进行device_node转换
for_each_child_of_node(bus, child)
pr_debug(" create child: %s\\n", child->full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc)
of_node_put(child);
break;
//设置device_node节点的状态,改为已经向总线注册过的状态
of_node_set_flag(bus, OF_POPULATED_BUS);
return rc;
4、of_platform_device_create_pdata()函数
static struct platform_device *of_platform_device_create_pdata(struct device_node *np,
const char *bus_id,void *platform_data,struct device *parent)
struct platform_device *dev;
//判断该节点的status属性是否是okay
//设置节点的标志位OF_POPULATED,表示已经实例化
if (!of_device_is_available(np) ||
of_node_test_and_set_flag(np, OF_POPULATED))
return NULL;
//定义并初始化一个platform_device结构体
//platform_device结构体会解析device_node结构体进行填充
dev = of_device_alloc(np, bus_id, parent);
if (!dev)
goto err_clear_flag;
//设置节点的总线属性是platform总线
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
of_dma_configure(&dev->dev, dev->dev.of_node);
of_msi_configure(&dev->dev, dev->dev.of_node);
//将构建的platform_device结构体注册到platform总线
if (of_device_add(dev) != 0)
of_dma_deconfigure(&dev->dev);
platform_device_put(dev);
goto err_clear_flag;
return dev;
err_clear_flag:
of_node_clear_flag(np, OF_POPULATED);
return NULL;
5、of_device_alloc()函数
struct platform_device *of_device_alloc(struct device_node *np,
const char *bus_id,
struct device *parent)
struct platform_device *dev;
int rc, i, num_reg = 0, num_irq;
struct resource *res, temp_res;
//先申请一个platform_device结构体并初始化
dev = platform_device_alloc("", -1);
if (!dev)
return NULL;
/* 解析device_node中的IO、中断资源的个数 */
while (of_address_to_resource(np, num_reg, &temp_res) == 0)
num_reg++;
num_irq = of_irq_count(np);
/* IO、中断资源并转换成platform_device结构中的resource */
if (num_irq || num_reg)
res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
if (!res)
platform_device_put(dev);
return NULL;
dev->num_resources = num_reg + num_irq;
dev->resource = res;
for (i = 0; i < num_reg; i++, res++)
rc = of_address_to_resource(np, i, res);
WARN_ON(rc);
if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
pr_debug("not all legacy IRQ resources mapped for %s\\n",
np->name);
dev->dev.of_node = of_node_get(np);
dev->dev.fwnode = &np->fwnode;
dev->dev.parent = parent ? : &platform_bus;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
else
of_device_make_bus_id(&dev->dev);
return dev;
EXPORT_SYMBOL(of_device_alloc);
以上是关于device node结构体转换成platform_device结构体的主要内容,如果未能解决你的问题,请参考以下文章