sys/firmware/devicetree/base目录下面为设备树展开成sysfs的目录和二进制属性文件,所有的node节点就是一个目录,所有的property属性就是一个二进制属性文件.
包含2个,一个是初始化、设备节点目录的创建,一个是节点属性二进制文件的创建在sysfs 中.
相关结构体定义
struct device_node {//最终在内存中形成一个树形的设备信息
const char *name; /* node的名称,取最后一次“/”和“@”之间子串 */
const char *type; /*设备类型,来自节点中的device_type属性, 如果没有该属性, 则设为"NULL"*/
phandle phandle;//u32 phandle
const char *full_name; /* 指向该结构体结束的位置,存放node的路径全名*/
struct fwnode_handle fwnode;
struct property *properties;/*指向该节点下的第一个属性,其他属性与该属性链表相接 */
struct property *deadprops; /* removed properties */
struct device_node *parent;//parent node
struct device_node *child;//child
struct device_node *sibling;//same level node
struct kobject kobj;//kobj,和syfs关联接口
unsigned long _flags;//node flag,see flag descriptions@current file
void *data;
};
struct property {//node的 属性,读到内存中的属性
char *name;//key
int length;//value's length
void *value;//value, for key = value
struct property *next;//下一个属性
unsigned long _flags;
unsigned int unique_id;
struct bin_attribute attr;//for sys
};
np-->kobject 在哪里初始化的呢,在dtb-->device_node 解压中,
unflatten_dt_node---》of_node_init(np);//node sysfs init
struct kobj_type of_node_ktype = {
.release = of_node_release,
};
/* initialize a node */
extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
node->fwnode.type = FWNODE_OF;
}
设备树节点目录创建和属性文件创建
start_kernel()→rest_init()→kernel_thread():kernel_init()→do_basic_setup()→driver_init()→of_core_init()
void __init of_core_init(void)
{
struct device_node *np;
/* Create the kset, and register existing nodes */
mutex_lock(&of_mutex);
of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);//sys/firmware/devicetree,创建目录
if (!of_kset) {
mutex_unlock(&of_mutex);
pr_err("devicetree: failed to register existing nodes\n");
return;
}
for_each_of_allnodes(np)
__of_attach_node_sysfs(np);//创建节点目录和节点属性文件
mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */
if (of_root)
proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
}
int __of_attach_node_sysfs(struct device_node *np)
{
const char *name;
struct property *pp;
int rc;
if (!IS_ENABLED(CONFIG_SYSFS))
return 0;
if (!of_kset)
return 0;
np->kobj.kset = of_kset;//kset 赋值
if (!np->parent) {
/* Nodes without parents are new top level trees */
rc = kobject_add(&np->kobj, NULL, "%s",
safe_name(&of_kset->kobj, "base"));//没有父节点的情况,即叶子节点
} else {
name = safe_name(&np->parent->kobj, kbasename(np->full_name));
if (!name || !name[0])
return -EINVAL;
rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);//存在父节点情况
}
if (rc)
return rc;
for_each_property_of_node(np, pp)//遍历节点的属性,通过next指针
__of_add_property_sysfs(np, pp);//属性添加到sysfs 中
return 0;
}
int __of_add_property_sysfs(struct device_node *np, struct property *pp)---------------节点属性文件的创建
{
int rc;
/* Important: Don't leak passwords */
bool secure = strncmp(pp->name, "security-", 9) == 0;
if (!IS_ENABLED(CONFIG_SYSFS))
return 0;
if (!of_kset || !of_node_is_attached(np))
return 0;
sysfs_bin_attr_init(&pp->attr);//first step
pp->attr.attr.name = safe_name(&np->kobj, pp->name);
pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
pp->attr.size = secure ? 0 : pp->length;
pp->attr.read = of_node_property_read;---读节点属性函数接口
rc = sysfs_create_bin_file(&np->kobj, &pp->attr);//second step
WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name);
return rc;
}
最后就创建成功了节点目录和节点属性文件。