Linux version: 4.14
Code link: Linux source code (v4.14) - Bootlin
1 函数 device_for_each_child_node
(1)对于函数 device_for_each_child_node
#define device_for_each_child_node(dev, child) \
for (child = device_get_next_child_node(dev, NULL); child; \
child = device_get_next_child_node(dev, child))
(2)其中调用了函数 device_get_next_child_node
struct fwnode_handle *device_get_next_child_node(struct device *dev,
struct fwnode_handle *child)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct fwnode_handle *fwnode = NULL;
if (dev->of_node)
fwnode = &dev->of_node->fwnode;
else if (adev)
fwnode = acpi_fwnode_handle(adev);
return fwnode_get_next_child_node(fwnode, child);
}
EXPORT_SYMBOL_GPL(device_get_next_child_node);
(3)在 device_get_next_child_node 中调用了 fwnode_get_next_child_node
struct fwnode_handle *
fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
return fwnode_call_ptr_op(fwnode, get_next_child_node, child);
}
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
(4)fwnode_get_next_child_node 函数中 fwnode_call_ptr_op 调用了 fwnode 中 fwnode_operations 的 get_next_child_node ,并把参数传进 get_next_child_node。
#define fwnode_has_op(fwnode, op) \
((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
#define fwnode_call_ptr_op(fwnode, op, ...) \
(fwnode_has_op(fwnode, op) ? \
(fwnode)->ops->op(fwnode, ## __VA_ARGS__) : NULL)
另外,通过 of_fwnode_ops 结构体可以看出 get_next_child_node 对应的是 of_fwnode_get_next_child_node
const struct fwnode_operations of_fwnode_ops = {
.get = of_fwnode_get,
.put = of_fwnode_put,
.device_is_available = of_fwnode_device_is_available,
.property_present = of_fwnode_property_present,
.property_read_int_array = of_fwnode_property_read_int_array,
.property_read_string_array = of_fwnode_property_read_string_array,
.get_parent = of_fwnode_get_parent,
.get_next_child_node = of_fwnode_get_next_child_node,
.get_named_child_node = of_fwnode_get_named_child_node,
.get_reference_args = of_fwnode_get_reference_args,
.graph_get_next_endpoint = of_fwnode_graph_get_next_endpoint,
.graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
.graph_get_port_parent = of_fwnode_graph_get_port_parent,
.graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
};
EXPORT_SYMBOL_GPL(of_fwnode_ops);
(5)of_fwnode_get_next_child_node 函数
static struct fwnode_handle *
of_fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
return of_fwnode_handle(of_get_next_available_child(to_of_node(fwnode),
to_of_node(child)));
}
对于 of_get_next_available_child 函数
struct device_node *of_get_next_available_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
unsigned long flags;
if (!node)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
if (!__of_device_is_available(next))
continue;
if (of_node_get(next))
break;
}
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
EXPORT_SYMBOL(of_get_next_available_child);
如果传入的prev为NULL则返回node节点的第一个子节点,否则返回prev节点的下一个兄弟节点。注意这里返回的类型为device_node,而of_fwnode_handle函数将device_node对应的节点转换为fwnode_handle类型返回。
#define of_fwnode_handle(node) \
({ \
typeof(node) __of_fwnode_handle_node = (node); \
\
__of_fwnode_handle_node ? \
&__of_fwnode_handle_node->fwnode : NULL; \
})
因此,device_for_each_child_node(dev, child); 函数的功能是遍历 dev 设备对应的 fwnode_handle 节点的每一个子节点并通过 child 变量返回。至此,函数解析完毕。
2 函数 device_get_child_node_count
unsigned int device_get_child_node_count(struct device *dev)
{
struct fwnode_handle *child;
unsigned int count = 0;
device_for_each_child_node(dev, child)
count++;
return count;
}
EXPORT_SYMBOL_GPL(device_get_child_node_count);
从函数定义可以看出,device_get_child_node_count 的功能是统计 dev 设备子节点的个数。