3.3 I/O

Input and output (I/O) are central to the role of any computerized device. As with other OSes, Linux supports a wide range of I/O devices. The following does not pretend to be a complete run-down of all of them. For such a compilation, you may want to read through the Hardware Compatibility HOWTO available from LDP. Instead, the following concentrates on the way the different types of I/O devices are supported by Linux, either by the kernel or by user applications.

Some of the I/O devices discussed are supported in two forms by the kernel, first by a native driver that handles the device's direct connection to the system, and second through the USB layer to which the device may be attached. There are, for instance, PS/2 keyboards and parallel port printers and there are USB keyboards and USB printers. Because USB has already been discussed earlier, and in-depth discussion of Linux's USB stack would require a lengthy text of its own, I will cover only the support provided by Linux to the devices directly attached to the system. Note, however, that USB drivers for similar devices tend to rely on the infrastructure already available in Linux to support the native devices. A USB serial adapter driver, for example, relies on the same facilities as the traditional serial driver, in addition to the USB stack.

3.3.1 Serial Port

The serial port is arguably every embedded system developer's best friend (or her worst enemy, depending on her past experience with this ubiquitous interface). Many embedded systems are developed and debugged using an RS232 serial link between the host and the target. Sometimes, PCBs are laid out to accommodate a serial port, but only development versions of the boards ever include the actual connector, while production systems are shipped without it. The simplicity of the RS232 interface has encouraged its wide-spread use and adoption, even though its bandwidth is rather limited compared to other means of transmission. Note that there are other serial interfaces besides RS232, some of which are less noise-sensitive and therefore more adapted to industrial environments. The hardware serial protocol, however, isn't as important as the actual programming interface provided by the serial device's hardware.

Since RS232 is a hardware interface, the kernel doesn't need to support RS232 itself. Rather, the kernel includes drivers to the chips that actually enact RS232 communication, Universal Asynchronous Receiver-Transmitters (UARTs). UARTs vary from one architecture to another, although some UARTs, such as the 16550, are used on more than one architecture.

The main serial (UART) driver in the kernel is drivers/char/serial.c. Some architectures, such as the SH, have other serial drivers to accommodate their hardware. Some architecture-independent peripheral cards also provide serial interfaces. As with other Unix systems, nonetheless, serial devices in Linux are uniformly accessed as terminal devices, regardless of the underlying hardware and related drivers. The corresponding device entries start with /dev/ttyS0 and can go up to /dev/ttyS191. In most cases, however, there are only a handful of serial device entries in a system's /dev directory.

Serial port basics, setup, and configuration are discussed in the Serial HOWTO available from LDP. Programming the serial port in Linux is discussed in the Serial Programming HOWTO from LDP. Since serial port programming is actually terminal programming, any good reference on Unix systems programming would be a good start. Worthy of note is Richard Stevens' Advanced Programming in the UNIX Environment, which is one of the most widely recognized works on the subject of Unix systems programming, including terminal I/O.

3.3.2 Parallel Port

In comparison to the serial port, the parallel port is seldom an important part of an embedded system. Unless the embedded system is actually a PC-style SBC, the parallel port is, in fact, rarely even part of the system's hardware. In some cases, a parallel port is used because the embedded system has to drive a printer or some sort of external device, but with the advent of USB and IEEE1394, this use is bound to diminish.

One area of embedded systems development where the parallel port fits quite nicely, however, is simple multibit I/O. When debugging, for instance, you can easily attach a set of LEDs to the parallel ports' pins and use those LEDs to indicate a position in the code. The trick is to insert a set of parallel port output commands in different portions of the code and to use the LEDs to identify the last position reached prior to machine lockup. This is possible, because the parallel ports' hardware keeps the last value output to it unchanged regardless of the state of the rest of the system. The Linux Device Drivers book provides a more detailed description of how to use the parallel port as a simple I/O interface and how to set up an LED array to display the parallel port's output.

Linux supports parallel port I/O through a set of three layers. At the middle level is the architecture-independent parport driver. This driver provides a central management facility for the parallel port resources. This middle-level driver is not visible from user space and is not accessible as an entry in the /dev directory. Low-level drivers that control the actual hardware register their presence with this driver to make their services accessible to higher-level drivers. The latter may provide a number of different functions. Both low- and middle-level drivers are found in the drivers/parport directory of the kernel sources.

The most common high-level driver is the line printer driver, which enables user applications to use a printer directly attached to the system's parallel port. The first line printer device is visible in user space as /dev/lp0, the second as /dev/lp1, and so on. Some other high-level drivers use the parallel port as an extension bus to access an external device attached to the system, as discussed in Section 3.2.7. They all use the parallel port middle-level driver and are visible, in one way or another, as entries in /dev. Finally, the parallel port itself is accessible natively from user space via the user-space parallel port driver, which is seen as /dev/parportX, where X is the number of the parallel port. This latter driver is in the drivers/char/ppdev.c file in the kernel sources.

Apart from the usual PC architecture references mentioned earlier and the device drivers book, Linux parallel port subsystem and API are documented in The Linux 2.4 Parallel Port Subsystem document available from http://people.redhat.com/twaugh/parport/ and in the Documentation directory of the kernel sources.

3.3.3 Modem

Embedded systems that use a modem to call a data center are quite common. Alarm systems, bank machines, and remote-monitoring hardware are all examples of embedded systems that need to communicate with a central system to fulfill their primary purposes. The goals are different, but all these systems use conventional modems to interface with the POTS (plain old telephone system) to access a remote host.

Modems in Linux are seen as serial ports, which is very much the same way they are seen across a variety of OSes, including Unix. As such, they are accessible through the appropriate serial device /dev entry and are controlled by the same driver as the native serial UARTs, regardless of whether they are internal or external. This support, however, applies only to real modems.

Recently, a sort of modem called a WinModem has appeared in the PC market. WinModems contain only the bare minimal hardware that make up a modem and are capable of providing real modem services only because of software that runs on the OS. As the name implies, these modems are mainly targeted to systems running Windows. They work fine with that OS, because their vendors provide the appropriate drivers. With Linux, however, they do not work, because they don't contain real modem hardware and the kernel can't use its serial driver to operate them.

To provide support for these types of (handicapped) devices, a number of projects have sprung up to develop the necessary software packages. A central authority on these projects is the Linmodems web site at http://www.linmodems.org/. The site provides documentation, news, and links to the various WinModem support projects. At the time of this writing, however, there is no body of code that provides uniform support for the various WinModems.

Real modem setup and operation is described in the Modem HOWTO from the LDP. Linmodem setup and operation is described in the Linmodem HOWTO from the LDP. Since modems are serial ports, the documentation mentioned above regarding serial ports also applies to modems.

3.3.4 Data Acquisition

As described in Section, DAQ is at the basis of any process automation system. Any modern factory or scientific lab is filled with DAQ equipment linked, in one way or another, to computers running data analysis software. Typically, as described earlier, the events occurring in the real world are measured by means of transducers, which convert a physical phenomenon into an electrical value. These values are then sampled using DAQ hardware and are thereafter accessible to software.

There is no standard interface in Unix, or any other OS for that matter, for interfacing with data acquisition hardware.[11] Comedi, the Linux control and measurement device interface, is the main package for interfacing with DAQ hardware. Comedi is found at http://www.comedi.org/ and contains device drivers for a great number of DAQ boards. The complete list of boards supported is found in the Supported hardware section of the web site.

[11] DAQ hardware may actually take a number of forms. It can be an Ethernet-enabled device, a PCI card, or use some other type of connection. However, most DAQ devices used with workstations connect through some standard interface such as ISA, PCI, or PCMCIA.

Along with providing drivers for DAQ hardware, the Comedi project includes Comedilib, a user-space library that provides a unified API to interface with all DAQ hardware, regardless of model or manufacturer. This is very useful, because it allows you to develop the analysis software independently of the underlying hardware, and avoid being locked in to a particular vendor.

Similarly, Kcomedilib, a kernel module providing an API similar to Comedilib, enables other kernel modules, which could be real-time tasks, to have access to the DAQ hardware.

No discussion about DAQ would be complete without covering some of the most well-known commercial (proprietary) packages used along with DAQ, such as LabVIEW, Matlab, and Simulink. Given the popularity of Linux in this field, all three packages have been made available for Linux by their respective vendors. Note, however, that there are a number of packages in development that aim at providing open source replacements for these packages. Scilab and Octave, for instance, are Matlab replacements found at http://www-rocq.inria.fr/scilab/ and http://www.octave.org/, respectively.

Documentation regarding the installation and configuration of Comedi can be found on the project's web site along with examples. The site also includes a number of useful links to other Linux DAQ-related sites. Documentation regarding the closed-source packages can be found on their vendors' web sites.

Although I haven't covered them, some DAQ hardware vendors do provide drivers for their hardware, either in open source form or under a proprietary license. When evaluating whether to use such drivers, it is important to ponder future vendor support so you don't find yourself trapped with dead and unmaintained code. Even when source is available under an open source or free software license, be sure to evaluate its quality to ensure that you can actually maintain it if the vendor decides to drop its support.

3.3.5 Process Control

As with DAQ, process control is at the basis of any process automation system. As I said in Section, there are many ways to control a process, the most common being the use of PLCs. More recently, mainstream hardware such as PCs have been used for process automation and control.

Linux can be used for control in many ways. First, you can use serial or parallel ports to drive external hardware such as step motors. This involves serial and parallel port programming, which I covered earlier. There is no standard software package to interface with externally controlled hardware in this manner, such packages or APIs are specific to the application being designed.

Examples of serial or parallel ports for control are readily available both in print and online. Sometimes these examples are oriented towards the PC running DOS or Windows. In that case, they need to be adapted to Linux and the facilities it provides. If you need such a port, you will find the Linux Device Drivers book to be helpful.

Second, external processes can be controlled using specialized boards attached to the computer through a peripheral bus. In this case, you need a driver specific to the board being used. The Comedi package mentioned earlier provides support for some control boards. Also, control board manufacturers are becoming increasingly aware of the demand for Linux drivers for their hardware and are providing them accordingly.

Last, there is an effort underway to let a standard Linux system replace traditional PLCs. The project, Machine Automation Tools LinuxPLC (MAT LPLC), located at http://mat.sourceforge.net/, provides PLC language interpreters, hardware drivers, a PLC module synchronization library, example modules, and a GUI interface to visualize the controlled process. Building a PLC using LPLC consists of programming independent modules, either in C or an interpreted language such as "ladder logic," that are synchronized through LPLC facilities such as shared memory. Because each module is an independent process, you can add and remove control modules with ease.

The LPLC team provides information regarding the use and programming of their package on their project's web site. Although the project is still in its early stages, the development team lists practical examples showing the package's usability in real scenarios.

3.3.6 Home Automation

As with DAQ and process control, home automation is a vast domain. I will not attempt to cover the basics of home automation or the required background, because other authors have documented them. If you are new to home automation or would like to have more information about this field, you can find an extensive list of links and reference material in Dan Hoehnen's Home Automation Index located at http://www.homeautomationindex.com/.

One technology often used in home automation is X10 Power Line Carrier (PLC)[12] developed in the 1970s by Pico Electronics in Scotland. Although other protocols have been put forward by manufacturers, X10 remains the dominant protocol in home automation.

[12] X10 PLC should not be confused with the PLCs used in process automation. These are actual control devices unrelated to the X10 PLC hardware protocol.

Pico later formed X10 corporation as a joint venture with BSR. To this day, X10 corporation still sells X10 technology components. In the meantime however, the original X10 patent expired in 1997. Hence, many manufacturers currently provide X10-compatible equipment. The X10 PLC protocol enables transmitters and receivers to communicate using short RF bursts over power line wiring. There is therefore no need for additional wiring, because all communication occurs on the house's existing electrical wiring.

Unlike other fields in which Linux is used, there is no central open source home automation project for Linux. Instead, there are a number of active projects being developed independently. Furthermore, there is no particular home automation driver within the kernel. The required software components are all part of the various packages distributed by the home automation projects.

The following is a list of Linux-compatible open source home automation projects:


MisterHouse is a complete home automation solution. It includes a user interface and X10 interface software, can be controlled using a variety of voice recognition packages, and can interface with voice synthesis software. MisterHouse is entirely written in Perl and can therefore be used with a number of OSes, including Linux. MisterHouse is available for download under the terms of the GPL from the project's web site with complete documentation at http://misterhouse.sourceforge.net/.


The Automation Light Interface Control Environment (ALICE) provides a user interface and software to interact with X10 devices. ALICE is written in Java and runs on any appropriate JVM, including the Linux JVM available from the Blackdown project. ALICE is distributed under the terms of the GPL with documentation from the project's web site at http://jhome.sourceforge.net/.


HEYU! is a command-line utility that enables the control of X10 devices. It is available from the project's web site at http://heyu.tanj.com/heyu/. HEYU! is distributed under a special license similar to other open source licenses. You will find the exact wording of the license in the source files' headers.

Neil Cherry has put together an impressive repertoire of resources and links about home automation and Linux home automation projects. His Linux Home Automation web site is located at http://mywebpages.comcast.net/ncherry/. Neil also maintains the Linux Home Automation project at http://linuxha.sourceforge.net/. It provides a number of links and documentation related to Linux home automation.

3.3.7 Keyboard

Most embedded systems are not equipped with keyboards. Some may have a limited input interface, but keyboards are usually considered a luxury found only on traditional workstation and server configurations. In fact, the idea that an embedded system may have a keyboard would be viewed as awkward by most traditional embedded system designers. Nonetheless, recent breeds of web-enabled and consumer-oriented embedded systems have some form of keyboard attached to them.

As with other Unix-like systems, communication with the user in Linux is done by means of a terminal, in the Unix tty sense, where a keyboard is used for input and a console for output. This is of course a simplification of the very complex world of Unix terminal I/O, but it will suffice for the current discussion. Hence, all keyboard input is considered by the kernel as input to a terminal. The conversion from the actual data inputted by the user to actual terminal input may involve many different layers of kernel drivers, but all keyboard input is eventually fed to the terminal I/O driver.

In a PC, for instance, keyboard input is processed sequentially by the code found in the following files of the drivers/char directory of the kernel sources: pc_keyb.c, keyboard.c, and tty_io.c. The last file in the sequence is the terminal I/O driver. For systems based on other architectures, the Input layer mechanism is usually used. This mechanism specifies a standard way for input devices such as keyboards, mice, and joysticks to interface with the system. In the case of USB keyboards, for instance, the input processing sequence is the following, starting from the drivers directory of the kernel: usb/usbkbd.c, input/keybdev.c, char/keyboard.c, and again, char/tty_io.c.

There are other ways to provide input to a terminal, apart from the use of a physically connected keyboard. Terminal input is also possible through remote-logging, serial-linking between computers, and in the case of PDAs, hand-writing recognition software. In each case, accessing the character input programmatically requires terminal I/O programming.

3.3.8 Mouse

Embedded systems that have a user interface often offer some form of touch-based interaction. Whether it be a bank terminal or a PDA, the input generated by the user's touch of a screen area is treated the same way as input from a conventional workstation mouse. In this sense, many embedded systems have a "mouse." In fact, there are many more embedded systems that provide a mouse-like pointer interface than there are that provide a keyboard interface.

Since traditional Unix terminals do not account for mouse input, information about the pointer device's input doesn't follow the same path as data about keyboard activity. Instead, the pointer device is seen on most Linux systems as /dev/mouse, which itself is often a symbolic link to the actual pointer device. The device can be polled and read to obtain information regarding the pointer device's movements and events. Although the name of the entry in /dev where the pointer is found is usually constant, the format of the data retrieved from the device varies according to the type of device. There are, in fact, many mouse protocols that define different input formats. Note that the protocol used by a mouse is not directly tied to its manufacturer or even the type of physical connection used to link it to the system. This is why the configuration of the X server, for example, requires the user to specify a protocol for the mouse device. The kernel, on the other hand, has drivers that manage the actual physical link between the mouse and the system.

Any programming that involves a pointer device would require an understanding of the protocol used by the device. Fortunately, a number of libraries and environments already have this level of decoding implemented, and easy-to-use APIs are provided to obtain and react to pointer input.

3.3.9 Display

Blinking lights, LEDs, and alpha-numeric LCDs are the traditional visual apparel of embedded systems. With the growing incursion of embedded devices in many facets of our daily lives, including service automation, there is a push to replace such traditional display methods with visually rich interfaces. In other areas of embedded systems deployment, such as factory automation or avionics, visually rich interfaces have been the norm for quite a while.

As I mentioned above, traditional Unix systems provide output in the form of terminal consoles. This, however, is too rudimentary of an interface for today's demands. If nothing else, consoles can output only text. Other more elaborate interfaces are needed when building graphic interfaces, which may include some form of windowing system.

With Linux there are many ways to control and program a display. Some of these involve kernel support, but most rely mainly on code running in user space, hence favoring system stability and facilitating modularity. The most common way to provide a graphical interface with Linux is, of course, the X Window System, but there are other packages that may be preferable in certain circumstances.

3.3.10 Sound

Beep, Beep, Beep... that's what Sputnik emitted and that's pretty similar to what most embedded systems still sound like. Even the very graphic-rich avionics and factory automation systems don't have more sound output, except maybe in terms of decibel. Sound-rich embedded systems are, however, becoming more and more popular with the proliferation of consumer and service-oriented devices.

Unix, however, was never designed to accommodate sound. Over the years, a number of schemes appeared to provide sound support. In Linux, the main sound device is usually /dev/dsp. Other audio-hardware related devices are also available for other sound capabilities such as /dev/mixer and /dev/sequencer.

Contrary to many other parts of development in Linux, audio is an area that has yet to mature. There are two independent projects that provide both support for sound hardware and an API to program the hardware.

The first, and oldest, is the Open Sound System (OSS) introduced by Hannu Savolainen. Most sound card drivers found in kernel releases prior to 2.5 are based on the OSS architecture and API put forth by Hannu. Over the years, these APIs changed and have been "cleaned up" by Alan Cox. Nonetheless, many consider them to be ill-adapted for modern audio hardware. The OSS drivers and API are actually a publicly available subset of a commercial product from Hannu's company, 4Front Technologies, which has broader support for hardware and a richer API. Documentation regarding OSS programming can be found at http://www.opensound.com/pguide/.

The second audio project is the Advanced Linux Sound Architecture (ALSA). ALSA's aims are to provide a completely modularized sound driver package and offer a superior environment to OSS, both in terms of the API and in terms of management infrastructure. In terms of hardware support, the ALSA project supports hardware not supported by the OSS. Since the ALSA project and all its components have always been open source, all documentation and source is available online at the project's web site, http://www.alsa-project.org/.

It was expected that the ALSA project would at some point replace the OSS content in the kernel. Starting with Linux 2.5, ALSA has indeed been integrated in the kernel, although the OSS drivers have been kept for the time being. As with other areas of Linux support, audio support varies with the target architecture. The more mainstream the architecture, the better the support.

3.3.11 Printer

As with many mainstream peripherals, printers don't use usually grace embedded systems. There are, however, exceptions. An embedded web server that supports printing is an example of an embedded system that needs an OS with printer support. Traditional embedded system developers would usually consider "embedded web server" to be an oxymoron, but devices that provide these types of packaged services are more and more common and involve development methods similar to those of more constrained embedded devices.

Conventional Unix printer support is rather outdated in comparison to the support provided by many other OSes. Linux's printer support is, unfortunately, largely based on other Unix printing systems. There are, nonetheless, a number of projects that aim at facilitating and modernizing printing services in Linux and Unix in general.

To understand how document printing and printer support is implemented in Linux, let us review the steps a document generally goes through, starting from the user's print request to the actual printing of the document by the printer:

  1. A user submits a document for printing. This may be done either at the command line or via a menu in a graphical application; there is little difference between them in Linux. Usually, printable output of Unix programs is in PostScript (PS) format and is sent as such to the printer. As not all printers available on the market are PS capable, PS output has to be converted to a format understandable by the actual printer being used. This conversion is done at a later stage, if necessary.

  2. The document, along with the user's print options, is stored in a queue dedicated to a single printer. This queue may be either local, if the printer is directly attached to the system, or remote, if the printer is attached to a server on the network. In both cases, the process is transparent to the user.

  3. A spooling system takes care of the print queue and queues the document for printing whenever the printer becomes available. It is at this stage that the conversion of the document from PS or another format to the actual format recognized by the printer takes place. The conversion is done using a set of filters, each taking care of the conversion of one type of format to another. The most important of these is the PS-to-printer filter, which is specific to each type of printer.

Depending on the print-management software being used, these steps may vary slightly. There are currently five different print-management packages available for Linux: LPD, PDQ, LPRng, CUPS, and PPR. LPD is the traditional package found on most distributions. The other packages are making inroads and are slowly replacing LPD. Whichever package is used, however, the final conversion from PS to printer format is usually done by GhostScript,[13] a very important package that enables the viewing and manipulation of PS files. Once this conversion is done, the output is finally fed to the actual printer device, whether it be a parallel port printer or a USB printer.

[13] GhostScript has a large memory footprint and may not be suitable for some small-sized embedded Linux systems.

Keep in mind that all the work is done in user space. The kernel drivers get involved only at the very end to feed the filtered output to the actual printer.

If you intend to add printer support to your embedded system, I suggest you read up on Unix printer management from any of the good conventional Unix or Linux systems management books available. Running Linux by Welsh, Dalheimer, and Kaufman (O'Reilly) provides a good description of how printer setup is done in Linux when using LPD. For bleeding edge information regarding Linux printing, take a look at http://www.linuxprinting.org/, the main resource on the subject. On that same web site, you will find the Printing HOWTO, which contains extensive information about the different print-management packages, their operation, and relevant links.