字符设备驱动程序 — 2 设备树

简介

image-20240529104213893

DTS文件

用来描述设备树文件,也就是开发板上的设备信息

设备树的引用原因

以LED驱动为例,如果你要更换LED所用的GPIO引脚,需要修改驱动程序源码、重新编译驱动、重新加载驱动。

在内核中,使用同一个芯片的板子,它们所用的外设资源不一样,比如A板用GPIO A,B板用GPIO B。而GPIO的驱动程序既支持GPIO A也支持GPIO B,你需要指定使用哪一个引脚,怎么指定?在.c文件中指定。

随着ARM芯片的流行,内核中针对这些ARM板保存有大量的、没有技术含量的文件(上述的指定资源的.c文件)。

Linus大发雷霆:“this whole ARM thing is a f*cking pain in the ass”。

于是,Linux内核开始引入设备树。设备树并不是重新发明出来的,在Linux内核中其他平台如PowerPC,早就使用设备树来描述硬件了。

Linus发火之后,内核开始全面使用设备树来改造,神人就神人。

/sys/firmware/devicetree目录下是以目录结构程现的dtb文件, 根节点对应base目录, 每一个节点对应一个目录, 每一个属性对应一个文件。

这些属性的值如果是字符串,可以用cat命令把它打印出来;对于数值,可以用hexdump把它打印出来。

一个单板启动时,u-boot先运行,它的作用是启动内核。U-boot会把内核和设备树文件都读入内存,然后启动内核。在启动内核时会把设备树在内存中的地址告诉内核。

设备树名词关系

DTS:设备树源码文件

DTB:DTS编译得到的二进制文件

DTS —> DTB 需要用到DTC编译工具

DTC 工具源码在 Linux 内核的 scripts/dtc 目录下.另外dtsi就相当于C语言的.h文件的概念

dtsi文件:设备树模板,一般 dts 文件可以 include 包含 dtsi 文件,类似于头文件

设备树语法

Device格式

DTS文件格式

/dts-v1/;                // 表示版本
[memory reservations]    // 格式为: /memreserve/ <address> <length>;
/ {
    [property definitions]
    [child nodes]
};

node格式

设备树中的基本单元,被称为“node”,其格式为:
[label:] node-name[@unit-address] {            // unit-address 寄存器/设备地址
    [properties definitions]
    [child nodes]
};

label是标号,可以省略,作用是方便引用node,比如:

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

可以使用下面 2 种方法来修改 uart@fe001000 这个 node:

  1. 标签
  2. 全路径
// 在根节点之外使用 label 引用 node:
&uart0 {
    status = “disabled”;   // 状态设为 disabled 那么这个节点的定义就会失效
};

或在根节点之外使用全路径:
&{/uart@fe001000} {
    status = “disabled”;
};

常用属性(propertics)

value表示

properties就是“property-name = value”,value有多种取值方式

property格式1:

[label:] property-name = value;

property格式2(没有值):

[label:] property-name

property的取值只有4种

1. arrays of cells(1 个或多个 32 位数据, 64 位数据使用 2 个 32 位数据表示),
2. string(字符串),
3. bytestring(1 个或多个字节)
4. 各种值的组合
  1. arrays of cells (cell就是一个32位数据,64位数据用两个cell表示)

    用尖括号包围起来

    interrupts = <17 0xc>                // 两个32位数据
    
    interrupts = <0x00000001 0x00000000> // 一个64位数据
    
  2. A null-terminated string (有结束符的字符串),用双引号包围起来

    compatible = "simple-bus";
    
  3. A bytestring(字节序列) ,用中括号包围起来

    local-mac-address = [00 00 12 34 56 78]; 
    // 每个 byte 使用 2 个 16 进制数来表示
    local-mac-address = [000012345678]; 
    // 每个 byte 使用 2 个 16 进制数来表示
    
  4. 可以是各种值的组合, 用逗号隔开

    compatible = "ns16550", "ns8250";
    example = <0xf00f0000 19>, "a strange property format";
    

1.#address-cells、size-cells

cell指一个32位的数值

address-cells:address要用多少个32位数来表示

size-cells:size要用多少个32位数来表示

表示这个节点下一级节点的地址属性要如何表示

/ {
    #address-cells = <1>;
    #size-cells = <1>;
    memory {
        reg = <0x80000000 0x20000000>;
    };
};
// reg中第一个32位数据表示这块内存的起始地址
// 第二个32位数据表示这块内存的大小

2.compatible

“ compatible ” 表示 " 兼容 ",对于某个LED,内核中可能有A、B、C三个驱动都支持它,那就可以这么写:

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

内核启动时,就会为这个LED按这样的优先顺序为它找到驱动程序:A、B、C

根节点下也有compatible属性,用来选择哪一个“machine desc”:一个内核可以支持machine A,也支持machine B,内核启动后会根据根节点的compatible属性找到对应的machine desc结构体,执行其中的初始化函数。

compatible的值,建议取这样的形式:“manufacturer,model”,即“厂家名,模块名”。

比如:compatibl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值