做彩投网站犯法吗,火车头wordpress 缩略图,网站开发后台服务器功能,青岛网站建设的方案一、概述
设备树(Device Tree)是一种描述硬件的数据结构#xff0c;用于将硬件设备的信息传递给操作系统内核。它的主要作用是使内核能够以一种统一、灵活的方式了解硬件平台的细节#xff0c;包括设备的拓扑结构、资源分配#xff08;如内存地址、中断号等#xff09;等信…一、概述
设备树(Device Tree)是一种描述硬件的数据结构用于将硬件设备的信息传递给操作系统内核。它的主要作用是使内核能够以一种统一、灵活的方式了解硬件平台的细节包括设备的拓扑结构、资源分配如内存地址、中断号等等信息从而减少了将硬件信息硬编码到内核中的情况增强了内核的可移植性和可维护性。
1、设备树的基本结构
1.节点(Node)
设备树以节点为基本单元节点用于描述一个设备或者一个设备集合。每个节点都有一个名字名字通常反映了设备的类型或者功能。例如一个典型的节点名字可能是 “uart0x1000”其中 “uart” 表示这是一个串口设备“0x1000” 可能是该设备的基地址。节点可以包含属性(Properties)和子节点(Child Nodes)。
2.属性(Properties)
属性是节点的重要组成部分用于描述设备的各种特性。属性由键 - 值对(key - value pairs)组成。键是一个字符串用于标识属性的名称值可以是多种数据类型如整数、字符串、字节数组等。例如一个设备节点可能有一个属性 “compatible”其值为 “nvidia,tegra - uart”这个属性用于告诉内核该设备与哪种驱动程序兼容。
3.子节点(Child Nodes)
一个节点可以包含多个子节点用于描述设备的层次结构。比如在一个 SoC(片上系统)设备树中可能有一个 “cpu” 节点它下面会有多个代表不同 CPU 核心的子节点每个子节点可以包含自己的属性用于描述该核心的特性如频率、缓存大小等。
2、基本概念
1.DTSDevice Tree Source
DTS 是设备树源文件它是一种文本格式的文件用于描述硬件设备的详细信息。其内容包括设备的拓扑结构、设备之间的连接关系、资源分配如内存地址、中断号等以及设备的各种属性等。
这里的/{表示根节点node1是根节点下的一个子节点它有两个属性property1和property2并且还有一个子节点child_node这个子节点有自己的属性child_property。属性的值可以是整数用包围、字符串用双引号包围等多种形式。
/{node1 {property1 value1;property2 string_value;child_node {child_property value2;}}
}2.DTCDevice Tree Compiler
DTC是设备树编译器它是一个工具用于将DTS文件编译成二进制的DTB文件。DTC会对DTS文件进行语法检查、格式转换等操作以确保设备树信息的正确性和有效性并将其转换为内核能够解析的二进制格式。
DTC读取DTS文件的文本内容根据设备树的语法规则进行解析。它会识别节点、属性等元素并将其转换为二进制格式存储在DTB文件中。在编译过程中DTC还可以进行一些优化操作例如去除注释、压缩数据等以减小DTB文件的大小。
通常在构建内核或者制作嵌入式系统镜像时使用。例如在交叉编译环境中开发人员在完成DTS文件的编写后会使用DTC工具将DTS编译为DTB文件然后将DTB文件与内核镜像一起部署到目标设备上。
3.DTBDevice Tree Blob
DTB是设备树二进制文件它是DTS文件经过DTC编译后的产物。内核在启动过程中能够直接解析DTB文件来获取硬件设备的信息。文件包含了设备树的所有信息不过是以二进制形式存储。它的结构包括头部信息如文件版本、大小等和设备树数据部分。数据部分按照一定的格式组织内核通过特定的解析代码可以从中提取出设备节点、属性等信息。
当系统启动时内核会读取 DTB 文件。例如在一个基于 ARM 架构的嵌入式系统中引导加载程序如 U - Boot会将 DTB 文件加载到内存中然后内核启动时会解析 DTB 文件根据其中的信息来识别硬件设备如发现系统中的存储设备、网络设备等并为这些设备分配资源同时将设备与相应的驱动程序进行匹配。
4.DTSIDevice Tree Source Include
DTSI 是设备树源文件包含Include文件。它也是一种文本格式的文件主要用于将设备树描述信息进行模块化和复用。
在复杂的硬件系统中可能有多个设备具有相同的基本属性或者结构。DTSI 文件可以用来定义这些通用的部分然后在多个 DTS 文件中进行引用。例如对于一个具有多个相同类型的 UART 设备的系统可以将 UART 设备的通用属性如基本的寄存器定义、中断处理方式等定义在一个 DTSI 文件中然后在每个具体描述 UART 设备的 DTS 文件中包含这个 DTSI 文件从而减少代码的重复编写。
#include xxx.dtsi
二、实操
1、设备树文件修改
/include/ system-conf.dtsi
/ {chosen{bootargs earlycon consolettyPS0,115200 clk_ignore_unused root/dev/mmcblk0p2 rw rootwait;};gpio-led {compatible zynqMP-led;gpios gpio 0x2A 0x0 gpio 0x28 0x0;};
};gpio {emio-gpio-width 32;gpio-mask-high 0x0;gpio-mask-low 0x5600;status okay;
};sdhci1 {clock-frequency 100000000;status okay;xlnx,mio_bank 0x1;no-1-8-v;disable-wp;
};uart0 {cts-override ;device_type serial;port-number 0;status okay;u-boot,dm-pre-reloc ;
};usb0 {status okay;xlnx,tz-nonsecure 0x1;xlnx,usb-polarity 0x0;xlnx,usb-reset-mode 0x0;
};2、驱动文件编写
//1、添加头文件
#include linux/init.h
#include linux/module.h
#include linux/fs.h
#include linux/of_gpio.h
#include linux/platform_device.h
#include linux/mod_devicetable.hstatic unsigned int led_major;
static struct class *led_class;struct led_driver
{int gpio1;int gpio2;int irq;struct device dev;
};
struct led_driver *led_dri NULL;const struct file_operations led_fops {};//在probe函数中打印获取数据包里面的名字及GPIO
int gpio_pdrv_probe(struct platform_device *pdev)
{struct device_node *node;unsigned int gpio1, gpio2;unsigned int ret 0;printk(gpio pdrv probe!\n);printk(pdrv name %s!\n, pdev-name);//申请主设备号led_major register_chrdev(0, led_drv, led_fops);if (led_major 0){printk(register chrdev led major error!\n);return -ENOMEM;}//创建类led_class class_create(THIS_MODULE, led_class);//创建设备device_create(led_class, NULL, MKDEV(led_major, 0), NULL, led_device%d, 0);//硬件初始化//申请空间led_dri devm_kmalloc(pdev-dev, sizeof(struct led_driver), GFP_KERNEL);if (led_dri NULL){printk(devm kmalloc led_driver error!\n);return -1;}//获取从设备节点传过来的pdev中的dev及node节点led_dri-dev pdev-dev;node pdev-dev.of_node;//3.从node节点处获得GPIO号gpio1 of_get_gpio(node, 0);printk(of get gpio1 number %d\n, gpio1); //GPIO基数 338 40338 是 512 - 174 得到的。if (gpio1 0){printk(of get gpio error!\n);return -1;}gpio2 of_get_gpio(node, 1);printk(of get gpio2 number %d\n, gpio2); //GPIO基数 338 42if (gpio2 0){printk(of get gpio error!\n);return -1;}//4.申请GPIOret gpio_request(gpio1, plattree_led);if (ret 0){printk(plattree led gpio request error!\n);return ret;}ret gpio_request(gpio2, plattree_led);if (ret 0){printk(plattree led gpio request error!\n);return ret;}//5.设置GPIO为输出模式并设备为0灭灯gpio_direction_output(gpio1, 0);gpio_direction_output(gpio2, 0);led_dri-gpio1 gpio1;led_dri-gpio2 gpio2;return 0;
}int gpio_pdrv_remove(struct platform_device *pdev)
{printk(led pdrv remove!\n);//6.将gpio设为输出。gpio_set_value(led_dri-gpio1, 1);gpio_set_value(led_dri-gpio2, 1);gpio_free(led_dri-gpio1);gpio_free(led_dri-gpio2);device_destroy(led_class, MKDEV(led_major, 0));class_destroy(led_class);unregister_chrdev(led_major, led_drv);return 0;
}//of_match_table实现
const struct of_device_id gpio_of_match_table[] {{.compatible zynqMP-led,},{}
};//2.当驱动在设备中找到name之后进行配对获取resource资源进入probe函数
struct platform_driver gpio_drv {.driver {.name zynqmp_led,.of_match_table gpio_of_match_table,},.probe gpio_pdrv_probe,.remove gpio_pdrv_remove,
};//实现装载入口函数和卸载入口函数
static __init int platform_gpio_drv_init(void)
{//1.创建pdrv并且注册到总线中return platform_driver_register(gpio_drv);
}
static __exit void platform_gpio_drv_exit(void)
{//7.注销设备platform_driver_unregister(gpio_drv);
}//声明装载入口函数和卸载入口函数
module_init(platform_gpio_drv_init);
module_exit(platform_gpio_drv_exit);//添加GPL协议
MODULE_LICENSE(GPL);
MODULE_AUTHOR(Popeye);