内容简介
本书介绍了Linux设备驱动开发理论、框架与实例,详细说明了自旋锁、信号量、完成量、中断顶/底半部、定时器、内存和I/O映射以及异步通知、阻塞I/O、非阻塞I/O等Linux设备驱动理论,以及字符设备、块设备、tty设备、I2c设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动架构中各个复杂数据结构和函数的关系,并讲解了Linux驱动开发的大量实例,使读者能够独立开发各类Linux设备驱动。
目录
                                                        目  录 
赞誉 
推荐序一 
推荐序二 
前言 
第1章 Linux设备驱动概述及开发环境构建 1 
1.1 设备驱动的作用 1 
1.2 无操作系统时的设备驱动 2 
1.3 有操作系统时的设备驱动 4 
1.4 Linux设备驱动 5 
1.4.1 设备的分类及特点 5 
1.4.2 Linux设备驱动与整个软硬件系统的关系 6 
1.4.3 Linux设备驱动的重点、难点 7 
1.5 Linux设备驱动的开发环境构建 8 
1.5.1 PC上的Linux环境 8 
1.5.2 QEMU实验平台 11 
1.5.3 源代码阅读和编辑 13 
1.6 设备驱动Hello World:LED驱动 15 
1.6.1 无操作系统时的LED驱动 15 
1.6.2 Linux下的LED驱动 15 
第2章 驱动设计的硬件基础 20 
2.1 处理器 20 
2.1.1 通用处理器 20 
2.1.2 数字信号处理器 22 
2.2 存储器 24 
2.3 接口与总线 28 
2.3.1 串口 28 
2.3.2 I2C 29 
2.3.3 SPI 30 
2.3.4 USB 31 
2.3.5 以太网接口 33 
2.3.6 PCI和PCI-E 34 
2.3.7 SD和SDIO 36 
2.4 CPLD和FPGA 37 
2.5 原理图分析 40 
2.6 硬件时序分析 42 
2.6.1 时序分析的概念 42 
2.6.2 典型的硬件时序 43 
2.7 芯片数据手册阅读方法 44 
2.8 仪器仪表使用 47 
2.8.1 万用表 47 
2.8.2 示波器 47 
2.8.3 逻辑分析仪 49 
2.9 总结 51 
第3章 Linux内核及内核编程 52 
3.1 Linux内核的发展与演变 52 
3.2 Linux 2.6后的内核特点 56 
3.3 Linux内核的组成 59 
3.3.1 Linux内核源代码的目录结构 59 
3.3.2 Linux内核的组成部分 60 
3.3.3 Linux内核空间与用户空间 64 
3.4 Linux内核的编译及加载 64 
3.4.1 Linux内核的编译 64 
3.4.2 Kconfig和Makefile 66 
3.4.3 Linux内核的引导 74 
3.5 Linux下的C编程特点 75 
3.5.1 Linux编码风格 75 
3.5.2 GNU C与ANSI C 78 
3.5.3 do { } while(0) 语句 83 
3.5.4 goto语句 85 
3.6 工具链 85 
3.7 实验室建设 88 
3.8 串口工具 89 
3.9 总结 91 
第4章 Linux内核模块 92 
4.1 Linux内核模块简介 92 
4.2 Linux内核模块程序结构 95 
4.3 模块加载函数 95 
4.4 模块卸载函数 97 
4.5 模块参数 97 
4.6 导出符号 99 
4.7 模块声明与描述 100 
4.8 模块的使用计数 100 
4.9 模块的编译 101 
4.10 使用模块“绕开”GPL 102 
4.11 总结 103 
第5章 Linux文件系统与设备文件 104 
5.1 Linux文件操作 104 
5.1.1 文件操作系统调用 104 
5.1.2 C库文件操作 108 
5.2 Linux文件系统 109 
5.2.1 Linux文件系统目录结构 109 
5.2.2 Linux文件系统与设备驱动 110 
5.3 devfs 114 
5.4 udev用户空间设备管理 116 
5.4.1 udev与devfs的区别 116 
5.4.2 sysfs文件系统与Linux设备模型 119 
5.4.3 udev的组成 128 
5.4.4 udev规则文件 129 
5.5 总结 133 
第6章 字符设备驱动 134 
6.1 Linux字符设备驱动结构 134 
6.1.1 cdev结构体 134 
6.1.2 分配和释放设备号 136 
6.1.3 f?ile_operations结构体 136 
6.1.4 Linux字符设备驱动的组成 138 
6.2 globalmem虚拟设备实例描述 142 
6.3 globalmem设备驱动 142 
6.3.1 头文件、宏及设备结构体 142 
6.3.2 加载与卸载设备驱动 143 
6.3.3 读写函数 144 
6.3.4 seek函数 146 
6.3.5 ioctl函数 146 
6.3.6 使用文件私有数据 148 
6.4 globalmem驱动在用户空间中的验证 156 
6.5 总结 157 
第7章 Linux设备驱动中的并发控制 158 
7.1 并发与竞态 158 
7.2 编译乱序和执行乱序 160 
7.3 中断屏蔽 165 
7.4 原子操作 166 
7.4.1 整型原子操作 167 
7.4.2 位原子操作 168 
7.5 自旋锁 169 
7.5.1 自旋锁的使用 169 
7.5.2 读写自旋锁 173 
7.5.3 顺序锁 174 
7.5.4 读-复制-更新 176 
7.6 信号量 181 
7.7 互斥体 183 
7.8 完成量 184 
7.9 增加并发控制后的globalmem的设备驱动 185 
7.10 总结 188 
第8章 Linux设备驱动中的阻塞与非阻塞I/O 189 
8.1 阻塞与非阻塞I/O 189 
8.1.1 等待队列 191 
8.1.2 支持阻塞操作的globalf?ifo设备驱动 194 
8.1.3 在用户空间验证global
                                                    
前言/序言
                                                        前??言Linux从未停歇前进的脚步。Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,现在仍然在没日没夜地合并补丁、升级内核。做技术的人,从来没有终南捷径,拼得就是坐冷板凳的傻劲。 
这是一个连阅读都被碎片化的时代,在这样一个时代,人们趋向于激进、浮躁,内心的不安宁使我们极难静下心来研究什么。我见过许多Linux工程师,他们的简历上写着“精通”Linux内核,有多年的工作经验,而他们的“精通”却只是把某个寄存器从0改成1,从1改成0的不断重复;我也见过许多Linux工程师,他们终日埋头苦干,敲打着自己的机器和电路板,却从未冷静下来思考,并不断重构和升华自己的知识体系。 
这是要把“牢底”坐穿的程序员,这样“忙忙碌碌”的程序员,从来都不算是好程序员。 
对于优秀的程序员,其最优秀的品质是能够心平气和地学习与思考问题,透析代码背后的架构、原理和设计思想。没有思想的代码是垃圾代码,没有思想的程序员,只是在完成低水平重复建设的体力活。很多程序员从不过问自己写的代码最后在机器里面是怎么跑的,很多事情莫名其妙地发生了,很多bug莫名其妙地消失了……他们永远都在得过且过。 
由此,衍生出了本书的第一个出发点,那就是带给读者更多关于Linux开发思想的讲解,帮助读者奠定根基。本书呈现给读者的更多的是一种思考方法,而不是知识点的简单罗列。 
本书除对基础理论部分进行了详细的讲解外,还加强了对驱动编程所涉及的Linux内核最底层机理的讲解,内容包括中断、定时器、进程生命周期、uevent、并发、编译乱序、执行乱序、等待队列、I/O模型、内存管理等。这些知识点非常重要,是真正证明程序员理解了Linux的部分内容,程序员只有打好根基,才能游刃有余。 
本书没有大量描述各种具体驱动类型的章节,如Sound、PCI、MTD、tty等,而将更多的焦点转移到了驱动编程背后的内核原理,并试图从Linux内核的上百个驱动子系统中寻找出内部规律,以培养读者举一反三的能力。 
Linux内核有上百个驱动子系统,这一点从内核的drivers子目录中就可以看出来: 
好吧,傻子才会一个目录一个目录地去看,一个目录一个目录地从头学起。我们势必要寻找各种驱动子系统的共性,摸索规律。在本书中,我们将更多地看到各驱动子系统的类比,以及驱动子系统的层次化设计。 
技术工作从来都不能一劳永逸。世界变化得太快,当前技术革新的速度数倍于我们父辈、祖辈、祖祖辈经历过的任何时代。证明你是“真球迷”还是“伪球迷”的时候到了,这个时代是伪程序员的地狱,也是真程序员的天堂。 
从浩如烟海的知识体系、不断更新的软件版本中终生学习,不断攻克一个个挑战,获取新养分,寻找新灵感,这实在是黑暗的码农生涯中不断闪现的璀璨光芒。 
Linux的内核版本不断更新,出现了Linux 3.0、Linux 3.1、Linux 3.2、…、Linux 3.19、Linux 4.0、Linux 4.1,变化的是软件的架构,不变的是Linus的热情。 
这无疑也是本书的第二个出发点,更新Linux驱动编程的知识体系以迎合最新的时代需求。因此,本书有大量关于设备树、ARM Linux移植、Linux电源管理、GPIO、时钟、定时器、pinmux、DMA等内容。我们的操作平台也转移到了QEMU模拟的4核Cortex-A9电路板上,书中的实例基本都转移到了市面流行的新芯片上。 
最近两三年,老是听许多程序员抱怨,市面上缺乏讲解新内核的资料、缺乏从头到尾讲解设备树的资料,但是我想说,这实在不是什么难点。难点仍然是本书基于第一个出发点要解决的问题,如果有好的基础,以优秀程序员极强的学习能力,应该很快就可以掌握这些新知识。机制没有变,变化的只是策略。 
因此学习能力也是优秀程序员的又一个重要品质。没有人生下来就是天才,良好的学习能力也是通过后天的不断学习培养的。可以说,学得越多的人,学新东西的速度一定越快,学习能力也变得越强。因为,知识的共通性实在太多。 
读者在阅读本书时,不应该企图把它当成一本工具书和查API的书,而是应该把它当作一本梳理理论体系、开发思想、软件架构的书。唯如此,我们才能适应未来新的变化。 
时代的滚滚车轮推动着Linux内核的版本不断向前,也推动着每个人的人生。红尘滚滚,我不去想是否能够成功,既然选择了远方,便只顾风雨兼程。 
最后,本书能得以出版,要感谢带领我向前的人生导师和我的众多小伙伴,他们或者在我人生的关键时刻改变了我,或者给我黑暗的程序生涯带来了无尽的快乐和动力。我的小伙伴,他们力挺我、鼓励我,也辱骂我、奚落我,这些都是真挚的友情。 
谨以此书,致以对杨平先生、何昭然、方毅伟、李华毅、宋志武、杜向龙、叶祥振、刘昊、王榕、何晔、王立赛、曾过、刘永生、段丙华、章君义、王文琪、卢鹏、刘涛、徐西宁、吴赫、任桥伟、秦龙廷、胡良兵、张家旺、王雷、Bryan Wu、Eric Miao、Cliff Cai、Qipan Li、Guoying Zhang、陈健松、Haoyu Z
                                                    
                      

                   


















