本书面向的读者是那些想在Linux操作系统下支持各种计算机外设,或者想开发新的硬件并在Linux下运行的人们。Linux是Unix市场中增长最快的部分,并且在许多应用领域获得了广泛的支持。现在,人们越来越清楚地认识到Linux是嵌入式系统的一个极佳平台,本书第二版已经成为该领域的经典之作。本书作者将以往那些口述式的经验和知识、或者隐晦的源代码注释上升为系统地讲述各种设备驱动程序编写方法的著作。\r\n Linux内核的2.4版在设备驱动程序方面发生了重大变化,它简化了许多工作,但同时提供了许多精细的新功能,可让驱动程序更加高效、灵活。本书第二版透彻地讲述了这些变化,并介绍了许多新的处理器和总线结构。\r\n 要阅读和欣赏本书,并不要求您是一名内核黑客,您所需要具备的只是对C语言和一些Unix系统调用的背景知识的了解。本书循序渐进地讲述了字符设备、块设备和网络接口的驱动程序,并且给出了功能完善的示例驱动程序。这些示例驱动程序说明了驱动程序设计中的许多问题以及解决方法,并且不需要任何特定的硬件就可以运行。本书第二版的重要修订包括:对对称多处理器(SMP)系统和锁机制的讨论、对新CPU以及新近支持的总线的讨论等等。\r\n 如果您对操作系统完成其任务的方式感兴趣,那么本书还提供了对地址空间、异步事件和 I/O的深入讨论。\r\n 可移植性是本书的一个主要关注点。尽管本书主要讲述2.4版本,但在可能的情况下,我们也讲述了2.4版本以前直到2.0版本的相关内容。本书还介绍了如何在各种硬件平台上实现最大程度的可移植性。示例驱动程序已经在IA32(PC)和IA64、PowerPC、SPARC和SPARC64、Alpha、ARM以及MIPS等平台上经过了测试。
前言\r\n\r\n第一章 设备驱动程序简介\r\n\r\n设备驱动程序的作用\r\n内核功能划分\r\n设备和模块分类\r\n安全问题\r\n版本编号\r\n许可证条款\r\n加入内核开发社团\r\n本书概要\r\n\r\n第二章 构建和运行模块\r\n\r\n核心模块与应用程序的对比\r\n编译和装载\r\n内核符号表\r\n初始化和关闭\r\n使用资源\r\n自动和手动配置\r\n在用户空间编写驱动程序\r\n向后兼容性\r\n快速参考\r\n\r\n第三章 字符设备驱动程序\r\n\r\nscull的设计\r\n主设备号和次设备号\r\n文件操作\r\nfile结构\r\nopen和release\r\nscull的内存使用\r\n竞态简介\r\nread 和 write\r\n试试新设备\r\n设备文件系统\r\n向后兼容性\r\n快速参考\r\n\r\n第四章 调试技术\r\n\r\n通过输出调试\r\n通过查询调试\r\n通过监视调试\r\n调试系统故障\r\n调试程序和相关工具\r\n\r\n第五章 增强的字符驱动程序操作\r\n\r\ninctl\r\n阻塞型I/O\r\npoll和 select\r\n异步通知\r\n定位设备\r\n设备文件的访问控制\r\n向后兼容性\r\n快速参考\r\n\r\n第六章 时间流\r\n\r\n内核中的时间间隔\r\n获取当前时间\r\n延迟执行\r\n任务队列\r\n内核定时器\r\n向后兼容性\r\n快速参考\r\n\r\n第七章 获取内存\r\n\r\nkmalloc函数的内幕\r\n后备高速缓存\r\nget_free_page和相关函数\r\nvmalloc与相关函数\r\n引导时的内存分配\r\n向后兼容性\r\n快速参考\r\n\r\n第八章 硬件管理\r\n\r\nI/O端口和 I/O内存\r\n使用I/O端口\r\n使用数字 I/O端口\r\n使用I/O内存\r\n向后兼容性\r\n快速参考\r\n\r\n第九章 中断处理\r\n\r\n中断的整体控制\r\n准备并口\r\n安装中断处理程序\r\n实现中断处理程序\r\ntasklet和底半部处理\r\n中断共享\r\n中断驱动的I/O\r\n竞态\r\n向后兼容性\r\n快速参考\r\n\r\n第十章 合理使用数据类型\r\n\r\n使用标准C语言类型\r\n为数据项分配确定的空间大小\r\n接口特定的类型\r\n其他有关移植性的问题\r\n链表\r\n快速参考\r\n\r\n第十一章 kmod和高级模块化\r\n\r\n按需加载模块\r\n模块间通信\r\n模块中的版本控制\r\n向后兼容性\r\n快速参考\r\n\r\n第十二章 装载块设备驱动程序\r\n\r\n注册驱动程序\r\n头文件bib.h\r\n请求处理简介\r\n请求处理详解\r\n挂装和卸装是如何工作的\r\nioctl方法\r\n可移动设备\r\n可分区设备\r\n中断驱动的块设备驱动程序\r\n向后兼容性\r\n快速参考\r\n\r\n第十三章 mmap和 DMA\r\n\r\nLinux的内存管理\r\nmmap设备操作\r\nkiobuf接口\r\n直接内存访问和总线主控\r\n向后兼容性\r\n快速参考\r\n\r\n第十四章 网络驱动程序\r\n\r\nsnull的设计\r\n连接到内核\r\nnet_device结构的细节\r\n打开和关闭\r\n数据包传输\r\n数据包的接收\r\n中断处理程序\r\n链路状态的改变\r\n套接字缓冲区\r\nMAC地址解析\r\n定制ioctl命令\r\n统计信息\r\n组播\r\n向后兼容性\r\n快速参考\r\n\r\n第十五章 外设总线综述\r\n\r\nPCI接口\r\nISA回顾\r\nPC/104和 PC/104+\r\n其他的PC总线\r\nSBus\r\nNuBus\r\n外部总线\r\n向后兼容性\r\n快速参考\r\n\r\n第十六章 内核源代码的物理布局\r\n\r\n引导内核\r\n引导之前\r\ninit进程\r\nkernel目录\r\nfs目录\r\nmm目录\r\nnet目录\r\nipc和lib\r\ninclude和 arch\r\ndrivers目录\r\n\r\n参考文献\r\n词汇表
顾名思义,本书是讲述如何编写 Linux设备驱动程序的。面对层出不穷的新硬件产品,必须有人不断编写新的驱动程序以便让这些设备能够在Linux下正常工作。从这个意义上讲,讲述驱动程序的编写本身就是一件非常有意义的工作。但本书也涉及到Linux内核的工作原理,同时还将讲述如何根据自己的需要和兴趣来定制Linux内核。Linux是一个开放的系统,我们希望借助本书它能够更加开放,从而能够吸引更多的开发人员。
自本书第一版问世以来,Linux的变化非常巨大。现在的Linux能够在更多的处理器上运行,并且支持更加广泛的硬件,许多内部的编程接口也相应发生了重大变化,因此,我们决定编写本书的第二版。本版以Linux 2.4版本的内核为主,讲述了新内核提供的所有新特色,同时,仍然兼顾了早期的内核版本。
我们希望读者能够从本书的学习当中获得乐趣,就像我们自己从编写本书的过程中获得乐趣一样。
Alessanaro 的介绍
作为一个喜欢DIY的电子工程师,我一直乐于使用计算机来控制一些外部的硬件设备。从小时候使用父亲的Apple IIe计算机起,我就开始寻找另外一个平台,以便能够将我自制的电路板连接到它上面,并能够编写自己的驱动程序。不幸的是,不管是从硬件级别还是从软件级别来看,20世纪SO年代PC的功能都不是非常强大:PC的内部设计比起Apple II来简直是差远了,而且可供利用的文档也远远不能令人满意。但在Linux出现之后,我决定尝试利用这个新的操作系统,为此,我购买了一个昂贵的386主板,但没有购买任何受到所有权保护的软件。
那时,我在大学里使用Unix系统,这个设计精巧的系统令我激动不已,尤其在有了由GNU项目提供给用户使用的、更加精巧的工具之后,这个系统更加令我着迷了。对我来讲,在我自己的PC主板上使用Linux内核,一直是最为难忘的经历,我不仅可以编写自己的设备驱动程序,而且还有机会再次拿起电烙铁。我不停地告诉别人:“我长大之后,一定要成为一名黑客”,而GNU/Linux则是实现这一梦想的最佳平台。可是,我不知道我是否已经长大。
随着Linux的成熟,越来越多的人开始乐于为自制的电子设备或者商用设备编写驱动程序。就像Linus Torvalds所说的那样,“我们又回到了能掌握自己的命运、从而自己编写设备驱动程序的时代”。
回顾1996年,我经常为那些从别人那里借来的,或者别人给我的,或者是我自己制作的硬件设备编写自己的设备驱动程序,并且乐此不疲。那时,我已经为MichaelJohnson所著的 《Kernel Hacker’s Guideb撰写了一些内容,并开始为由Michael创办和负责的《Linux Journal》编写内核相关的文章。在Michael的引荐下,我认识了在 O’Redlly工作的 Andy Oram,他希望我能就设备驱动程序编写一本书,我非常高兴地接受了这一工作,有很长一段时间我一直忙于编写这本书。
到1999年,我发现,我已经没有足够的精力来独自完成本书的更新工作了:我的家庭添丁进口,而且我更多的时间要花在编写GPL’d软件的工作上。除此之外,内核变得更大,而且可以支持比以往更多的平台,而API也变得更加复杂和成熟。这时,Jonathan开始帮助我更新本书。他拥有足够的技巧、能力和热情,不断催促我跟上落下很多的进度。他凭着自己良好的技能和热情,已经成为推进这个进程的最得力助手,这些却是我无法企及的。我非常高兴能够和他共事,不管在技术上还是在私人方面。
Jon的介绍
我从1994年初开始接触Linux,那时,我正在说服自己的老板为我购买一台Fintronic Systems公司生产的笔记本电脑。作为 20世纪 80年代初期(从那时起我就在和源代码打交道)的一名 Unix用户,我立即被 Linux所吸引。甚至在 1994年, Linux就已经成为一个非常实用的系统,而且也是我所遇到的第一个真正自由的系统。那时,我几乎完全丧失了对专有系统的兴趣。
但我并没有一个完整的、想为Linux编写什么著作的计划。当O'Reilly和我讨论有关帮助编写本书第二版的时候,我刚刚从我工作了18年的公司辞职,并成立了一个Linux咨询公司。为了吸引别人的注意力,我们建立了一个Linux新闻站点,即Linux Weekly News(http://lwu.net),该站点的内容主要集中子内核开发。随着Linux的大众化,该Web站点也变得非常知名,而我们的咨询业务却最终被人遗忘。
然而,我的第一兴趣却始终是系统编程。早些时候,我“修正”最初的BSD Unix系统当中的分页代码(这是一个可怕的黑客工作),或者在VAX/VMS系统上编写磁带驱动器的驱动程序(这些源代码是可获得的,如果你不在意这些由汇编和Bliss语言编写的代码的话)。随着时间的推移,我又为 Alliant、Ardent和 Sun等系统编写驱动程序。后来,我开始利用Linux开发实时雷达数据收集系统。这个时候,也就是编写本书的时候,我正致力于修正Linux软盘驱动程序中的I/O请求队列锁的实现。
我为能参与本书的编写而感到高兴。首先,通过本书的编写,我能够更加深入地研究内核代码,同时能够帮助别人达到同样的目的。Linux是个实用的系统,同时也是一个能带给人乐趣的系统,而围绕内核工作则是所有事情当中最有趣的(至少对那些兴趣乖僻的黑客是如此)。和 Alessandro一起工作也令人高兴,我必须感谢他对我如此信任,让我修改他撰写的优秀文字,也感谢他在我出现错误或者不能赶上进度时的耐心,当然也得感谢那次到Pavia的自行车旅行。编写本书的那些时光的确令人难忘!
本书的读者对象
在技术方面,本书提供了一条便捷的途径,让读者可以理解内核内幕以及一些Linux开发者所做出的设计决策。尽管本书的主要目的是教读者如何编写设备驱动程序,但同时也给出了内核实现方面的概览。
尽管真正的黑客能够从正式的内核源代码中找到所有必要的信息,但通常来讲,好的书籍能够更好地帮助读者提高编程技巧。本书内容来自对内核源代码的仔细分析,我们希望我们所付出的努力是值得的。
本书对那些希望编写计算机设备驱动程序的人员,或者对那些要解决Linux机器内部问题的程序员来讲,将是非常有帮助的。请注意,“Linux机器”是一个比“运行Linux的PC”更为宽泛的概念,因为Linux现在能够支持许多不同的硬件平台,所以内核编程不再绑定到某个特定的平台。我们希望本书能够成为那些想成为内核黑客但却不知如何下手的人们的良好起点。
Linux的狂热爱好者将能从本书中找到深入内核代码的足够精神食粮;通过本书的学习,此类读者将有能力加入到为增加功能或提高性能而不停工作的开发小组当中。本书并没有涵盖Linux内核的全部,但是,作为Linux设备驱动程序的开发人员,需要了解如何和许多内核子系统一起工作。因此,本书对内核编程做了一个一般性的介绍。Linux仍然在不断改进和发展,因此,新程序员始终有机会加入到Linux的开发大军中。
另一方面,如果你只是为了为自己的设备编写一个驱动程序,而不想过多了解内核的内幕信息的话,那么本书的模块化结构足以满足你的需求。如果你不想深入到细节当中,则可以简单地跳过大部分的技术章节,而直接阅读可由设备驱动程序使用的、能够和内核的其他部分无缝结合的标准API部分。
本书的主要目标是为Linux内核2.4版本编写内核模块。模块(module)是能够在运行时装载到内核的目标代码,它能够为正在运行的内核添加新的功能。我们尽可能地让示例代码也能够在内核的2.2和2.0版本中运行,如果需要做些改动则会特别指出。
内容的组织
本书内容由简到难,并被划分为两大部分。第一部分(第一章到第十章)首先讲述了如何编写内核模块,然后讲述了编写功能完备的字符设备驱动程序所涉及的各个编程主题。每一章分别讲述某一个特定问题,并在每章结尾包含了一个“符号表”,该符号表可在实际开发中作为参考。
在本书的第一部分中,内容从面向软件的概念过渡到硬件相关的概念。这种组织方法意味着,你能够尽可能地不在机器中插入任何外部硬件而测试示例代码。每章都包含有源代码,并给出了能够在任何Linux计算机上运行的示例驱动程序。但是,在第八章和第九章中,我们需要你在并行端口上连接一些电线,以便测试硬件处理代码,当然,这一要求对任何人来讲都是可以做到的。
本书的第二部分讲述了块设备驱动程序和网络接口,并深入讨论了一些更高级的内容。许多驱动程序编写者可能不需要这些内容,但我们建议你阅读这些章节。尽管对某个特定的项目来说,你并不需要了解这些知识,但第二部分的许多内容对了解Linux内核的工作原理也很重要。
背景信息
为了更好地利用本书,我们希望读者熟悉C语言编程。因为我们经常会提到Unix命令和管线,因此,也需要读者拥有Unix的使用经验。
在硬件级,即使没有任何经验的读者也可以理解本书的内容,当然,对一些一般性的概念必须清楚。本书内容并不基于某个特定的PC硬件,我们在提到某个特定的硬件时,会提供给读者所有必要的信息。
建立内核需要一些自由软件工具,而且经常要求使用这些工具的特定版本。太老的工具可能缺少一些必要的特性,而太新的工具有时又可能会生成不能正常工作的内核。通常而言,当前流行的Linux发行版所提供的工具能够很好地工作。不同的内核版本对工具的版本要求也不同,你可以参考内核源代码树中的Documentation/Changes文件。
其他信息的来源
本书提供的大部分信息直接来自内核源代码以及相关文档。我们要特别注意内核源代码树中的Documentation目录,其中包含有大量有用的信息,比如内核API中新增部分的文档(在DocBook子目录中)。
还有一些有用的书籍包含了更为广泛的内容,这些书籍列在本书的“参考文献”中。Internet上有大量可用的信息,下面将列出部分站点。当然,Internet站点的更新非常快,而印刷书籍却难以及时更新。因此,下面的清单可能已经过时了。
http://www.kernel.org
ftp://ftp.kernel.ong
本站点是Linux内核开发的主站点,其中包含了最新的内核发行版本以及相关信息。注意该FTP站点的镜像已遍布全球,因此,应该选择最近的镜像站点下载Linux源代码。
http://www.linuxdoc.org Linux Documentation Prqect(Linux文档项目)拥有大量称为“HOWTO”的
文档,其中一些是技术性的,并涉及到一些内核相关的主题。
http://www.linux-mag.com/depts/gear.html
来自《Linux Magazine》的“Gearheads only”专栏,经常发表由知名开发人员编写的关于内核的文章。
http://www.linux.it/kerneldocs
其中包含许多由Alessandro撰写的有关内核的文章。
http://lwn.net
王婆卖瓜一下,该新闻站点由本书的作者之一Jonathan Corbet编辑维护,提供了定期的与内核开发相关的报道。
http://kt.zork.net
Kernel Traffic是一个颇受欢迎的站点,它提供了每周Linux内核开发邮件列表中的讨论总结。
http.//www.atof.csiro.au/-rgooch/linux/docs/kernel-newsflash.html
Kernel Newsflash站点是一个内核新闻的集散地。该站点尤其专注于当前内核版本中的兼容性问题,人们可以非常容易地搞清为什么自己的驱动程序不能在最新的内核中正常工作。
http://www.kernelnotes.org
Kernel Notes是一个关于内核版本信息、非正式补丁等的经典站点。
http://www.kernelnewbies.org
该站点面向新的内核开发人员。其中包含有针对初学者的内容和FAQ(常见问题),而且还有一个IRC频道,从中可获得即时的帮助。
http://ksr.org
Linux Kernel Source Reference是几乎所有内核历史版本的CVS归档的Web界面。如果你想知道某个特定主题的历史变迁,这个站点再合适不过了。
http//www.linux-mm.org
该网页面向Linux内存管理开发,其中包含大量有用信息,并且还包含大量与内核相关的Web站点链接。
http://www.conecta.it/linux
这个意大利站点几乎包含了所有正在开发的Linux相关项目的信息,而且更新及时。也许你已经知道了与Linux开发有关的HTTP链接的站点,如果不知道,那么这个站点将是一个非常好的选择。
在线版本和条款
本书作者已经选择让本书在GNU Free Documentation License(GNU自由文档许可证)版本1.l的保护下免费获取。