内核3.x版本之后设备树机制

Based  on  Linux  3.10.24  source  code 

参考/documentation/devicetree/Booting-without-of.txt文档

目录

内核3.x版本之后设备树机制
1

一、设备树(Device  Tree)基本概念及作用
3

二、设备树的组成和使用
4

①DTS和DTSI
4

②DTC
4

③DTB
5

④Bootloader
5

三、设备树中dts、dtsi文件的基本语法
5

㈠chosen node
8

㈡aliases node
8

㈢memory node
9

㈣ 其他节点
10

四、DTB相关结构
13

㈠Header
14

㈢字符串块
16

㈣ memory reserve map
16

五、解析DTB的函数及相关数据结构
17

㈠machine_desc结构
17

㈡设备节点结构体
18

㈢属性结构体
19

㈣ uboot下的相关结构体
19

六、DTB加载及解析过程
21

七、OF的API接口
32

一、设备树(Device  Tree)基本概念及作用

在内核源码中,存在大量对板级细节信息描述的代码。这些代码充斥在/arch/arm/plat-xxx和/arch/arm/mach-xxx目录,对内核而言这些platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data绝大多数纯属垃圾冗余代码。为了解决这一问题,ARM内核版本3.x之后引入了原先在Power PC等其他体系架构已经使用的Flattened Device Tree。

“A data structure by which bootloaders pass hardware layout to Linux in a device-independent manner, simplifying hardware probing.”开源文档中对设备树的描述是,一种描述硬件资源的数据结构,它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立。

Device Tree可以描述的信息包括CPU的数量和类别、内存基地址和大小、总线和桥、外设连接、中断控制器和中断使用情况、GPIO控制器和GPIO使用情况、Clock控制器和Clock使用情况。

另外,设备树对于可热插拔的热备不进行具体描述,它只描述用于控制该热插拔设备的控制器。

设备树的主要优势:对于同一SOC的不同主板,只需更换设备树文件.dtb即可实现不同主板的无差异支持,而无需更换内核文件。

注:要使得3.x之后的内核支持使用设备树,除了内核编译时需要打开相对应的选项外,bootloader也需要支持将设备树的数据结构传给内核。

二、设备树的组成和使用

设备树包含DTC(device tree compiler),DTS(device tree source和DTB(device tree blob)。其对应关系如图1-1所示:

图1-1 DTS、DTC、DTB之间的关系

①DTS和DTSI

.dts文件是一种ASCII文本对Device Tree的描述,放置在内核的/arch/arm/boot/dts目录。一般而言,一个.dts文件对应一个ARM的machine。

由于一个SOC可能有多个不同的电路板,而每个电路板拥有一个 .dts。这些dts势必会存在许多共同部分,为了减少代码的冗余,设备树将这些共同部分提炼保存在.dtsi文件中,供不同的dts共同使用。.dtsi的使用方法,类似于C语言的头文件,在dts文件中需要进行include .dtsi文件。当然,dtsi本身也支持include 另一个dtsi文件。

②DTC

DTC为编译工具,它可以将.dts文件编译成.dtb文件。DTC的源码位于内核的scripts/dtc目录,内核选中CONFIG_OF,编译内核的时候,主机可执行程序DTC就会被编译出来。 即scripts/dtc/Makefile中

hostprogs-y := dtc

always := $(hostprogs-y)

在内核的arch/arm/boot/dts/Makefile中,若选中某种SOC,则与其对应相关的所有dtb文件都将编译出来。在linux下,make dtbs可单独编译dtb。以下截取了TEGRA平台的一部分。

ifeq ($(CONFIG_OF),y)

dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \

tegra30-beaver.dtb \

tegra114-dalmore.dtb \

tegra124-ardbeg.dtb

③DTB

DTC编译.dts生成的二进制文件(.dtb),bootloader在引导内核时,会预先读取.dtb到内存,进而由内核解析。

④Bootloader

Bootloader需要将设备树在内存中的地址传给内核。在ARM中通过bootm或bootz命令来进行传递。bootm [kernel_addr] [initrd_address] [dtb_address],其中kernel_addr为内核镜像的地址,initrd为initrd的地址,dtb_address为dtb所在的地址。若initrd_address为空,则用“-”来代替。

三、设备树中dts、dtsi文件的基本语法

DTS的基本语法范例,如图3-1 所示。

它包括一系列节点,以及描述节点的属性。

“/”为root节点。在一个.dts文件中,有且仅有一个root节点;在root节点下有“node1”,“node2”子节点,称root为“node1”和“node2”的parent节点,除了root节点外,每个节点有且仅有一个parent;其中子节点node1下还存在子节点“child-nodel1”和“child-node2”。

注:如果看过内核/arch/arm/boot/dts目录的读者看到这可能有一个疑问。在每个.dsti和.dts中都会存在一个“/”根节点,那么如果在一个设备树文件中include一个.dtsi文件,那么岂不是存在多个“/”根节点了么。其实不然,编译器DTC在对.dts进行编译生成dtb时,会对node进行合并操作,最终生成的dtb只有一个root node。Dtc会进行合并操作这一点从属性上也可以得到验证。这个稍后做讲解。

在节点的{}里面是描述该节点的属性(property),即设备的特性。它的值是多样化的:

1.它可以是字符串string,如①;也可能是字符串数组string-list,如②

2.它也可以是32 bit unsigned integers,如cell⑧,用<>表示

3.它也可以是binary data,如③,用[]表示

4.它也可能是空,如⑦



图3-1  DTS的基本语法范例

在/arch/arm/boot/dts/目录中有一个文件skeleton.dtsi,该文件为各ARM vendor共用的一些硬件定义信息。以下为skeleton.dtsi的全部内容。

/ {

#address-cells = <1>;

#size-cells = <1>;

chosen { };

aliases { };

memory { device_type = "memory"; reg = <0 0>; };

};

如上,属性# address-cells的值为1,它代表以“/”根节点为parent的子节点中,reg属性中存在一个address值;#size-cells的值为1,它代表以“\” 根节点为parent的子节点中,reg属性中存在一个size值。即父节点的# address-cells和#size-cells决定了子节点的address和size的长度;Reg的组织形式为reg =

下面列举例子,对一些典型节点进行具体描述。

㈠chosen node

chosen {

bootargs = "tegraid=40.0.0.00.00 vmalloc=256M video=tegrafb console=ttyS0,115200n8 earlyprintk";

};

chosen node 主要用来描述由系统指定的runtime parameter,它并没有描述任何硬件设备节点信息。原先通过tag list传递的一些linux kernel运行的参数,可以通过chosen节点来传递。如command line可以通过bootargs这个property来传递。如果存在chosen node,它的parent节点必须为“/”根节点。

㈡aliases node

aliases {

i2c6 = &pca9546_i2c0;

i2c7 = &pca9546_i2c1;

i2c8 = &pca9546_i2c2;

i2c9 = &pca9546_i2c3;

};

aliases node用来定义别名,类似C++中引用。上面是一个在.dtsi中的典型应用,当使用i2c6时,也即使用pca9546_i2c0,使得引用节点变得简单方便。例:当.dts  include 该.dtsi时,将i2c6的status属性赋值为okay,则表明该主板上的pca9546_i2c0处于enable状态;反之,status赋值为disabled,则表明该主板上的pca9546_i2c0处于disenable状态。如下是引用的具体例子:

&i2c6 {

status = "okay";

};

㈢memory node

memory {

device_type = "memory";

reg = <0x00000000 0x20000000>; /* 512 MB */

};

对于memory node,device_type必须为memory,由之前的描述可以知道该memory node是以0x00000000为起始地址,以0x20000000为结束地址的512MB的空间。

一般而言,在.dts中不对memory进行描述,而是通过bootargs中类似521M@0x00000000的方式传递给内核。

㈣ 其他节点

由于其他设备节点依据属性进行描述,具有类似的形式。接下来的部分主要分析各种属性的含义及作用,并结合相关的例子进行阐述。

㈠ Reg属性

在device node 中,reg是描述memory-mapped IO register的offset和length。子节点的reg属性address和length长度取决于父节点对应的#address-cells和#size-cells的值。例:

在上述的aips节点中,存在子节点spda。spda中的中reg为<0x70000000 0x40000 >,其0x700000000为address,0x40000为size。这一点在图3-1下有作介绍。

这里补充的一点是:

;本例中,aips为0x70000000。

㈡ compatible属性

在①中,compatible属性为string list,用来将设备匹配对应的driver驱动,优先级为从左向右。本例中spba的驱动优先考虑“fsl,aips-bus”驱动;若没有“fsl,aips-bus”驱动,则用字符串“simple-bus”来继续寻找合适的驱动。即compatible实现了原先内核版本3.x之前,platform_device中.name的功能,至于具体的实现方法,本文后面会做讲解。

注:对于“/”root节点,它也存在compatible属性,用来匹配machine type。具体说明将在后面给出。

㈢ interrupts属性

设备节点通过interrupt-parent来指定它所依附的中断控制器,当节点没有指定interrupt-parent时,则从parent节点中继承。上面例子中,root节点的interrupt-parent = <&mic>。这里使用了引用,即mic引用了②中的inrerrupt-controller @40008000;root节点的子节点并没有指定interrupt-controller,如ahb、fab,它们均使用从根节点继承过来的mic,即位于0x40008000的中断控制器。

若子节点使用到中断(中断号、触发方法等等),则需用interrupt属性来指定,该属性的数值长度受中断控制器中#inrerrupt-controller值③控制,即interrupt属性<>中数值的个数为#inrerrupt-controller的值;本例中#inrerrupt-controller=<2>,因而④中interrupts的值为<0x3d 0>形式,具体每个数值的含义由驱动实现决定。

㈣ ranges属性

ranges属性为地址转换表,这在pcie中使用较为常见,它表明了该设备在到parent节点中所对用的地址映射关系。ranges格式长度受当前节点#address-cell、parent节点#address-cells、当前节点#size-cell所控制。顺序为ranges=<前节点#address-cell, parent节点#address-cells , 当前节点#size-cell。在本例中,当前节点#address-cell=<1>,对应于⑤中的第一个0x20000000;parent节点#address-cells=<1>,对应于⑤中的第二个0x20000000;当前节点#size-cell=<1>,对应于⑤中的0x30000000。即ahb0节点所占空间从0x20000000地址开始,对应于父节点的0x20000000地址开始的0x30000000地址空间大小。

注:对于相同名称的节点,dtc会根据定义的先后顺序进行合并,其相同属性,取后定义的那个。

四、DTB相关结构

本节讲下.dts编译生成的dtb文件,其布局结构。

DTB由三部分组成:头(Header)、结构块(device-tree structure)、字符串块(string block)。下面将详细介绍这三部分的内容。

㈠Header

在\kernel\include\linux\of_fdt.h文件中有相关定义

device-tree structure

设备树结构块是一个线性化的结构体,是设备树的主体,以节点的形式保存了主板上的设备信息。

在结构块中,以宏OF_DT_BEGIN_NODE标志一个节点的开始,以宏OF_DT_END_NODE标识一个节点的结束,整个结构块以宏OF_DT_END (0x00000009)结束。在\kernel\include\linux\of_fdt.h中有相关定义,我们把这些宏称之为token。

(1)FDT_BEGIN_NODE (0x00000001)。该token描述了一个node的开始位置,紧挨着该token的就是node name(包括unit address)

(2)FDT_END_NODE (0x00000002)。该token描述了一个node的结束位置。

(3)FDT_PROP (0x00000003)。该token描述了一个property的开始位置,该token之后是两个u32的数据,分别是length和name offset。length表示该property value data的size。name offset表示该属性字符串在device tree strings block的偏移值。length和name offset之后就是长度为length具体的属性值数据。

(4)FDT_NOP (0x00000004)。

(5)FDT_END (0x00000009)。该token标识了一个DTB的结束位置。

一个节点的结构如下:

(1)节点开始标志:一般为OF_DT_BEGIN_NODE(0x00000001)。

(2)节点路径或者节点的单元名(version<3以节点路径表示,version>=0x10以节点单元名表示)

(3)填充字段(对齐到四字节)

(4)节点属性。每个属性以宏OF_DT_PROP(0x00000003)开始,后面依次为属性值的字节长度(4字节)、属性名称在字符串块中的偏移量(4字节)、属性值和填充(对齐到四字节)。

(5)如果存在子节点,则定义子节点。

(6)节点结束标志OF_DT_END_NODE(0x00000002)。

㈢字符串块

通过节点的定义知道节点都有若干属性,而不同的节点的属性又有大量相同的属性名称,因此将这些属性名称提取出一张表,当节点需要应用某个属性名称时,直接在属性名字段保存该属性名称在字符串块中的偏移量。

㈣ memory reserve map

这个区域包括了若干的reserve memory描述符。每个reserve memory描述符是由address和size组成。其中address和size都是用U64来描述。

有些系统,我们也许会保留一些memory有特殊用途(例如DTB或者initrd image),或者在有些DSP+ARM的SOC platform上,有些memory被保留用于ARM和DSP进行信息交互。这些保留内存不会进入内存管理系统。

五、解析DTB的函数及相关数据结构

㈠machine_desc结构

内核将机器信息记录为machine_desc结构体(该定义在/arch/arm/include/asm/mach/arch.h),并保存在_arch_info_begin到_arch_info_end之间(_arch_info_begin,_arch_info_end为虚拟地址,是编译内核时指定的,此时mmu还未进行初始化。它其实通过汇编完成地址偏移操作)

machine_desc结构体用宏MACHINE_START进行定义,一般在/arch/arm/子目录,与板级相关的文件中进行成员函数及变量的赋值。由linker将machine_desc聚集在.arch.info.init节区形成列表。

bootloader引导内核时,ARM寄存器r2会将.dtb的首地址传给内核,内核根据该地址,解析.dtb中根节点的compatible属性,将该属性与内核中预先定义machine_desc结构体的dt_compat成员做匹配,得到最匹配的一个machine_desc。

在代码中,内核通过在start_kernel->setup_arch中调用setup_machine_fdt来实现上述功能,该函数的具体实现可参见/arch/arm/kernel/devtree.c。

㈡设备节点结构体

1.

记录节点信息的结构体。.dtb经过解析之后将以device_node列表的形式存储节点信息。

㈢属性结构体

device_node结构体中的成员结构体,用于描述节点属性信息。

㈣ uboot下的相关结构体

首先我们看下uboot用于记录os、initrd、fdt信息的数据结构bootm_headers,其定义在/include/image.h中,这边截取了其中与dtb相关的一小部分。

fit_hdr_fdt指向DTB设备树镜像的头。

lmb为uboot下的一种内存管理机制,全称为logical memory blocks。用于管理镜像的内存。lmb所记录的内存信息最终会传递给kernel。这里对lmb不做展开描述。在/include/lmb.h和/lib/lmb.c中有对lmb的接口和定义的具体描述。有兴趣的读者可以看下,所包含的代码量不多。

六、DTB加载及解析过程

先从uboot里的do_bootm出发,根据之前描述,DTB在内存中的地址通过bootm命令进行传递。在bootm中,它会根据所传进来的DTB地址,对DTB所在内存做一系列操作,为内核解析DTB提供保证。上图为对应的函数调用关系图。

在do_bootm中,主要调用函数为do_bootm_states,第四个参数为bootm所要处理的阶段和状态。

在do_bootm_states中,bootm_start会对lmb进行初始化操作,lmb所管理的物理内存块有三种方式获取。起始地址,优先级从上往下:

1. 环境变量“bootm_low”

2. 宏CONFIG_SYS_SDRAM_BASE(在tegra124中为0x80000000)

3. gd->bd->bi_dram[0].start

大小:

1. 环境变量“bootm_size”

2. gd->bd->bi_dram[0].size

经过初始化之后,这块内存就归lmb所管辖。接着,调用bootm_find_os进行kernel镜像的相关操作,这里不具体阐述。

还记得之前讲过bootm的三个参数么,第一个参数内核地址已经被bootm_find_os处理,而接下来的两个参数会在bootm_find_other中执行操作。

首先,bootm_find_other根据第二个参数找到ramdisk的地址,得到ramdisk的镜像;然后根据第三个参数得到DTB镜像,同检查kernel和ramdisk镜像一样,检查DTB镜像也会进行一系列的校验工作,如果校验错误,将无法正常启动内核。另外,uboot在确认DTB镜像无误之后,会将该地址保存在环境变量“fdtaddr”中。

接着,uboot会把DTB镜像reload一次,使得DTB镜像所在的物理内存归lmb所管理:①boot_fdt_add_mem_rsv_regions会将原先的内存DTB镜像所在的内存置为reserve,保证该段内存不会被其他非法使用,保证接下来的reload数据是正确的;②boot_relocate_fdt会在bootmap区域中申请一块未被使用的内存,接着将DTB镜像内容复制到这块区域(即归lmb所管理的区域)

注:若环境变量中,指定“fdt_high”参数,则会根据该值,调用lmb_alloc_base函数来分配DTB镜像reload的地址空间。若分配失败,则会停止bootm操作。因而,不建议设置fdt_high参数。

接下来,do_bootm会根据内核的类型调用对应的启动函数。与linux对应的是do_bootm_linux。

① boot_prep_linux

为启动后的kernel准备参数

② boot_jump_linux

以上是boot_jump_linux的片段代码,可以看出:若使用DTB,则原先用来存储ATAG的寄存器R2,将会用来存储.dtb镜像地址。

boot_jump_linux最后将调用kernel_entry,将.dtb镜像地址传给内核。

下面我们来看下内核的处理部分:

在arch/arm/kernel/head.S中,有这样一段:

_vet_atags定义在/arch/arm/kernel/head-common.S中,它主要对DTB镜像做了一个简单的校验。

真正解析处理dbt的开始部分,是setup_arch->setup_machine_fdt。这部分的处理在第五部分的machine_mdesc中有提及。

如图,是setup_machine_fdt中的解析过程。

解析chosen节点将对boot_command_line进行初始化。

解析根节点的{size,address}将对dt_root_size_cells,dt_root_addr_cells进行初始化。为之后解析memory等其他节点提供依据。

解析memory节点,将会把节点中描述的内存,加入memory的bank。为之后的内存初始化提供条件。

解析设备树在函数unflatten_device_tree中完成,它将.dtb解析成device_node结构(第五部分有其定义),并构成单项链表,以供OF的API接口使用。

下面主要结合代码分析:/drivers/of/fdt.c

总的归纳为:

① kernel入口处获取到uboot传过来的.dtb镜像的基地址

② 通过early_init_dt_scan()函数来获取kernel初始化时需要的bootargs和cmd_line等系统引导参数。

③ 调用unflatten_device_tree函数来解析dtb文件,构建一个由device_node结构连接而成的单向链表,并使用全局变量of_allnodes保存这个链表的头指针。

④ 内核调用OF的API接口,获取of_allnodes链表信息来初始化内核其他子系统、设备等。

七、OF的API接口

OF的接口函数在/drivers/of/目录下,有of_i2c.c、of_mdio.c、of_mtd.c、Adress.c等等

这里将列出几个常用的API接口。

1. 用来查找在dtb中的根节点

unsigned long __init of_get_flat_dt_root(void)

2. 根据deice_node结构的full_name参数,在全局链表of_allnodes中,查找合适的device_node

struct device_node *of_find_node_by_path(const char *path)

例如:

struct device_node *cpus;

cpus=of_find_node_by_path("/cpus");

3. 若from=NULL,则在全局链表of_allnodes中根据name查找合适的device_node

struct device_node *of_find_node_by_name(struct device_node *from,const char *name)

例如:

struct device_node *np;

np = of_find_node_by_name(NULL,"firewire");

4. 根据设备类型查找相应的device_node

struct device_node *of_find_node_by_type(struct device_node *from,const char *type)

例如:

struct device_node *tsi_pci;

tsi_pci= of_find_node_by_type(NULL,"pci");

5. 根据compatible字符串查找device_node

struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible)

6. 根据节点属性的name查找device_node

struct device_node *of_find_node_with_property(struct device_node *from,const char *prop_name)

7. 根据phandle查找device_node

struct device_node *of_find_node_by_phandle(phandle handle)

8. 根据alias的name获得设备id号

int of_alias_get_id(struct device_node *np, const char *stem)

9. device node计数增加/减少

struct device_node *of_node_get(struct device_node *node)

void of_node_put(struct device_node *node)

10. 根据property结构的name参数,在指定的device node中查找合适的property

struct property *of_find_property(const struct device_node *np,const char *name,int *lenp)

11. 根据property结构的name参数,返回该属性的属性值

const void *of_get_property(const struct device_node *np, const char *name,int *lenp)

12. 根据compat参数与device node的compatible匹配,返回匹配度

int of_device_is_compatible(const struct device_node *device,const char *compat)

13. 获得父节点的device node

struct device_node *of_get_parent(const struct device_node *node)

14. 将matches数组中of_device_id结构的name和type与device node的compatible和type匹配,返回匹配度最高的of_device_id结构

const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)

15. 根据属性名propname,读出属性值中的第index个u32数值给out_value

int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index, u32 *out_value)

16. 根据属性名propname,读出该属性的数组中sz个属性值给out_values

int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)

int of_property_read_u16_array(const struct device_node *np,const char *propname, u16 *out_values, size_t sz)

int of_property_read_u32_array(const struct device_node *np,const char *propname, u32 *out_values,size_t sz)

17. 根据属性名propname,读出该属性的u64属性值

int of_property_read_u64(const struct device_node *np, const char *propname,u64 *out_value)

18. 根据属性名propname,读出该属性的字符串属性值

int of_property_read_string(struct device_node *np, const char *propname,const char **out_string)

19. 根据属性名propname,读出该字符串属性值数组中的第index个字符串

int of_property_read_string_index(struct device_node *np, const char *propname,int index, const char **output)

20. 读取属性名propname中,字符串属性值的个数

int of_property_count_strings(struct device_node *np, const char *propname)

21. 读取该设备的第index个irq号

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)

22. 读取该设备的第index个irq号,并填充一个irq资源结构体

int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)

23. 获取该设备的irq个数

int of_irq_count(struct device_node *dev)

24. 获取设备寄存器地址,并填充寄存器资源结构体

int of_address_to_resource(struct device_node *dev, int index,struct resource *r)

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,unsigned int *flags)

25. 获取经过映射的寄存器虚拟地址

void __iomem *of_iomap(struct device_node *np, int index)

24. 根据device_node查找返回该设备对应的platform_device结构

struct platform_device *of_find_device_by_node(struct device_node *np)

25. 根据device node,bus id以及父节点创建该设备的platform_device结构

struct platform_device *of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)

static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,

void *platform_data,struct device *parent)

26. 遍历of_allnodes中的节点挂接到of_platform_bus_type总线上,由于此时of_platform_bus_type总线上还没有驱动,所以此时不进行匹配

int of_platform_bus_probe(struct device_node *root,const struct of_device_id *matches,struct device *parent)

【ARM-Linux开发】内核3.x版本之后设备树机制的更多相关文章

  1. 在Ubuntu上建立Arm Linux 开发环境

    我使用的是友善2410的板子,以前都是用Fedora,现在家里的电脑被我转为Linux专用的了,装的是Ubuntu.但是嵌入式还是要玩的,在装载过程中也遇到一些小麻烦.在此记录一下,一来自己比较健忘, ...

  2. 【Qt开发】【Linux开发】Qt程序在嵌入式设备(arm) 上运行,鼠标擦除界面的解决方案

    笔者最近想在arm开发板上,开发一个应用程序,经过网上查询发现qt作为跨平台开发软件很不错,于是便选择了qt开发,笔者的qt版本是4.8.6的.由于arm的主频太低,在arm上进行开发编译,效率会大大 ...

  3. 成功移植SQLite3到ARM Linux开发板

    SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了 ...

  4. Linux查看内核和系统版本

    1. 查看内核版本命令: 1) [root@q1test01 ~]# cat /proc/version Linux version 2.6.9-22.ELsmp (bhcompile@crowe.d ...

  5. minigui移植到arm linux开发板上无法执行

    要保证目录下有该文件 /etc/MiniGUI.cfg 复制过程使用cp –af 强制复制

  6. C#.NET 大型通用信息化系统集成快速开发平台 4.0 版本 - 用户权限树的实现 -- 权限递归树

    业务系统里经常会需要计算类似的树形权限树的业务需求 1:往往会有一些需求,a 对 b 有权限, b对c 有权限, 等等. 2:还需要很直观的看到,整个权限的树形关系,一目了然的那种. 3:程序调用简单 ...

  7. 《linux设备驱动开发详解》笔记——18 ARM linux设备树

    18.1 设备树的起源 linux 2.6及之前,大量板级信息被硬编码到内核里,十分庞大,大量冗余代码: linux 2.6之前,引入了设备树: 设备树源于OpenFirmware,描述硬件的数据结构 ...

  8. arm linux利用alsa驱动并使用usb音频设备

    一.背景: arm linux的内核版本是3.13.0 二.准备工作 添加alsa驱动到内核中,也就是在编译内核的时候加入以下选项: 接下来就重新编译内核即可 三.交叉编译alsa-lib和alsa- ...

  9. 迅为iMX6Q/PLUS开发板烧写设备树内核 Qt 系统

    迅为iMX6Q 和 iMX6PLUS 两个硬件版本,设备树镜像的烧写方法以及镜像所在目录,镜像名称全部一致. 如果用的是 iMX6Q 版本,想要烧写设备树版本镜像,请使用 iMX6Q 设备树版本的光盘 ...

随机推荐

  1. ACM-ICPC 2018 徐州赛区现场赛 I. Rikka with Sorting Networks (思维+DFS)

    题目链接:https://codeforces.com/gym/102012/problem/I 题意:问有多少个 1 到 n 的排列,使得用给定的 k 个比较器(使 au 和 av 有序)排序后,整 ...

  2. 2、组件注册-@Configuration&@Bean给容器中注册组件

    2.组件注册-@Configuration&@Bean给容器中注册组件 2.1 创建maven项目 spring-annotation pom.xml文件添加 spring-context 依 ...

  3. UVA1426 Discrete Square Roots

    思路:\(exgcd\) 提交:\(2\)次 错因:输出格式错误OTZ 题解: 求:\(r^2 ≡ x \mod N , 0 \leq r < N\),并且题目会给出 \(x,N\) 和一个合法 ...

  4. php MySQL 查询数据

    以下为在MySQL数据库中查询数据通用的 SELECT 语法: SELECT column_name,column_name FROM table_name [WHERE Clause] [LIMIT ...

  5. JAVA的带参数的方法

    一.带参数的方法 1.1 语法:                            <访问修饰符>  返回类型  <方法名>(<形式参数列表>) { //方法的 ...

  6. 029_检测 MySQL 数据库连接数量

    #!/bin/bash#本脚本每 2 秒检测一次 MySQL 并发连接数,可以将本脚本设置为开机启动脚本,或在特定时间段执行#以满足对 MySQL 数据库的监控需求,查看 MySQL 连接是否正常#本 ...

  7. java+超大文件上传与下载

    ​这里先说下spring mvc 遇到的坑,就是如果文件上传时,后端这样写public String file1(HttpServletRequest request),根据request拿到的东西是 ...

  8. 7zip使用相关

    造冰箱的大熊猫@cnblogs 2019/11/2 1.仅存储不压缩 7z a -mx0 compressed.7z FileFolderPath 将FileFolderPath指向的文件或文件夹打包 ...

  9. Visual Studio Code:以十六进制格式显示文件内容

    造冰箱的大熊猫@cnblogs 2019/9/4 发现Visual Studio Code很好用,无论是作为源代码编辑器还是文本编辑器在Win平台下用的都很不错.但有时候需要以十六进制格式查看数据文件 ...

  10. mysql 查询整个数据库所有表的行数

    >use information_schema; >select sum(table_rows) from tables where TABLE_SCHEMA = "test&q ...