《Essential Linux Device Drivers》第1章

来源:互联网 发布:hm在淘宝没有旗舰店吗 编辑:程序博客网 时间:2024/04/30 11:35

http://21cnbao.blog.51cto.com/109393/119973


第1章 简介
Linux具有诱人的魅力,它是一个由全世界不同民族、不同信仰、不同性别的人共同参与和协作的国际性项目。免费提供源代码以及容易理解的类UNIX应用程序编程环境,促成了Linux的重大成功。通过因特网从专家处即时获得的高质量的免费支持发挥了重要的作用,这促使了一个庞大的Linux社区的形成。
由于在技术方面开发人员可以获得所有源码,并由此给出一些创新方案,因此他们感到无比振奋。例如,你可以hack[①]Linux的源码,并对其进行定制,以让其在你的设备上于几秒钟之内启动,而使用一个专有操作系统则很难完成这样的壮举。
1.1 演化
Linux于1991年起源于一位名为Linus Torvalds的芬兰大学生的业余爱好,但很快就发展成为受全球欢迎的先进的操作系统。Linux第一次发布时仅支持Intel 386处理器,但是后来,内核在复杂性上逐步增加,可以支持众多的体系结构、多处理机系统和高性能集群。Linux支持很多CPU,主要支持的一些体系结构有x86、IA64 、ARM、PowerPC、Alpha、s390、MIPS和SPARC。Linux已经被移植到成千上万个基于这些处理器的硬件平台之上。与此同时,内核还在不断完善,并以飞快的脚步发展。
虽然开始的时候只是一个桌面操作系统,但目前Linux已经进入嵌入式和企业领域,并渗入我们的日常生活。当你按掌上电脑的按键、调节你的遥控器到天气频道或者在医院接受体检的时候,很有可能某些Linux代码正在为你提供服务。一方面,Linux有很大的技术优势,另一方面,Linux可以免费获得,这两方面对它的变革发挥着重大的作用。由于能够降低消费类电子产品的价格,Linux已成为该领域一个很好的选择,因为专有操作系统的价格有时候比硬件本身的价格还贵。
1.2 GNU copyleft
GNU项目(GNU是GNU’s Not UNIX的递归缩写,即GNU不是UNIX)比Linux诞生得更早,它发起的目标是定制一个免费的类UNIX操作系统。一个完整的GNU操作系统包含Linux内核,但也包含一些其他组件,如库、编译器和实用工具(utility)。因此,基于Linux的计算机的更准确称呼应该是 GNU /Linux系统。GNU/Linux系统的所有组成部分都建立在自由软件之上。
自由软件的种类有很多,其中一种是公共领域(public domain)的软件。公共领域发布的软件没有版权,对它的使用也不会强加任何限制。你可以免费使用它,随意修改它,甚至限制你修改后代码的发布。你会发现,“没有限制”在下行过程中反而引入了限制。
GNU项目的主要支撑者——自由软件基金会,创造了GNU公共许可证(GNU Public License,GPL),它也被称为copyleft[②],以防止有人中途将自由软件转化为专有软件。如果某人修改了copyleft的软件,就必须以copyleft的方式分享他的软件。GNU系统中的Linux内核以及像GNU编译器(GNU Compiler Collection,GCC)等大部分组件都以GPL发布。因此,如果你修改了内核,你就必须在社区分享此修改。基本上,你必须以copyleft的形式将授予你的权利传递出去。
 
Linux内核基于GPL第2版。在内核社区,人们一直在争论是否应该支持GPL的最新版本GPLv3。目前的趋势似乎是反对采取GPLv3。
 
通过系统调用访问内核服务的Linux应用程序没有被看作衍生的工作,因此并不受限于GPL。而库则采用GNU轻量级通用公共许可证(GNU Lesser General Public License,LGPL),其限制要少于GPL。专有软件也允许与LGPL下的库动态链接。
1.3 kernel.org
Linux内核源代码的主要存放仓库是[url]www.kernel.org[/url]。该网站包含所有已经发布的内核版本,世界上许多地方都有kernel.org的镜像网站。
除了已经发布的版本以外,kernel.org还包含了由一线开发人员提供的补丁,这些补丁可以作为未来稳定版本的试验床(test bed)。补丁是一种文本文件,其包含了开发树中原始版本和开发人员提供的新版本之间的源码差异。由Linux内核维护领袖Andrew Morton定期提供的-mm补丁是一种流行的补丁(可在kernel.org上获得),在该补丁中,我们可以找到在主线源代码树中尚未提供的实验性的功能。kernel.org上另一个会定期公布的补丁是由Ingo Molnar维护的-rt(real time,实时)补丁。-rt补丁的一些功能已经被融入Linux内核主线中。
1.4 邮件列表和论坛
Linux内核邮件列表(Linux Kernel Mailing List,LKML)是开发人员就设计问题进行辩论并决定Linux未来要包含的功能的论坛。你可以在[url]www.lkml.org[/url]看到实时的邮件列表。Linux内核目前包含由遍布于世界各地的成千上万的开发人员贡献的数百万行代码,正是lkml将他们连在一起。
LKML并不是为了解答一般的Linux问题,其基本规则是只能张贴与内核有关的、以前没有被回答过并且在众所周知的文档中没有提及的问题。如果在你编译Linux应用程序的时候C编译器崩溃了,你应该在其他地方张贴这样的问题。
LKML中讨论的一些问题线索甚至比畅销的《纽约时报》更有趣,花几个小时浏览LKML的压缩包将有助于你洞察Linux内核背后的理念。
内核的大部分的子项目都拥有自己的邮件列表。因此,如果你正在开发Flash设备的驱动,就可以订阅linux-mtd邮件列表;如果你发现了Linux USB存储设备驱动的bug,就可以在linux-usb-devel 邮件列表发起一个线索。在以后的几章中,我们就参考了相关的邮件列表。
在各种论坛上,来自世界各地的内核专家会聚集于同一个屋檐下共同商讨Linux技术。加拿大渥太华每年举行一次的Linux Symposium就是这样的一个会议。其他的还包括在德国举行的Linux Kongress和在澳大利亚组织举行的linux.conf.au。也有一些Linux论坛聚集了众多的商界领袖,他们在论坛上分享真知灼见,其中的一个例子就是每年在北美举行的LinuxWorld Conference and Expo。
[url]http://lwn.net/[/url]上可以获得Linux开发社区的最新消息。如果你只是想简单地了解内核的最新发布版,不想阅读太多的资料,[url]http://lwn.net/[/url]可能是一个好地方。另一个网络社区[url]http://kerneltrap.org/[/url]则讨论当前的内核议题。
在每个主线Linux内核版本发布中,你都会看到重大的改进,如内核抢占、不受限于锁(lock-free)的读操作、分担中断处理工作的新服务或者新体系结构的支持。因此,请一直跟踪邮件列表、网站和论坛,以保证自己在Linux技术上厚重的份量。
1.5 Linux发行版
一个GNU/Linux系统除了内核以外,还由大量的实用工具(utility)、程序、库和工具(tool)组成,因此,获得和正确安装所有的组件将是一项艰巨的任务。而Linux发行版则有序地将这些组件进行了分类,并捆绑成相应的包。一个典型的发行版包含了数以千计现成的包。这使得用户无需担心下载不到正确版本的程序,也无需关心程序间的依赖问题。
因为打包是GNU许可证范围内的一种有效的赚钱方式,因此,目前的市场上诞生了不少Linux发行版。其中,Red Hat/Fedora、Debian、SuSE、Slackware、Gentoo、Ubuntu和Mandriva这些发行版定位于桌面用户;而MontaVista、TimeSys和Wind River发行版则面向嵌入式系统开发。通常,嵌入式Linux的发行版还包括一套可动态配置的紧凑的应用程序集,以便针对资源的限制为系统进行量体裁衣。
除了打包以外,发行版还为内核的开发提供了增值服务。因此,许多项目都开始于发行版提供的内核而非kernel.org发布的官方内核,之所以要这样做,理由有如下几个。
n         Linux发行版遵守设备工业领域的标准,因此是开发的更好起点。特殊兴趣组(Special Interest Group,SIG)已经成立,其目的是促进Linux在各个领域的应用。消费电子产品Linux论坛(Consumer Electronics Linux Forum,CELF,网址为[url]www.celinuxforum.org[/url])集中于消费类电子领域的Linux应用。CELF规范定义了一些功能的支持等级,如可扩展性、快速启动、片上执行以及电源管理等。开源开发实验室(Open Source Development Lab,OSDL,网址为[url]www.osdl.org[/url])则集中于电信级设备。OSDL的电信级Linux(Carrier Grade Linux,CGL)规范包含了对稳定性、高可用性、运行时补丁以及增强的错误恢复能力的诠释,这些问题在电信领域非常重要。
n         主线内核版本可能并未包含对用户所选择的嵌入式控制器的充分支持,即使控制器建立在内核所支持的CPU核心之上。但是,Linux发行版可能包含了控制器内部所有外设的设备驱动程序。
n         在内核开发过程中你计划使用的调试工具可能不包含在主线内核中。例如,内核并不包含内建的调试器支持。如果想在内核开发过程中使用内建的调试器,用户必须单独下载并打上相应的补丁。如果针对用户内核版本的测试过的补丁并不易用,用户必须忍受更多的麻烦。而发行版则包含了很多有用的调试功能,所以你可以立即开始使用它们。
n         一些发行版提供了法律补偿,让你的公司无须为任何由于内核bug所产生的诉讼承担责任。
n         发行版往往会对他们发布的内核进行较多的测试[③]。
n         用户可以从内核发行版的供应商处购买到他们提供的服务以及软件包支持。
1.6 查看源代码
在进入内核领域进行热身之前,让我们先下载Linux源代码,学会打补丁,并查看内核源码树的分布。
首先,到[url]www.kernel.org[/url]下载最新的稳定的源代码(源代码以gzip(.zip)和bzip2 (.bz2)两种压缩格式提供),然后进行解压缩。在下列命令中,请用最新的内核版本号(例如2.6.23)代替X.Y.Z:
bash> wget [url]www.kernel.org/pub/linux/kernel/vX.Y/linux-X.Y.Z.tar.bz2[/url]
bash> tar xvfj linux-X.Y.Z.tar.bz2
 
现在,你已经拥有位于/usr/src/linux-X.Y.Z/目录的源代码树,下面将通过打-mm补丁(Andrew Morton)进行一项增加一些实验性功能的实验。
运行如下命令:
bash> wget [url]www.kernel.org/pub/linux/kernel/people/akpm/patches/X.Y/X.Y.Z/X.Y.Z-[/url]
bash> cd /usr/src/linux-X.Y.Z/
asmlinkage void __init start_kernel(void)
    char *command_line;
           __stop___param[];
+   printk("Penguins are cute, but so are polar bears\n");
    /* ... */
    rest_init();
bash> cd /usr/src/linux-X.Y.Z/
bash> make menuconfig
 
menuconfig是内核配置菜单的文本界面,使用make xconfig可以产生一个图形界面。你所选择的配置信息被存放在内核源码树根目录的.config文件中。如果你不想从头开始进行配置,可以使用 arch/your-arch/defconfig或者arch/your-arch/configs/your-machine_defconfig(如果你的体系结构中包含一些可被支持的平台的话)文件作为起点。因此,如果你正在为32位x86体系结构编译内核,则运行如下命令:
bash> make bzImage
 
现在,内核映像将位于arch/x86/boot/bzImage,更新你的启动分区:
bash> /sbin/lilo
bash> reboot
 
启动后的第一条信息显示了你对北极熊的热爱。
1.8 可加载的模块
由于Linux可运行于各种各样的体系结构,并支持无数的I/O设备,因此把所有要支持的设备都直接编译进内核并不可行。发行版通常包含一个最小的内核映像,而将其他的功能以模块的形式提供。在运行的时候,模块会按需动态加载。
要产生模块,则进入内核源码树根目录并编译:
bash> make modules
 
运行如下命令安装编译生成的模块:
bash> modprobe vfat
Module       Size     Used by
fat          49052    1 vfat
/lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko:
/lib/modules/X.Y.Z/kernel/fs/nls/nls_base.ko
 
于是它首先加载了fat.ko和nls_base.ko这2个模块,之后加载vfat.ko,这样,你挂载VFAT分区时所需要的所有模块都被自动加载了。
使用modinfo实用工具可以提取模块的详细信息:    
filename:      /lib/modules/X.Y.Z/kernel/fs/vfat/vfat.ko
description:   VFAT filesystem support
depends:       fat, nls_base
 
为了将内核驱动编译为模块,在配置内核的时候,请将相应的菜单选择按钮置为<M>。本书中的大部分设备驱动例子以内核模块的形式实现。为了从mymodule.c源文件构造mymodule.ko模块,可以创建一个一行的Makefile文件,并且以如下方式执行它:
bash> echo "obj-m += mymodule.ko" > Makefile
make: Entering directory '/path/to/kernel-sources'
  MODPOST
  LD [M] /path/to/module-sources/mymodule.ko
bash> insmod ./mymodule.ko
 
内核模块减小了内核的尺码,并缩短了开发—编译—测试的周期。对于一次修改而言,你仅仅需要重新编译特定的模块并重新加载它。在第21章中,我们将学习模块调试技术。将驱动设计为内核模块也有一些缺陷。不像内建的驱动,模块无法在系统启动时预留资源,在加载时预留资源成功的几率会减小。
1.9 整装待发
Linux已经跋涉了许多的地域,成为一门艺术。所以你可以基于它来学习操作系统的概念、处理器体系结构甚至工业领域。当你学习某一设备驱动子系统所使用的技术时,可以更深入地探索其背后潜在的设计由来。
在没有明确说明的情况下,书中都假定为32位x86体系结构。但是,本书也考虑到了一个事实:你更有可能为嵌入式设备而非传统的PC兼容的系统编写驱动程序。因此,对于串口驱动一章,讲解了2个设备:一个PC衍生器件上的触摸控制器和一个手机上的UART。对于I2C设备驱动程序一章,则讲解了PC系统中的EEPROM和嵌入式设备中的实时钟。本书也将介绍内核为大多数设备驱动类所提供的核心基础设施,它们隐藏了设备驱动程序的体系结构相关性。
在本书接近尾声的第21章讨论了设备驱动的调试技术。你可能会发现,在阅读本书的过程中,开发驱动时提前阅读该章会很有用。
本书基于2.6内核,它包含了对2.4内核的大量改变,覆盖了所有的主要的子系统。因此,希望你已经在你的系统中安装了基于2.6的Linux,并开始用内核源代码进行实验。基于以下两个主要的原因,本书的每一章都充分地指出了相关的内核源文件:
(1) 因为内核中的每个驱动子系统包含成千上万行的源代码,所以本书只可能进行一个相对简单的呈现,查看源代码中与书中例子相关的真实的驱动将为你提供更广阔的视角。
(2) 在开发一个驱动之前,参考drivers/目录中现存的、与你的要求相似的驱动并以之作为起点是一个好主意。
因此,为了从本书中获得最大的益处,要通过频繁地浏览源码树和啃代码来熟悉内核。在代码探索的过程中,也要跟踪邮件列表的进展。

原创粉丝点击