前 言
开发Linux设备驱动是我的工作,也是我的生活。Linux设备驱动开发工作是如此地有趣,以至于生活也因此而兴致盎然。自Linus一时“意气用事”编写出Linux内核以后,这个名字叫做Linux的企鹅从此在世界开疆辟壤。地球村上无数的组织和个人将这只企鹅安放在不同的硬件平台上,让它支持各种层出不穷的外设芯片,这样的演变过程无一不伴随着设备驱动的开发,于是乎,时至今日,Linux内核中的绝大多数源代码都集中在设备驱动这一层面上。在村长Linus的带领下,参与这个全球互动的驱动开发活动,将企鹅玩弄于鼓掌之中,总是令人兴奋的。
天性自由的技术人员们总是希望能够摆布和掌控企鹅,但这只企鹅并非沉默的羔羊,它是那么的桀骜不驯。掌控它,无疑需要强硬的手腕,否则,没有能够掌控企鹅,反而会被它折腾地信心全无,再也不敢靠近。因此,本书的第一要务便是传授内核驱动编程的基本手段,把内核驱动编程的方法和理念呈现出来,把Linux内核中的自旋锁、信号量、完成量、中断顶/底半部、定时器、内存和I/O映射以及异步通知、阻塞/非阻塞I/O等拿出来分析。在这些知识的讲解中,空谈理论是毫无意义的,必须借助实例,而实例的背景过于复杂就会转移读者的注意力,因此,本书“发明”了一个虚拟的字符设备globalmem,这一字符设备将内核中的一部分内存作为一个字符设备提供给用户空间去读写和控制,本书讲解基础理论的数章均基于此设备以及此设备的变体globalfifo而展开,变体globalfifo意味着把这片内存作为全局的FIFO。
掌握驱动编程的理论无疑非常重要,但是你仅仅拿到了一杆抢、一颗炮、一架战斗机,并非意味着你就能去打一场漂亮的战役。因为战役是需要严密组织,而组织是有结构的,那就是军、师、旅、团、营、连、排。Linux设备驱动也是如此,不管是“自旋锁、信号量、异步通知、完成量、内存映射、I/O映射”这些枪,“中断顶/底半部、定时器”这些炮,还是“异步通知、阻塞/非阻塞I/O”这些战斗机,不放在一个宏大的结构里作战都是散兵游击,打不得大仗,必须有严格的组织和部署。在Linux设备驱动和其它的软件领域里,这样的组织和部署被称为框架(mainframe)。
一日,与几位同行聚首麻辣火锅点,兴致浓处,大家纷纷开始骂娘,话题的焦点集中到了Linux设备驱动。“你说这驱动本身是多么简单的事情啊,如果没有Linux操作系统,串口的驱动顶多也就三、两函数,几百行代码,偏要整出个TTY层,还搞出N多数据结构”,“还有那个I2C,就2根线,Linux搞出无数的东东,什么i2c_adapter,什么i2c_algorithm,什么i2c_client、i2c_driver,原本简单的东西变得如此复杂”……是的,这番牢骚道出了Linux设备驱动的一大难点,那就是框架!
在最艰难的日子里,你的团队一声呐喊:“你不是一个人在战斗!”这句话听来是如此的振奋,如同黑夜里的明灯。然而,“你不是一个人在战斗”原本就有双重含义,除了意味着你的团队与你风雨同行,坚定地支持你以外,还意味着,你是团队的一份子,因此要遵守团队的规则,扶持你的队友。Linux设备驱动开发工作也诚如是也,“你不是一个人在开发Linux设备驱动”,你站在前人的肩膀上,享受Linux源码中已有的驱动成果,然而,你编写的Linux设备驱动也不得不受限于前人制定的框架。
Linux开发高手们显然更愿意做建筑设计师而不是做工匠,于是乎,近年来,内核中更多的是提供设备驱动的框架而不是单个的设备驱动。围坐火锅,一番牢骚之后,众友终于道出了Linux设备驱动框架的特性,那就是,当没有掌握某类设备驱动框架的时候,工程师们好似在云中漫步,而一旦掌握,便觉脚踏实地。其实,在了解框架以后,块设备、串口、网口、I2C、音频、视频、USB、PCI等各类设备的Linux驱动也不过如此,不会比无操作系统时的硬件驱动麻烦多少。
框架总是令人欢喜令人愁,某类设备驱动的框架总是能对纷繁芜杂的该类设备的无数个体提供最广泛的支持,而框架的学习过程又是令人烦躁。一流高手创造框架,二流高手利用框架,而初学者却难得框架要领。因此,本书的另一大要务便是解剖这些框架,将它们抽筋拔骨,以原始的面貌呈现在读者的面前。本书不定位于讲解如何创造框架,而是定位于剖析现有框架。因此,它的目标是把读者改造成二流高手(如果你是一流高手,请不要购买此书)。倘使读者深受这些框架的启发,创造出新的框架并被采纳,成为一点五流以上高手,那真是令人高兴的事情!
“我不是一个人在写作”,人民邮电出版社的黄焱老师为本书付出了大量辛苦卓绝的劳动。在本书的编写过程中,我还得到了许多人的支持和帮助。......
“你不是一个人在阅读本书”,所以请和其它的读者朋友们一起讨论吧!笔者开通了