01.2168 Page 3Thursday,January20,2005 9:21AMarray of data blocks. Higher levels of the system provide policies, such as who mayaccess the floppy drive, whether the drive is accessed directly or via a filesystem, andwhetherusers maymountfilesystemsonthedrive.Sincedifferentenvironments usu-ally need to use hardware in different ways, it's important to be as policy free aspossible.When writing drivers, a programmer should pay particular attention to this funda-mental concept: write kernel code to access the hardware, but don't force particularpolicies on the user, since different users have different needs.The driver should dealwithmakingthehardwareavailable,leavingall the issues abouthowtousethehard-ware to the applications. A driver, then, is flexible if it offers access to the hardwarecapabilities without adding constraints. Sometimes, however, some policy decisionsmust be made. For example, a digital I/O driver may only offer byte-wide access tothe hardware in order to avoid the extra code needed to handle individual bits.You can also look at your driver from a different perspective:it is a software layerthat lies between the applications and the actual device. This privileged role of thedriver allows the driver programmer to choose exactly how the device should appear:different drivers can offer different capabilities, even for the same device. The actualdriver design should be a balance between many different considerations. Forinstance, a single device may be used concurrentlyby different programs, and thedriver programmerhas completefreedomtodeterminehowtohandleconcurrencyYoucouldimplementmemorymappingonthedeviceindependentlyof itshardwarecapabilities, or you could provide a user library to help application programmersimplement new policies on top of the available primitives, and so forth. One majorconsideration is the trade-off between the desire to present the user with as manyoptions as possible and the time you have to write the driver, as well as the need tokeep things simple so that errors don't creep in.Policy-free drivers have a number of typical characteristics.These include support forboth synchronous and asynchronous operation,the ability to beopened multipletimes, the ability to exploit thefull capabilities of the hardware, and the lack of software layers to“simplify things" or provide policy-related operations. Drivers of thissortnot onlyworkbetterfortheir end users.butalso turn outto be easier to writeand maintain as well.Beingpolicy-freeis actually a common targetfor softwaredesigners.Many device drivers, indeed, are released together with user programs to help withconfiguration and access to thetarget device.Those programs can range from simpleutilities to complete graphical applications. Examples include the tunelp program,which adjusts how the parallel port printer driver operates, and the graphical cardctlutility that is part of the PCMCIA driver package. Often a client library is provided aswell, which provides capabilities that do not need to be implemented as part of thedriveritself.The Role of the Device Driver13
This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. The Role of the Device Driver | 3 array of data blocks. Higher levels of the system provide policies, such as who may access the floppy drive, whether the drive is accessed directly or via a filesystem, and whether users may mount filesystems on the drive. Since different environments usually need to use hardware in different ways, it’s important to be as policy free as possible. When writing drivers, a programmer should pay particular attention to this fundamental concept: write kernel code to access the hardware, but don’t force particular policies on the user, since different users have different needs. The driver should deal with making the hardware available, leaving all the issues about how to use the hardware to the applications. A driver, then, is flexible if it offers access to the hardware capabilities without adding constraints. Sometimes, however, some policy decisions must be made. For example, a digital I/O driver may only offer byte-wide access to the hardware in order to avoid the extra code needed to handle individual bits. You can also look at your driver from a different perspective: it is a software layer that lies between the applications and the actual device. This privileged role of the driver allows the driver programmer to choose exactly how the device should appear: different drivers can offer different capabilities, even for the same device. The actual driver design should be a balance between many different considerations. For instance, a single device may be used concurrently by different programs, and the driver programmer has complete freedom to determine how to handle concurrency. You could implement memory mapping on the device independently of its hardware capabilities, or you could provide a user library to help application programmers implement new policies on top of the available primitives, and so forth. One major consideration is the trade-off between the desire to present the user with as many options as possible and the time you have to write the driver, as well as the need to keep things simple so that errors don’t creep in. Policy-free drivers have a number of typical characteristics. These include support for both synchronous and asynchronous operation, the ability to be opened multiple times, the ability to exploit the full capabilities of the hardware, and the lack of software layers to “simplify things” or provide policy-related operations. Drivers of this sort not only work better for their end users, but also turn out to be easier to write and maintain as well. Being policy-free is actually a common target for software designers. Many device drivers, indeed, are released together with user programs to help with configuration and access to the target device. Those programs can range from simple utilities to complete graphical applications. Examples include the tunelp program, which adjusts how the parallel port printer driver operates, and the graphical cardctl utility that is part of the PCMCIA driver package. Often a client library is provided as well, which provides capabilities that do not need to be implemented as part of the driver itself. ,ch01.2168 Page 3 Thursday, January 20, 2005 9:21 AM
D1.2168Page 4Thursday,January20,20059:21AMThe scope of this book is thekernel,sowe try not todeal with policy issues or withapplication programs or support libraries.Sometimes we talk about different poli-cies and how to support them, but we won't go into much detail about programsusing the device or the policies they enforce. You should understand, however, thatuser programs are an integral part of a software package and that even policy-freepackages are distributed with configuration files that apply a default behavior to theunderlyingmechanisms.Splitting the KernelIn a Unix system, several concurrent processes attend to different tasks. Each processasksfor system resources,be it computing power,memory,network connectivity,orsome other resource.The kernel is the big chunk of executable code in charge of han-dling all such requests. Although the distinction between the different kernel tasksisn't always clearlymarked, thekernel's role can be split (as shown in Figure 1-1)into the following parts:ProcessmanagementThe kernel is in charge of creating and destroying processes and handling theirconnection to the outside world (input and output). Communication among dif-ferent processes (through signals, pipes, or interprocess communication primi-tives)is basic to the overall system functionality and is also handled by thekernel.In addition,the scheduler,which controls howprocesses sharethe CPUis part of process management. More generally, the kernel's process manage-ment activity implements the abstraction of several processes on top of a singleCPU or a few of them.Memory managementThe computer's memory is a major resource, and the policy used to deal with itis a critical one for system performance. The kernel builds up a virtual address-ing spacefor any and all processes on top of the limited availableresources.Thedifferent parts of the kernel interact with the memory-management subsystemthrougha set of function calls,ranging from the simple malloc/free pair to muchmorecomplexfunctionalities.FilesystemsUnix is heavily based on the filesystem concept; almost everything in Unix canbe treated as a file. The kernel builds a structured filesystem on top of unstruc-tured hardware, and the resulting file abstraction is heavily used throughout thewhole system.In addition,Linux supports multiplefilesystem types,that is,different ways of organizing data on the physical medium.For example, disks maybeformatted with theLinux-standard ext3filesystem,the commonly used FATfilesystemorseveral others.↓Chapter 1: An Introduction to DeviceDrivers
This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. 4 | Chapter 1: An Introduction to Device Drivers The scope of this book is the kernel, so we try not to deal with policy issues or with application programs or support libraries. Sometimes we talk about different policies and how to support them, but we won’t go into much detail about programs using the device or the policies they enforce. You should understand, however, that user programs are an integral part of a software package and that even policy-free packages are distributed with configuration files that apply a default behavior to the underlying mechanisms. Splitting the Kernel In a Unix system, several concurrent processes attend to different tasks. Each process asks for system resources, be it computing power, memory, network connectivity, or some other resource. The kernel is the big chunk of executable code in charge of handling all such requests. Although the distinction between the different kernel tasks isn’t always clearly marked, the kernel’s role can be split (as shown in Figure 1-1) into the following parts: Process management The kernel is in charge of creating and destroying processes and handling their connection to the outside world (input and output). Communication among different processes (through signals, pipes, or interprocess communication primitives) is basic to the overall system functionality and is also handled by the kernel. In addition, the scheduler, which controls how processes share the CPU, is part of process management. More generally, the kernel’s process management activity implements the abstraction of several processes on top of a single CPU or a few of them. Memory management The computer’s memory is a major resource, and the policy used to deal with it is a critical one for system performance. The kernel builds up a virtual addressing space for any and all processes on top of the limited available resources. The different parts of the kernel interact with the memory-management subsystem through a set of function calls, ranging from the simple malloc/free pair to much more complex functionalities. Filesystems Unix is heavily based on the filesystem concept; almost everything in Unix can be treated as a file. The kernel builds a structured filesystem on top of unstructured hardware, and the resulting file abstraction is heavily used throughout the whole system. In addition, Linux supports multiple filesystem types, that is, different ways of organizing data on the physical medium. For example, disks may be formatted with the Linux-standard ext3 filesystem, the commonly used FAT filesystem or several others. ,ch01.2168 Page 4 Thursday, January 20, 2005 9:21 AM
D1.2168Page5Thursday,January20,20059:21AMDevicecontrolAlmost every system operation eventually maps to a physical device. With theexception of theprocessor,memory,and averyfew otherentities,any and alldevice control operations are performed by code that is specific to the devicebeing addressed. That code is called a device driver.The kernel must haveembedded in it a device driver for every peripheral present on a system, from thehard drive to the keyboard and the tape drive. This aspect of the kernel's func-tionsisourprimaryinterestinthisbook.NetworkingNetworking must be managed by the operating system, because most networkoperations are not specific to a process:incoming packets are asynchronousevents. The packets must be collected, identified, and dispatched before a pro-cess takes care of them. The system is in charge of delivering data packets acrossprogram and network interfaces,and itmustcontrol theexecution ofprogramsaccording to their network activity.Additionally,all the routing and address resolution issues are implemented within the kernel.LoadableModulesOne of thegood features of Linux is the ability to extend at runtime the set of fea-tures offered by the kernel. This means that you can add functionality to the kernel(and remove functionality as well) while the system is up and running.Each piece of code that can be added to thekernel at runtime is called a module.TheLinuxkernel offers supportforquitea few differenttypes (or classes)of modules.including,but not limited to, device drivers.Each module is made up of object code(notlinked into a completeexecutable)that can be dynamicallylinked to therun-ning kernel by the insmod program and can be unlinked by the rmmod program.Figure 1-1 identifies different classes of modules in charge of specific tasks-a mod-ule is said to belong to a specific class according to the functionality it offers. Theplacement of modules inFigure1-1 covers themost important classes,but is far fromcomplete because moreand more functionality in Linux isbeing modularized.ClassesofDevicesandModulesThe Linux way of looking at devices distinguishes between three fundamental devicetypes.Each module usually implements one ofthese types,and thus is classifiableasachar module,a block module,or a network module.This division ofmodules into different types, or classes, is not a rigid one; the programmer can choose to build hugemodules implementing different drivers in a single chunk of code.Good programmers,nonetheless,usually create a different module for each new functionality theyimplement,becausedecomposition isakeyelementof scalabilityand extendabilityClasses of Devices and Modules 5
This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. Classes of Devices and Modules | 5 Device control Almost every system operation eventually maps to a physical device. With the exception of the processor, memory, and a very few other entities, any and all device control operations are performed by code that is specific to the device being addressed. That code is called a device driver. The kernel must have embedded in it a device driver for every peripheral present on a system, from the hard drive to the keyboard and the tape drive. This aspect of the kernel’s functions is our primary interest in this book. Networking Networking must be managed by the operating system, because most network operations are not specific to a process: incoming packets are asynchronous events. The packets must be collected, identified, and dispatched before a process takes care of them. The system is in charge of delivering data packets across program and network interfaces, and it must control the execution of programs according to their network activity. Additionally, all the routing and address resolution issues are implemented within the kernel. Loadable Modules One of the good features of Linux is the ability to extend at runtime the set of features offered by the kernel. This means that you can add functionality to the kernel (and remove functionality as well) while the system is up and running. Each piece of code that can be added to the kernel at runtime is called a module. The Linux kernel offers support for quite a few different types (or classes) of modules, including, but not limited to, device drivers. Each module is made up of object code (not linked into a complete executable) that can be dynamically linked to the running kernel by the insmod program and can be unlinked by the rmmod program. Figure 1-1 identifies different classes of modules in charge of specific tasks—a module is said to belong to a specific class according to the functionality it offers. The placement of modules in Figure 1-1 covers the most important classes, but is far from complete because more and more functionality in Linux is being modularized. Classes of Devices and Modules The Linux way of looking at devices distinguishes between three fundamental device types. Each module usually implements one of these types, and thus is classifiable as a char module, a block module, or a network module. This division of modules into different types, or classes, is not a rigid one; the programmer can choose to build huge modules implementing different drivers in a single chunk of code. Good programmers, nonetheless, usually create a different module for each new functionality they implement, because decomposition is a key element of scalability and extendability. ,ch01.2168 Page 5 Thursday, January 20, 2005 9:21 AM
ch01.2168Page 6Thursday,January 20,20059:21AMTheSystemCall InterfaceProcessMemoryFilesystemsDeviceNetworkingmanagementmanagementcontrolKernelsubsystemsVirtualFiles and dirs:Ttys&FeaturesConcurrencyConnectivityimplementedmultitaskingtheVFSdevice accessmemoryFile systemNetworkCharacterArch-Memorytypessubsystemdevicesdependentmanager一二SoftwarecodesupportBlockdevicesIF drivers口00000HardwareCPUMemoryDisks & CDsConsoles,Networket.interfacesfegtures implementedgsmodulesFigure1-1.Asplitviewof thekernelThe three classes are:CharacterdevicesA character (char) device is one that can be accessed as a stream of bytes (like afile); a char driver is in charge of implementing this behavior. Such a driver usu-ally implements at least the open, close, read, and write system calls. The textconsole (/dev/console)and the serial ports (/dev/ttyso and friends)are examplesof char devices, as they are well represented by the stream abstraction. Chardevicesareaccessedbymeansoffilesystemnodes,suchas/dev/ttyland/dev/poThe only relevant difference between a char device and a regular file is that youcan always move back and forth in the regular file,whereas most char devicesare just data channels, which you can only access sequentially. There exist,nonetheless, char devices that look like data areas, and you can move back andforth in them; for instance,this usually applies to framegrabbers, where theapplications can access the whole acquired imageusing mmap orlseek.6↓Chapter1: An Introduction to Device Drivers
This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. 6 | Chapter 1: An Introduction to Device Drivers The three classes are: Character devices A character (char) device is one that can be accessed as a stream of bytes (like a file); a char driver is in charge of implementing this behavior. Such a driver usually implements at least the open, close, read, and write system calls. The text console (/dev/console) and the serial ports (/dev/ttyS0 and friends) are examples of char devices, as they are well represented by the stream abstraction. Char devices are accessed by means of filesystem nodes, such as /dev/tty1 and /dev/lp0. The only relevant difference between a char device and a regular file is that you can always move back and forth in the regular file, whereas most char devices are just data channels, which you can only access sequentially. There exist, nonetheless, char devices that look like data areas, and you can move back and forth in them; for instance, this usually applies to frame grabbers, where the applications can access the whole acquired image using mmap or lseek. Figure 1-1. A split view of the kernel features implemented as modules Process management Memory management Filesystems Device control Networking Archdependent code Memory manager Character devices Network subsystem CPU Memory Concurrency, multitasking Virtual memory Files and dirs: the VFS Kernel subsystems Features implemented Software support Hardware Block devices IF drivers File system types Ttys & device access Connectivity Disks & CDs Consoles, etc. Network interfaces The System Call Interface ,ch01.2168 Page 6 Thursday, January 20, 2005 9:21 AM
D1.2168Page 7Thursday,January20,20059:21AMBlockdevicesLike char devices,blockdevices are accessed by filesystem nodes in the /devdirectory. A block device is a device (e.g., a disk) that can host a filesystem. Inmost Unix systems,a block device can onlyhandleI/O operations that transferone or more whole blocks,which are usually512bytes (or a larger power oftwo)bytes in length.Linux,instead,allows the application to read and writeablock device like a char deviceit permits the transfer of any number ofbytes ata time. As a result, block and char devices differ only in the way data is managedinternally by the kernel, and thus in thekernel/driver software interface. Like achar device,each block device is accessed through a filesystem node,and the difference between them is transparent to the user. Block drivers have a completelydifferent interface to the kernel than char drivers.NetworkinterfacesAny network transaction is made through an interface,that is,a device that isable to exchange data with other hosts. Usually, an interface is a hardwaredevice,but it mightalso bea pure software device, like the loopback interface.Anetwork interface is in charge of sending and receiving data packets,driven bythe network subsystem of thekernel, withoutknowing how individual transac-tions map to the actual packets being transmitted.Many network connections(especially those using TCP) are stream-oriented, but network devices are, usu-ally,designed around thetransmissionand receiptof packets.Anetworkdriverknows nothingabout individual connections;itonlyhandlespackets.Not being a stream-oriented device, a network interface isn't easily mapped to anode in thefilesystem, as /dev/ttyl is.TheUnix way to provide access to interfaces is still by assigning a unique name to them (such as etho), but that namedoesn't have a corresponding entry in the filesystem.Communication betweenthe kernel and a network device driver is completely different from that usedwith char and block drivers.Instead of read and write,the kernel calls functionsrelatedtopackettransmission.There are other ways of classifying driver modules that are orthogonal to the abovedevice types. In general, some types of drivers work with additional layers of kernelsupport functions for a given type of device. For example, one can talk of universalserial bus (USB)modules,serial modules,SCSI modules,and so on.EveryUSBdevice is driven by a USB module that works with the USB subsystem, but the deviceitself shows up in the system as a char device (a USB serial port, say),a block device(a USB memory card reader), or a network device (a USB Ethernet interface).Otherclasses ofdevice drivers havebeen added to thekernel in recent times,includ-ing FireWire drivers and I2O drivers.In the same way that they handled USB andSCSI drivers, kernel developers collected class-wide features and exported them todriver implementers to avoid duplicating work and bugs,thus simplifying andstrengtheningtheprocessofwritingsuchdrivers.Classes of Devices and Modules1
This is the Title of the Book, eMatter Edition Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved. Classes of Devices and Modules | 7 Block devices Like char devices, block devices are accessed by filesystem nodes in the /dev directory. A block device is a device (e.g., a disk) that can host a filesystem. In most Unix systems, a block device can only handle I/O operations that transfer one or more whole blocks, which are usually 512 bytes (or a larger power of two) bytes in length. Linux, instead, allows the application to read and write a block device like a char device—it permits the transfer of any number of bytes at a time. As a result, block and char devices differ only in the way data is managed internally by the kernel, and thus in the kernel/driver software interface. Like a char device, each block device is accessed through a filesystem node, and the difference between them is transparent to the user. Block drivers have a completely different interface to the kernel than char drivers. Network interfaces Any network transaction is made through an interface, that is, a device that is able to exchange data with other hosts. Usually, an interface is a hardware device, but it might also be a pure software device, like the loopback interface. A network interface is in charge of sending and receiving data packets, driven by the network subsystem of the kernel, without knowing how individual transactions map to the actual packets being transmitted. Many network connections (especially those using TCP) are stream-oriented, but network devices are, usually, designed around the transmission and receipt of packets. A network driver knows nothing about individual connections; it only handles packets. Not being a stream-oriented device, a network interface isn’t easily mapped to a node in the filesystem, as /dev/tty1 is. The Unix way to provide access to interfaces is still by assigning a unique name to them (such as eth0), but that name doesn’t have a corresponding entry in the filesystem. Communication between the kernel and a network device driver is completely different from that used with char and block drivers. Instead of read and write, the kernel calls functions related to packet transmission. There are other ways of classifying driver modules that are orthogonal to the above device types. In general, some types of drivers work with additional layers of kernel support functions for a given type of device. For example, one can talk of universal serial bus (USB) modules, serial modules, SCSI modules, and so on. Every USB device is driven by a USB module that works with the USB subsystem, but the device itself shows up in the system as a char device (a USB serial port, say), a block device (a USB memory card reader), or a network device (a USB Ethernet interface). Other classes of device drivers have been added to the kernel in recent times, including FireWire drivers and I2O drivers. In the same way that they handled USB and SCSI drivers, kernel developers collected class-wide features and exported them to driver implementers to avoid duplicating work and bugs, thus simplifying and strengthening the process of writing such drivers. ,ch01.2168 Page 7 Thursday, January 20, 2005 9:21 AM