设备树解析【转】

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

设备树解析【转】
转⾃:
⼀、描述
ARM Device Tree起源于OpenFirmware (OF),在过去的中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着⼤量的垃圾代码,相当多数的代码只是在描述板级细节,⽽这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的
platform_data。

为了改变这种局⾯,Linux社区的⼤⽜们参考了PowerPC等体系中使⽤的Flattened Device Tree(FDT),也采⽤了Device Tree结构,许多硬件的细节可以直接透过它传递给Linux,⽽不再需要在kernel中进⾏⼤量的冗余编码。

Device Tree是⼀种描述硬件的,它起源于 OpenFirmware (OF)。

在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和
arch/arm/mach-xxx,采⽤Device Tree后,许多硬件的细节可以直接透过它传递给Linux,⽽不再需要在kernel中进⾏⼤量的冗余编码。

Device Tree由⼀系列被命名的结点(node)和属性(property)组成,⽽结点本⾝可包含⼦结点。

所谓属性,其实就是成对出现的name和value。

在Device Tree中,可描述的信息包括(原先这些信息⼤多被hard code到kernel中):
CPU的数量和类别
内存基地址和⼤⼩
总线和桥
外设连接
中断控制器和中断使⽤情况
GPIO控制器和GPIO使⽤情况
Clock控制器和Clock使⽤情况
它基本上就是画⼀棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,⽽这些设备⽤到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

通常由
⼆、相关结构体
1、U-Boot需要将设备树在内存中的存储地址传给内核。

该树主要由三⼤部分组成:头(Header)、结构块(Structure block)、字符串块(Strings block)。

设备树在内存中的存储布局图:
1.1 头(header)
头主要描述设备树的⼀些基本信息,例如设备树⼤⼩,结构块偏移地址,字符串块偏移地址等。

偏移地址是相对于设备树头的起始地址计算的。

[cpp]
struct
01.
02. __be32 off_dt_struct;
03.
04. __be32 off_mem_rsvmap;
05.
06. __be32 last_comp_version;
07.
08. __be32 dt_strings_size;
09.
10. };
1.2 结构块(struct block)
设备树结构块是⼀个线性化的结构体,是设备树的主体,以节点node的形式保存了⽬标单板上的设备信息。

在结构块中以宏OF_DT_BEGIN_NODE标志⼀个节点的开始,以宏OF_DT_END_NODE标识⼀个节点的结束,整个结构块以宏OF_DT_END结束。

⼀个节点主要由以下⼏部分组成。

(1)节点开始标志:⼀般为OF_DT_BEGIN_NODE。

(2)节点路径或者节点的单元名(ersion<3以节点路径表⽰,version>=0x10以节点单元名表⽰)
(3)填充字段(对齐到四字节)
(4)节点属性。

每个属性以宏OF_DT_PROP开始,后⾯依次为属性值的字节长度(4字节)、属性名称在字符串块中的偏移量(4字节)、属性值和填充(对齐到四字节)。

(5)如果存在⼦节点,则定义⼦节点。

(6)节点结束标志OF_DT_END_NODE 。

1.3 字符串块
通过节点的定义知道节点都有若⼲属性,⽽不同的节点的属性⼜有⼤量相同的属性名称,因此将这些属性名称提取出⼀张表,当节点需要应⽤某个属性名称时直接在属性名字段保存该属性名称在字符串块中的偏移量。

1.4 设备树源码 DTS 表⽰
设备树源码⽂件(.dts)以可读可编辑的⽂本形式描述系统硬件配置设备树,⽀持 C/C++⽅式的注释,该结构有⼀个唯⼀的根节点“/”,每个节点都有⾃⼰的名字并可以包含多个⼦节点。

设备树的数据格式遵循了 Open Firmware IEEE standard 1275。

这个设备树中有很多节点,每个节点都指定了节点单元名称。

每⼀个属性后⾯都给出相应的值。

以双引号引出的内容为 ASCII 字符串,以尖括号给出的是 32 位的16进制值。

这个树结构是启动 Linux 内核所需节点和属性简化后的集合,包括了根节点的基本模式信息、CPU 和物理内存布局,它还包括通过/chosen 节点传递给内核的命令⾏参数信息。

1.5 machine_desc 结构
内核提供了⼀个重要的结构体struct machine_desc ,这个结构体在内核移植中起到相当重要的作⽤,内核通过machine_desc 结构体来控制系统体系架构相关部分的初始化。

machine_desc 结构体通过MACHINE_START 宏来初始化,在代码中, 通过在start_kernel->setup_arch 中调⽤setup_machine_fdt 来获取。

struct nr;
01. *name; 02. unsigned atag_offset; 03. * *dt_compat; 04. unsigned nr_irqs; 05. #ifdef CONFIG_ZONE_DMA 06. 07. video_start; 08. video_end; 09. 10. reserve_lp0 :1; 11. unsigned reserve_lp1 :1; 12. reserve_lp2 :1; 13. reboot_mode reboot_mode; 14. smp_operations *smp; 15. (*smp_init)(); 16. (*fixup)( tag *, **, meminfo *); 17. (*init_meminfo)(); 18. (*reserve)(); 19. (*map_io)(); 20. (*init_early)(); 21. (*init_irq)(); 22. (*init_time)(); 23. (*init_machine)(); 24. (*init_late)(); 25. 26. (*handle_irq)( pt_regs *); 27. 28. (*restart)( reboot_mode, *); 29. };
1.6 设备节点结构体
struct *name;
01. *type; 02. phandle phandle; 03. *full_name; 04. 05. property *properties; 06. property *deadprops; 07. device_node *parent; 08. device_node *child; 09. device_node *sibling; 10. device_node *next; 11. device_node *allnext; 12. proc_dir_entry *pde; 13. kref kref; 14. unsigned _flags; 15. *data; [cpp]
[cpp]
16. 17. *path_component_name; 18. unsigned unique_id; 19. of_irq_controller *irq_trans; 20. 21. };
1.7 属性结构体
struct *name;
01. length; 02. *value; 03. property *next; 04. unsigned _flags; 05. unique_id; 06. };
三、设备树初始化及解析
分析Linux 内核的源码,可以看到其对扁平设备树的解析流程如下:
//kernel 初始化的代码(init/main.c ) __init start_kernel()
01. 02. setup_arch(&command_line); 03. void **cmdline_p) 04. machine_desc *mdesc; 05. 06. mdesc = setup_machine_fdt(__atags_pointer); 07. (!mdesc) 08. mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type); 09. (mdesc->reboot_mode != REBOOT_HARD) 10. ) _text; 11. init_mm.end_code = (unsigned ) _etext; 12. ) _edata; 13. init_mm.brk = (unsigned ) _end; 14. (meminfo.bank[0]), meminfo_cmp, NULL); 15. 16. (mdesc->restart) 17. arm_pm_restart = mdesc->restart; 18. 19. }</span>
(⼀) 函数获取内核前期初始化所需的bootargs ,cmd_line 等系统引导参数
1. setup_machine_fdt()函数获取内核前期初始化所需的bootargs ,cmd_line 等系统引导参数。

const machine_desc * __init setup_machine_fdt(unsigned dt_phys)
01. { 02. machine_desc *mdesc, *mdesc_best = NULL; 03. 04. #ifdef CONFIG_ARCH_MULTIPLATFORM #endif 05. 06. (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) 07. NULL; 08. 09. 10. mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); 11. (!mdesc) { 12. *prop; 13. size; [cpp] [cpp]
[cpp]
14. unsigned dt_root;
15.
16.
17. , &size);
18.
19. (size > 0) {
20. early_print();
21.
22.
23. __machine_arch_type = mdesc->nr;
24. mdesc;
25. struct bool *params)
26. (!params)
27. ;
28.
29.
30. initial_boot_params = params;
31.
32. (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
33. initial_boot_params = NULL;
34. ;
35. }
36.
37.
38. of_scan_flat_dt(early_init_dt_scan_root, NULL);
39.
40. ;
41. }
42. int (*it)(unsigned node, *uname, depth, *data), *data)
43.
44. p = ((unsigned )initial_boot_params) + be32_to_cpu(initial_boot_params->off_dt_struct);
45. rc = 0;
46. depth = -1;
47.
48. {
49.
50. *pathp;
51.
52.
53. (tag == OF_DT_END_NODE) {
54. depth--;
55. ;
56. }
57.
58. (tag == OF_DT_NOP)
59. ;
60.
61. (tag == OF_DT_END)
62. ;
63.
64. (tag == OF_DT_PROP) {
65.
66.
67. (be32_to_cpu(initial_boot_params->version) < 0x10)
68. p = ALIGN(p, sz >= 8 ? 8 : 4);
69.
70. p += sz;
71.
72. p = ALIGN(p, 4);
73.
74. ;
75.
76. (tag != OF_DT_BEGIN_NODE) {
77. -EINVAL;
78.
79. depth++;
80.
81. pathp = ( *)p;
82.
83. p = ALIGN(p + strlen(pathp) + 1, 4);
84.
85. (*pathp == )
86.
87. (rc != 0)
88. ;
89. } (1);
90. rc;
91. }
1.1 chosen节点
chosen 节点并不代表⼀个真实的设备,只是作为⼀个为固件和操作系统之间传递数据的地⽅,⽐如引导参数。

chosen 节点⾥的数据也不代表硬件。

通常,chosen 节点在.dts 源⽂件中为空,并在启动时填充。

在我们的⽰例系统中,固件可以往 chosen 节点添加以下信息:
chosen {
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; //节点属性
linux,initrd-start = <0x85500000>; //节点属性
linux,initrd-end = <0x855a3212>; //节点属性
};
[cpp]
int node, *uname, depth, *data)
01. {
02. l;
03. *p;
04.
05.
06.
07. (depth != 1 || !data || (strcmp(uname, ) != 0 && strcmp(uname, ) != 0))
08. 0;
09.
10.
11. p = of_get_flat_dt_prop(node, , &l);
12. (p != NULL && l > 0)
13. strlcpy(data, p, min(()l, COMMAND_LINE_SIZE));
14. *)data);
15. 1;
16. static __init early_init_dt_check_for_initrd(unsigned node)
17. {
18. len;
19.
20. prop = of_get_flat_dt_prop(node, , &len);
21. (!prop)
22. ;
23.
24. start = of_read_number(prop, len/4);
25.
26. , &len);
27. (!prop)
28. ;
29.
30.
31. initrd_start = (unsigned )__va(start);
32. )__va(end);
33. initrd_below_start_ok = 1;
34. )start, (unsigned )end);
35. void node, *name,unsigned *size)
36. {
37. of_fdt_get_property(initial_boot_params, node, name, size);
38. }
39. void boot_param_header *blob,unsigned node, *name,unsigned *size)
40.
41. p = node;
42.
43.
44. {
45.
46. u32 tag = be32_to_cpup((__be32 *)p);
47. *nstr;
48.
49.
50. (tag == OF_DT_NOP)
51. ;
52.
53. (tag != OF_DT_PROP)
54. NULL;
55.
56.
57.
58.
59.
60. (be32_to_cpu(blob->version) < 0x10)
61.
62. nstr = of_fdt_get_string(blob, noff);
63. (nstr == NULL) {
64. pr_warning( NULL;
65. }
66.
67. (strcmp(name, nstr) == 0) {
68. (size)
69.
70.
71. ( *)p;
72. }
73.
74. p += sz;
75. (1);
76. char boot_param_header *blob, u32 offset)
77. {
78.
79. (( *)blob) + be32_to_cpu(blob->off_dt_strings) + offset;
80. static u64 of_read_number( __be32 *cell, size)
81. {
82.
83. (size--)
84. r = (r << 32) | be32_to_cpu(*(cell++));
85. r;
86. }
1.2 根节点"/"
设备树有且仅有⼀个根节点,即“/”,根节点下包含很多⼦节点,例⼊下图,根节点为"/",根节点的⼦节点为"chosen",根节点的属性包含"compatible","#address-cells","#size-cells","interrupt-parent"等。

属性model指明了⽬标板平台或模块的名称,属性compatible值指明和⽬标板为同⼀系列的兼容的开发板名称。

对于⼤多数32位平台,属性#address-cells和#size-cells的值⼀般为1。

#address-cells = <1>; 1表⽰地址32位,2表⽰地址64位。

#size-cells = <1>;1表⽰rangs的每部分占⼀个cell,依此类推
{
compatible = "sprd,spx15";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&gic>;
chosen {
bootargs = "loglevel=8 console=ttyS1,115200n8 init=/init root=/dev/ram0 rw";
linux,initrd-start = <0x85500000>;
linux,initrd-end = <0x855a3212>;
};
}
所以本函数就是读取根节点的"#address-cells","#size-cells"属性
[cpp]
int node, *uname, depth, *data)
01. {
02.
03. (depth != 0)
04. 0;
05.
06.
07. , NULL);
08. (prop)
09.
10.
11.
12. prop = of_get_flat_dt_prop(node, , NULL);
13. (prop)
14. dt_root_addr_cells = be32_to_cpup(prop);
15. 1;
16. }
1.3 memory 节点
memory 节点⽤于描述⽬标板上物理内存范围,⼀般称作/memory 节点,可以有⼀个或多个。

当有多个节点时,需要后跟单元地址予以区分;只有⼀个单元地址时,可以不写单元地址,默认为0。

此节点包含板上物理内存的属性,⼀般要指定device_type (固定为"memory")和reg 属性。

其中reg 的属性值以<起始地址 空间⼤⼩>的形式给出,如下⽰例中⽬标板内存起始地址为0x80000000,⼤⼩为0x20000000字节。

memory {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
int node, *uname, depth, *data)
01. { 02. 03. *type = of_get_flat_dt_prop(node, , NULL); 04. l; 05. 06. (type == NULL) { 07. (depth != 1 || strcmp(uname, ) != 0) 08. 0; 09. } (strcmp(type, ) != 0) 10. 0; 11. 12. 13. reg = of_get_flat_dt_prop(node, , &l); 14. (reg == NULL) 15. reg = of_get_flat_dt_prop(node, , &l); 16. (reg == NULL) 17. 0; 18. 19. (__be32)); 20. 21. ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 22. 23. base = dt_mem_next_cell(dt_root_addr_cells, &reg); 24. (size == 0) 25. ; 26. )base,(unsigned )size); 27. 28. 29. early_init_dt_add_memory_arch(base, size); 30. 0; 31. }
2. 通过⽐较根节点属性compatible 值指明和⽬标板为同⼀系列的兼容的开发板名称
compatible 制定系统的名称。

它包含"<manufacture>,<model>"格式的字符串。

准确地确定器件型号是⾮常重要的,并且我们需要包含⼚商的名字来避免名字空间冲突。

因为操作系统会使⽤compatible 这个值来决定怎样在这个机器上运⾏,所以在这个属性中放⼊正确的值是⾮常重要的。

const * __init of_flat_dt_match_machine( *default_match,
01. * (*get_next_compat)( * **)) 02. *data = NULL; 03. *best_data = default_match; 04. * *compat; 05. dt_root; 06. unsigned best_score = ~1, score = 0; 07. 08. 09. ((data = get_next_compat(&compat))) { 10. 11. score = of_flat_dt_match(dt_root, compat); 12. 13. (score > 0 && score < best_score) { [cpp]
[cpp]
14. (!best_data) {
15. *prop;
16. size;
17. , &size);
18. (prop) {
19. (size > 0) {
20. );
21. NULL;
22. }
23. best_data;
24. //查找设备树的根节点 __init of_get_flat_dt_root()
25. {
26.
27. unsigned p = ((unsigned )initial_boot_params) +
28.
29. (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
30.
31. ALIGN(p + strlen(( *)p) + 1, 4);
32. }
33. //arch/arm/kernel/devtree.c 是location counter。

在__arch_info_begin 的位置上,放置所有⽂件中的段的内容,然后紧接着
是 __arch_info_end 的位置. 段中定义了设备的machine_desc结构。

34.
35. static * __init arch_get_next_mach( * **match)
36. {
37. machine_desc *mdesc = __arch_info_begin;
38. machine_desc *m = mdesc;
39. (m >= __arch_info_end)
40. NULL;
41.
42.
43. *match = m->dt_compat;
44. m;
45. }
46. //与设备树根节点进⾏match int node, * *compat)
47. {
48.
49.
50.
51. of_fdt_match(initial_boot_params, node, compat);
52. int boot_param_header *blob, unsigned node, * *compat)
53. {
54. tmp, score = 0;
55.
56. (!compat)
57. 0;
58.
59. (*compat) {
60.
61. (tmp && (score == 0 || (tmp < score)))
62.
63. compat++;
64. score;
65. }
66. int boot_param_header *blob,unsigned node, *compat)
67. *cp;
68. cplen, l, score = 0;
69.
70.
71. cp = of_fdt_get_property(blob, node, , &cplen);
72. (cp == NULL)
73. 0;
74.
75. (cplen > 0) {
76. score++;
77. (of_compat_cmp(cp, compat, strlen(compat)) == 0)
78. score;
79. 0;
80. }
(⼆)、解析设备树
unflatten_device_tree()函数来解析dtb⽂件,构建⼀个由device_node结构连接⽽成的单项链表,并使⽤全局变量of_allnodes指针来保存这个链表的头指针。

内核调⽤OF提供的API函数获取of_allnodes链表信息来初始化内核其他⼦系统、设备。

[cpp]
void)
01. {
02.
03. __unflatten_device_tree(initial_boot_params, &of_allnodes,early_init_dt_alloc_memory_arch);
04.
05. static __unflatten_device_tree( boot_param_header *blob,
06. device_node **mynodes,
07. * (*dt_alloc)(u64 size, u64 align))
08. size;
09. *start, *mem;
10. device_node **allnextp = mynodes;
11. (!blob) {
12. ;
13.
14. (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
15. pr_err(;
16. }
17.
18. *)blob) + be32_to_cpu(blob->off_dt_struct);
19.
20. )unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
21. size = ALIGN(size, 4);
22.
23. device_node));
24. memset(mem, 0, size);
25.
26.
27. *)blob) + be32_to_cpu(blob->off_dt_struct);
28.
29. (be32_to_cpup(start) != OF_DT_END)
30. (be32_to_cpup(mem + size) != 0xdeadbeef)
31. static * unflatten_dt_node( boot_param_header *blob,
32. *mem, **p,
33. device_node *dad,
34. device_node ***allnextpp,
35. fpsize)
36. {
37. device_node *np;
38. property *pp, **prev_pp = NULL;
39. *pathp;
40. u32 tag;
41. l, allocl;
42. has_name = 0;
43. new_format = 0;
44.
45.
46. tag = be32_to_cpup(*p);
47.
48. (tag != OF_DT_BEGIN_NODE) {
49. mem;
50.
51. pathp = *p;
52.
53. *p = PTR_ALIGN(*p + l, 4);
54.
55. ((*pathp) != ) {
56. new_format = 1;
57. (fpsize == 0) {
58. fpsize = 1;
59. ;
60. } {
61.
62. allocl = fpsize;
63.
64. ( device_node) + allocl,__alignof__( device_node));
65.
66.
67.
68. (allnextpp) {
69. *fn;
70.
71. np->full_name = fn = (( *)np) + (*np);
72.
73. (new_format) {
74. (dad && dad->parent) {
75. strcpy(fn, dad->full_name);
76. ;
77. }
78.
79.
80.
81. prev_pp = &np->properties;
82.
83.
84. (dad != NULL) {
85. np->parent = dad;
86. (dad->next == NULL)
87. dad->child = np;
88.
89. dad->next->sibling = np;
90.
91. (1) {
92. u32 sz, noff;
93. *pname;
94.
95.
96. tag = be32_to_cpup(*p);
97.
98. (tag == OF_DT_NOP) {
99. ;
100.
101. (tag != OF_DT_PROP)
102. ;
103.
104. *p += 4;
105.
106. sz = be32_to_cpup(*p);
107.
108. noff = be32_to_cpup(*p + 4);
109.
110. *p += 8;
111.
112. (be32_to_cpu(blob->version) < 0x10)
113.
114. pname = of_fdt_get_string(blob, noff);
115. (pname == NULL) {
116. pr_info(;
117. }
118.
119. (strcmp(pname, ) == 0)
120. has_name = 1;
121.
122. l = strlen(pname) + 1;
123.
124.
125. pp = unflatten_dt_alloc(&mem, ( property),__alignof__( property)); 126.
127.
128. (allnextpp) {
129. ((strcmp(pname, ) == 0) || (strcmp(pname, ) == 0)) {
130. (np->phandle == 0)
131. (strcmp(pname, ) == 0)
132. np->phandle = be32_to_cpup((__be32 *)*p);
133.
134. pp->length = sz;
135.
136.
137.
138. *prev_pp = pp;
139.
140. }
141.
142.
143.
144. (!has_name) {
145. *p1 = pathp, *ps = pathp, *pa = NULL;
146. sz;
147. (*p1) {
148. ((*p1) == )
149. pa = p1;
150. ((*p1) == )
151. ps = p1 + 1;
152. (pa < ps)
153. pa = p1;
154. ( property) + sz,__alignof__( property));
155. (allnextpp) {
156. pp->name = ;
157. *)pp->value)[sz - 1] = 0;
158. *)pp->value);
159. }
160.
161. (allnextpp) {
162.
163. , NULL);
164.
165. , NULL);
166.
167. (!np->name)
168. np->name = (!np->type)
169. np->type =
170.
171. (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
172.
173. (tag == OF_DT_NOP)
174. *p += 4;
175.
176.
177.
178. (tag != OF_DT_END_NODE) {
179. mem;
180.
181. mem;
182. //从mem分配内存空间,*mem记录分配了多⼤空间static *unflatten_dt_alloc( **mem, unsigned size,unsigned align) 183. {
184. *res;
185.
186. res;
187. }
188. //⼀个特定的节点通常是以完整的路径来引⽤,⽐如/external-bus/ethernet@0,0,不过当⼀个⽤户真的想知道“哪个设备是eth0”时,这将会很繁琐。

aliases节点可以⽤来为⼀个完整的设备路径分配⼀个短的别名。

⽐如: //aliases { // serial0 = &uart0;
// serial1 = &uart1; // serial2 = &uart2; // serial3 = &uart3; // ethernet0 = ð0; // serial0 = &serial0; //}; //当需要为设备指定⼀个标⽰符时,操作系统欢迎⼤家使⽤别名。

//设置内核输出终端,以及遍历“/aliases”节点下的所有的属性,挂⼊相应链表
void * (*dt_alloc)(u64 size, u64 align))
189. {
190. property *pp;
191.
192.
193. of_chosen = of_find_node_by_path();
194. (of_chosen == NULL)
195. of_chosen = of_find_node_by_path();
196.
197.
198. (of_chosen) {
199. *name;
200.
201. , NULL);
202.
203. (name)
204. of_stdout = of_find_node_by_path(name);
205.
206. of_aliases = of_find_node_by_path();
207. (!of_aliases)
208. ;
209.
210. *start = pp->name;
211. *end = start + strlen(start);
212. device_node *np;
213. alias_prop *ap;
214. id, len;
215.
216. (!strcmp(pp->name, ) ||
217. !strcmp(pp->name, ) ||
218. ))
219. ;
220.
221. (!np)
222. ;
223.
224.
225. (isdigit(*(end-1)) && end > start)
226.
227.
228.
229.
230. (kstrtoint(end, 10, &id) < 0)
231. ;
232.
233.
234. ap = dt_alloc((*ap) + len + 1, 4);
235. (!ap)
236. ;
237. (*ap) + len + 1);
238. ap->alias = start;
239.
240. of_alias_add(ap, np, id, start, len);
241. }
四、OF提供的常⽤API函数
OF提供的函数主要集中在drivers/of/⽬录下,有address.c,base.c,device.c,fdt.c,irq.c,platform.c等等
1. ⽤来查找在dtb中的根节点
unsigned long __init of_get_flat_dt_root(void)
2. 根据deice_node结构的full_name参数,在全局链表of_allnodes中,查找合适的device_node
struct device_node *of_find_node_by_path(const char *path)
例如:
struct device_node *cpus;
cpus=of_find_node_by_path("/cpus");
3. 若from=NULL,则在全局链表of_allnodes中根据name查找合适的device_node
struct device_node *of_find_node_by_name(struct device_node *from,const char *name)
例如:
struct device_node *np;
np = of_find_node_by_name(NULL,"firewire");
4. 根据设备类型查找相应的device_node
struct device_node *of_find_node_by_type(struct device_node *from,const char *type)
例如:
struct device_node *tsi_pci;
tsi_pci= of_find_node_by_type(NULL,"pci");
5. 根据compatible字符串查找device_node
struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible)
6. 根据节点属性的name查找device_node
struct device_node *of_find_node_with_property(struct device_node *from,const char *prop_name)
7. 根据phandle查找device_node
struct device_node *of_find_node_by_phandle(phandle handle)
8. 根据alias的name获得设备id号
int of_alias_get_id(struct device_node *np, const char *stem)
9. device node计数增加/减少
struct device_node *of_node_get(struct device_node *node)
void of_node_put(struct device_node *node)
10. 根据property结构的name参数,在指定的device node中查找合适的property
struct property *of_find_property(const struct device_node *np,const char *name,int *lenp)
11. 根据property结构的name参数,返回该属性的属性值
const void *of_get_property(const struct device_node *np, const char *name,int *lenp)
12. 根据compat参数与device node的compatible匹配,返回匹配度
int of_device_is_compatible(const struct device_node *device,const char *compat)
13. 获得⽗节点的device node
struct device_node *of_get_parent(const struct device_node *node)
14. 将matches数组中of_device_id结构的name和type与device node的compatible和type匹配,返回匹配度最⾼的of_device_id结构const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)
15. 根据属性名propname,读出属性值中的第index个u32数值给out_value
int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index, u32 *out_value)
16. 根据属性名propname,读出该属性的数组中sz个属性值给out_values
int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
int of_property_read_u16_array(const struct device_node *np,const char *propname, u16 *out_values, size_t sz)
int of_property_read_u32_array(const struct device_node *np,const char *propname, u32 *out_values,size_t sz)
17. 根据属性名propname,读出该属性的u64属性值
int of_property_read_u64(const struct device_node *np, const char *propname,u64 *out_value)
18. 根据属性名propname,读出该属性的字符串属性值
int of_property_read_string(struct device_node *np, const char *propname,const char **out_string)
19. 根据属性名propname,读出该字符串属性值数组中的第index个字符串
int of_property_read_string_index(struct device_node *np, const char *propname,int index, const char **output)
20. 读取属性名propname中,字符串属性值的个数
int of_property_count_strings(struct device_node *np, const char *propname)
21. 读取该设备的第index个irq号
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
22. 读取该设备的第index个irq号,并填充⼀个irq资源结构体
int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
23. 获取该设备的irq个数
int of_irq_count(struct device_node *dev)
24. 获取设备寄存器地址,并填充寄存器资源结构体
int of_address_to_resource(struct device_node *dev, int index,struct resource *r)
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,unsigned int *flags)
25. 获取经过映射的寄存器虚拟地址
void __iomem *of_iomap(struct device_node *np, int index)
24. 根据device_node查找返回该设备对应的platform_device结构
struct platform_device *of_find_device_by_node(struct device_node *np)
25. 根据device node,bus id以及⽗节点创建该设备的platform_device结构
struct platform_device *of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)
static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,
void *platform_data,struct device *parent)
26. 遍历of_allnodes中的节点挂接到of_platform_bus_type总线上,由于此时of_platform_bus_type总线上还没有驱动,所以此时不进⾏匹配int of_platform_bus_probe(struct device_node *root,const struct of_device_id *matches,struct device *parent)
27. 遍历of_allnodes中的所有节点,⽣成并初始化platform_device结构
int of_platform_populate(struct device_node *root,const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,struct device *parent)
{
struct device_node *child;
int rc = 0;
//获得设备树的根节点
root = root ? of_node_get(root) : of_find_node_by_path("/。

相关文档
最新文档