标题：深入Linux设备驱动程序内核机制
出版信息
深入Linux设备驱动程序内核机制
陈学松 著  ISBN 978-7-121-15052-4
2012年1月出版
定价：98.00元
16开
540页
出版社：电子工业出版社
内容简介
这是一本系统阐述Linux设备驱动程序技术内幕的专业书籍，它的侧重点不是讨论如何在Linux系统下编写设备驱动程序，而是要告诉读者隐藏在这些设备驱动程序背后的那些内核机制及原理。作者通过对Linux内核源码抽丝剥茧般的解读，再辅之以精心设计的大量图片，使读者在阅读完本书后对驱动程序前台所展现出来的那些行为特点变得豁然开朗。
本书涵盖了编写设备驱动程序所需要的几乎所有的内核设施，比如内核模块、中断处理、互斥与同步、内存分配、延迟操作、时间管理，以及新设备驱动模型等内容。为了避免读者迷失在某一技术细节的讨论当中，本书在一个比较高的层面上进行展开，以一种先框架再细节的结构安排极大地简化了读者的阅读与学习。
本书不仅适合那些在Linux系统下从事设备驱动程序开发的专业技术人员阅读，也同样适合有志于从事Linux设备驱动程序开发或对Linux设备驱动程序及Linux内核感兴趣的在校学生等阅读。对于没有任何Linux设备驱动程序开发经验的初学者，建议先阅读那些讨论“如何”在Linux系统下编写设备驱动程序的入门书籍，然后再阅读本书来理解“为什么”要以这样或者那样的方式来编写设备驱动程序。
推荐序
这不是一本单纯的关于Linux设备驱动程序入门的书。它是给有一定的Linux设备驱动程序编写经验并且对众多Linux底层设备驱动内幕机制感兴趣的读者量身定制的。与市面上已经出版的Linux相关方面的图书的不同之处在于，本书并不着重于全面描述Linux内核，也不只是简单地告诉你如何去写一个Linux下的设备驱动程序。它是从设备驱动程序的视角出发，深入到Linux内核去剖析那些和驱动程序实现机制密切相关的技术内幕。比如让你理解为什么在这个地方驱动程序应该使用work queue而不是tasklet，为什么在中断处理例程里应该使用spin_lock而不是mutex_lock……因为只有当你对驱动程序中使用的各种内核实现有了清晰的认识，你才能在日常的工作当中随心所欲地驾驭它们，写出更高性能更安全的代码。知其然，更知其所以然，对于沉迷于技术领域的人而言，这种不断探索的好奇心是对技术工作能长期保持热情的一个基本特质。相对于市面上已经出版的相关书籍而言，本书具有以下两个鲜明的特色：
细节揭秘目前市场上已经出版的Linux内核和驱动程序方面的书籍，大体上可分为两种。一种是侧重于内核本身，鉴于目前Linux的内核源码已经十分庞大，这些讲解内核的书有些本身非常全面，作者的写作态度也非常严谨，比如Deep Understanding Linux Kernel，还有新近出版的Professional Linux Kernel Architecture，后者几乎涵盖了新版Linux内核中绝大部分重要的构件，但也正因如此，这样的书籍就不可能在与驱动程序相关的机制上留下太多笔墨。另外还有一种是专门讲解Linux驱动方面的书籍，典型的有Linux Device Driver和Essential Linux Device Driver。这些书着重于介绍Linux驱动的基本概念和架构，但是对于想了解更多幕后的技术细节的读者来说，《深入Linux设备驱动程序内核机制》一书可提供更详细的资源和帮助。通常当你想深入理解一些一般书籍没有描述的机制时，你可能会采用在线搜索或查看源码的方式，但有时这不仅费时也未必能得到满意的答案。本书提供了另一途径让你更系统、有效地理解这些内核机制。我相信对于广大忙于在校学习、职场深造或课题攻关的读者来说，本书可提供很多有益的帮助。
图片说理这本书另外一个很大的特点是，作者大量使用其精心设计的图片来帮助你清晰地理解一些复杂的概念、流程和架构。这在中文版原创的图书中是很难能可贵的，相对而言外文书在这方面做得就要好很多。形象直观的图片胜过大量的文字，也能节省读者大量的时间。可以看到，本书的作者在这一方面做了很大的努力去加以完善，在我看来，这是一个非常好的尝试。本书作者当前正在AMD上海研发中心从事Linux显卡驱动等系统软件方面的研发工作，能在繁忙的工作之余，通过对自己学习和实践经验的总结写下这样一本书，对增进国内读者的 Linux 系统开发能力将起到很大的作用。我相信，如果作者有足够的时间与精力的话，这本书还可以进一步完善，包括在某些技术方面可以有更精细的描述。
AMD图形软件架构师  PMTS  俞辉
2011年8月24日于加拿大
前　言
在Linux庞大的源码树中，设备驱动程序部分的代码已经占了相当大的比例。现实的工作中，大量的采用Linux系统的平台需要设备驱动程序才能把Linux的内核真正运行起来，同时通过编写Linux设备驱动程序，使得我们经由亲手编写具有特权等级的代码来一探Linux内核幕后的秘密成为可能。所以，无论是从日常工作的需要还是只为单纯满足对Linux内核机制好奇心的角度来说，学习并掌握Linux设备驱动程序的编写都是非常必要的，同时也是一件非常有趣且有意义的事情。
初衷与定位这本书并不仅仅是单纯地讨论如何在Linux系统下编写一个设备驱动程序，因为关于这方面的内容，市面上已经有大量类似的图书可供参考。本书的总体思想是从内核的角度来看设备驱动程序，从设备驱动程序的角度深入到内核中，比如通过对spin_lock以及spin_lock_irq等内核源码的分析，来告诉你在什么场合下应该使用spin_lock，什么场合下又应该选择spin_lock_irq。还有，比如我们几乎每天都会在设备驱动程序所代表的内核模块中使用MODULE_LICENSE("GPL")这样的声明，这个声明是如此地平凡，以至于我们常常忽略它存在的价值。但是在某个夜深人静的夜晚，感觉长夜漫漫无心睡眠时，在你内心深处的某个地方是否会想过，这个声明对一个内核模块而言，它到底意味着什么，如果没有它，加载这样一个模块对系统又会造成什么样的影响，如此等等，读者都可以在阅读本书的过程中找到答案。
很显然，只有当你清楚地理解了一个东西的内在机制，你才能更好地去使用它们，如果不幸在使用过程中出现问题，也才可以快速将其定位并最终予以解决。台湾著名技术作家侯捷曾引林雨堂先生在《朱门》中的一句话，“只用一样东西，不明白它的道理，实在不高明”，来描述他当时写作时的心境，其实这句话也同样适合我用来阐明写作本书的初衷之一。
但是这并不意味着只有Linux系统下设备驱动程序的编写老手才适合阅读本书，因为我在本书写作过程中，一般会先给出一个总体的框架，然后在此基础上对Linux提供给设备驱动程序使用的每一个常见而重要的内核设施进行细致地分析，同时辅之以验证性质的代码来使得这种略嫌抽象的讨论具体化，以激发读者对技术探索的兴趣。所以即便是入门级的读者，也可以通过阅读本书来加深对Linux下编写设备驱动程序的理解。
另外要说的是，读者不应该寄希望于阅读两三本书就可以掌握Linux下设备驱动程序编写的精髓，所有的书籍只能在大体上给你一个参考借鉴的作用，真正的理解还要靠读者自己去努力，诚所谓“纸上得来终觉浅，绝知此事要躬行”。
编排与范围在本书的结构编排上，我努力使各章节独立起来，但是少量的向前或者向后引用还是必不可少的。但是总体上，我将最基本的篇章尽量放到前面，一些加强型或者高级点的话题尽量放到后边。在描述驱动程序内核机制方面，为了避免单纯的代码解释所带来的抽象感，我会使用具体的例子来将所能看到的驱动程序的前台行为和它的幕后机制串联起来，以帮助读者建立起全面立体的设备驱动程序架构蓝图。不过Linux对某些特性的支持因为考虑到各种平台和性能等诸多因素，其实现很可能会有多种不同的方法，比如从内核态驱动程序向用户空间导出信息的文件系统方面，就至少有proc和sysfs两种形式。因此本书在描述具体的例子时，一定是遵循其中的某种实现，在诸多实现机制的选择上，本书会从实用性和实时性角度出发，采用内核中最新引入或者是最有发展前景的实现，对于某些即将过时的实现机制（因为兼容或者代码维护工作量的关系，一些老的机制可能依然残留在新版的内核代码中），除非出于技术细节的对比或者从增加知识面的角度考虑会有所涉及，否则将不会作为本书的主线。
在代码的引用上，为了突出功能主线部分和削减本书的篇幅，我会删除代码中用来增加调试信息、性能增强及防御性代码这些部分。对于系统体系架构相关的代码，我主要以x86与ARM平台为主，因为这两者是当前最流行的两种处理器架构。关于本书所参考的Linux内核源码的版本，在本书刚开始写作时参考的是2.6.35的版本，在写作的中后期，已经将内核版本更新到了2.6.39，在本书的修订阶段，我已经努力将之前完成的内容更新到了2.6.39。当然，因为作者时间精力所限，加之Linux内核本身就博大精深，内核版本也一直在不断更新变化中，所以书中肯定还会有这样那样潜在的错误，希望读者朋友们能不吝批评指正，以使我们得以共同提高。
创作历程我有幸自参加工作以来，在Linux下从事设备驱动程序相关的开发工作已经有9年多的时间，这期间在Linux上所接触的平台既有x86，也有ARM，甚至包括少量的PowerPC。在我看来，学习某一操作系统下的设备驱动程序的编写，主要包含两个方面：一个是该操作系统本身对设备驱动程序框架的支持，也可以称之为设备驱动模型，另一个则是对要驱动的硬件的理解。对于后者，设备驱动程序开发者将要面对各种各样的硬件设备，了解它们的最好也最直接的方法当然是这样硬件的datasheet。前者则主要和操作系统息息相关，比如在Linux系统下开发设备驱动程序，必然要熟练掌握Linux为设备驱动的编写所提供的各种内核实施及相关的各种数据结构，本书的内容主要就是探讨Linux内核为设备驱动程序编写所提供的所有这些设施的幕后技术。
本书最早的写作酝酿大约在2010年10月份前后，在此之前，或者是出于自己对以往积累的技术总结的需要，或者是出于将自己的一些技术心得与同行分享的目的，总之，我陆陆续续在一些论坛上发表了若干剖析Linux设备驱动程序内核机制的帖子，这些帖子最终使我萌发了用一本书来总结自己以往的Linux设备驱动程序开发经验的想法。我把最初的大约一章半的稿子发给了电子工业出版社，很快就得到了策划编辑张春雨先生的肯定，接下来也很顺利地通过了选题的论证，这之后就是一段极其漫长且非常辛苦的写作过程。时间是最大的挑战，由于白天需要工作，写作的时间只能是留给夜晚或者周末，在写作最紧张的时刻，经常要写到凌晨2点多。除了时间上的困难之外，如何将一个技术点用最透彻最简洁的语言描述清楚，如何对Linux内核中纷繁复杂的内容进行取舍，这些也都是非常耗费精力的事情。技术本身的理解也许并不困难，难在如何去把你心中掌握的东西清晰准确地以文字的方式表达出来，这不同于论坛的发帖，可以非常自由甚至随心所欲，写书的话，必须考虑它的完整性、逻辑性以及可读性，同时还要考虑将来潜在的读者群。尤其是如果你想认认真真写一本书的话，有时候甚至需要反复推敲一个技术点的表达方式。在写作灵感枯竭的时候，看着时间飞快掠过，而眼前的文档却没有留下几行字，那种强烈的挫折感与沮丧感真得会让人动摇自己的信念：自己是否还能坚持下去？！所以当这本书即将出版时，我还很有些恍惚，不敢相信自己居然磕磕绊绊地最终完成了这些书稿。
意见反馈读者如果在阅读本书的过程中有任何意见或者建议，欢迎通过下面的E-mail与我取得联系。
关于本书使用到的源代码，读者可在网站上下载。另外，关于本书后续的一些勘误、某些技术细节方面的讨论也会在该网站相应的版面上进行。
致 谢首先，我要感谢我的家人，如前所述，写书占去了我大量的业余时间，我的父母和怀孕的妻子在此期间承担了几乎所有的家务劳动，替我捣腾出不少的写作时间，感谢她们！我的宝贝女儿在今年8月15日健康出生，成为我的家庭中新的一员，这本书也正好可以作为父亲的见面礼送给她——可爱的萌萌同学。
其次是电子工业出版社的张春雨与白涛编辑，从选题的论证到文字编辑，他们都付出了极其辛苦的劳动并且提出了很多有益的建议，那些逝去的不堪回首岁月里满眼尘封的E-mail见证了这一点！当然，还要感谢我现在所效力的AMD公司，因为它使得我不必为生活所迫去写一本书，对技术的热情与兴趣才是我最终得以坚持下来的最大因素。
最后，在本书的审核方面，AMD的PMTS及显卡驱动软件架构师俞辉在百忙中为本书作序并审核了部分章节，AMD上海研发中心Linux Graphic Base Driver团队的Lisa Wu及研发经理刘刚也为本书的写作提供了支持，诺基亚与西门子的研发经理胡兵全审核了本书第1章及第12章，EMC的PE Thomas审核了本书第3章及第4章。Marvell的资深软件工程师James Lai亦审核了本书部分章节并有宝贵意见，在此一并表示感谢！
陈学松
2011年8月29日于上海
目 录
第1章  内核模块 1
第2章  字符设备驱动程序 57
第3章  分配内存 87
第4章  互斥与同步 127
第5章  中断处理 169
第6章  延迟操作 203
第7章  设备文件的高级操作 231
第8章  时间管理 274
第9章  Linux设备驱动模型 295
第10章  内存映射与DMA 356
第11章  块设备驱动程序 407
第12章  网络设备驱动程序 473