Linux设备树翻译计划

本文翻译自Device Tree Usage主页:
http://devicetree.org/Device_Tree_Usage
此译文为本人原创,若要转载请注明!
Linux device tree的背景(引用自宋宝华博客):
        Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pain in the ass”,引发ARM Linux社区的地震,随后ARM社区进行了一系列的重大修正。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。读者有兴趣可以统计下常见的s3c2410、s3c6410等板级目录,代码量在数万行。
        社区必须改变这种局面,于是PowerPC等其他体系架构下已经使用的Flattened Device Tree(FDT)进入ARM社区的视野。Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。

设备树使用
________________________________________________
本页演示怎样为一个新的机器编写设备树。这主要为了给出设备树的整体概念以及他们是怎样被用来描述机器的。
如果需要设备树数据格式的完整描述,请参考ePAPR规范。本本主页只是讲述了一些基本主题,而ePAPR规范讲述了很多这些主题的细节,对于本页中没有讲述的高级用法,请参考ePAPR。
基本数据格式
________________________________________________
设备树是具有简单树形结构的节点和属性。属性是成对的键值,节点可能包含属性和子节点。举个例子来说,下面是一个简单的.dts格式的树:

/ {
    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 {
        };
    };
};

这棵树很明显是没用的,因为它没用描述任何东西,但是它确实展示出了节点属性。即:
  • 单个根节点:"/"
  • 一对子节点:"node1", "node2"
  • 一对node1的子节点:"child-node1", "child-node2"
  • 树上散布的一堆属性
属性是简单的键值对,其中键值既可以是空也可以包含任何字节流。虽然数据类型没用被编码在数据结构中,但是在设备树源文件中有一些基本的数据表示方法。
  • 文本字符串(以null作为终止)以双引号的形式表示:
    • string-property = "a string'
  • 'Cells'是32位无符号整数,并且使用尖括号分隔:
    • cell-property = <0xbeef 123 0xabcd1234>
  • 二进制数据使用方括号分隔:
    • binary-perperty = [0x01 0x23 0x45 0x67]
  • 不同表示类型的数据可以通过逗号级联在一起:
    • mixed-perperty = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
  • 逗号也可以用来创建字符串列表:
    • string-list = "red fish", "blue fish";

基本概念
________________________________________________
为了理解怎样使用设备树,我们从一个样品机开始并且搭建设备树来一步步描述它
样品机
考虑下面的假想机器(粗略地基于ARM Versatile),"Acme"制造,命名 “Coyote's Revenge":
  • 32位 ARM CPU单核
  • PLB粘附在内存映射串口上,spi总线控制器,i2c控制器,中断控制器以及外部总线桥
  • 256MB SDRAM基址从0开始
  • 2个串口,基址从0x101F1000,0X101F2000开始
  • GPIO控制器,基址从0x101F3000开始
  • SPI控制器,基址从0x10170000并且总线上挂载着下列设备:
    • MMC卡槽并且SS引脚连接在GPIO #1上
  • 外部总线桥并且总线上挂载着下列设备:
    • SMC SMC91111以太网设备连接在基址从0x10100000开始的外部总线上
    • i2c控制器,基址从0x10160000开始并且总线上挂载着如下设备:
      • Maxim DS1338实时时钟。该器件响应0x58的从机地址。
    • 64MB NOR flash,基址从0x30000000开始
初始结构
第一步是为机器制定框架结构。下面是一个合法的设备树所需的最小结构。在这个节点,你想想要能够唯一地识别该机器

/ {
    compatible = "acme,coyotes-revenge";
};

compatible制定系统的名称。它包含"<manufacture>,<model>"格式的字符串。准确地确定器件型号是非常重要的,并且我们需要包含厂商的名字来避免名字空间冲突。因为操作系统会使用compatible这个值来决定怎样在这个机器上运行,所以在这个属性中放入正确的值是非常重要的。
理论上来说,compatible是一个OS需要唯一地识别机器所需要的唯一数据。如果所有机器的细节都是写死的,那么OS可以在顶层compatible属性中专门查找"acme,coyotes-revenge"。
CPUs
下一步是描述每个CPU。一个命名为"cpus"的容器节点跟有对应每个CPU的子节点。在这个例子中,系统是一个双核ARM Cortex A9的系统。

/ {
    compatible = "acme,coyotes-revenge";
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };
};

每个CPU节点中的compatible属性是以<manufacturer>,<model>的格式确定CPU型号的字符串,就像顶层的compatible属性那样。
更多的属性会在稍后添加到cpu节点中,但是我们首先需要讨论更多基本的概念。
节点名字
我们值得花一段时间讨论命名习惯。每一个几点必须要有一个以<name>[@<unit-address>]形式的名字。
<name>是简单的ascii字符串并且长度最大可以到31个字符。通常来说,节点是根据它所代表的设备类型来命名的。举个例子,3com公司的以太网适配器节点可能会使用ethernet作为它的名字,而不是3com509。
unit-address只有在节点描述含有地址的设备时会被包含进来。通常来说,unit address是用来访问设备的基址,并且在节点的reg属性中被罗列出来。我们稍后会在本文档中介绍reg属性。
兄弟节点必须被唯一地命名,不过对于不只一个节点的情况,我们通常会使用通用的名字,只要它们的地址不一样就可以。(比如:seriali@101f1000 和serial@101f2000)。
如果需要更多节点命名方面的详细情况,请参考ePAPR规范的第2.21部分
设备
系统中的每一个设备都由一个设备树节点来代表。下一步就是用每一个设备对应的节点来填充树。现在来说,新节点将会被置空知道我们可以讨论地址范围以及终端是怎样安排的。

/ {
    compatible = "acme,coyotes-revenge";
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };
    serial@101F0000 {
        compatible = "arm,pl011";
    };
    serial@101F2000 {
        compatible = "arm,pl011";
    };
    gpio@101F3000 {
        compatible = "arm,pl061";
    };
    interrupt-controller@10140000 {
        compatible = "arm,pl190";
    };
    spi@10115000 {
        compatible = "arm,pl022";
    };
    external-bus {
        ethernet@0,0 {
            compatible = "smc,smc91c111";
        };
        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            rtc@58 {
                compatible = "maxim,ds1338";
            };
        };
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
        };
    };
};

在这棵树中,系统中的每个设备都被添加了响应的节点,并且层次结构反映了设备时怎样连接到系统的。举个例子来说,外部总线上的设备是外部总线的子节点,并且i2c设备是i2c总线控制器的子节点。通常来说,层次结构代表了从CPU角度看到的系统视图。
在这里这棵树并不是合法的。它缺少了设备之间连接的信息。那部分数据会在稍后添加。
这棵树中有一些需要注意的地方:
  • 每一个设备节点都有一个compatible属性
  • flash节点的compatible属性中有两个字符串。阅读下一部分来了解为什么会这样。
  • 之前提到过,节点的名字反映了设备的类型,而不是特定的型号。情况ePAPR规范的2.2.2部分,规范中提到了一系列已经定义好了随处可能用到的通用节点名字
理解compatible属性
设备树中代表设备的每一个节点必须要有compatible属性。compatible是操作系统用来决定哪个设备驱动绑定哪个设备的关键字。
compatible是字符串列表。列表中的第一个字符串以"<manufacturer>,<model>"的形式确定了节点代表的设备。接下来的字符串表示该设备可以兼容的其他设备。
举个例子来说,Freescale MPC8349 片上系统(SoC)有一个串行设备实现了国家半导体 ns16550寄存器接口。MPC8349穿行设备的compatible属性因此应该是:compatible = "fsl,mpc8349-uart","ns16550"。在这个例子中,fsl,mpc8349-uart确定了设备并且ns16550表示它在寄存器级别兼容国家半导体16550 UART。
注意:ns16550没有厂商前缀纯粹是因为历史原因(IBM-PC/AT吧..)。所有新的compatible值应该使用厂商前缀。
该操作允许现存的设备驱动绑定到更新的设备上,不过它仍然唯一地识别确切的硬件。
警告:不要在compatible值中使用通配符,比如"fsl,mpc83xx-uart"或者类似地。硅片厂商总是会做一些打破你通配符假设的变化,到那时再改变就为时已晚了。相反,选择一个特定的硅片实现并且使所有随后的硅片与之兼容。
寻址是如何工作的
________________________________________________
可寻址的设备使用下面的属性来将地址信息编码进入设备树:
  • reg
  • #address-cells
  • #size-cells
        每一个可寻址的设备获取的reg,是以reg = <address1 length1 [address2 length2] [address3 length3] ...>形式的表格元组。每一个元组代表设备所使用的地址范围。每一个地址值是被称为cells的一个或者多个32位整数的列表。相似地,长度值既可以是cells的列表,也可以是空的。
因为地址和长度域都是长度可变的,所以父节点中的#address-cells和#size-cells属性是用来说明每一个域中有多少个cells。换句话说,正确地翻译一个reg属性需要父节点的#address-cells和#size-cells值。为了看到这一切是怎样工作的,让我们将寻址属性添加到样例设备树中,首先从CPU开始
CPU寻址
讨论到寻址时,CPU节点代表最简单的情况。每一个CPU被赋予了一个唯一的ID并且CPU的ID没有关联的尺寸。

    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };

cpu节点中,#address-cells被设置为1,#size-cells被设置为0.这意味着子节点的reg值是代表地址且没有size域的单个32位无符号整数。在这个例子中,2个cpu被赋予了地址0和1。cpu节点的#size-cells是0,因为cpu仅仅被赋予了单个地址。
你能注意到reg值匹配节点名字中的值。按照惯例,如果一个节点具有reg属性,这个节点必须包含单元地址,也就是reg属性中的第一个地址值。
内存映射设备
不同于cpu节点中找到的单地址值,内存映射设备被分配了它会响应的一个地址范围。#size-cells用来说明每一个子节点中的reg元组有多长。接下来的例子中,每一个地址值都是一个单元的(32位),每一个长度值也是一个单元,即典型的32位系统。64位系统可以把#address-cells和#size-cells赋值为2从而在设备设备树中得到64位寻址。

/ {
    #address-cells = <1>;
    #size-cells = <1>;
    ...
    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
    };
    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
    };
    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
               0x101f4000 0x0010>;
    };
    interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
    };
    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
    };
    ...
};

每一个设备都被分配了一个基地址,以及它被分配的区域的尺寸。本例中的GPIO设备地址被分配了两个地址范围:0x101f3000...0x101f3fff 和0x101f4000..0x101f400f。
有一些设备挂载在具有不同寻址策略的总线上。举个例子来说,一个设备可以被连接到具有独立片选信号的外部总线上。因为每一个父节点定义了它子节点的寻址域,所以我们可以从最佳描述系统的角度来选择地址映射方案。下面的代码显示了连接到外部总线上的设备的地址分配情况,并且这些外部总线具有编码如地址的片选数字。

    external-bus {
        #address-cells = <2>
        #size-cells = <1>;
        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
        };
        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            reg = <1 0 0x1000>;
            rtc@58 {
                compatible = "maxim,ds1338";
            };
        };
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };

外部总线使用了2个单元的地址值。一个是片选数字,另一个是片选基地址的偏移。长度域仍旧是单个单元,因为只有地址的偏移部分需要一个范围。因此在本例中,每一个reg入口都包含了3个单元:片选数字,偏移以及长度。
因为地址域被包含在节点以及它的子节点中,所以父节点可以自由定义任何总线上可行的寻址方案。直接父节点之外的节点通常不需要考虑本地寻址域,并且为了从一个域到另一个域,地址必须被映射。
非内存映射设备
其他设备并没有内存映射在处理器总线上。它们可以有寻址范围,但是它们并不能直接被CPU访问。相反,父节点设备的驱动会代表CPU间接地访问。
现在来看i2c设备的例子,每一个设备被分配了一个地址,但是它没有关联的长度或者范围。这看上去与CPU地址分配时一样的。

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
            };
        };
范围(地址转换)
我们已经讨论过了怎样为设备分配地址,但是这里的这些地址只是本地的设备节点地址。它缺并没有描述怎样从那些地址映射到CPU可以使用的地址。
根节点总是描述从CPU的视角看到的地址空间。根节点的子节点已经使用了CPU的地址域,是、因此不需要任何显示地映射。举个例子来说,serial@101f0000设备是直接被分配了0x101f0000地址。
那些不是根节点的直接子节点的节点不能使用CPU的地址域。为了得到一个内存映射的地址,设备树必须制定如何从一个域地址转换到另一个域。ranges属性就是用于这个目的的。
这里是添加了ranges属性的设备树例子。

/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    ...
    external-bus {
        #address-cells = <2>
        #size-cells = <1>;
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash
        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
        };
        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
            };
        };
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};

ranges是地址转换清单。ranges表中的每一个条目是包含子节点地址,父节点地址以及子节点地址空间区域大小的元组。每一个域的大小分别由子节点的#address-cells值,父节点的#address-cells值以及子节点的#size-cells值决定。对于本例子中的外部总线,子节点地址是2个单元,父节点地址是1个单元,大小也是一个单元的。三个ranges是这样被转换的:
  • 从片选0处偏移0开始的地方被映射到地址范围0x10100000...0x1010ffff
  • 从片选1处偏移0开始的地方被映射到地址范围0x10160000...0x1016ffff
  • 从片选2处偏移0开始的地方被映射到地址范围0x30000000...0x10000000
或者,如果父节点和子节点的地址空间是相同的,那么节点也可以添加空的ranges属性。空的ranges属性意味着子节点地址空间中的地址被1:1地映射到父节点地址空间。
你可能会问为什么地址转换总是用在所有1:1映射的情况下。一些总线(比如PCI)具有完全不同的地址空间,而这些细节必须暴露给操作系统。其他总线具有DMA引擎,这些引擎需要知道总线上的实际滴孩子。有时候设备需要被组合在一起,因为它们都共享有同样的软件可编程物理地址映射方法。该不该用1:1映射更大程度上取决于操作系统所需的信息以及硬件设计。
你应该也注意到,i2c@1,0节点中没有ranges属性,原因是不像外部总线,i2c总线上的设备没有内存映射到CPU的地址域。相反地,CPU通过i2c@1,0设备间接地访问rtc@58设备。缺少ranges属性意味着,设备不能直接被除了其父节点之外的任何设备访问
中断是怎样工作的
________________________________________________
中断不同于遵循树自然结构的地址范围转换,中断信号可能来自以及终止在机器的任何设备。不像设备树中自然表示的设备寻址,中断信号是以独立于设备树的节点之间的链接表示的。四个属性用来描述中断的联系:
  • interrupt-controller  ——  一个空的属性声明接收中断信号的设备为节点
  • #interrupt-cells  —— 这是中断控制器节点的属性。它表明这个中断控制器的中断描述符符中有多少单元。(类似于#adderss-cells以及#size-cells)
  • interrupt-parent —— 包含phandle的设备节点的一个属性,这个phandle指向它所连接到的中断控制器
  • interrupts —— 包含中断描述符列表的设备节点的一个属性,每一个设备上的中断输出信号都有一个
        中断描述符是一个或多个单元的数据(由#interrupt-cells指定),它们指定设备连接到哪个中断输入。大部分设备只有单个中断输出,如下面的例子所示,不过设备上也有可能有多个中断输出。中断描述符的意义完全取决于中断控制器设备的绑定。每一个中断控制器可以决定需要多少个单元才能唯一地定义一个中断输入。
下面的代码添加了连接到我们的Coyote's Revenge样例机器的中断。

/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&intc>;
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };
    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
        interrupts = < 1 0 >;
    };
    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
        interrupts = < 2 0 >;
    };
    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
               0x101f4000 0x0010>;
        interrupts = < 3 0 >;
    };
    intc: interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
        interrupt-controller;
        #interrupt-cells = <2>;
    };
    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
        interrupts = < 4 0 >;
    };
    external-bus {
        #address-cells = <2>
        #size-cells = <1>;
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash
        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
            interrupts = < 5 2 >;
        };
        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>;
            #size-cells = <0>;
            reg = <1 0 0x1000>;
            interrupts = < 6 2 >;
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;
                interrupts = < 7 3 >;
            };
        };
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};

有一些事情需要注意:
  • 这个机器只有一个中断控制器,interrupt-controller@10140000
  • 标签'intc:'已经被添加到中断控制器节点,并且标签被用来分配指向根节点的interrupt-parent属性的phandle。这个interrupt-parent值变成了系统的默认值,因为所有的子节点都继承了它,除非它被显示地覆盖。
  • 每一个设备都使用一个interrupt属性来制定一个不同的中断输入信号。
  • #interrupt-cells是2,因此每一个中断描述符有2个单元。这个例子采用了使用了常见的模式,用第一个单元来编码中断线号,用第二个单元来编码标志,比如高有效还是低有效又或者是边缘触发还是电平触发。对于任何给定的中断控制器,请参考控制器绑定文档来了解描述符是怎样编码的。
设备特定数据
除了公共的属性之外,我们可以添加任何属性以及子节点到节点。我们可以添加操作系统需要的任何数据,只要遵守一些规则即可。
首先,新的设备特定的属性名字应该使用生产厂商的前缀从而它们不会与现存的标准属性名称冲突。
其次,属性以及子节点的意义必须以绑定的形式记录下来从而设备驱动作者了解怎样翻译数据。绑定记录一个特定的compatible值意味着什么,它应该要有什么属性,它可能会有什么样的子节点以及设备表示什么。每一个唯一的compatible值应该有它自己的绑定(或者声明与其他compatible值得兼容性)。新设备的绑定在这个wiki中被记录。请看主页描述文档格和审查过程。
第三,请将新的绑定提交到devicetree-discuss@lists.ozlabs.org邮件列表进行审查。审查新的绑定会抓住许多将来可能导致问题常见错误。
特殊节点
________________________________________________
aliases节点
一个特定的节点通常是以完整的路径来引用,比如/external-bus/ethernet@0,0,不过当一个用户真的想知道“哪个设备是eth0”时,这将会很繁琐。aliases节点可以用来为一个完整的设备路径分配一个短的别名。比如:

    aliases {
        ethernet0 = &eth0;
        serial0 = &serial0;
    };

当需要为设备指定一个标示符时,操作系统欢迎大家使用别名。
你将会注意到这里使用了一个新的语法。propert = &label; 语法分配由标签引用并作为字符串属性的的完整节点路径。这与早前使用的phandle = <&label>;不同,它在单元中嵌入了phandle值。
chosen节点
chosen节点并不代表真实的设备,不过充当为在固件和操作系统之间传递数据的地方,比如启动参数。在chosen节点中的数据不代表硬件。典型情况下,chosen节点在.dts源文件中留空并在启动时填充。
在我们的系统中,固件可能会添加下面的内容到chosen节点:

    chosen {
        bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
    };
高级主题
________________________________________________
高级的样例机器
现在我们已经理解了基本定义,让我们添加一些硬件到样例机器中来讨论一些更复杂的使用案例。
高级的样例机器添加了一个PCI主桥配有内存映射到0x10180000的控制寄存器和编程至从0x80000000地址以上开始的BARs。
假设我们已经知道关于设备树以上内容,我们可以从添加如下节点描述PCI主桥开始。
        pci@10180000 {
            compatible = "arm,versatile-pci-hostbridge", "pci";
            reg = <0x10180000 0x1000>;
            interrupts = <8 0>;
        };

(接下来的内容大部分为PCI设备相关,不太常用,由于本人精力有限,留着以后再翻译了)





参考链接:
http://blog.csdn.net/21cnbao/article/details/8457546

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432624.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

像postman上传文件_90%的测试工程师是这样使用Postman做接口测试的……

postman介绍&测试准备postman介绍&#xff1a;postman是一个开源的接口测试工具&#xff0c;无论是做单个接口的测试还是整套测试脚本的拨测都非常方便。前期准备&#xff1a;测试前&#xff0c;需要安装好postman, 客户端版本跟插件版本都行&#xff0c;根据个人需要选择安…

浅析STL allocator

一般而言&#xff0c;我们习惯的 C 内存配置操作和释放操作是这样的&#xff1a; 1 class FOO{}; 2 FOO *pf new FOO; 3 delete pf; 我们看其中第二行和第三行&#xff0c;虽然都是只有一句&#xff0c;当是都完成了两个动作。但你 new 一个对象的时候两个动作是&#xff…

十六进制除法运算法则_苏教版数学七年级上册 微课视频 2.6 有理数的乘法与除法(1)...

第一章《数学与我们同行》视频讲解 同步练习2.1 《正数与负数》2.2 有理数与无理数2.3 数轴2.4 绝对值与相反数(1)2.4 绝对值与相反数(2)2.5 有理数的加法与减法(1)2.5 有理数的加法与减法(2)2.6 有理数的乘法与除法(1)七、有理数的乘除法1.有理数的乘法法则法则一&#xff1…

为自己尝试写点东西吧,程序员们!(转)

2012年秋季&#xff0c;正是大伙急于找实习工作的时候。尝试出去找过很多实习单位&#xff0c;但是基本上都是不靠谱&#xff0c;然后就是我自己能力的不足。所以找工作之路也是异常艰辛和曲折。 学了那么久的Java&#xff0c;做过那么多的小练习&#xff0c;但是说实话&#x…

a5d27 emmc启动 修改1

a5d27第1级bootloader是从sdhc0(emmc)加载还是从sdhc1(sd卡)加载&#xff0c; 只需要修改board/sama5d2_xplained文件即可 修改CONFIG_SDHC* y 这个宏定义在board/sama5d2_xplained.c中的void at91_sdhc_hw_init(void)函数实现 从上面代码可以看出第1级的bootloader只支持一…

矩阵每一行重复_【剑指offer】65 矩阵中的路径

- 题目描述请设计一个函数&#xff0c;用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始&#xff0c;每一步可以在矩阵中向左&#xff0c;向右&#xff0c;向上&#xff0c;向下移动一个格子。如果一条路径经过了矩阵中的某一…

什么是单工、半双工和双工通信?有哪些实际应用的例子

根据数据信息在传输线上的传送方向&#xff0c;数据通信方式分为单工通信 半双工通信和全双工通信3种。 1&#xff09;单工通信 数据信息在通信线上始终向一个方向传输。数据信息永远从发送端传输到接收端。列如&#xff0c;广播电视就是单工传输方式&#xff0c;收音机电视机只…

mysql5.464位下载_MySQL Front 64位

MySQL-Front是一款实用的MYSQL数据库管理工具&#xff0c;软件自带了简体中文语言&#xff0c;与mysql数据库连接后就可以对其地蚝各类管理操作了&#xff0c;比如对域进行编辑、增加和删除&#xff0c;执行sql脚本或者导出数据库等操作&#xff0c;除此之外还可以将数据库保存…

a5d27 emmc启动 修改2

修改第2级bootloader的include/configs/sama5d2_xplained.h文件 #define FAT_ENV_DEVICE_AND_PART "0" #define CONFIG_BOOTCOMMAND "fatload mmc 0:1 0x21000000 at91-sama5d2_xplained.dtb; " \ "fatload mmc 0:1 0x22000000 zImage; " \ &q…

监听APP升级广播处理

当旧版本的用户升级新版本的时候需要重新设定一些值处理,这时候需要监听升级版本的广播 <receiver android:name".OnUpgradeReceiver"><intent-filter><action android:name"android.intent.action.PACKAGE_REPLACED" /><data androi…

mysql linux 优化_mysql在linux中内核优化

linux内核优化,直接修改/etc/sysctl.conf执行 sysctl -p立即生效# 每个端口监听队列最大长度net.core.somaxconn 65535# 增加系统文件描述符限制fs.file-max 65535# 当网络接受速率大于内核处理速率时&#xff0c;允许发送到队列中的包数目net.core.netdev_max_backlog 6553…

a5d27 第1级bootloader启动问题

drivers/sdhc.c里的 static int sdhc_set_clock(struct sd_card *sdcard, unsigned int clock) 这段代码总是会超时&#xff0c;造成启动失败。 log如下图

LDA-Latent Dirichlet Allocation 学习笔记

以下内容主要基于《Latent Dirichlet Allocation》,JMLR-2003一文&#xff0c;另加入了一些自己的理解,刚开始了解&#xff0c;有不对的还请各位指正。 LDA-Latent Dirichlet Allocation JMLR-2003 摘要&#xff1a;本文讨论的LDA是对于离散数据集&#xff0c;如文本集&#xf…

A5D2应用程序无法启动问题

给/lib/ld-2.22.so文件&#xff0c;建立名称为ld-linux.so.3的软连接即可。 或者编译程序的时候&#xff0c;用-s选项&#xff0c;将库文件编译进程序

mysql 表上限_mysql 数据库表的上限

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

app 图标规格参考表

转自&#xff1a;http://www.cocoachina.com/appstore/top/2012/1105/5031.html 像我一样记不住iOS应用图标像素尺寸的开发者不在少数&#xff0c;我经常需要查询不同设备上的应用尺寸&#xff0c;为了方便自己、方便大家&#xff0c;我制作了下面的图表供大家参考。 iPhone、i…

visual studio 的各个版本下载地址

Microsoft Visual Studio 6.0 下载&#xff1a;英文版360云盘下载&#xff1a; http://l11.yunpan.cn/lk/sVeBLC3bhumrI英文版115网盘下载&#xff1a; http://115.com/file/bew2qrau英文版迅雷下载&#xff1a; http://61.138.140.18/download/jlste_nw/vs6en.isoFTP下载&…

mysql数据表内容_MySQL数据表

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

.net Reflection(反射)- 二

反射 Reflection 中访问方法 新建一个ClassLibrary类库&#xff1a; public class Student{public string Name{ get; set; }public string School{ get; set; }public int Sum(int a, int b){return a b;}public string GetName(){return "this is book" ;} } /…

osg坐标系统

OpenGL的世界坐标轴向可以看做是&#xff1a;x轴向右&#xff0c;y轴向上&#xff0c;z轴向屏幕外。 在osg中实际上也是一样的&#xff0c;只不过漫游器在设置视点时把视点设置在了y轴负方向并朝向y轴正向&#xff0c;导致这二者看起来坐标系统不一致。 感觉像是OpenGL坐标系…