- 1 I/O Architecture
- 2 The Device Driver Model
- 3 Device Files
- 4 Device Drivers
- 5 Character Device Drivers
In the section “I/O Architecture,” we give a brief survey of the 80×86 I/O architecture. In the section “The Device Driver Model,” we introduce the Linux device driver model. Next, in the section “Device Files,” we show how the VFS associates a special file called “device file” with each different hardware device, so that application programs can use all kinds of devices in the same way. We then introduce in the section “Device Drivers” some common characteristics of device drivers. Finally, in the section “Character Device Drivers,” we illustrate the overall organization of character device drivers in Linux.
The data path that connects a CPU to an I/O device is generically called an I/O bus. The 80 × 86 microprocessors use 16 of their address pins to address I/O devices and 8, 16, or 32 of their data pins to transfer data. The I/O bus, in turn, is connected to each I/O device by means of a hierarchy of hardware components including up to three elements: I/O ports, interfaces, and device controllers. Figure 13-1 shows the components of the I/O architecture.
Each device connected to the I/O bus has its own set of I/O addresses, which are usually called I/O ports. Four special assembly language instructions called
outs allow the CPU to read from and write into an I/O port.
I/O ports may also be mapped into addresses of the physical address space.
The I/O ports of each device are structured into a set of specialized registers, as shown in Figure 13-2.
outs assembly language instructions access I/O ports.
While accessing I/O ports is simple, detecting which I/O ports have been assigned to I/O devices may not be easy, in particular, for systems based on an ISA bus. Often a device driver must blindly write into some I/O port to probe the hardware device; if, however, this I/O port is already used by some other hardware device, a system crash could occur. To prevent such situations, the kernel keeps track of I/O ports assigned to each hardware device by means of “resources.”
An I/O interface is a hardware circuit inserted between a group of I/O ports and the corresponding device controller. It acts as an interpreter that translates the values in the I/O ports into commands and data for the device. In the opposite direction, it detects changes in the device state and correspondingly updates the I/O port that plays the role of status register. This circuit can also be connected through an IRQ line to a Programmable Interrupt Controller, so that it issues interrupt requests on behalf of the device.
There are two types of interfaces:
- Custom I/O interfaces
- General-purpose I/O interfaces
A complex device may require a device controller to drive it. Essentially, the controller plays two important roles:
- It interprets the high-level commands received from the I/O interface and forces the device to execute specific actions by sending proper sequences of electrical signals to it.
- It converts and properly interprets the electrical signals received from the device and modifies (through the I/O interface) the value of the status register.
A typical device controller is the disk controller.
Simpler devices do not have a device controller.
Several hardware devices include their own memory, which is often called I/O shared memory.
Recent hardware devices, even of different classes, support similar functionalities. Drivers for such devices should typically take care of:
- Power management
- Plug and play
Linux 2.6 provides some data structures and helper functions that offer a unifying view of all buses, devices, and device drivers in the system; this framework is called the device driver model.
A goal of the
sysfs filesystem is to expose the hierarchical relationships among the components of the device driver model. The related top-level directories of this filesystem are:
The core data structure of the device driver model is a generic data structure named kobject, which is inherently tied to the
sysfs filesystem: each kobject corresponds to a directory in that filesystem.
The device driver model is built upon a handful of basic data structures, which represent buses, devices, device drivers, etc.
I/O devices are treated as special files called device file.
According to the characteristics of the underlying device drivers, device files can be of two types: block or character.
- The data of a block device can be addressed randomly, and the time needed to transfer a data block is small and roughly the same, at least from the point of view of the human user. Typical examples of block devices are hard disks, floppy disks, CD-ROM drives, and DVD players.
- The data of a character device either cannot be addressed randomly, or they can be addressed randomly, but the time required to access a random datum largely depends on its position inside the device.
A device file is usually a real file stored in a filesystem. Its inode, however, doesn’t need to include pointers to blocks of data on the disk (the file’s data) because there are none. Instead, the inode must include an identifier of the hardware device corresponding to the character or block device file.
Traditionally, this identifier consists of the type of device file (character or block) and a pair of numbers. The first number, called the major number, identifies the device type. Traditionally, all device files that have the same major number and the same type share the same set of file operations, because they are handled by the same device driver. The second number, called the minor number, identifies a specific device among a group of devices that share the same major number. For instance, a group of disks managed by the same disk controller have the same major number and different minor numbers.
Device files live in the system directory tree but are intrinsically different from regular files and directories. When a process accesses a regular file, it is accessing some data blocks in a disk partition through a filesystem; when a process accesses a device file, it is just driving a hardware device.
A device driver is the set of kernel routines that makes a hardware device respond to the programming interface defined by the canonical set of VFS functions (
ioctl, and so forth) that control a device. The actual implementation of all these functions is delegated to the device driver. Because each device has a different I/O controller, and thus different commands and different state information, most I/O devices have their own drivers.
A device driver does not consist only of the functions that implement the device file operations. Before using a device driver, several activities must have taken place.
Every DMA transfer involves (at least) one memory buffer, which contains the data to be read or written by the hardware device. In general, before activating the transfer, the device driver must ensure that the DMA circuit can directly access the RAM locations.
Until now we have distinguished three kinds of memory addresses: logical and linear addresses, which are used internally by the CPU, and physical addresses, which are the memory addresses used by the CPU to physically drive the data bus. However, there is a fourth kind of memory address: the so-called bus address. It corresponds to the memory addresses used by all hardware devices except the CPU to drive the data bus.
In the 80×86 architecture, bus addresses coincide with physical addresses.