Linux设备驱动开发详解:基于最新的Linux4.0内核
上QQ阅读APP看书,第一时间看更新

前言

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 Zhong、刘洪涛、季久峰、邴杰、孙志忠、吴国举、Bob Liu、赵小吾、EJ Zhao、贺亚锋、刘仕杰、Hao Yin等老师和小伙伴的深深感激;谨以此书,致以对我的父母大人、老婆大人、兄长和姐姐、伟大丈母娘的深深感激,本书的写作时间超过一年,其过程是一种巨大的肉体和精神折磨,没有他们的默默支持和不断鞭策,本书是不可能完成的;谨以此书,对为本书做出巨大贡献的编辑、策划老师,尤其是张国强老师致以深深的感激!

由于篇幅的关系,我没有办法一一列举我要感激的所有人,但是,这些年从你们那里获得的,远远大于我付出的,所以,在内心深处,唯有怀着对你们的深深感恩,不断前行。岁月如歌,吾歌狂行。

全书结构

本书首先介绍Linux设备驱动的基础。第1章简要地介绍了设备驱动,并从无操作系统的设备驱动引出了Linux操作系统下的设备驱动,介绍了本书所基于的开发环境。第2章系统地讲解了Linux驱动工程师应该掌握的硬件知识,为工程师打下Linux驱动编程的硬件基础,详细介绍了各种类型的CPU、存储器和常见的外设,并阐述了硬件时序分析方法和数据手册阅读方法。第3章将Linux设备驱动放在Linux 2.6内核背景中进行讲解,说明Linux内核的编程方法。由于驱动编程也在内核编程的范畴,因此,这一章实质是为编写Linux设备驱动打下软件基础。

其次,讲解Linux设备驱动编程的基础理论、字符设备驱动及设备驱动设计中涉及的并发控制、同步等问题。第4、5章分别讲解Linux内核模块和Linux设备文件系统;第6~9章以虚拟设备globalmem和globalfifo为主线,逐步给其添加高级控制功能;第10、11章分别阐述Linux驱动编程中所涉及的中断和定时器、内核和I/O操作处理方法。

接着,剖析复杂设备驱动的体系结构以及块设备、网络设备驱动。该篇讲解了设备与驱动的分离、主机控制器驱动与外设驱动的分离,并以大量实例(如input、tty、LCD、platform、I2C、SPI、USB等)来佐证。其中第12章和第17章遥相呼应,力图全面地展示驱动的架构。Linux有100多个驱动子系统,逐个讲解和学习都是不现实的,授人以鱼不如授人以渔,因此我们将更多的焦点放在了架构讲解方面,以便读者可以举一反三。

本书最后4章分析了Linux的设备树、Linux移植到新的SoC上的具体工作以及Linux内核和驱动的一些调试方法。这些内容,对于理解如何从头开始搭建一个Linux,以及整个Linux板级支持包上上下下的关系尤为重要。

另外,本书的主要代码都引用自Linux源代码,为保留原汁原味,均延用了代码的英文注释,而其他非引用的代码则使用了中文注释或无注释,特此说明。

本书配套的相关素材和代码,读者均可从与本书相关的微信公众号中获得,相关公众号是:Linuxer,欢迎扫描二维码

宋宝华

2015年4月于上海浦东