当前位置:网站首页>device node结构体转换成platform_device结构体
device node结构体转换成platform_device结构体
2022-08-01 01:18:00 【正在起飞的蜗牛】
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);
边栏推荐
- RTL8762DK PWM (seven)
- 如何编辑epub电子书的目录
- Classes and Objects: Medium
- Daily practice of LeetCode - Circular linked list question (interview four consecutive questions)
- What is the meaning of JS timestamp?Know SQL will consider to add a timestamp, JS timestamp for the scene?
- RTL8762DK UART (two)
- GDB 源码分析系列文章五:动态库延迟断点实现机制
- You need to know the TCP wave four times
- STK8321 I2C (Shengjia-accelerometer) example
- ECCV2022 Workshop | 复杂环境中的多目标跟踪和分割
猜你喜欢
Rainbow share | how to use moving targets defense technology to guard against the unknown
You need to know the TCP wave four times
leetcode:1562. 查找大小为 M 的最新分组【模拟 + 端点记录 + 范围合并】
How to get started with YOLO?How to implement your own training set?
Unity3D学习笔记10——纹理数组
Super like the keyboard made from zero, IT people love it
Modern Enterprise Architecture Framework 1
Cmake introductory study notes
【Cryptography/Cryptanalysis】Cryptanalysis method based on TMTO
RTL8762DK RTC(五)
随机推荐
WebApi hits an Attribute to handle exceptions uniformly
Super like the keyboard made from zero, IT people love it
RTL8762DK 使用DebugAnalyzer(四)
/usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*Solution
Detailed explanation of TCP protocol
Notes on how to use zeno
RTL8762DK PWM (seven)
mySql data view
机器学习初学者可以学哪些实战项目?
C字符串数组反转
You need to know the TCP wave four times
ECCV2022 Workshop | 复杂环境中的多目标跟踪和分割
设计消息队列存储消息数据的MySQL表格
STK8321 I2C (Shengjia-accelerometer) example
你需要知道的 TCP 四次挥手
OSD读取SAP CRM One Order应用日志的优化方式
Rasa 3.x 学习系列- Rasa - Issues 4918 学习笔记
如何编辑epub电子书的目录
OSF understands the agile development model in one minute
Daily practice of LeetCode - Circular linked list question (interview four consecutive questions)