Linux에서 하드웨어 장치용 드라이버를 작성하는 방법이 궁금하신가요? Linux의 다양한 하드웨어 플랫폼 및 구성에 맞게 드라이버를 조정하는 방법에 대해 궁금한 적이 있습니까? 드라이버가 핫 플러그, 전원 관리, 장치 공유 등과 같은 일부 고급 기능을 Linux 시스템에서 구현하도록 활성화하는 방법에 대해 생각해 본 적이 있습니까? 이러한 문제에 관심이 있다면 이 기사에서는 이러한 목표를 달성하기 위한 효과적인 방법인 Linux 장치 드라이버 장치 트리를 소개합니다. Devicetree는 하드웨어 장치를 설명하는 데 사용되는 데이터 구조로, 하드웨어 장치의 정보와 속성을 간단하고 통일된 방식으로 커널에 전달하여 장치 식별 및 드라이버를 실현할 수 있습니다. Devicetree는 하드웨어 독립성을 달성하기 위한 메커니즘이기도 합니다. 이를 통해 드라이버 코드에서 하드웨어 장치의 구성 및 관리를 유연하고 이식 가능한 방식으로 분리하여 다중 플랫폼 지원을 달성할 수 있습니다. Devicetree는 다양한 하드웨어 장치의 인터페이스와 프로토콜을 표준적이고 보편적인 방식으로 정의하고 사용함으로써 핫 플러깅, 전원 관리, 장치 공유 등의 기능을 구현하기 위한 프레임워크이기도 합니다. 이 글에서는 리눅스 디바이스 드라이버에서 디바이스트리의 기본 개념, 문법 규칙, 작성 방법, 컴파일 과정, 로딩 방법 등을 자세하게 소개하고, 이 유용하고 강력한 방법을 익히는 데 도움이 될 것입니다.
Devicetree(디바이스 트리)는 시스템 하드웨어 정보를 설명하는 데 사용되는 트리 모델로, 커널을 통합하도록 설계되었습니다. 장치 트리 정보는 부트로더를 통해 커널로 전달되고, 커널은 이러한 장치 설명을 기반으로 해당 보드 수준 드라이버를 초기화하여 여러 플랫폼에서 하나의 커널을 공유하는 목적을 달성합니다.
Devicetree는 주로 플러그형이 아닌(비동적) 장치의 보드 수준 하드웨어 정보를 설명하도록 설계되었습니다. 장치 정보를 설명하는 노드의 계층적 트리 구조로 구성됩니다. 각 노드에 포함된 콘텐츠는 속성/값 쌍으로 표시됩니다. 루트 노드를 제외한 모든 노드에는 상위 노드가 있습니다. 그림과 같이:
이름이 '/'로 표시되는 루트 노드를 제외하고 다른 노드는 node-name@unit-address
로 이름이 지정되며 동일한 수준에서 고유해야 합니다.
노드 이름
으아아아단위 주소
으아아아는 노드의 전체 경로를 나타냅니다. 예:
으아아아각 노드에 포함된 주요 콘텐츠는 이름과 값으로 구성된 설명된 장치의 속성 정보입니다.
속성 이름
으아아아속성 값
가치 | 설명 |
---|---|
비어있음 | 속성 값이 비어 있으며 참-거짓 정보를 나타내는 데 사용됩니다. |
u32/u64 | 32/64비트 빅엔디안 부호 없는 정수, 표현 시
| 추가 필요
문자열,문자열 목록 | null로 끝나는 문자열 또는 해당 구성 요소 목록 |
compatible
Value type: Description: 表示兼容的设备类型,内核据此选择合适的驱动程序。由多个字符串组成,从左到由列出 这个设备兼容的驱动(from most specific to most general)。 推荐的格式为:“制造商名,具体型号”。 Example: compatible = "fsl,mpc8641-uart", "ns16550"; 内核先搜索支持“fsl,mpc8641-uart”的驱动,如未找到,则搜索支持更通用的“ns16550” 设备类型的驱动。
model
Value type: Description: 表明设备型号。 推荐的格式为:“制造商名,具体型号”。 Example: model = "fsl,MPC8349EMITX";
phandle
Value type: Description: 用一个树内唯一的数字标识所在的这个节点,其他节点可以直接通过这个数字标识来引用 这个节点。 Example: pic@10000000 { phandle = ; interrupt-controller; }; interrupt-parent = ;
status
Value type: Description: 表示设备的可用状态: "okay" -> 设备可用 "disabled" -> 目前不可用,但以后可能会可用 "fail" -> 不可用。出现严重问题,得修一下 "fail-sss" -> 不可用。出现严重问题,得修一下。sss指明错误类型。
#address-cells and #size-cells
Value type: Description: 在拥有子节点的节点中使用,来描述它的字节点的地址分配问题。即分别表示子节点中使 用多少个u32大小的cell来编码reg属性中的address域和size域。 这两个属性不会继承,必须明确指出。如未指出,默认#address-cells=2,#size- cells=1。 Example: soc { #address-cells = ; #size-cells = ; serial { reg = ; }; };
reg
Value type: encoded as an arbitraty number of (address, length) pairs. Description: 描述该设备在parent bus定义的地址空间中的地址资源分配。 Example: reg = ; a 32-byte block at offset 0x3000 and a 256-byte block at offset 0xFE00。
virtual-reg
Value type: Description: 表示映射到reg第一个物理地址对应的effective address。使bootloader能够提供给内 核它所建立的virtual-to-physical mappings。
ranges
Value type: or encoded as an arbitrary number of (child-bus-address,parent-bus- address, length) triplets. Description: 提供了子地址空间与父地址空间的映射关系,如果值为空则父子地址相等,无需转换。 Example: soc { compatible = "simple-bus"; #address-cells = ; #size-cells = ; ranges = ; serial { compatible = "ns16550"; reg = ; }; }; 将子节点serial的0x0地址映射到父节点soc的0xe0000000,映射长度为0x100000。此时 reg的实际物理地址就为0xe0004600。
dma-ranges
Value type: or encoded as an arbitrary number of (child-bus-address,parent-bus-address, length) triplets. Description: 提供了dma地址的映射方法。
描述中断的属性有4个:
interrupt-controller
一个空的属性用来指示这个节点设备是接收中断信号的控制器。
#interrupt-cells
这是上面所说中断控制器中的一个属性,用来描述需要用多少个cell来描述这个中断控制器的 interrupt specifier(类似#address-cells和#size-cells)。
interrupt-parent
常出现在根节点的一个属性,它的属性值是指向interrupt-controller的一个phandle。可从 parent继承。
interrupts
包含interrupt specifiers列表,每一个specifier表示一个中断输出信号。
Example
/ { interrupt-parent = ; intc: interrupt-controller@10140000 { compatible = "arm,pl190"; reg = ; interrupt-controller; #interrupt-cells = ; }; serial@101f0000 { interrupts = ; }; };
所有的设备树都必须有一个root节点,且root节点下必须包含一个cpus节点和至少一个memory节点。
root node
root节点须包含 #address-cells、#size-cells、model、compatible等属性。
/cpus node
是cpu子节点的父节点容器。须包含 #address-cells、#size-cells属性。
/cpus/cpu* node
是描述系统cpu的节点。
/memory node
描述系统物理内存的layout。须包含reg节点。 Example: 假如一个64位系统有如下两块物理内存: - RAM: starting address 0x0, length 0x80000000 (2GB) - RAM: starting address 0x100000000, length 0x100000000 (4GB) 则我们可以有下面两种描述方法(#address-cells = and #size-cells =): Example #1 memory@0 { reg = ; }; Example #2 memory@0 { reg = ; }; memory@100000000 { reg = ; };
/chosen node
根节点下的一个子节点,不是描述设备而是描述运行时参数。常用来给内核传递bootargs: chosen { bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; };
/aliases node
由1-31个字母、数字或下划线组成的设备节点full path的别名。它的值是节点的全路径,因此最终会被编码成字符串。 aliases { serial0 = "/simple-bus@fe000000/serial@llc500"; }
更多具体设备具体类别的描述信息:内核源代码/Documentation/devicetree/bindings。
DTS是描述devicetree的源文本文件,它通过内核中的DTC(Devicetree Compiler)编译后生成相应平台可烧写的二进制DTB。
DTB又称Flattened Devicetree(FDT),在内存中的结构如下图所示:
大端字节序结构体:
struct fdt_header { uint32_t magic; /* contain the value 0xd00dfeed (big-endian) */ uint32_t totalsize; /* the total size of the devicetree data structure */ uint32_t off_dt_struct; /* offset in bytes of the structure block */ uint32_t off_dt_strings; /* offset in bytes of the strings block */ uint32_t off_mem_rsvmap; /* offset in bytes of the memory reservation block */ uint32_t version; /* the version of the devicetree data structure */ uint32_t last_comp_version; /* the lowest version used is backwards compatible */ uint32_t boot_cpuid_phys; /* the physical ID of the system’s boot CPU */ uint32_t size_dt_strings; /* the length in bytes of the strings block */ uint32_t size_dt_struct; /* the length in bytes of the structure block */ };
Purpose
为系统保留一些特殊用途的memory。这些保留内存不会进入内存管理系统。
Format
struct fdt_reserve_entry { uint64_t address; uint64_t size; };
Devicetree结构体存放的位置。由一行行“token+内容”片段线性组成。
token | Description |
---|---|
FDT_BEGIN_NODE (0x00000001) | 节点起始,其后内容为节点名 |
FDT_END_NODE (0x00000002) | 节点结束 |
FDT_PROP (0x00000003) | 描述属性 |
FDT_NOP (0x00000004) | nothing,devicetree解析器忽略它 |
FDT_END (0x00000009) | block结束 |
[label:] node-name[@unit-address] { [properties definitions] [child nodes] };
Version 1 DTS files have the overall layout:
/dts-v1/; /* dts 版本1 */ [memory reservations] /* DTB中内存保留表的入口 */ / { [property definitions] [child nodes] };
通过本文,我们了解了devicetree在Linux设备驱动中的应用和作用,学习了如何编写、编译、加载、修改和调试devicetree。我们发现,devicetree是一种非常适合嵌入式系统开发的方法,它可以让我们方便地描述和管理硬件设备,实现硬件无关性和高级功能。当然,devicetree也有一些注意事项和限制,比如需要遵循语法规范、需要注意兼容性问题、需要注意内存占用和性能影响等。因此,在使用devicetree时,我们需要有一定的硬件知识和经验,以及良好的编程习惯和调试技巧。希望本文能够为你提供一个入门级的指导,让你对devicetree有一个初步的认识和理解。如果你想深入学习devicetree,建议你参考更多的资料和示例,以及自己动手实践和探索。
위 내용은 Linux 장치 드라이버 장치 트리: 하드웨어 장치를 설명하고 관리하는 효율적인 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!