- 易迪拓培训,专注于微波、射频、天线设计工程师的培养
7.DB410c开发板dts加载功能测试
录入:edatop.com 点击:
DTS是Device Tree Source的缩写,用来描述设备的硬件细节。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。为了去掉这些垃圾代码,Linux采用DTS这种新的数据结构来描述硬件设备。采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
Linux在启动后,到C入口时,会执行以下操作,加载系统平台上的总线和设备:
start_kernel() init/main.c
--> setup_arch() arch/arm64/kernel/setup.c
--> unflatten_device_tree() drivers/of/fdt.c
unflatten_device_tree函数将DTS节点信息解析出来,保存到allnodes链表中。
随后系统启动,接着调用arch/arm64/kernel/setup.c文件中arm64_device_init函数-->of_platform_populate(....)接口,加载平台总线和平台设备。至此,系统平台上的所有已配置的总线和设备将被注册到系统中。
注意:不是dtsi文件中所有的节点都会被注册,在注册总线和设备时,会对dts节点的状态作一个判断,如果节点里面的status属性没有被定义,或者status属性被定义了并且值被设为“ok”或者“okay”,其他情况则不被注册到系统中。
dtsi定义:
dtsi加载代码:#include "unflatten_dts.dtsi"
驱动源代码:
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/device.h>
- #include <linux/platform_device.h>
- #include <linux/sysfs.h>
- #include <linux/slab.h>
- #include <linux/kernel.h>
- #include <linux/kobject.h>
- #include <linux/string.h>
- #include <linux/of.h>
- #define UNFLATTEN_DTS_TIP "unflatten_dts_tip"
- char unflatten_dts_code[64] = "UNFLATTEN_DTS, unflatten_dts_show";
- static ssize_t show(struct device_driver *driver, char *buf)
- {
- if(NULL != buf)
- {
- /* Newline is not appended on purpose, for convenience of reader programs */
- snprintf(buf, PAGE_SIZE, "%s\n", unflatten_dts_code);
- return strlen(buf);
- }
- return 0;
- }
- DRIVER_ATTR(unflatten_dts, 0444, show, NULL);
- static struct attribute *unflatten_dts_attrs[] = {
- &driver_attr_unflatten_dts.attr,
- NULL,
- };
- static struct attribute_group unflatten_dts_group = {
- .name ="unflatten_dts",
- .attrs = unflatten_dts_attrs,
- };
- static const struct attribute_group *unflatten_dts_groups[] = {
- &unflatten_dts_group,
- NULL,
- };
- static int unflatten_dts_probe(struct platform_device *pdev)
- {
- int nNum;
- const char *m_string;
- if(NULL == pdev)
- {
- printk("xiaomi_test: unflatten_dts_probe failed, pdev is NULL\n");
- return 0;
- }
- if(NULL == pdev->dev.of_node)
- {
- printk( "xiaomi_test: unflatten_dts_probe failed, of_node is NULL\n");
- return 0;
- }
- /* UNFLATTEN_DTS_TIP*/
- if(of_property_read_bool(pdev->dev.of_node, UNFLATTEN_DTS_TIP))
- {
- printk( "unflatten_dts_probe: dtsi<%s> is existing\n", UNFLATTEN_DTS_TIP);
- }
- if (of_property_read_u32(pdev->dev.of_node, "linux,code", &nNum))
- {
- printk(KERN_INFO "=11= nNum=%d\n", nNum);
- }
- else
- {
- printk(KERN_INFO "=12= nNum=%d\n", nNum);
- }
- if (of_property_read_string(pdev->dev.of_node, "linux,string", &m_string))
- {
- printk(KERN_INFO "=11= m_string=%s\n", m_string);
- }
- else
- {
- printk(KERN_INFO "=12= m_string=%s\n", m_string);
- }
- return 0;
- }
- /* .compatible的信息要与dtsi中的compatible一致 */
- static struct of_device_id unflatten_dts_info_match_table[] = {
- { .compatible = "unflatten_dts",},
- { },
- };
- static struct platform_driver unflatten_dts = {
- .driver = {
- /* 当然这里的name要跟dtsi的节点DTS_TEST一致 */
- .name = "unflatten_dts",
- .owner = THIS_MODULE,
- .groups = unflatten_dts_groups,
- .of_match_table = unflatten_dts_info_match_table,
- },
- .probe = unflatten_dts_probe,
- .remove = NULL,
- };
- static int __init unflatten_dts_init(void)
- {
- return platform_driver_register(&unflatten_dts);
- }
- static void __exit unflatten_dts_exit(void)
- {
- platform_driver_unregister(&unflatten_dts);
- }
- module_init(unflatten_dts_init);
- module_exit(unflatten_dts_exit);
- MODULE_LICENSE("GPL");
Makefile文件:
编译,拷贝,insmod后的运行信息如下:
将前者与dtsi的内容做比较,我们可以确定dtsi文件里面的信息显示完全正确。
后者则是sysfs的一个显示,修改代码可以将dtsi中的内容在设备节点中显示。
知识点:
1.linux kernel的加载顺序;
2.dts dtsi的概念,应用;
3.sysfs概念,应用;
4.驱动模块编译,加载。
代码那块好乱。