linux驱动程序编译下载流程及详细介绍

流程:

一、汇编程序编译

汇编代码为led.s
1.编译出在 ARM 开发板上运行的可执行文件

arm-linux-gnueabihf-gcc -g -c led.s -o led.o

2.链接文件

arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf

3.格式转换

arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin

4.反汇编(可不操作)

arm-linux-gnueabihf-objdump -D led.elf > led.dis

Makefile文件形式,文件内容:

led.bin:led.s
	arm-linux-gnueabihf-gcc -g -c led.s -o led.o
	arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
	arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
	arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
	rm -rf *.o led.bin led.elf led.dis。

二、代码烧写

1.给予 imxdownload 可执行权限

chmod 777 imxdownload

2.向 SD 卡烧写 bin 文件

./imxdownload led.bin /dev/sdd

三、C语言程序编译
代码包括start.S(汇编文件)、main.c、main.h
1.链接脚本(imx6ul.lds):

SECTIONS{
	. = 0X87800000;
	.text :
	{
		start.o 
		main.o 
		*(.text)
	}
	.rodata ALIGN(4) : {*(.rodata*)} 
	.data ALIGN(4) : { *(.data) } 
	__bss_start = .; 
	.bss ALIGN(4) : { *(.bss) *(COMMON) } 
	__bss_end = .;
}

2.Makefile

objs := start.o main.o
 
ledc.bin:$(objs)
	arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^
	arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
	arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis

%.o:%.s
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
 
%.o:%.S
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<

%.o:%.c
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<

clean:
	rm -rf *.o ledc.bin ledc.elf ledc.dis

详细解释:

一 、汇编程序编译

1.编写完成汇编代码led.s
2.编译出在 ARM 开发板上运行的可执行文件 arm-linux-gnueabihf-gcc
使用安装好的交叉编译器 arm-linux-gnueabihf-gcc来编译

arm-linux-gnueabihf-gcc -g -c led.s -o led.o

3.链接文件 arm-linux-gnueabihf-ld
本教程所有的裸机例程都是烧写到 SD 卡中,上电以后 I.MX6U 的内部 boot rom 程序会将
可执行文件拷贝到链接地址处,这个链接地址可以在 I.MX6U 的内部 128KB RAM 中
(0X900000~0X91FFFF),也可以在外部的 DDR 中。本教程所有裸机例程的链接地址都在 DDR
中,链接起始地址为 0X87800000。I.MX6U-ALPHA 开发板的 DDR 容量有两种:512MB 和
256MB,起始地址都为 0X80000000,只不过 512MB 的终止地址为 0X9FFFFFFF,而 256MB 容
量的终止地址为 0X8FFFFFFF。之所以选择 0X87800000 这个地址是因为后面要讲的 Uboot 其
链接地址就是 0X87800000,这样我们统一使用 0X87800000 这个链接地址,不容易记混。
确定了链接地址以后就可以使用 arm-linux-gnueabihf-ld 来将前面编译出来的 led.o 文件链
接到 0X87800000 这个地址,使用如下命令:

arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf

中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。
4.格式转换 arm-linux-gnueabihf-objcopy
led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还
需要将 led.elf 文件转换为.bin 文件,这里我们就需要用到 arm-linux-gnueabihf-objcopy 这个工具了

arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin

5.反汇编 arm-linux-gnueabihf-objdump
大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,
因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:

arm-linux-gnueabihf-objdump -D led.elf > led.dis

6.总结
总结一下我们为了编译 ARM 开发板上运行的 led.o 这个文件使用了如下命令:

arm-linux-gnueabihf-gcc -g -c led.s -o led.o
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
arm-linux-gnueabihf-objdump -D led.elf > led.dis

如果我们修改了 led.s 文件,那么就需要在重复一次上面的这些命令,太麻烦了,这个时候
我们就可以使用第三章讲解的 Makefile 文件了。
7.创建Makefile文件
是用“touch”命令在工程根目录下创建一个名为“Makefile”的文件

led.bin:led.s
 arm-linux-gnueabihf-gcc -g -c led.s -o led.o
 arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
 arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
 arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
 rm -rf *.o led.bin led.elf led.dis

创建好 Makefile 以后我们就只需要执行一次“make”命令即可完成编译

二、代码烧写

将 led.bin 烧写到 SD 卡中。
bin文件不能直接复制进SD卡,正点原子专门编写了一个软件来将编译出来的.bin 文件烧写到 SD 卡中,这个软件叫做“imxdownload”。
1.将 imxdownload 拷贝到工程根目录
要将 imxdownload 拷贝到工程根目录下,也就是和 led.bin 处于同一个文件夹下
2.给予 imxdownload 可执行权限

chmod 777 imxdownload

当给予 imxdownload 可执行权限以后其名字变成了绿色的,如果没有可执行权限的话其名字颜色是白色的。
3.确定要烧写的 SD 卡。
准备一张新的 SD(TF)卡,确保 SD 卡里面没有数据,因为我们在烧写代码的时候可能会格式化 SD 卡!!!
Ubuntu 下所有的设备文件都在目录“/dev”里面,所以插上 SD 卡以后也会出现在“/dev”里面,其中存储设备都是以“/dev/sd”开头的。
ls /dev/sd*
4.向 SD 卡烧写 bin 文件
使用 imxdownload 向 SD 卡烧写 led.bin 文件,命令格式如下:
./imxdownload <.bin file>
其中.bin 就是要烧写的.bin 文件,SD Card 就是你要烧写的 SD 卡,如果U盘是sdb和sdb1此处一定要烧录到sdb 而不是sdb1

./imxdownload led.bin /dev/sdd //不能烧写到/dev/sda 或 sda1 设备里面!那是系统磁盘

烧写的过程中可能会让你输入密码,输入你的 Ubuntu 密码即可完成烧写
烧写完成以后会在当前工程目录下生成一个 load.imx 的文件
load.imx 这个文件就是软件 imxdownload 根据 NXP 官方启动方式介绍的内容,在 led.bin 文件前面添加了一些数据头以后生成的。最终烧写到 SD 卡里面的就是这个 load.imx 文件

三、c语言程序编写编译下载

1.新建 VScode 工程,工程名字为“ledc”,新建三个文件:start.S、main.c 和 main.h。其中 start.S
是汇编文件,main.c 和 main.h 是 C 语言相关文件。
2. start.s 中输入如下代码:
示例代码 10.3.1.2 start.s 文件代码

/***************************************************************
描述 : I.MX6U-ALPHA/I.MX6ULL 开发板启动文件,完成 C 环境初始化,
 C 环境初始化完成以后跳转到 C 代码。
**************************************************************/
1 .global _start /* 全局标号 */
2 
3 /*
4 * 描述: _start 函数,程序从此函数开始执行,此函数主要功能是设置 C
5 * 运行环境。
6 */
7 _start:
8 
9 /* 进入 SVC 模式 */
10 mrs r0, cpsr
11 bic r0, r0, #0x1f /* 将 r0 的低 5 位清零,也就是 cpsr 的 M0~M4 */
12 orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */
13 msr cpsr, r0 /* 将 r0 的数据写入到 cpsr_c 中 */
14
15 ldr sp, =0X80200000 /* 设置栈指针 */
16 b main /* 跳转到 main 函数 */

3.C 语言部分实验程序编写
在main.h 和 main.c中编写C语言程序

4.编写Makefile
新建 Makefile 文件,在 Makefile 文件里面输入如下内容:

1 objs := start.o main.o
2 
3 ledc.bin:$(objs)
4 arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^
5 arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
6 arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
7 
8 %.o:%.s
9 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
10 
11 %.o:%.S
12 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
13 
14 %.o:%.c
15 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
16 
17 clean:
18 rm -rf *.o ledc.bin ledc.elf ledc.dis

第 1 行定义了一个变量 objs,objs 包含着要生成 ledc.bin 所需的材料:start.o 和 main.o,也
就是当前工程下的 start.s 和 main.c 这两个文件编译后的.o 文件。这里要注意 start.o 一定要放到
最前面!因为在后面链接的时候 start.o 要在最前面,因为 start.o 是最先要执行的文件!
第 3 行就是默认目标,目的是生成最终的可执行文件 ledc.bin,ledc.bin 依赖 start.o 和 main.o
如果当前工程没有 start.o 和 main.o 的时候就会找到相应的规则去生成 start.o 和 main.o。比如
start.o 是 start.s 文件编译生成的,因此会执行第 8 行的规则。
第 4 行是使用 arm-linux-gnueabihf-ld 进行链接,链接起始地址是 0X87800000,但是这一行
用到了自动变量“ ” ,“ ^”,“ ^”的意思是所有依赖文件的集合,在这里就是 objs 这个变量的值:
start.o 和 main.o。链接的时候 start.o 要链接到最前面,因为第一行代码就是 start.o 里面的,因
此这一行就相当于:
arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf start.o main.o
第 5 行使用 arm-linux-gnueabihf-objcopy 来将 ledc.elf 文件转为 ledc.bin,本行也用到了自动变量
@ ”,“ @”,“ @”@”的意思是目标集合,在这里就是“ledc.bin”,那么本行就相当于:

arm-linux-gnueabihf-objcopy -O binary -S ledc.elf ledc.bin

第 6 行使用 arm-linux-gnueabihf-objdump 来反汇编,生成 ledc.dis 文件。
第 8~15 行就是针对不同的文件类型将其编译成对应的.o 文件,其实就是汇编.s(.S)和.c 文
件,比如 start.s 就会使用第 8 行的规则来生成对应的 start.o 文件。第 9 行就是具体的命令,这
行也用到了自动变量“ @ ”和“ @”和“ @”<”,其中“$<”的意思是依赖目标集合的第一个文件。比如
start.s 要编译成 start.o 的话第 8 行和第 9 行就相当于:
start.o:start.s

 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o start.o start.s

第 17 行就是工程清理规则,通过命令“make clean”就可以清理工程。

5.我们可以将整个工程拿到 Ubuntu 下去编译,编译完成以后可以使用
软件 imxdownload 将其下载到 SD 卡中,命令如下:

chmod 777 imxdownload //给予 imxdownoad 可执行权限,一次即可
./imxdownload ledc.bin /dev/sdd //下载到 SD 卡中, 不能烧写到/dev/sda 或 sda1 设备里面!

6.链接脚本

在上面的 Makefile 中我们链接代码的时候使用如下语句:

arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^

上面语句中我们是通过“-Ttext”来指定链接地址是 0X87800000 的,这样的话所有的文件都会链接到以 0X87800000 为起始地址的区域。
但是有时候我们很多文件需要链接到指定的区域,或者叫做段里面,比如在 Linux 里面初始化函数就会放到 init 段里面。因此我们需要能够自定义一些段,这些段的起始地址我们可以自由指定,同样的我们也可以指定一个文件或者函数应该存放到哪个段里面去。
要完成这个功能我们就需要使用到链接脚本,看名字就知道链接
脚本主要用于链接的,用于描述文件应该如何被链接在一起形成最终的可执行文件。其主要目的是描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。比如我们编译生成的文件一般都包含 text 段、data 段等等。
链接脚本的语法很简单,就是编写一系列的命令,这些命令组成了链接脚本,每个命令是一个带有参数的关键字或者一个对符号的赋值,可以使用分号分隔命令。像文件名之类的字符串可以直接键入,也可以使用通配符“*”。最简单的链接脚本可以只包含一个命令“SECTIONS”,我们可以在这一个“SECTIONS”里面来描述输出文件的内存布局。我们一般编译出来的代码都包含在 text、data、bss 和 rodata 这四个段内,假设现在的代码要被链接到 0X10000000 这个地址,数据要被链接到 0X30000000 这个地方,下面就是完成此功能的最简单的链接脚本:

SECTIONS{
2 . = 0X10000000;
3 .text : {*(.text)}
4 . = 0X30000000;
5 .data ALIGN(4) : { *(.data) } 
6 .bss ALIGN(4) : { *(.bss) } 
7 }

第 1 行我们先写了一个关键字“SECTIONS”,后面跟了一个大括号,这个大括号和第 7 行的大括号是一对,这是必须的。看起来就跟 C 语言里面的函数一样。
第 2 行对一个特殊符号“.”进行赋值,“.”在链接脚本里面叫做定位计数器,默认的定位计数器为 0。我们要求代码链接到以 0X10000000 为起始地址的地方,因此这一行给“.”赋值0X10000000,表示以 0X10000000 开始,后面的文件或者段都会以0X10000000 为起始地址开始链接。
第 3 行的“.text”是段名,后面的冒号是语法要求,冒号后面的大括号里面可以填上要链接到“.text”这个段里面的所有文件,“(.text)”中的“”是通配符,表示所有输入文件的.text段都放到“.text”中。
第 4 行,我们的要求是数据放到 0X30000000 开始的地方,所以我们需要重新设置定位计数器“.”,将其改为 0X30000000。如果不重新设置的话会怎么样?假设“.text”段大小为 0X10000,那么接下来的.data 段开始地址就是0X10000000+0X10000=0X10010000,这明显不符合我们的要求。所以我们必须调整定位计数器为 0X30000000。
第 5 行跟第 3 行一样,定义了一个名为“.data”的段,然后所有文件的“.data”段都放到这里面。但是这一行多了一个“ALIGN(4)”,这是什么意思呢?这是用来对“.data”这个段的起始地址做字节对齐的,ALIGN(4)表示 4 字节对齐。也就是说段“.data”的起始地址要能被 4 整除,一般常见的都是 ALIGN(4)或者 ALIGN(8),也就是 4 字节或者 8 字节对齐。
第 6 行定义了一个“.bss”段,所有文件中的“.bss”数据都会被放到这个里面,“.bss”数
据就是那些定义了但是没有被初始化的变量。
上面就是链接脚本最基本的语法格式,我们接下来就按照这个基本的语法格式来编写我们本试
验的链接脚本,我们本试验的链接脚本要求如下:
①、链接起始地址为 0X87800000。
②、start.o 要被链接到最开始的地方,因为 start.o 里面包含这第一个要执行的命令。
根据要求,在 Makefile 同目录下新建一个名为“imx6ul.lds”的文件,然后在此文件里面输入如下所示代码:

1 SECTIONS{
2 . = 0X87800000;
3 .text :
4 {
5 start.o 
6 main.o 
7 *(.text)
8 }
9 .rodata ALIGN(4) : {*(.rodata*)} 
10 .data ALIGN(4) : { *(.data) } 
11 __bss_start = .; 
12 .bss ALIGN(4) : { *(.bss) *(COMMON) } 
13 __bss_end = .;
14 }

上面的链接脚本文件和示例代码 10.4.2.1 基本一致的,第 2 行设置定位计数器为0X87800000,因为我们的链接地址就是0X87800000。
第5行设置链接到开始位置的文件为start.o,因为 start.o 里面包含着第一个要执行的指令,所以一定要链接到最开始的地方。
第 6 行是 main.o这个文件,其实可以不用写出来,因为 main.o 的位置就无所谓了,可以由编译器自行决定链接位置。
在第 11、13 行有“__bss_start”和“__bss_end”这两个东西?这个是什么呢?“__bss_start”和“__bss_end”是符号,第 11、13 这两行其实就是对这两个符号进行赋值,其值为定位符“.”,这两个符号用来保存.bss 段的起始地址和结束地址。前面说了.bss 段是定义了但是没有被初始化的变量,我们需要手动对.bss 段的变量清零的,因此我们需要知道.bss 段的起始和结束地址,
这样我们直接对这段内存赋 0 即可完成清零。
通过第 11、13 行代码,.bss 段的起始地址和结束地址就保存在了“__bss_start”和“__bss_end”中,我们就可以直接在汇编或者 C 文件里面使用这两个符号。

7.修改Makefile
在上一小节中我们已经编写好了链接脚本文件:imx6ul.lds,我们肯定是要使用这个链接脚本文件的,将 Makefile 中的如下一行代码:

arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^

改为:

arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^

其实就是将-T 后面的 0X87800000 改为 imx6ul.lds,表示使用 imx6ul.lds 这个链接脚本文
件。修改完成以后使用新的 Makefile 和链接脚本文件重新编译工程,编译成功以后就可以烧写
到 SD 卡中验证了。

8.下载认证

chmod 777 imxdownload //给予imxdownload可执行权限,一次即可
./imxdownload ledc.bin /dev/sdd //烧写到SD卡中,不能烧写到/dev/sda或sda1设备里面

三、Ubuntu交叉编译工具链安装

1.交叉编译器安装
可以编译 ARM 架构代码的 GCC 编译器,这个编译器就叫做交叉编译器,总结一下交叉编译器就是:
(1)、它肯定是一个 GCC 编译器。
(2)、这个 GCC 编译器是运行在 X86 架构的 PC 上的。
(3)、这个 GCC 编译器是编译 ARM 架构代码的,也就是编译出来的可执行文件是在 ARM 芯片上运行的。
交叉编译器中“交叉”的意思就是在一个架构上编译另外一个架构的代码,相当于两种架构“交叉”起来了。
Linaro GCC 编译器下载地址如下:

https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/,

我 们 需 要 下 载 4.9 版 本 的 编 译 器 , 下 载 地 址 为 :

https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/

我安装的 Ubuntu 16.04 是 64 位系统,因此我要使用 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz。
a.在 Ubuntu 中创建目录:/usr/local/arm,命令如下:

sudo mkdir /usr/local/arm

b.创建完成以后将刚刚拷贝的交叉编译器复制到/usr/local/arm 这个目录中

sudo cp gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz /usr/local/arm/ -f

c.拷贝完成以后在/usr/local/arm 目录中对交叉编译工具进行解压,解压命令如下:

sudo tar -vxf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz

等待解压完成,解压完成以后会生成一个名为“gcc-linaro-4.9.4-2017.01-x86_64_arm-linuxgnueabihf”的文件夹,这个文件夹里面就是我们的交叉编译工具链
d.修改环境变量,使用 VI 打开/etc/profile 文件,命令如下:

sudo vi /etc/profile

e.打开/etc/profile 以后,在最后面输入如下所示内容:

export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin

f.修改好以后就保存退出,重启 Ubuntu 系统,交叉编译工具链(编译器)就安装成功了。
2.安装相关库
在使用交叉编译器之前还需要安装一下其它的库,命令如下:

sudo apt-get install lsb-core lib32stdc++6

等待这些库安装完成。
3.交叉编译器验证
首先查看一下交叉编译工具的版本号,输入如下命令:

arm-linux-gnueabihf-gcc -v

如果交叉编译器安装正确的话就会显示版本号
4.要使用刚刚安装的交叉编译器的时候使用的命令是“arm-linux-gnueabihf-gcc”,“arm-linux-gnueabihfgcc”的含义如下:

1、arm 表示这是编译 arm 架构代码的编译器。
2、linux 表示运行在 linux 环境下。
3、gnueabihf 表示嵌入式二进制接口。
4、gcc 表示是 gcc 工具。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目  录 第1章 引言 1 1.1 演进 1 1.2 gnu copyleft 2 1.3 kernel.org 2 1.4 邮件列表和论坛 3 1.5 linux发行版 3 1.6 查看源代码 4 1.7 编译内核 7 1.8 可加载的模块 8 1.9 整装待发 9 第2章 内核 11 2.1 启动过程 11 2.1.1 bios-provided physical ram map 12 2.1.2 758mb lowmem available 14 2.1.3 kernel command line: ro root=/dev/hda1 14 2.1.4 calibrating delay...1197.46 .bogomips (lpj=2394935) 15 2.1.5 checking hlt instruction 16 2.1.6 net: registered protocol family 2 17 2.1.7 freeing initrd memory: 387k freed 17 2.1.8 io scheduler anticipatory registered (default) 18 2.1.9 setting up standard pci resources 18 2.1.10 ext3-fs: mounted filesystem 19 2.1.11 init: version 2.85 booting 19 2.2 内核模式和用户模式 20 2.3 进程上下文和中断上下文 20 2.4 内核定时器 21 2.4.1 hz和jiffies 21 2.4.2 长延时 22 2.4.3 短延时 24 2.4.4 pentium时间戳计数器 24 2.4.5 实时钟 25 2.5 内核中的并发 26 2.5.1 自旋锁和互斥体 26 2.5.2 原子操作 30 2.5.3 读—写锁 31 2.5.4 调试 32 2.6 proc文件系统 32 2.7 内存分配 33 2.8 查看源代码 34 第3章 内核组件 37 3.1 内核线程 37 3.1.1 创建内核线程 37 3.1.2 进程状态和等待队列 41 3.1.3 用户模式辅助程序 42 3.2 辅助接口 43 3.2.1 链表 44 3.2.2 散列链表 49 3.2.3 工作队列 49 3.2.4 通知链 51 3.2.5 完成接口 54 3.2.6 kthread辅助接口 56 3.2.7 错误处理助手 57 3.3 查看源代码 58 第4章 基本概念 61 4.1 设备和驱动程序介绍 61 4.2 中断处理 63 4.2.1 中断上下文 63 4.2.2 分配irq号 64 4.2.3 设备实例:导航杆 65 4.2.4 softirq和tasklet 68 4.3 linux设备模型 71 4.3.1 udev 71 4.3.2 sysfs、kobject和设备类 73 4.3.3 热插拔和冷插拔 76 4.3.4 微码下载 76 4.3.5 模块自动加载 77 4.4 内存屏障 78 4.5 电源管理 79 4.6 查看源代码 79 第5章 字符设备驱动程序 81 5.1 字符设备驱动程序基础 81 5.2 设备实例:系统cmos 82 5.2.1 驱动程序初始化 83 5.2.2 打开与释放 86 5.2.3 数据交换 88 5.2.4 查找 92 5.2.5 控制 94 5.3 检测数据可用性 95 5.3.1 轮询 95 5.3.2 fasync 98 5.4 和并行端口交互 99 5.5 rtc子系统 108 5.6 伪字符驱动程序 109 5.7 混杂驱动程序 110 5.8 字符设备驱动程序注意事项 115 5.9 查看源代码 115 第6章 串行设备驱动程序 118 6.1 层次架构 119 6.2 uart驱动程序 121 6.2.1 设备实例:手机 122 6.2.2 rs-485 132 6.3 tty驱动程序 132 6.4 线路规程 134 6.5 查看源代码 141 第7章 输入设备驱动程序 143 7.1 输入事件驱动程序 144 7.2 输入设备驱动程序 150 7.2.1 serio 150 7.2.2 键盘 150 7.2.3 鼠标 152 7.2.4 触摸控制器 157 7.2.5 加速度传感器 158 7.2.6 输出事件 158 7.3 调试 159 7.4 查看源代码 160 第8章 i2c协议 161 8.1 i2c/smbus是什么 161 8.2 i2c核心 162 8.3 总线事务 164 8.4 设备实例:eeprom 164 8.4.1 初始化 165 8.4.2 探测设备 167 8.4.3 检查适配器的功能 169 8.4.4 访问设备 169 8.4.5 其他函数 170 8.5 设备实例:实时时钟 171 8.6 i2c-dev 174 8.7 使用lm-sensors监控硬件 174 8.8 spi总线 174 8.9 1-wire总线 176 8.10 调试 176 8.11 查看源代码 176 第9章 pcmcia和cf 179 9.1 pcmcia/cf是什么 179 9.2 linux-pcmcia子系统 181 9.3 主机控制器驱动程序 183 9.4 pcmcia核心 183 9.5 驱动程序服务 183 9.6 客户驱动程序 183 9.6.1 数据结构 184 9.6.2 设备实例:pcmcia卡 185 9.7 将零件组装在一起 188 9.8 pcmcia存储 189 9.9 串行pcmcia 189 9.10 调试 191 9.11 查看源代码 191 第10章 pci 193 10.1 pci系列 193 10.2 寻址和识别 195 10.3 访问pci 198 10.3.1 配置区 198 10.3.2 i/o和内存 199 10.4 dma 200 10.5 设备实例:以太网—调制解调器卡 203 10.5.1 初始化和探测 203 10.5.2 数据传输 209 10.6 调试 214 10.7 查看源代码 214 第11章 usb 216 11.1 usb体系架构 216 11.1.1 总线速度 218 11.1.2 主机控制器 218 11.1.3 传输模式 219 11.1.4 寻址 219 11.2 linux-usb子系统 220 11.3 驱动程序的数据结构 221 11.3.1 usb_device结构体 221 11.3.2 urb 222 11.3.3 管道 223 11.3.4 描述符结构 223 11.4 枚举 225 11.5 设备实例:遥测卡 225 11.5.1 初始化和探测过程 226 11.5.2 卡寄存器的访问 230 11.5.3 数据传输 233 11.6 类驱动程序 236 11.6.1 大容量存储设备 236 11.6.2 usb-串行端口转换器 241 11.6.3 人机接口设备 243 11.6.4 蓝牙 243 11.7 gadget驱动程序 243 11.8 调试 244 11.9 查看源代码 245 第12章 视频驱动程序 247 12.1 显示架构 247 12.2 linux视频子系统 249 12.3 显示参数 251 12.4 帧缓冲api 252 12.5 帧缓冲驱动程序 254 12.6 控制台驱动程序 265 12.6.1 设备实例:手机 266 12.6.2 启动logo 270 12.7 调试 270 12.8 查看源代码 271 第13章 音频驱动程序 273 13.1 音频架构 273 13.2 linux声音子系统 275 13.3 设备实例:mp3播放器 277 13.3.1 驱动程序函数和结构体 278 13.3.2 alsa编程 287 13.4 调试 288 13.5 查看源代码 289 第14章 块设备驱动程序 291 14.1 存储技术 291 14.2 linux块i/o层 295 14.3 i/o调度器 295 14.4 块驱动程序数据结构和方法 296 14.5 设备实例:简单存储控制器 298 14.5.1 初始化 299 14.5.2 块设备操作 301 14.5.3 磁盘访问 302 14.6 高级主题 304 14.7 调试 306 14.8 查看源代码 306 第15章 网络接口卡 308 15.1 驱动程序数据结构 308 15.1.1 套接字缓冲区 309 15.1.2 网络设备接口 310 15.1.3 激活 311 15.1.4 数据传输 311 15.1.5 看门狗 311 15.1.6 统计 312 15.1.7 配置 313 15.1.8 总线相关内容 314 15.2 与协议层会话 314 15.2.1 接收路径 314 15.2.2 发送路径 315 15.2.3 流量控制 315 15.3 缓冲区管理和并发控制 315 15.4 设备实例:以太网nic 316 15.5 isa网络驱动程序 321 15.6 atm 321 15.7 网络吞吐量 322 15.7.1 驱动程序性能 322 15.7.2 协议性能 323 15.8 查看源代码 324 第16章 linux无线设备驱动 326 16.1 蓝牙 327 16.1.1 bluez 328 16.1.2 设备实例:cf卡 329 16.1.3 设备实例:usb适配器 330 16.1.4 rfcomm 331 16.1.5 网络 332 16.1.6 hid 334 16.1.7 音频 334 16.1.8 调试 334 16.1.9 关于源代码 334 16.2 红外 335 16.2.1 linux-irda 335 16.2.2 设备实例:超级i/o芯片 337 16.2.3 设备实例:ir dongle 338 16.2.4 ircomm 340 16.2.5 联网 340 16.2.6 irda套接字 341 16.2.7 lirc 341 16.2.8 查看源代码 342 16.3 wifi 343 16.3.1 配置 343 16.3.2 设备驱动程序 346 16.3.3 查看源代码 347 16.4 蜂窝网络 347 16.4.1 gprs 347 16.4.2 cdma 349 16.5 当前趋势 350 第17章 存储技术设备 352 17.1 什么是闪存 352 17.2 linux-mtd子系统 353 17.3 映射驱动程序 353 17.4 nor芯片驱动程序 358 17.5 nand芯片驱动程序 359 17.6 用户模块 361 17.6.1 块设备模拟 361 17.6.2 字符设备模拟 361 17.6.3 jffs2 362 17.6.4 yaffs2 363 17.7 mtd工具 363 17.8 配置mtd 363 17.9 xip 364 17.10 fwh 364 17.11 调试 367 17.12 查看源代码 367 第18章 嵌入式linux 369 18.1 挑战 369 18.2 元器件选择 370 18.3 工具链 371 18.4 bootloader 372 18.5 内存布局 374 18.6 内核移植 375 18.7 嵌入式驱动程序 376 18.7.1 闪存 377 18.7.2 uart 377 18.7.3 按钮和滚轮 378 18.7.4 pcmcia/cf 378 18.7.5 sd/mmc 378 18.7.6 usb 378 18.7.7 rtc 378 18.7.8 音频 378 18.7.9 触摸屏 379 18.7.10 视频 379 18.7.11 cpld/fpga 379 18.7.12 连接性 379 18.7.13 专用领域电子器件 380 18.7.14 更多驱动程序 380 18.8 根文件系统 380 18.8.1 nfs挂载的根文件系统 381 18.8.2 紧凑型中间件 382 18.9 测试基础设施 383 18.10 调试 383 18.10.1 电路板返工 384 18.10.2 调试器 385 第19章 用户空间的驱动程序 386 19.1 进程调度和响应时间 387 19.1.1 原先的调度器 387 19.1.2 o(1)调度器 387 19.1.3 cfs 388 19.1.4 响应时间 388 19.2 访问i/o区域 390 19.3 访问内存区域 393 19.4 用户模式scsi 395 19.5 用户模式usb 397 19.6 用户模式i2c 400 19.7 uio 401 19.8 查看源代码 402 第20章 其他设备和驱动程序 403 20.1 ecc报告 403 20.2 频率调整 407 20.3 嵌入式控制器 408 20.4 acpi 408 20.5 isa与mca 410 20.6 火线 410 20.7 智能输入/输出 411 20.8 业余无线电 411 20.9 voip 411 20.10 高速互联 412 20.10.1 infiniband 413 20.10.2 rapidio 413 20.10.3 光纤通道 413 20.10.4 iscsi 413 第21章 调试设备驱动程序 414 21.1 kdb 414 21.1.1 进入调试器 415 21.1.2 kdb 415 21.1.3 kgdb 417 21.1.4 gdb 420 21.1.5 jtag调试器 421 21.1.6 下载 423 21.2 内核探测器 423 21.2.1 kprobe 423 21.2.2 jprobe 427 21.2.3 返回探针 429 21.2.4 局限性 431 21.2.5 查看源代码 431 21.3 kexec与kdump 431 21.3.1 kexec 432 21.3.2 kdump与kexec协同工作 432 21.3.3 kdump 433 21.3.4 查看源代码 437 21.4 性能剖析 437 21.4.1 利用oprofile剖析内核性能 438 21.4.2 利用gprof剖析应用程序性能 440 21.5 跟踪 441 21.6 ltp 444 21.7 uml 444 21.8 诊断工具 444 21.9 内核修改配置选项 444 21.10 测试设备 445 第22章 维护与发布 446 22.1 代码风格 446 22.2 修改标记 446 22.3 版本控制 447 22.4 一致性检查 447 22.5 构建脚本 448 22.6 可移植代码 450 第23章 结束语 451 23.1 流程一览表 451 23.2 下一步该做什么 452 附录a linux汇编 453 附录b linux与bios 457 附录c seq文件 461

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值