-->
Previous | Table of Contents | Next |
Interrupts are signals from the devices to the operating system to indicate that attention is required. Interrupts are generated whenever an I/O is processed and the device is ready for another process. The interrupts used by Linux are similar to those used by DOS, so if you are familiar with DOS interrupts, you know most of the story already.
Upon receipt of an interrupt, the operating system suspends whatever it is executing and processes the interrupt. In most cases, interrupts are handled by the device driver. Interrupts must be checked to ensure that they are valid and do not affect operation of a process underway, except to suspend it momentarily.
A problem with handling interrupts is that the interrupt should not suspend the Linux kernels operation or that of the device drivers themselves, except under controlled conditions. Interrupts that are not properly handled or carefully checked can cause suspension of a device driver that was processing the I/O that the interrupt requested.
The processing of an interrupt is usually suspended during the stages when critical operation would be affected. The areas of device driver code that should not allow an interrupt to stop their processing are termed non-stoppable or critical code. Typically, interrupt suspension during critical code segments is performed by raising the CPU priority equal to or greater than the interrupt priority level. After critical code execution, the CPU priority level is lowered again.
Interrupt priority is usually manipulated with four functions: spl5(), spl6(), spl7(), and splx(). Calling one of the first three causes interrupts not to be acknowledged during processing. spl5() disables disk drives, printer, and keyboard interrupts. spl6() disables the system clock, while spl7() disables all interrupts, including serial devices. These three functions always return a code indicating the previous value of the interrupt level. splx() is used to restore interrupts to their previous values.
Therefore, before processing critical code, embedding the command
old_level = spl5();
in the device driver source disables interrupts until the following command is issued:
splx(old_level);
Multiple level changes are combined into device drivers as in the following example:
int level_a, level_b; level_a = spl5(); /* do any code that cant be */ /* interrupted by disk drives */ level_b = spl7(); /* do all code that cant be */ /* interrupted by anything */ splx(level_b); /* any final code thats not */ /* interrupted by disk drives */ splx(level_a);
This seemingly awkward method of bouncing between levels is necessary to avoid freezing the device driver and kernel, which prevents the system from operating normally. The protection mechanisms must be invoked only for as short a time as necessary.
It is usually unwise to use the spl6() and spl7() functions. spl6() can cause the system clock to lose time in some cases, and spl7() causes loss of characters in serial I/O, unless it is used for very short time spans. Even then, it is usually sufficient to use spl5() for all interrupts in critical code.
Device driver code is similar to normal code in its structure. In Linux, drivers are generally written in C, although assembler and C++ are still occasionally used.
A typical device driver has a header that consists of include statements for system functions, device register addresses, content definitions, and driver global variable definitions. Most device drivers use a standard list of include files, such as:
param.h | Kernel parameters |
dir.h | Directory parameters |
user.h | User area definitions |
tty.h | Terminal and clist definitions |
buf.h | Buffer header information |
The tty.h file is used for character mode drivers, while buf.h is used by all block mode devices.
Device registers are defined in the device driver header and are based on the device. For a character mode device, these registers commonly refer to port addresses, such as I/O address, status bits, and control bits. Toggle commands for the device are defined as their device codes.
Previous | Table of Contents | Next |