<a>Preface</a>
It was the late 1990s and at IBM, we were putting the Linux kernel on a wrist watch. The target device was tiny, but the task was turning out to be tough. The Memory Technology Devices subsystem didn’t exist in the kernel, which meant that before a filesystem could start life on the watch’s flash memory, we had to develop the necessary storage driver from scratch. Interfacing the watch’s touch screen with user applications was complicated since the kernel’s input event driver interface hadn’t been conceived yet. Getting X-Windows to run on the watch's LCD wasn’t easy since it didn’t work well with frame buffer drivers. Of what use is a water-proof Linux wrist watch if you can’t stream stock quotes from your bath tub? Bluetooth integration with Linux was several years away, and months were spent porting a proprietary Bluetooth stack to Internet-enable the watch. Power management support was good enough only to squeeze a few hours of juice from the watch's battery, hence we had work cut out on that front too. Linux-Infrared was still unstable, so we had to coax the stack before we could use an Infrared keyboard for data entry. And we had to compile the compiler and cross-compile a compact application-set since there were no accepted distributions in the consumer electronics space.
Fast forward to the present: The baby penguin has grown into a healthy teenager. What took thousands of lines of code and a year in development back then, can be accomplished in a few days with the current kernels. But to become a versatile kernel engineer who can magically weave solutions, you need to understand the myriad features and facilities that Linux offers today.
<a>About the Book</a>
Among the various subsystems residing in the kernel source tree, the drivers/directory constitutes the single largest chunk and is several times bigger than the others. With new and diverse technologies arriving in popular form factors, the development of new device drivers in the kernel is accelerating steadily. The latest kernels support over 70 device driver families.
This book is about writing Linux device drivers. It covers the design and development of major device classes supported by the kernel, including those I missed during my Linux-on-Watch days. The discussion of each driver family starts by looking at the corresponding technology, moves on to develop a practical example, and ends by looking at relevant kernel source files. But before foraying into the world of device drivers, the book introduces you to the kernel and discusses the important features of 2.6 Linux, emphasizing those portions that are of special interest to device driver writers.
<a>Audience</a>
This book is intended for the intermediate-level programmer eager to tweak the kernel to enable new devices. You should have a working knowledge of operating system concepts. For example, you should know what a system call is, and why concurrency issues have to be factored in while writing kernel code. The book assumes that you have downloaded Linux on your system, poked through the kernel sources, and at least skimmed through some related documentation. And you should be pretty good in C.
<a>Summary of Chapters</a>
The first four chapters prepare you to digest the rest of the book. The next sixteen chapters discuss drivers for different device families. A chapter that describes device driver debugging techniques comes next. The penultimate chapter provides perspective on maintenance and delivery. We will shut down by walking through a checklist that summarizes how to set forth on your way to Linux-enablement when you get hold of a new device.
Chapter 1, “Introduction”, starts our tryst with Linux. It hurries you through downloading the kernel sources, making trivial code changes, and building a bootable kernel image.
Chapter 2, “A Peek Inside the Kernel”, takes a brisk look into the innards of the Linux kernel and teaches you some must-know kernel concepts. It first takes you through the boot process and then describes kernel services particularly relevant to driver development such as kernel timers, concurrency management, and memory allocation.
Chapter 3, “Kernel Facilities”, examines several kernel services that are useful components in the tool box of driver developers. The chapter starts by looking at kernel threads, which is a way to implement background tasks inside the kernel. It then moves on to helper interfaces such as linked lists, work queues, completion functions, and notifier chains. These helper facilities simplify your code, weed out redundancies from the kernel, and help long-term maintenance.
Chapter 4, “Laying the Groundwork”, builds the foundation for mastering the art of writing Linux device drivers. It introduces devices and drivers by giving you a bird's eye view of the architecture of a typical PC-compatible system and an embedded device. It then looks at basic driver concepts such as interrupt handling and the kernel’s device model.
Chapter 5, “Character Drivers”, looks at the architecture of character device drivers. Several concepts introduced in this chapter such as polling, asynchronous notification, and I/O control, are relevant to subsequent chapters as well, since many device classes discussed in the rest of the book are ‘super’ character devices.
Chapter 6, “Serial Drivers”, explains the kernel layer that handles serial devices.
Chapter 7, “Input Drivers”, discusses the kernel’s input subsystem that is responsible for servicing devices such as keyboards, mice, and touch screen controllers.
Chapter 8, “The Inter-Integrated Circuit Protocol”, dissects drivers for devices such as EEPROMs that are connected to a system’s I2C bus or SMBus. This chapter also looks at other serial interfaces such as SPI bus and 1-wire bus.
Chapter 9, “PCMCIA and Compact Flash”, delves into the PCMCIA subsystem. It teaches you to write drivers for devices having a PCMCIA or Compact Flash form factor.
Chapter 10, “Peripheral Component Interconnect”, looks at kernel support for PCI and its derivatives.
Chapter 11, “Universal Serial Bus”,explores USB architecture and explains how you can use the services of the Linux-USB subsystem to write drivers for USB devices.
Chapter 12, “Video Drivers”, examines the Linux-Video subsystem. It finds out the advantages offered by the frame buffer abstraction and teaches you to write frame buffer drivers.
Chapter 13, “Audio Drivers”,describes the Linux-Audio framework and explains how to implement audio drivers.
Chapter 14, “Block Drivers”,focuses on drivers for storage devices such as hard disks. In this chapter, you will also learn about the different I/O schedulers supported by the Linux Block subsystem.
Chapter 15, “Network Interface Cards”, is devoted to network device drivers. You will learn about kernel networking data structures and how to interface network drivers with protocol layers.
Chapter 16, “Linux without Wires”, looks at driving different wireless technologies such as Bluetooth, Infrared, WiFi, and cellular communication.
Chapter 17, “Memory Technology Devices”, discusses flash memory enablement on embedded devices.The chapter ends by examining drivers for the Firmware Hub found on PC systems.
Chapter 18, “Embedding Linux”, steps into the world of embedded Linux. It takes you through the main firmware components of an embedded solution such as bootloader, kernel, and device drivers. Given the soaring popularity of Linux in the embedded space, it’s more likely that you will use the device driver skills that you acquire from this book to enable embedded systems.
Chapter 19, “Drivers in User Space”, looks at driving different types of devices from user space. Some device drivers, especially ones that are heavy on policy and light on performance requirements, are better off residing in user land. This chapter also explains how the Linux process scheduler affects the response times of user mode drivers.
Chapter 20, “More Devices and Drivers”, takes a tour of a potpourri of driver families not covered thus far, such as Error Detection And Correction (EDAC), FireWire, and ACPI.
Chapter 21, “Debugging Device Drivers”, teaches about different types of debuggers that you can use to debug kernel code. In this chapter, you will also learn to use trace tools, kernel probes, crash-dump, and profilers. When you develop a driver, be armed with the driver debugging skills that you learn in this chapter.
Chapter 22, “Maintenance and Delivery”, provides perspective on the software development life cycle.
Chapter 23, “Shutting Down”, takes you through a checklist of work items when you embark on Linux-enabling a new device. The book ends by pondering What next?
Device drivers sometimes need to implement code snippets in assembly, so Appendix A takes a look at the different facets of assembly programming on Linux. Some device drivers on x86-based systemsdepend directly or indirectly on the BIOS, so Appendix B teaches you how Linux interacts with the BIOS. Appendix C describes seq files, a kernel helper interface introduced in the 2.6 kernel that device drivers can use to monitor and trend data points.
The book is generally organized according to device and bus complexity, coupled with practical reasons of dependencies between chapters. So, we start off with basic device classes such as character, serial, and input. Next, we look at simple serial buses such as I2C and SMBus. External I/O buses such as PCMCIA, PCI, and USB follow. Video, audio, block, and network devices usually interface with the processor via these I/O buses, so we look at them soon after. The next portions of the book are oriented towards embedded Linux, and cover technologies such as wireless networking and flash memory. User space drivers are discussed towards the end of the book.
Kernel Version
This book is generally up to date as of the 2.6.23/2.6.24 kernel versions. Most code listings in this book have been tested on a 2.6.23 kernel. If you are using a later version, look at Linux websites such as lwn.net to learn about the kernel changes since 2.6.23/24.
<a>Conventions Used</a>
Source code, function names, and shell commands, are written like this. The shell prompt used is bash>. Filename are written in italics like this. Italics are also used to introduce new terms.
Some chapters modify original kernel source files while implementing code examples. To clearly point out the changes, newly inserted code lines are prefixed with ‘+’, and any deleted code lines with ‘-’.
Sometimes, for simplicity, the book uses generic references. So if the text points you to the arch/your-arch/ directory, it should be translated for example, to arch/i386/ if you are compiling the kernel for the x86 architecture. Similarly, any mention of the include/asm-your-arch/ directory should be read as include/asm-arm/ if you are, for instance, building the kernel for the ARM architecture. The ‘*’ symbol and ‘X’are occasionally used as wild card characters in filenames. So, if a chapter asks you to look at include/linux/time*.h, look at the header files, time.h, timer.h, times.h and timex.h,residing in the include/linux/ directory. If a section talks about /dev/input/eventX or /sys/devices/platform/i8042/serioX/, X is the interface number that the kernel assigns to your device in the context of your system configuration.
The 'à' symbol is sometimes inserted between command or kernel output to attach explanations.
Simple regular expressions are occasionally used to compactly list function prototypes. For example, the section “Direct Memory Access” in Chapter 10, “Peripheral Component Interconnect”, refers to pci_[map|unmap|dma_sync]_single() instead of explicitly citing pci_map_single(), pci_umap_single(), and pci_dma_sync_single().
Several chapters refer you to user space configuration files. For example, the section that describes the bootprocess opens /etc/rc.sysinit, while the chapter that discusses Bluetooth opens /etc/bluetooth/pin. The exact names and locations of such files might, however, vary according to the Linux distribution you use.
Acknowledgments
First, I raise my hat to my editors at Prentice Hall: Debra Williams Cauley, Anne Goebel, and Keith Cline. Without their supporting work, this book would not have materialized. I thank Mark Taub for his interest in this project and for initiating it.
Several sources have contributed to my learning in the past decade: the many teammates with whom I worked on Linux projects, the mighty kernel sources, mailing lists, and the Internet. All these have played a part in helping me write this book.
Martin Streicher of Linux Magazine changed me from a full-time coder to a spare-time writer when he offered me the magazine’s “Gearheads” kernel column. I gratefully acknowledge the many lessons in technical writing that I’ve learned from him.
I owe a special debt of gratitude to my technical reviewers. Vamsi Krishna patiently read through each chapter of the manuscript. His numerous suggestions have made this a better book. Jim Lieb provided valuable feedback on several chapters. Arnold Robbins reviewed the first few chapters and provided insightful comments.
Finally, I thank my parents and my wife for their love and support. And thanks to my baby daughter for constantly reminding me to spend cycles on the book by her wobbly walk that bears an uncanny resemblance to that of a penguin.
<a>Dedication</a>
This book is dedicated to the ten million visually challenged citizens of India. All author proceeds will go to their cause.
前言
(宋寶華譯)
上世紀90年代末期,我們IBM的一群同僚進行了一項将Linux移植到一種智能手表上的工作。目标裝置看起來是一個微不足道的小系統,但是移植Linux的任務卻相當艱巨。在當時,核心中還不存在MTD子系統,這意味着在檔案系統能夠運作于這種手表的Flash存儲器之前,我們不得不從頭開始開發儲存設備驅動。而由于當時核心的輸入事件驅動接口尚未誕生,手表的觸摸屏與使用者空間應用程式的接口也變得非常複雜。同樣地,由于手表的LCD采用幀緩沖驅動方式工作地并不好,讓X Windows運作在手表的LCD上也十分困難。另外,對于一塊防水的Linux手表而言,如果你不能躺在浴缸裡實時獲得股票行情,這塊手表還有什麼用?幾年前,Linux內建了藍牙,而當時我們卻花費了數月的時間來完成将一種商用藍牙協定棧移植到手表上的工作,進而使得這種手表具備了Internet聯網能力。蹩腳的能量管理系統讓這種手表使用電池僅能運作幾個小時,我們不得不提前就能量管理進行開創性的研究。那時候,Linux紅外項目Linux-infrared仍然不穩定,為了讓一個紅外鍵盤能作為手表的輸入,我們不得不小心伺候紅外協定棧。最後,由于當時還沒有可接受的應用于消費類電子的編譯器釋出版,我們也不得不親自編譯出編譯器,并交叉編譯出要用到的應用程式集。
時光飛逝,當年嗷嗷待撫的嬰兒已經成長為一個健壯的少年,過去我們編寫了成千上萬行代碼并耗時一年完成的任務若采用現在的核心,隻需要幾天的時間就可以完成。但是,為了成為一名能解決很多問題的高手級的核心工程師,您還是需要了解今天的Linux核心提供的難以想象的特性和便利。
關于本書
在Linux核心源代碼樹提供的各個子系統中,drivers/目錄是其中最大的一個分支,它比其他子系統大數倍。而随着各種新技術的廣泛應用,核心中驅動的開發工作還在穩步加速。最新的Linux支援多達70餘種裝置驅動家族。
這本書主要講解Linux裝置驅動開發技術。它覆寫了目前核心所支援的主要的裝置類型,這其中包括當年我在開發Linux-on-Watch項目時錯過的裝置。在講解每個裝置驅動的時候,本書先介紹一下與該驅動相關的技術,接着給出一個實際例子,最後列出相關的核心源代碼。在踏入Linux驅動領域之前,本書事先對核心以及Linux 2.6的重要特性進行了介紹,重點講解了裝置驅動編寫者感興趣的核心知識。
讀者對象
這本書面向要在Linux核心上開發新裝置驅動的中級程式員。為了閱讀本書,您需要具備作業系統相關的基本知識,知道什麼是系統調用并了解為什麼在核心開發中需要關注并發問題。本書假定您已經下載下傳了Linux,浏覽過Linux核心源代碼,并至少閱讀過一些相關的文檔。另外,您必須能非常熟練地使用C語言。
各章概述
本書前4章為您閱讀本書的剩餘部分打下基礎,接下來的16章讨論不同類型的Linux裝置驅動,之後的1章描述裝置驅動的調試技術,倒數第2章講解裝置驅動的維護和送出相關事宜,最後1章給出了當您接到一個新裝置驅動開發任務的時候,要首先查驗的項目清單。
第1章帶您走入Linux的世界,這一章将加速讀者下載下傳核心源代碼、進行小小的代碼修改并建立一個可啟動的Linux核心映像的步伐。
第2章,《Linux核心概覽》,将引導讀者輕松地進入Linux的内部,講解一些必要的核心概念。這一章首先講述了核心的啟動過程,接下來描述了與驅動開發相關的核心API,譬如核心定時器、并發管理以及記憶體配置設定等。
第3章,《Linux核心驅動相關API》,講解了對驅動開發有用的一系列核心API。這一章首先介紹了核心線程(它提供了一種在核心空間運作背景任務的能力),接下來講解了一系列的輔助API(如連結清單、工作隊列、完成函數、通知鍊等)。這些輔助API能簡化代碼,剔除核心中的備援并有助于核心的長期維護。
第4章,《Linux驅動開發基礎》,為您打下駕馭Linux驅動開發藝術的基礎。這一章呈現了PC相容系統以及嵌入式系統中相關的裝置和驅動的鳥瞰圖,并講解了中斷處理和核心裝置模型等驅動基本概念。
第5章,《字元裝置驅動》,介紹了Linux字元裝置驅動的體系結構。這一章引入了幾個新概念,譬如輪詢、異步通知和I/O控制等。由于本書中介紹的大多數裝置都可以看作“超級”字元裝置,是以這些概念也與接下來的章節密切相關。
第6章,《序列槽驅動》,講解了核心序列槽裝置驅動的層次結構。
第7章,《輸入裝置驅動》,講解了核心中為鍵盤、滑鼠和觸摸屏控制器等輸入裝置提供的輸入子系統。
第8章,《I2C裝置驅動》,講解了通過I2C總線或SMBus總線與系統連接配接的裝置(如EEPROM)的驅動。同時,這一章也對SPI和1-wire等串行接口的驅動進行了介紹。
第9章,《PCMCIA和Compact Flash裝置驅動》,分析了PCMCIA子系統,該章将教會您如何編寫含PCMCIA或Compact Flash元件的裝置的驅動。
第10章,《PCI裝置驅動》,描述了核心對PCI以及其衍生總線裝置的支援。
第11章,《USB裝置驅動》,探讨了USB的體系結構并講解了如何利用Linux核心USB子系統的API來完成USB裝置驅動。
第12章,《視訊裝置驅動》,講解了Linux視訊子系統。該章分析了核心提供的幀緩沖結構的優點,并給出了幀緩沖裝置驅動的編寫方法。
第13章,《音頻裝置驅動》,描述了Linux音頻子系統的架構,并給出了音頻裝置驅動的編寫方法。
第14章,《塊裝置驅動》,集中于描述儲存設備(如硬碟)的驅動。在這一章裡,您也将學習到Linux塊子系統所支援的幾種不同的I/O排程政策。
第15章,《網卡驅動》,分析了網絡裝置驅動,您将學習到核心中與網絡相關的資料結構以及網絡裝置驅動與協定棧接口的方法。
第16章,《無線裝置驅動》,描述了各種無線網絡裝置的驅動,如藍牙、紅外、無線區域網路WiFi和蜂窩通信等。
第17章,《MTD裝置驅動》,講解了如何讓Flash在嵌入式系統上運作起來的方法,這一章以講解PC上的固件樞紐(Firmware Hub,譯者注:簡稱FWH)結束。
第18章,《嵌入式Linux》,步入嵌入式Linux的世界。該章對嵌入式裝置中Bootloader、核心以及裝置驅動等主要的固件組成進行了介紹,展示了Linux在嵌入式領域日益增長的受歡迎程度,很有可能您将把您從本書中學到的Linux驅動開發技能應用于嵌入式領域。
第19章,《使用者空間的裝置驅動》,講解了如何在使用者空間驅動各種裝置。一些裝置(尤其是那些重政策、輕性能的裝置)更适合在使用者空間被驅動。這一章也分析了Linux程序排程對使用者空間裝置驅動響應時間的影響。
第20章,《其他的裝置和驅動》,描述了之前尚未論及的裝置驅動 系統,如錯誤偵測和校驗(EDAC)、火線接口以及ACPI等。
第21章,《裝置驅動的調試》,講解了Linux核心代碼的各種調試方法。在這一章中,您也将學習到跟蹤(trace)工具、核心探測點(probe)、崩潰轉儲(crash-dump)和剖析器(profiler)的使用方法。當您在調試Linux驅動的時候,請用這些技能武裝自己。
第22章,《維護和送出》,給出了裝置驅動軟體開發生命周期的概況。
第23章,給出了當你開始進行一個新裝置驅動開發工作時,應該查驗的工作項目清單。整本書伴随着對“下一步怎麼做”的發問而結束。
裝置驅動中有時候需要以彙編語言實作一些代碼片段,是以,本書的附錄A《Linux彙編》介紹了Linux彙編程式設計的不同方面。X86系統上的一些裝置直接或間接地依賴于BIOS,是以,本書的附錄B《Linux和BIOS》講解了Linux如何與BIOS互動。附錄C《Seq檔案》描述了2.6核心提供的Seq檔案這種用于監控和最終資料點的輔助接口。
本書總體上根據裝置和總線的複雜度進行組織,同時也結合了章節中互相依賴的客觀情況。我們以講解基本的裝置類型(如字元裝置、序列槽和輸入裝置)開始,緊接着介紹簡單的串行總線(如I2C和SMBus),之後再介紹PCMCIA、PCI和USB等外部I/O總線,而由于視訊、音頻、塊和網絡裝置通常通過這些總線與處理器連接配接,是以,在介紹完這些總線之後,對這些裝置的驅動進行了介紹。書中接下來的部分面向嵌入式Linux,覆寫了無線網絡和Flash存儲器等技術。本書的最後讨論了使用者空間的裝置驅動。
核心版本
本書總體上緊跟2.6.23/2.6.24核心版本,書中列出的大部分代碼都在2.6.23上進行過測試。如果您正在使用更新的版本,請通過類似lwn.net的網站去了解核心自從2.6.23/2.6.24後進行了哪些更改。
本書網站
筆者特意建立了elinuxdd.com這個網站來提供與本書相關的更新、勘誤等資訊。
(在直譯的基礎上進行了部分意譯;對于部分國内已經習以為常的英文名詞,不做翻譯;部分英文單詞根據國内通用的稱謂進行了替換,如第3章标題從《kernel facilities》翻譯為《核心驅動相關API》,如果翻譯為《核心基礎設施》,讀者将不知所雲;一些地方根據上下文語意添加了少量語句。)
本文轉自 21cnbao 51CTO部落格,原文連結:http://blog.51cto.com/21cnbao/120002,如需轉載請自行聯系原作者