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总线的device;
(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结构体的主要内容,如果未能解决你的问题,请参考以下文章

设备树——dtb格式到struct device node结构体的转换

dtb展开成device_node

注册platform驱动-15

dtb转换为device_node

注册Platform设备-14

linux驱动之platform总线