Linux 设备驱动程序
(第二版)
ii
内容提要
本书面向的读者,是那些想在 Linux 操作系统下支持各种计算机外设,或者想开发新的硬件并在
Linux 下运行的人们。Linux 是 Unix 市场中增长最为快速的部分,并且在许多应用领域获得了广
泛而热情的支持。现在,人们越来越清楚地认识到 Linux 是嵌入式系统的一个极好平台。《Linux
设备驱动程序》已经成为该领域的一流著作,此书将以往那些口述式的经验和知识,或者隐晦的源
代码注释变成了系统地讲述各种设备驱动程序编写方法的著作。
Linux 内核的 2.4 版在设备驱动程序方面发生了重大变化,它简化了许多工作,但同时提供了许多
新的功能,可让驱动程序更加有效而且灵活。本书第二版彻底讲述了这些变化,并介绍了许多新的
处理器和总线结构。
要阅读此书,并不要求读者成为一名内核黑客;我们仅仅希望读者理解 C 语言并熟悉 Unix 系统
调用。我们循序渐进地讲述了字符设备、块设备和网络设备的驱动程序,并且给出了功能完善的示
例驱动程序。这些示例驱动程序说明了驱动程序设计中的许多问题以及解决方法,并且不需要任何
特定的硬件就可以运行。本书第二版的重要修订包括:对对称多处理器(SMP)系统和锁机制的讨
论、对新 CPU 的支持以及新近支持的总线的讨论等等。
如果读者对操作系统完成其任务的方式感兴趣,本书则提供了对地址空间、异步事件和 I/O 的深
入讨论。
可移植性是本书的一个主要关注点。尽管本书主要讲述 2.4 版本,但只要可能,我们也会讲述向
后直到 2.0 版本的相关内容。《Linux 设备驱动程序》也讲述了如何在各种硬件平台上实现最大的
可移植性;示例驱动程序已经在 IA32(PC)和 IA64、PowerPC、SPARC 和 SPARC64、Alpha、
ARM 以及 MIPS 等平台上经过了测试。
iii
作者简介
Alessandro Rubini 在他获得电子工程师职称后不久,就安装了 Linux 0.99.14 版本。后来,他
在 Pavia 大学获得了计算机科学博士学位。但很快他就离开了大学,因为他实在不想写很多的论
文。现在,他是一名自由撰稿人,编写和设备驱动程序相关的文章和论文(很有讽刺意味)。在他
的小孩出世之前,他曾是一名年轻的黑客;而现在则是一名年老的、偏爱非 PC 计算机平台开发
的自由软件鼓吹者。
Jonathan Corbet 早在 1981 年就接触了 BSD Unix 的源代码。那时,科罗拉多大学的一名教
员让他“修正”其中的分页算法。从那时起直到现在,他深入研究了他所遇到的每一个系统,其中
包括 VAX、Sun、Ardent 以及 x86 系统的驱动程序。他在 1993 年第一次接触 Linux 系统,从
此以后一直从事 Linux 的开发。Corbet 先生是 Linux Weekly News (http://LWN.net) 的奠基人和执
行主编;他和妻子及两个孩子生活在科罗拉多州巨石市。
iv
目 录
目 录
前 言 ....................................................... i
Alessandro 的介绍 ............................................................................................................i
Jon 的介绍........................................................................................................................ii
本书面向的读者 ...............................................................................................................ii
内容的组织 ......................................................................................................................iii
背景信息 ..........................................................................................................................iii
其它信息来源 ..................................................................................................................iv
在线版本和条款 ...............................................................................................................v
本书使用的约定 ...............................................................................................................v
我们希望得到来自读者的反馈 ......................................................................................vi
致谢 ..................................................................................................................................vi
第 1 章 设备驱动程序简介 .................................... 1
1.1 设备驱动程序的作用 ..............................................................................................2
1.2 内核功能划分 ..........................................................................................................3
进程管理...................................................................................................................................................... 3
内存管理...................................................................................................................................................... 4
文件系统...................................................................................................................................................... 4
设备控制...................................................................................................................................................... 4
网络功能...................................................................................................................................................... 4
1.3 设备和模块分类 ......................................................................................................5
字符设备...................................................................................................................................................... 5
块设备.......................................................................................................................................................... 5
网络接口...................................................................................................................................................... 5
1.4 安全问题 ..................................................................................................................6
1.5 版本编号 ..................................................................................................................7
1.6 许可证条款 ..............................................................................................................8
1.7 加入内核开发社团 ..................................................................................................9
1.8 本书概要 ..................................................................................................................9
第 2 章 构造和运行模块 ..................................... 11
2.1 核心模块与应用程序的对比 ................................................................................12
2.1.1 用户空间和内核空间..................................................................................................... 14
2.1.2 内核中的并发................................................................................................................. 15
2.1.3 当前进程......................................................................................................................... 15
2.2 编译和装载 ............................................................................................................16
2.2.1 版本依赖......................................................................................................................... 18
2.2.2 平台依赖......................................................................................................................... 19
2.3 内核符号表 ............................................................................................................20
2.4 初始化和关闭 ........................................................................................................22
2.4.1 init_module 中的出错处理 ............................................................................................ 22
i
目 录
2.4.2 使用计数......................................................................................................................... 24
2.4.3 卸载 ................................................................................................................................ 25
2.4.4 显式的初始化和清除函数............................................................................................. 25
2.5 使用资源 ................................................................................................................26
2.5.1 I/O 端口和 I/O 内存.................................................................................................... 27
端口............................................................................................................................................................ 27
内存............................................................................................................................................................ 29
2.5.2 Linux 2.4 中的资源分配 ................................................................................................ 30
2.6 自动和手动配置 ....................................................................................................31
2.7 在用户空间编写驱动程序 ....................................................................................33
2.8 向后兼容性 ............................................................................................................35
2.8.1 资源管理的改变............................................................................................................. 35
2.8.2 多处理器系统上的编译................................................................................................. 36
2.8.3 在 Linux 2.0 中导出符号 .............................................................................................. 36
2.8.4 模块配置参数................................................................................................................. 37
2.9 快速参考 ................................................................................................................37
第 3 章 字符设备驱动程序 ................................... 40
3.1 scull 的设计............................................................................................................40
3.2 主设备号和次设备号 ............................................................................................41
3.2.1 动态分配主设备号......................................................................................................... 43
3.2.2 从系统中删除设备驱动程序........................................................................................... 45
3.2.3 dev_t 和 kdev_t............................................................................................................. 46
3.3 文件操作 ................................................................................................................47
3.3.1 file 结构 ......................................................................................................................... 50
3.3.2 open 和 release.............................................................................................................. 51
open 方法.................................................................................................................................................. 51
release 方法............................................................................................................................................... 54
3.4 scull 的内存使用...................................................................................................54
3.5 竞态的简介 ............................................................................................................57
3.6 read 和 write.........................................................................................................58
3.6.1 read 方法........................................................................................................................ 60
3.6.2 write 方法 ...................................................................................................................... 62
3.6.3 readv 和 writev ............................................................................................................. 63
3.7 试试新设备 ............................................................................................................63
3.8 设备文件系统 ........................................................................................................64
3.8.1 实际使用 devfs.............................................................................................................. 66
3.8.2 可移植性问题和 devfs................................................................................................... 68
3.9 向后兼容性 ............................................................................................................68
3.9.1 文件操作数据结构的变化............................................................................................. 69
3.9.2 模块使用计数................................................................................................................. 71
3.9.3 信号量支持的变化......................................................................................................... 71
3.9.4 用户空间访问的变化..................................................................................................... 71
3.10 快速索引 ..............................................................................................................72
ii
目 录
第 4 章 调试技术 ........................................... 74
4.1 通过打印调试 ........................................................................................................74
4.1.1 printk............................................................................................................................... 74
4.1.2 消息如何被记录............................................................................................................. 76
4.1.3 开启及关闭消息............................................................................................................. 77
4.2 通过查询调试 ........................................................................................................79
4.2.1 使用 /proc 文件系统 .................................................................................................... 79
4.2.2 ioctl 方法 ....................................................................................................................... 83
4.3 通过监视调试 ........................................................................................................83
4.4 调试系统故障 ........................................................................................................85
4.4.1 oops 消息........................................................................................................................ 85
使用 klogd................................................................................................................................................. 87
使用 ksymoops.......................................................................................................................................... 88
4.4.2 系统挂起......................................................................................................................... 91
4.5 调试器和相关工具 ................................................................................................93
4.5.1 使用 gdb......................................................................................................................... 93
4.5.2 kdb 内核调试器............................................................................................................. 94
4.5.3 集成的内核调试器补丁................................................................................................. 96
4.5.4 kgdb 补丁....................................................................................................................... 97
4.5.5 内核崩溃转储分析器..................................................................................................... 97
4.5.6 用户模式的 Linux 虚拟机 ........................................................................................... 97
4.5.7 Linux 跟踪工具包 ......................................................................................................... 98
4.5.8 Dynamic Probes.............................................................................................................. 98
第 5 章 增强的字符驱动程序操作 ............................. 99
5.1 ioctl.........................................................................................................................99
5.1.1 选择 ioctl 命令 ........................................................................................................... 100
类型(type)........................................................................................................................................... 101
号码(number)...................................................................................................................................... 101
方向(direction).................................................................................................................................... 101
尺寸(size)............................................................................................................................................ 101
5.1.2 返回值........................................................................................................................... 103
5.1.3 预定义命令................................................................................................................... 103
5.1.4 使用 ioctl 参数 ........................................................................................................... 104
5.1.5 权能与受限操作........................................................................................................... 106
5.1.6 ioctl 命令的实现 .......................................................................................................... 107
5.1.7 非 ioctl 的设备控制.................................................................................................... 108
5.2 阻塞型 I/O............................................................................................................109
5.2.1 睡眠和唤醒................................................................................................................... 109
5.2.2 等待队列的深入分析....................................................................................................111
5.2.3 编写可重入代码........................................................................................................... 113
5.2.4 阻塞和非阻塞型操作................................................................................................... 114
5.2.5 一个样例实现:scullpipe ............................................................................................ 115
iii
目 录
5.3 poll 和 select....................................................................................................... 118
5.3.1 与 read 和 write 的交互............................................................................................ 121
从设备读取数据...................................................................................................................................... 121
向设备写数据.......................................................................................................................................... 121
刷新待处理输出...................................................................................................................................... 121
5.3.2 底层的数据结构........................................................................................................... 122
5.4 异步通知 ..............................................................................................................123
5.4.1 从驱动程序的角度看................................................................................................... 124
5.5 定位设备 ..............................................................................................................125
5.5.1 llseek 实现 ................................................................................................................... 125
5.6 设备文件的访问控制 ..........................................................................................126
5.6.1 独享设备....................................................................................................................... 127
5.6.2 关于竞态的问题........................................................................................................... 128
5.6.3 限制每次只由一个用户访问....................................................................................... 129
5.6.4 替代 EBUSY 的阻塞型 open.................................................................................... 129
5.6.5 在打开时复制设备....................................................................................................... 130
5.7 向后兼容性 ..........................................................................................................132
5.7.1 Linux 2.2 和 2.0 中的等待队列 ................................................................................ 132
5.7.2 异步通知....................................................................................................................... 133
5.7.3 fsync 方法.................................................................................................................... 133
5.7.4 在 Linux 2.0 中访问用户空间 ................................................................................... 134
5.7.5 2.0 中的权能................................................................................................................ 135
5.7.6 Linux 2.0 的 select 方法............................................................................................ 135
5.7.7 Linux 2.0 的设备定位 ................................................................................................. 136
5.7.8 2.0 和 SMP.................................................................................................................. 136
5.8 快速参考 ..............................................................................................................136
第 6 章 时间流 ............................................ 140
6.1 内核中的时间间隔 ..............................................................................................140
6.1.1 处理器特有的寄存器................................................................................................... 141
6.2 获取当前时间 ......................................................................................................142
6.3 延迟执行 ..............................................................................................................143
6.3.1 长延迟........................................................................................................................... 144
6.3.2 短延迟........................................................................................................................... 145
6.4 任务队列 ..............................................................................................................146
6.4.1 任务队列的本质........................................................................................................... 147
6.4.2 任务队列的运行........................................................................................................... 148
6.4.3 预定义的任务队列....................................................................................................... 149
示例程序是如何工作的 .......................................................................................................................... 150
调度器队列.............................................................................................................................................. 151
定时器队列.............................................................................................................................................. 152
立即队列.................................................................................................................................................. 153
6.4.4 运行自己的工作队列................................................................................................... 153
6.4.5 Tasklets ......................................................................................................................... 154
iv