首页 > 其他分享 >字符设备驱动-4.设备树

字符设备驱动-4.设备树

时间:2023-04-29 20:33:46浏览次数:30  
标签:字符 property device 驱动 2.1 设备 节点 属性

1.为什么引用设备树

在内核中,使用同一个芯片的板子,它们所用的外设资源不一样,比如 A 板用 GPIO A,B 板用 GPIO B, 如果用plateform_device定义资源信息,那么每次单板硬件资源变动后,都要改驱动程序源码,重新编译驱动,重新加载驱动,非常麻烦。
随着 ARM 芯片的流行,内核中针对这些 ARM 板保存有大量的、没有技术含量的文件。 Linus 大发雷霆:"this whole ARM thing is a f*cking pain in the ass"。于是,Linux 内核开始引入设备树。 设备树并不是重新发明出来的,在 Linux 内核中其他平台如 PowerPC,早就使用设备树来描述硬件了。
设备树只是用来给内核里的驱动程序,指定硬件的信息。

1.1根文件系统中查看设备树

image

烧录的dtb文件,显然,两者是完全相同的。
image

除了原始的dtb文件,根文件系统还以目录结构的方式呈现dtb文件,在devicetree目录下,则有一个base目录,这个base目录,就对应着根节点。
image

base目录下,每一个节点对应一个目录, 每一个属性对应一个文件.这些属性的值如果是字符串,可以使用 cat 命令把它打印出来。对于数值,可以用 hexdump 把它打印出来。
image

进入led目录,里面一共有三个文件,除name外,分别对应着led节点的两个属性,cat属性如下:
image

pin属性的值为0x00 05 00 05,也就是GPF5.
如果节点没有设置name属性,那么转换为device_node时,会将节点自己的名称作为name属性值。 所以这里name是led.
根文件系统下也可以查看platform_device。系统中所有的platform_device,都可以在/sys/devices/platform/路径下查看。
image

另外,系统中所有的platform_device,有来自设备树的,也有来自.c文件中注册的。那么,我们怎么知道哪些platform_device是来自设备树,哪些是来自.c文件中注册的?

答:可以查看该platform_device的相关目录下,是否有of_node,如果有of_node,那么这个platform_device就来自于设备树;否则,来自.c文件。

以led为例,进入led目录,可以看到有of_node,说明这个platform_device来自设备树。同时,可以看到这个of_node是一个链接文件,指向的是/sys/firmware/devicetree/base/led。也就是说,可以进入 /sys/devices/platform/<设备名>/of_node 查看它的设备树属性。
image

在/proc下有一个链接文件device-tree,它指向的是/sys/firmware/devicetree/base
image

2.设备树的语法

设备树文件(dts: device tree source),它需要编译为 dtb(device tree blob)文件,内核使用的是 dtb 文件。

2.1 DTS 文件

2.1.1 DTS文件的总体布局

设备树源文件通常以dts为后缀,其总体布局如下:

/dts-v1/;
[memory reservations]
/{
	[property definitions]
	[child nodes]
}

以上各项的含义分别为:

名称 含义
/dts-v1/ 设备树文件的版本
memory reservations 指定保留内存,内核不会使用保留内存
/ 根节点(使用花括号括出属于根节点的内容)
property definitions 根节点的属性,用来描述硬件
child nodes 孩子节点(使用花括号括出属于孩子节点的内容)

2.1.2 memory reservations的格式

该项是可选项,如果想要保留一段内存不让内核使用,可用如下格式指定:

/*
	address    指定要保留的内存的起始地址
	length     指定要保留的内存的长度
*/
/memreserve/<address><length>;

需要注意的是,address和length都是64位。

2.1.3 属性的格式

• 属性有值 [label:] property-name = value;
• 属性没有值 [label:] property-name;

其中各项的含义:

名称 含义
label 标签
property-name 属性名
value 属性值

2.1.3.1 有关属性名

属性名的长度为1~31个字符,可以自己取,只要能够提供可以解读该属性名的驱动即可。也有一些属性名有着特定的含义,比如compatible用于表示哪个或哪些驱动支持该设备。对于自己命名的属性,并非所有字符均可组成属性名,它需要由以下字符组成:
image

2.1.3.2 有关属性值

属性值有以下四种:

  1. array of cells 一个cell就是一个u32类型的数据,一个或多个cell用尖括号括起来,并以空格隔开就可以作为一种合法的属性值,如

     example = <0x1 0x2 0x3>;。
    
  2. 含有结束符的字符串

     example = "example value";
    
  3. 字节序列 用方括号括起一个或多个字节,字节之间可用也可不用空格隔开,且字节以两位16进制数表示,如

     example = [12 34 56 78];。
    
  4. 以上三种值的混合(以逗号隔开) 如

     compatible = "fsl,mpc8641", "ns16550";。
    

    ◆ 文本字符串(包含’\0’结束符)用双引号表示:

     string-property="a string";
    

    ◆ Cells(32位无符号整数)用尖括号表示:

     cell-property = <0xbeef 123 0xabcd1234>;
    

    ◆ 64bit 数据使用 2 个 cell 来表示:

     clock-frequency = <0x00000001 0x00000000>; 
    

    ◆ 二进制数据用方括号表示:

     binary-property=[0x01 0x23 0x45 0x67];
    

    ◆ 类型不同的数据的组合也是可以的,但需要用逗号隔开:

     mixed-property="a string", [0x01 0x23 0x45 0x67], <0x12345678>;
    

    ◆ 逗号同样用于创建字符串列表:

     string-list = "red fish", "blue fish";
    

举个例子:

/ {
	node1 {
		a-string-property = "A string";
		a-string-list-property = "first string", "second string";
		a-byte-data-property = [0x01 0x23 0x34 0x56];
		child-node1 {
			first-child-property;
			second-child-property = <1>;
			a-string-property = "Hello, world";
		};
		child-node2 {
		};
	};
	node2 {
		an-empty-property;
		a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
		child-node1 {
		};
	};
};

2.1.4 一些特定的属性

设备树文件中有一些特定的属性,他们拥有约定俗成的名称和含义,在devicetree-specification中,这些属性被称为Standard Properties,我们在使用这些属性时,应当遵守相应的约定。这些属性有很多,我将在下文中介绍它们中的一部分。

2.1.4.1 #address-cells

该属性的值表示在该节点的子节点的reg属性中,使用使用多少个cell,也即使用多少个u32整数来表示地址(对于32位系统,一个u32整数就够了;而对于64位系统,需要两个u32整数)。

2.1.4.2 #size-cells

该属性的值表示在该节点的子节点的reg属性中,使用多少个cell,也即使用多少个u32整数来表示大小(一段地址空间的长度)。
image

2.1.4.3 compatible

其值为一个或多个字符串,用来描述支持该设备的驱动程序。比如,该属性位于根节点时,用于指定内核中哪个machine_desc可以支持本设备,即当前设备与哪些平台兼容。其值的格式一般是"manufacturer, model",其中manufacturer表示厂家,model表示型号(厂家的哪型产品)。
当该属性的值有多个字符串时,从左往右,从最特殊到最一般。举例来说

	compatible = "samsung,smdk2416"

"samsung, s3c2416" 作为根节点的属性时,第一个字符串指示了一个具体的开发板型号,而第二个字符串要更一般,只指示了SoC的型号。在linux初始化时,会优先找支持"samsung,smdk2416"的machine_desc用以初始化硬件,找不到时才退而求其次找到"samsung, s3c2416"。

led { 
	compatible = “A”, “B”, “C”; 
}; 

“compatible”表示“兼容”,对于某个 LED,内核中可能有 A、B、C 三个驱 动都支持它。

2.1.4.4 model

其值为一个字符串,用来描述当前设备的型号(单板的名字)。当多个设备的compatible相同时,可以通过model来进一步区分多个设备。

{ 
	compatible = "samsung,smdk2440", "samsung,mini2440"; 
	model = "jz2440_v3"; 
}; 

它表示jz2440_v3这个单板,可以兼容内核中的“smdk2440”,也兼容“mini2440”.

2.1.4.5 phandle

该属性可以为节点指定一个全局唯一的数字标识符。这个标识符可以被需要引用该节点的另一个节点使用。举例来说,现有一个中断控制器:

pic@10000000{
	phandle =<1>;
	interrupt-controller;
};

还有一个可以产生中断的设备,且这个设备的中断信号线连接到了上述中断控制器,为了描述清楚这种关系,该设备的设备节点就需要引用中断控制器的节点:

another-device-node {
	interrupt-parent =<1>;/* 数字1就唯一标识了节点pic@10000000 */
};

2.1.4.6 interrupt-controller

这是一个没有值的属性,用在中断控制器的设备节点中,以表明这个节点描述的是一个中断控制器。

2.1.4.7 interrupt-parent

该属性用于可以产生中断,且中断信号连接到某中断控制器的设备的设备节点,用于表示该设备的中断信号连接到了哪个中断控制器。该属性的值通常是中断控制器设备节点的数字标识(phandle),具体示例在上文已经出现过了。

2.1.4.8 reg

reg属性描述了设备资源在其父总线定义的地址空间内的地址。通俗的说,该属性使用一对或多对(地址,长度)来描述设备所占的地址空间。至于地址和长度使用多少个cell来表示呢?这取决于上文介绍的#address-cells、#size-cells属性的值。
举个例子,当:

#address-cells =<1>;
#size-cells =<1>;

那么reg = <0x3000 0x20 0xFE00 0x100>,表示该属性所属的设备占据了两块内存空间,第一块是以0x3000为起始的32字节内存块;第二块是以0xFE00为起始的256字节内存块。

2.1.4.8 status

image

&uart1 { 
	status = "disabled"; 
}; 

2.1.5 节点的格式

节点的格式如下:

[label:]node-name[@unit-address]{
	[properties definitions]
	[child nodes]
};

以uart节点为例:

/ { 
	uart0: uart@fe001000 { 
		compatible="ns16550"; 
		reg=<0xfe001000 0x100>; 
	}; 
}; 

节点名node-name长为1~31个字符,这些字符可以是:
image
每个设备节点代表一个设备,因此节点名的命名通常要和设备相应,比如以太网控制器,我们可以给其取名ethernet。考虑到一个SoC中可能有多个以太网控制器,为了做区分,我们通常在其节点名后面加上设备的地址,也就是上文中出现的可选部分@unit-address。仍以以太网控制器为例,加入两个以太网控制器的寄存器组的首地址分别为0xfe002000和0xfe003000,那么相应的节点名可以取为ethernet@fe002000和ethernet@fe003000。
不难看出,设备节点允许嵌套,假设节点b嵌套于节点a中,那么节点a是节点b的父节点。根节点的名字比较特殊,就是一个斜杠/,其他的设备节点都是根节点的孩子,或者孩子的孩子…因此,所有的设备节点呈现出一个树状的层次结构(设备树因此得名),下图就是一个例子:
image

2.1.5.1 推荐的节点名

关于节点的命名,官方有一些推荐的命名,具体可见devicetree-specification-v0.3的2.2.2节。

2.1.5.2 节点的路径名

在文件系统中有个术语叫文件的路径名(pathname),在按照树状结构组织的众多文件中,用以唯一标识某个文件。类似的,节点也有路径名的概念。将根节点类比为根目录,以上图为例,其中cpu0节点的路径名为/cpus/cpu@0。我们在给节点命名时,必须保证每个节点拥有唯一的路径名(注意区别于每个节点拥有唯一的节点名)。

2.1.6 一些特殊的节点

有一些特殊的节点不代表任何设备,而是有着特定的用途,本节就将介绍一些这样的节点。

2.1.6.1 /aliases节点

/aliases节点应当作为根节点的孩子节点,用于定义一个或多个别名属性,每条别名属性会为一个设备节点的路径名设置一个别名,如下面这个例子所示:

aliases {
	serial0 ="/simple-bus@fe000000/serial@llc500";
	ethernet0 ="/simple-bus@fe000000/ethernet@31c000";
};

别名只能由1~31个下面的字符组成:
image
别名通常以数字结尾,比如别名为i2c1,设备树的初始化程序在解析别名属性时,会将数字1记录在struct alias_prop结构的id成员中,使用of_alias_get_id可以获得这个数字。因为本文主要介绍设备树文件的格式,因此这里不再深究这部分内容。

2.1.6.2 /chosen节点

/chosen节点应当用作根节点的孩子节点,有以下可选属性:
• bootargs
• stdout-path
• stdin-path
顾名思义,该节点可以指定启动参数、标准输出和标准输入,一个例子如下:

/{
	......
	chosen {
		bootargs ="root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
		};
	......
};

2.1.6.3/根节点

/ { 
	model = "SMDK24440"; 
	compatible = "samsung,smdk2440"; 
	#address-cells = <1>; 
	#size-cells = <1>; 
}; 

根节点中必须有这些属性:

#address-cells // 在它的子节点的 reg 属性中, 使用多少个 u32 整数来描述地址(address) 
#size-cells // 在它的子节点的 reg 属性中, 使用多少个 u32 整数来描述大小(size) 
compatible // 定义一系列的字符串, 用来指定内核中哪个 machine_desc 可以支持本设备 (即这个板子兼容哪些平台) 
model // 咱这个板子是什么

标签:字符,property,device,驱动,2.1,设备,节点,属性
From: https://www.cnblogs.com/fuzidage/p/17363949.html

相关文章

  • 驱动开发:通过MDL映射实现多次通信
    在前几篇文章中LyShark通过多种方式实现了驱动程序与应用层之间的通信,这其中就包括了通过运用SystemBuf缓冲区通信,运用ReadFile读写通信,运用PIPE管道通信,以及运用ASYNC反向通信,这些通信方式在应对一收一发模式的时候效率极高,但往往我们需要实现一次性吐出多种数据,例如ARK工具中当我......
  • 驱动开发:通过MDL映射实现多次通信
    在前几篇文章中LyShark通过多种方式实现了驱动程序与应用层之间的通信,这其中就包括了通过运用SystemBuf缓冲区通信,运用ReadFile读写通信,运用PIPE管道通信,以及运用ASYNC反向通信,这些通信方式在应对一收一发模式的时候效率极高,但往往我们需要实现一次性吐出多种数据,例如ARK工具中当......
  • Linux设备驱动开发详解
    Linux内核系列文章Linux内核设计与实现深入理解Linux内核Linux设备驱动程序Linux设备驱动开发详解文章目录Linux内核系列文章前言一、待续前言  本文主要用来摘录《Linux设备驱动开发详解第四版》一书中学习知识点,本书基于Linux4.0版本,源代码摘录基于Linux4.15.18......
  • R5F100GEAFB是超低功耗16位微控制器,L99MD02XPTR一款6×半桥式汽车应用驱动器。
    R5F100GEAFB16位微控制器具有超低功耗、增强性能、高集成度和各种强大的外设功能。得益于以上特性,RL78MCU非常适合用于各种应用,包括电池供电设备和家用应用。该MCU可为系统设计人员提供省电特性和高性能操作,从而实现超低功耗应用。该器件提供1KB到512KB的片上闪存。这种低功耗MC......
  • MySQL日期字符串转日期格式,日期格式数据转为字符串
    如下:1、日期字符串转换为日期格式数据SELECTDATE('2017-02-11');SELECTDATE('2017/02/11');SELECTSTR_TO_DATE('2015/02/25','%Y/%m/%d');SELECTSTR_TO_DATE('2015-02-25','%Y-%m-%d');返回日期格式数据 2、DATE_FORMAT将日期转......
  • 【带DC引脚SPI屏】STM32L010K8超低功耗单片机软件模拟SPI驱动ST7567点阵屏12864示例
    显示屏驱动芯片多种多样,有的不带DC,通过接收的数据的某个特定位确定是命令还是数据,比如常见的12864移植案例在【不带DC脚的spi屏】STM32F103C8移植u8g2在软件模拟spi模式下驱动st7920带字库的12864显示屏-不打鱼光晒网-博客园(cnblogs.com)和【不带DC脚的spi屏】stm32f1......
  • 8094: 字符串拼接
    描述 现在有长度为1且为小写字母的字符串str,请你按照规则完成t次拼接,每一次要将字符串str的最后一个字母后的第n个字母拼接到字符串str的末尾,如果最后一个字母后的第n个字母超出了小写字母z的范围,那么重新从小写字母a开始算。例如当str=a,n=1,t=3时,拼接的结果是str=abc......
  • 数组和字符串
    数组操作读取数组中的元素,是通过访问索引的方式来读取的,一般从0位置开始。对于数组,计算机在内存中为其申请一段连续的空间,且会记下索引为0处的内存地址。主要的四种操作为:读取,查找,插入和删除元素。1.寻找数组的中心索引:给定整数数组nums,计算数组的中心下标(其左侧所有元素相......
  • 2023-04-28:将一个给定字符串 s 根据给定的行数 numRows 以从上往下、从左到右进行 Z
    2023-04-28:将一个给定字符串s根据给定的行数numRows以从上往下、从左到右进行Z字形排列比如输入字符串为"PAYPALISHIRING"行数为3时,排列如下PAHNAPLSIIGYIR之后,你的输出需要从左往右逐行读取,产生出一个新的字符串"PAHNAPLSIIGYIR"请你实现......
  • 在终端(Terminal)执行 gradle build 命令控制台提示 GBK 字符编码错误
     1、错误提示: 1.1、使用EditPlus和IntellJIDEA都显示文件是UTF-8,明明都是UTF-8,却依然不同。 1.2、通过命令行工具查看活动代码页为936,其对应字符编码GBK,由此可知是字符编码不一致导致的。 1.3、EditPlus和IntellJIDEA和命令行(CMD)工具或终端使用的字符集不同,又由于......