Вы находитесь на странице: 1из 6

e m be dde d.

co m

http://www.embedded.co m/design/o perating-systems/4006653/A-survey-o f-Linux-device-drivers#

A survey of Linux device drivers

Bill Gatliff, Freelance Embedded Consultant May 15, 2006 In Linux, a device driver is code that implements a userspace or kernelspace abstraction of a physical device. Examples of device drivers include code that allows user applications to stream data through a 16550 UART, code that conf igures an Epson S1D13xxx LCD controller chip, and code manages the AT 91RM9200's built-in Ethernet controller. Device drivers come in several dif f erent types, depending on what abstraction they provide. Serial port drivers, f or example, of ten implement the character device type. T he f ramebuf f er driver type is normally used to enable userspace applications to write to an LCD or CRT display. Ethernet drivers allow the Linux kernel's T CP/IP protocol stack to send packets over an Ethernet network. A device driver abstraction is purely that, an abstraction. T he underlying hardware associated with an Ethernet device driver may not actually be an Ethernet controller, f or example; there may not even be any physical hardware at all! Such is the case f or the usbnet driver, which allows a USB Device to communicate with a USB Host as though the two were connected via Ethernet. (T he usbnet driver packages Ethernet packets and f orwards them to the USB host/device drivers f or transmission). T here may be more than one device driver abstraction associated with a particular piece of hardware. A multif unction chip, like the Silicon Motion SM501 Multimedia Controller, will usually have one or more associated f ramebuf f er drivers f or its video controllers, a USB Host bus controller driver f or its OHCI Host port, an AC97 codec driver f or its AC97-Link interf ace, and a character driver f or its serial ports. Device nodes For many device driver types, user applications communicate with the driver via a pseudof ile called a device node. Device nodes look like f iles, and applications can even open() and close() them. But when data is written to a device node, the data is passed to the node's associated driver, and not stored in a f ilesystem. To send data out a serial port, f or example, an application will of ten open and write data to a device node named /dev/ttyS0. T he device driver associated with that node handles enabling and disabling interrupts on the UART, queuing bytes f or transmission, and deactivating the UART when transmission is complete. T he name of a device node is arbitrary, but there are some conventions. Serial ports are of ten called ttyS, and f ramebuf f ers are of ten called f b, f or example. But the association between the device node and the device driver is actually controlled via the device's major number and minor number. Renaming the /dev/ttyS0 device node to /dev/cdrom does not magically transf orm the device node into one that streams data to a CD-ROM device! You can see the major and minor numbers associated with a device node using the ls command: $ ls -l /dev/console crw-------1 bgat root 5, 1 Mar 7 08:30 /dev/console T he /dev/console device node, which helps applications communicate with their associated display device, is major number 5, minor number 1. Within the Linux kernel sources, a device driver (the console device driver) registers itself as "driver major number 5", which associates it with the /dev/console device node. T he crw in the above output indicates that the console device node expects to be associated with a character device abstraction, and may be both read f rom and written to.

Character Devices T he character device driver implements a byte-oriented interf ace that can be read f rom or written to. T he interf ace is also stream-oriented, meaning that you cannot "seek" f orwards or backwards through the data the way you can with an ordinary data f ile. Character devices are appropriate f or things like serial port drivers, etc. T he most important data structure used by character device drivers is the f ile_operations structure, a portion of which appears below: Character device drivers at a minimum must implement the open() and release() methods, but usually also implement the read() and write() methods as well. T he poll() method assists applications in "sleeping" until data is available, and the ioctl() method provides an out-of -band channel of ten used f or things like specif ying the bit rate and parity settings in a UART driver's associated hardware device. About struct cdev Later Linux-2.6 kernels of f er a struct cdev structure, which encapsulates the f ile_operations structure and some other important driver inf ormation. By using cdev, character devices gain a more exible and unif orm interf ace to the kernel's internal character device resources, including proc f ilesystem entries and udev. All new character drivers are expected to use cdev; existing drivers are being migrated as time permits. ioctl() T he ioctl() entry point in a character device driver provides f or out-of -band communications with the device driver itself . Common uses f or this capability are to assert bit rate and parity settings f or serial port hardware, and to change f ramebuf f er modes. A character device driver's ioctl method looks like this: T his example prints the parameters passed via the ioctl() system call. Device drivers that of f er ioctls provide enumerations f or the cmd parameter, and when those commands need arguments, the arg parameter can pass either an unsigned long parameter value, or the address of a data structure containing a collection of parameter values. An application with a tweak_example_device() f unction that sends a hypothetical MYDRIVER_IOCT L1 command to a driver might look like this: A common usage f or ioctls is to enable the "user interrupt" f eature of the real-time clocks used in many PCs. T he code to do that might look like this: Interrupt Handlers Under Linux, interrupt handlers are not conf ined to device

drivers. Functions not associated with device drivers may also bind to interrupt sources. An LED that blinks when a button is pressed is most easily done using a simple interrupt handler, f or example. Interrupt handler f unctions bind to interrupt sources using the kernel's request_irq() f unction. Under Linux interrupt handlers are ordinary C f unctions, but they are restricted in the kernel f eatures they may use. Interrupt handlers cannot block on semaphores, f or example. A simple interrupt handler f or a hypothetical interrupt source named GPIO_PIN_PB29 looks like this: T his interrupt handler disables the associated interrupt source when ten interrupts are detected (a button is pressed ten times, f or example). Assuming the host processor provides a suitable def inition f or GPIO_PIN_PB29, the handler may be bound to the interrupt source using something similar to the f ollowing code: A call to request_irq() may f ail if a previouslyregistered interrupt handler did not permit the source to be shared with other handlers. Block Devices A block device driver implements an abstraction commonly associated with hard drives and other datablock-oriented media. A block device of f ers persistent storage, which (generally) allows applications to "seek" data within the device. Properly-implemented block device drivers can be controlled by the kernel's Virtual File System f unctionality, allowing all manner of devices to be used to store nearly all kernelsupported f ilesystems with little additional ef f ort. Block device drivers use the same f ile_operations structure used by character device drivers, but use structure members that are ignored by character devices. Block device drivers are more complex than character device drivers. T he best example of a block device driver is "sbull", f rom Rubini's Linux Device Drivers. MT D Chips and Maps T he Memory Technology Devices (MT D) implementation uses a layered driver approach. Chip drivers control the memory device itself , and map drivers use chip drivers to interact with memory chips using either a block or character device API. T he JFFS2 f ilesystem depends on MT D, but MT D may also be used with other f ilesystems.

Among other things, MT D chip device drivers can probe ash memory chips and similar media to identif y their geometry. T his inf ormation allows MT D to properly erase and program the device. With the rise of the Common Flash Interf ace (CFI) protocol, the need to implement new chip device drivers is f ast becoming history. MT D map drivers provide the lowest-level read/write f unctionality f or ash media, which is usef ul f or hardware that makes ash memory available in pages rather than one large window in the host's memory space (very large ash chips may exceed the memory space accessible by the hardware). Map drivers also tell MT D the physical addresses of available ash memory, and can be used to limit MT D's accesses to only certain areas of that memory. MT D block device nodes are usually named /dev/mtdblock. MT D character device nodes are usually named /dev/mtd. Framebuf f ers Framebuf f er device drivers provide f or direct userspace access to video frame buffers: the memory space used by an LCD controller to store the image actually visible on the LCD panel. XFree86, Qtopia, Microwindows and other GUI libraries interact directly with f rame buf f er memory. Framebuf f er drivers are mostly inf ormational; they provide standardized interf aces that allow applications to set and query video modes and ref resh rates. User applications use the f ramebuf f er driver's mmap() system call to locate f rame buf f er memory. T he properties of a f ramebuf f er driver's associated hardware are stored in a struct f b_inf o structure. T his structure also contains the physical address of the f rame buf f er memory, and the physical addresses of the registers that control display modes, geometry and timing. Framebuf f er drivers also use a struct f b_ops structure, which is roughly equivalent to the struct f ile_operations structure used by character and block device drivers. Applications like f bset use a standardized set of ioctls to invoke these f rame buf f er "operations". Framebuf f er device nodes are usually named /dev/f b. One way to tell if your kernel contains a working f ramebuf f er driver is to look f or Tux, the Linux mascot, on the display panel during kernel startup. I2C Bus Interf aces and Chips T he Linux I2C implementation uses a layered stack of device drivers to control chips connected to an I2Ccompatible bus. At the lowest level are "algorithm" and "bus" drivers, which provide a unif orm abstraction f or interacting with the physical I2C media. I2C bus implementations vary, f rom simple "bit bang" GPIO-based signaling to high-perf ormance dedicated peripherals. I2C "chip" drivers control a member of an I2C bus, including temperature sensors, GPIO controllers, ADCs, and so f orth. T he unif ormity provided by I2C algorithm and bus drivers allow the same chip driver to be used regardless of how the actual I2C bus is implemented. I2C chip drivers provide a detect() f unction that allows the I2C system to conf irm the presence of the associated device. If the device is f ound, the driver registers itself with the I2C system using the i2c_attach_client() f unction. Once registered, I2C chip drivers vary widely in the kernel resources they use. Touch screen controller chip drivers, f or example, may interact with the kernel's input subsystem, interrupt handlers, proc f ilesystem, and other f unctionality. Temperature and f an speed sensors are more unif orm, so that userspace monitoring applications will work across the wide range of devices employed by PCs and embedded hardware. Ethernet Devices Ethernet drivers provide an Ethernet-specif ic abstraction that f ocuses almost exclusively on data exchange with the network media access controller (MAC). Other network-related f unctions, like IP packet assembly and decoding, are handled within the kernel's network protocol stacks and do not directly inf luence the

implementation of an Ethernet device driver. T he most common reason f or getting involved with an Ethernet device driver is to add support f or a new physical access controller (PHY). In an existing Ethernet device driver's probe() f unction, the PHY must of ten be identif ied so that the Ethernet network controller can be properly conf igured. T he network controller generally provides control registers f or communicating with an attached PHY, including reading the device's ID register. Of ten, the only change required is to add an enumeration so that the new PHY will be recognized during probing. T he Platf orm Model T he Platf orm Model of f ered by kernel versions 2.6 and beyond provides a ref ined way to attach devices to drivers that eliminates the need f or device drivers to contain hard coded physical addresses of the devices they control. T he platf orm model also prevents resource conf licts and improves kernel portability, helps get startup ordering right, and integrates with the kernel's power management f eatures. Under the platf orm model, device drivers know how to control a device once inf ormed of its physical location and interrupt lines. T his inf ormation is provided to the driver in the f orm of a \resource list" passed to the driver during probing. A f ramebuf f er driver needs to know the physical addresses of the f rame buf f er memory and control registers. T he resource list might look like this:

Once the resources are def ined, that inf ormation is merged into a platf orm_device structure: Finally, the resource list and associated driver name are registered: platf orm_device_register(&lcd_panel_dev); At some point during kernel startup, a device driver named "s1d13xxxf b" may register itself . Af ter registration, the platf orm model implementation invokes the driver's probe() f unction, passing it the associated resource list. Helper f unctions allow the driver to extract resource entries f rom the list and thereby locate the device in question. Bill Gatlif f is a f reelance embedded developer and training consultant with 10 years of experience using GNU and other tools f or building embedded systems targeting automotive, aerospace, and medical instrumentation applications. He is a contributing editor f or Embedded Systems Design, author of the Embedded GNU Jumpstart and Embedded Linux Jumpstart series of training materials. T his paper was

written f or and presented at the Embedded Systems Conf erence Silicon Valley 2006. For more inf ormation, please visit www.embedded.com/esc/sv inShare0