第1章实验环境的设置与准备 1
1.1系统与Linux运行机制准备 2
1.1.1系统准备 2
1.1.2 Linux发布版的安装与环境设定 2
1.2内核源代码的准备 4
1.2.1获取源代码 5
1.2.2编译内核 5
1.2.3内核设定 8
1.3实验设备的准备 10
1.3.1打印机接口的准备 10
1.3.2实现输入输出的准备物品 13
1.4实验环境的检查 14
第2章 Linux内核与设备驱动程序 17
2.1 Linux操作系统 18
2.2 Linux内核 18
2.2.1 Linux的历史 18
2.2.2 Linux内核的功能 19
2.2.3 Linux内核的特点 20
2.2.4内核源代码的结构 21
2.2.5浏览内核源代码 23
2.3设备驱动程序 24
2.3.1向内核请求资源处理的方法 25
2.3.2模块和设备文件 25
2.3.3设备驱动程序的类型 27
2.3.4整合型设备驱动程序(2.6内核) 28
2.3.5设备驱动程序的层次 29
2.3.6设备驱动程序源代码的结构及介绍 31
第3章 设备文件和低级文件输入输出 35
3.1设备文件和文件输入输出函数 36
3.1.1应用程序中控制硬件的方法 36
3.1.2设备文件 36
3.1.3文件输入输出函数 38
3.2低级文件的输入输出函数 39
3.2.1打开和关闭文件函数open()和close() 39
3.2.2文件的读取和写入函数read()和write() 40
3.2.3文件指针处理函数Iseek() 41
3.2.4设备控制函数ioctl() 42
3.2.5同步处理函数fsync() 42
3.3设备文件相关函数 42
3.3.1设备文件的生成函数 mknod() 42
3.3.2 Error处理函数perror() 43
3.4低级文件输入输出函数的应用实例 44
3.4.1准备零部件 44
3.4.2基本低级文件输入输出函数的使用例子 44
3.4.3 loctl()函数的使用例子 47
3.5 mknod命令和低级文件输入输出函数 50
第4章 简单内核模块的测试 55
4.1内核模块编程的第一步 56
4.1.1“Hello world”的内核模块(内核版本2.4) 56
4.1.2“Hello world”的内核模块(内核版本2.6) 57
4.1.3另一种形式的内核版本2.4的模块程序 59
4.2 内核模块程序的准备 59
4.2.1模块实现原理 60
4.2.2内核提供的符号表:/proc/ksyms 61
4.2.3模块应用程序 61
4.3 内核模块程序的组成 63
4.3.1声明头文件 63
4.3.2模块初始化函数和删除函数的声明 63
4.3.3 2.6内核的权限登记 63
4.4 用于模块编译的Makefile 64
4.4.1 2.4内核中编译外部模块的Makefile 64
4.4.2 2.6内核中编译外部模块的Makefile 65
4.5 模块参数的说明 66
4.5.1 2.4内核模块变量的实例 66
4.5.2 2.6内核模块变量的使用实例 68
4.6 内核消息的输出 70
4.6.1.printk()函数 70
4.6.2管理内核内存的daemon 72
4.6.3 dmesg命令 72
4.6.4 /proc/kmsg 72
4.6.5 printk()函数的注意事项 72
4.7内核与模块 72
4.7.1创建为模块的原因 73
4.7.2内核内部的模块管理 73
4.7.3内核模式和内核内存地址空间 75
4.7.4单向的符号引用 75
4.7.5模块和模块的引用 76
第5章 内存的分配和释放 77
5.1变量 78
5.1.1局部变量和全局变量的选择 78
5.1.2防止函数和变量的重复命名 78
5.1.3可移植性和数据类型 78
5.1.4输入输出内存变量的处理 80
5.2动态内存 81
5.2.1函数kmalloc()和kfree() 82
5.2.2函数vmalloc()和vfree() 83
5.2.3函数_get_ree_pages()和free_ pages() 84
5.3动态内存实例 84
5.3.1实例源代码 85
5.3.2运行方法 88
5.4内存池 89
5.5内存池的实例 90
5.5.1实例源代码 90
5.5.2运行方法 92
5.6内存的分配与释放函数 93
第6章 设备的注册与注销 97
6.1设备驱动程序的控制方式 98
6.1.1设备驱动程序的类型 98
6.1.2字符设备驱动程序的运作 99
6.2struct file_operations 101
6.2.1 File_operations结构体域(field) 102
6.2.2低级输入输出函数和fileoperations结构体的域 103
6.3字符设备驱动程序的注册、注销及组成 106
6.3.1字符设备驱动程序的组成 107
6.3.2不同内核版本对structfile_operations变量的定义 108
6.3.3字符设备驱动程序的注册和注销 109
6.4字符设备驱动程序的创建实例 110
6.4.1实例源代码 110
6.4.2执行方法 117
6.5设备驱动程序的注册与注销函数 119
第7章 设备驱动程序的初始化与终止 121
7.1初始化与结束处理 122
7.1.1模块初始化和终止 123
7.1.2函数open()和函数release( )的初始化和终止处理 125
7.1.3整理初始化和终止处理 内容 129
7.2模块使用次数的管理 129
7.2.1 2.4内核 129
7.2.2 2.6内核 130
7.3输入输出空间的竞争处理函数 131
7.3.1输入输出端口域的竞争处理函数 131
7.3.2输入输出内存空间的竞争处理函数 133
7.4设备驱动程序的初始化与终止函数集 135
第8章 设备驱动程序的读取和写入 139
8.1读/写操作的实现 140
8.1.1函数Read() 141
8.1.2函数Write() 144
8.1.3Struct file*filp 146
8.2 I/O处理 147
8.2.1I/O映射输入输出处理函数 147
8.2.2内存映射输入输出函数 148
8.3用户进程空间和内核进程空间 149
8.4设备驱动程序的读/写实例 152
8.4.1实例源代码 153
8.4.2实施方法 158
8.5设备驱动程序的读/写函数 160
第9章 主设备号与次设备号的处理 167
9.1主设备号、次设备号及设备的种类 168
9.1.1主设备号 168
9.1.2次设备号 169
9.1.3设备的类型 172
9.2基于次设备号的文件处理方式 174
9.3基于次设备号的文件处理实例 176
9.4预留的主设备号 186
9.4.1被字符设备驱动程序预留的主设备号 186
9.4.2字符设备驱动程序的预留MISC相关次设备号 190
9.4.3块设备驱动程序中预留的主设备号 193
9.4.4分配到test或特定platform平台的主设备号和次设备号 195
第10章设备控制 197
10.1设备的控制 198
10.1.1设备控制ioctl()函数的作用 198
10.1.2函数ioctl()的一般状态 199
10.1.3 ioctl上传送的cmd和相关宏函数 200
10.2使用ioctl()函数的输入输出应用实例 203
10.2.1实例源代码 204
10.2.2实施方法 214
10.3设备控制函数 216
第11章时间处理与内核定时器 217
11.1时间处理 218
11.1.1定时器中断(timerinterrupt) 218
11.1.2处理较短的延迟时间 220
11.1.3处理较长的延迟时间 221
11.1.4系统时间的设置 221
11.2内核定时器 223
11.2.1 struct timer_list变量的初始化 224
11.2.2内核定时器的注册 225
11.2.3内核定时器的取消 226
11.3使用内核定时器控制LED的应用实例 226
11.3.1实例源代码 226
11.3.2实施方法 231
11.4时间处理与内核定时器相关函数 232
第12章 中断处理 235
12.1中断 236
12.1.1什么是中断 236
12.1.2 IRQ中断的处理过程 237
12.1.3中断服务函数的结构 238
12.1.4注册中断服务函数 239
12.1.5注销中断服务函数 240
12.1.6中断函数和设备驱动程序之间的数据共享 241
12.1.7中断服务注册和注销起点 243
12.1.8中断的共享 244
12.1.9中断的禁止和消除 245
12.1.*10 seqlock_t结构体 246
12.1.*11中断和随机数的处理 248
12.1.*12确认发生中断的次数 249
12.2中断发生时的检查实例 249
12.2.1实例源代码 250
12.2.2操作步骤 259
12.3中断处理函数 261
第13章 阻塞型输入输出 263
13.1进程的运行效率与睡眠 264
13.2阻塞型输入输出的实现 265
13.2.1阻塞型输入输出 265
13.2.2阻塞型模式和进程的处理过程 266
13.2.3以阻塞型输入输出模式打开 267
13.2.4等待队列和head_t结构体 268
13.2.5进程的睡眠(sleep)和唤醒(wake up) 269
13.3中断发生时的检查实例 270
13.3.1实例源代码 270
13.3.2实施方法 279
13.4 wait_event_interruptible宏 280
13.5阻塞型输入输出函数 282
第14章 输入输入的复用 285
14.1输入输出的复用 286
14.1.1函数select() 286
14.1.2函数poll() 288
14.2输入输出复用的实现 293
14.3打印机端口应用实例 295
14.4输入输出复用函数 308
第15章 任务队列和工作队列 311
15.1任务队列和工作队列的必要性 312
15.1.1需要持续监视特定输入输出时 312
15.1.2中断处理程序难于及时处理时 313
15.1.3需要处理中断服务程序不能胜任的其他工作时 313
15.1.4当设备驱动程序需要与内核结构关联时 313
15.2任务队列 313
15.3工作队列 316
15.3.1调度工作队列 317
15.3.2设备驱动程序自身的工作队列 320
15.4任务队列实例 323
15.4.1实例源代码 323
15.4.2运行方法 327
15.5工作队列实例 329
15.5.1实例源代码 329
15.5.2执行方法 333
15.6使用工作队列控制LED的应用实例 334
15.7使用工作队列防止键盘输入的chattering现象 338
15.8任务队列函数 343
15.9工作队列函数 344
第16章 Bottomhalf 349
16.1 Tophalf和Bottomhalf 350
16.2任务队列和mark_bh()函数 352
16.3任务队列处理过程的修改(2.4→2.6) 353
16.4中断发生时的检查实例 353
16.5中断函数 357
第17章proc文件系统 359
17.1系统信息的确认 360
17.2 proc文件系统 362
17.3 proc文件系统的运行机制 363
17.4虚拟机实例 365
17.4.1实例源代码 365
17.4.2实施方法 373
17.5 proc文件系统相关函数 374
第18章 内存映射 379
18.1物理地址和虚拟地址 380
18.1.1物理地址 380
18.1.2虚拟地址和MMU 380
18.1.3 Linux内核管理 383
18.2地址变换函数 384
18.2.1物理地址空间映射内核地址空间 384
18.2.2输入输出物理地址和虚拟地址之间的转换函数 385
18.3进程的内存映射 386
18.3.1应用程序中调用的函vmmap() 387
18.3.2设备驱动程序的mmap 388
18.3.3 nopage映射方式 392
18.4有关mmap()函数参数值传传递的实例 396
18.4.1实例源代码 396
18.4.2实施方法 400
18.5 VIDEO输入输出的内存mmap实现实例 401
18.5.1实例源代码 402
18.5.2实施方法 407
18.6使用nopage实现mmap的实例 408
18.6.1实例源代码 408
18.6.2实施方法 414
18.7内存映射相关函数 415
19.1模块间引用与 EXPORT_ SYMBOL宏 420
19.2不同版本中内核符号表的注 册方法 421
19.2.1 2.4内核的情况 421
19.2.2 2.6内核的情况 421
19.3模块间符号引用的实例*420 422
19.3.1实例源代码 422
19.3.2实施方法 426
20.1单进程环境下的设备驱动程序 430
20.2多进程环境下的处理 431
20.2.1多进程中的数据处理 431
20.2.2进程重入 432
20.3非抢占式内核环境下的设备驱动程序 434
20.4抢占式内核环境下的设备驱动程序 434
20.4.1抢占式内核的输入输动处理 435
20.4.2抢占式内核的重入处理 436
21.1.4内核源代码中合成设备驱动程序的位置 442
21.1.5内核编译选项文件的修改 442
21.1.6内核源代码中Makefile的修改 443
21.1需要考虑的事项 438
21.1.1头文件和模块编译区分常数 438
21.1.2设备驱动程序的初始化处理 439
21.1.3内核命令处理 440
21.2内核编译选项文件 443
21.2.1.config文件 443
21.2.2 include/linux/autoconf.h 444
21.2.3 2.4内核编译选项文件的语法规则 444
21.2.4 2.6内核编译选项文件的语法规则 449
21.3 Makefile文件的语法规则 454
21.3.1 2.4内核 455
21.3.2 2.6内核 456
21.4将设备驱动程序包含到内核的应用实例 456
21.4.1实例1 457
21.4.2实例2 461
22.1 Linux与块设备驱动程序 466
22.1.1硬盘和设备文件 466
22.1.2辅助记忆装置和设备文件 466
22.1.3 mount和文件系统 467
22.1.4块设备驱动程序 468
22.2硬盘的特点 468
22.2.1硬盘的结构 468
22.2.2硬盘的数据处理方式 469
22.3块设备驱动程序与请求队列 470
22.4不同版本中块设备驱动程序的处理 472
22.5 2.4内核中的块设备处理 474
22.5.1定义块设备的特性 474
22.5.2定义主设备号和从设备号及设备名 475
22.5.3定义与linux/blk.h相关的宏 476
22.5.4注册块设备驱动程序并处理file_ operation结构体 477
22.5.5请求队列相关处理及函数 480
22.5.6处理块设备特性相关的内核全局变量 484
22.5.7分区处理相关的gendisk结构体变量的定义和注册 484
22.5.8增加块设备并检索分区 487
22.5.9注销块设备驱动程序 487
22.6使用make_request方式创建RAM Disk的实例(2.4版) 488
22.6.1实例源代码 488
22.6.2实施方法 493
22.7利用request方式创建虚拟硬盘的实例(2.4版) 494
22.7.1实例源代码 495
22.7.2实施方法 506
22.8 2.6内核版的块设备驱动程序 508
22.8.1块设备驱动程序的注册和注销 508
22.8.2定义块设备驱动程序的结构体 509
22.8.3 struct block_device_operations 509
22.8.4请求队列相关的处理及函数 510
22.8.5 gendisk结构体的生成及注册 514
22.8.6设置块设备的容量 517
22.8.7注销块设备驱动程序 517
22.9利用make_request方式创建RAM Disk的实例(2.6版) 517
22.9.1实例源代码 518
22.9.2实施方法 523
22.10使用request方式创建虚拟硬盘的实例(2.6版) 524
22.10.1实例源代码 525
22.10.2实施方法 533
22.11块设备相关函数(2.4版) 535
22.12块设备相关函数(2.6版) 537
第23章 网络设备驱动程序 541
23.1 Linux系统网络设备驱动程序 542
23.1.1 Linux网络 542
23.1.2网络设备驱动程序的运行 546
23.2网络设备驱动程序的注册与注销 547
23.2.1使用提供函数注册的网络设备驱动程序 548
23.2.2注册新型网络设备驱动程序 551
23.3基本的初始化及注册过程 553
23.3.1初始化调用处理和Space.c 553
23.3.2 PC I设备的硬件检索和初始化 556
23.3.3模块变量io和irq 557
23.4 net_ device结构体的说明 558
23.5网络设备驱动程序的打开和关闭 564
23.5.1网络设备的控制 565
23.5.2网络界面的激活 565
23.5.3网络界面的非激活 566
23.6发送和接收 567
23.6.1 struct sk buff 568
23.6.2发送处理 570
23.6.3超出传送时间的处理 573
23.6.4中断(interrupt )处理 574
23.6.5接收处理 578
23.7统计处理 585
23.8网络设备驱动程序的控制 587
23.9多播处理 588
23.10网络设备驱动程序相关函数 589
第24章 设备文件系统 591
24.1 devfs文件系统 592
24.1.1激活devfs文件 592
24.1.2 2.6内核devfs文件系统支持函数 594
24.2设备文件的创建实例 596
24.2.1实例源代码 596
24.2.2实施方法 598
24.3 devfs相关函数 600
25.1 sysfs文件系统 604
25.1.1什么是sysfs文件系统 604
25.1.2 kobject结构体和sysfs文件系统 604
25.2 sysfs文件系统的应用 606
25.2.1 sysfs文件系统中显示文件 607
25.2.2从sysfs文件系统获得文件对象 609
第26章 移植系统的移植、信号和帮助 615
26.1向移植系统移植 616
26.2 ARM的DIO设备驱动程序实例 618
26.2.1回路说明 619
26.2.2设备驱动程序的设计 619
26.2.3测试用应用程序的设计 620
26.2.4测试用应用程序的设计 620
26.3信号和SIGIO 635
26.4 SIGIO信号处理实例 638
26.4.1实例源代码 639
26.4.2实施方法 643
26.5 call_usermodehelper的应用实例 644
26.5.1实例源代码 644
26.5.2实施方法 646
26.6 modprobe和模块加载请求的处理 646
第27章 DMAG与PCI设备 649
27.1 DMA 650
27.1.1什么是DMA 650
27.1.2 Linux中的DMA处理 651
27.1.3 DMA和MMAP 655
27.2 PCI 656
27.2.1 PnP和设备环境设置空间 657
27.2.2 PCI设备的设备驱动程序 665
27.2.3总线主控DMA 671