Whenever a data transfer to or from the managed hardware might be delayed for any reason, the driver writer should implement buffering. Data buffers help to detach data transmission and reception from the write and read system calls, and overall system performance benefits.
A good buffering mechanism leads to interrupt-driven
I/O, in which an input buffer is filled at interrupt time
and is emptied by processes that read the device; an output buffer is
filled by processes that write to the device and is emptied at interrupt
time. An example of interrupt-driven output is the implementation of
/dev/shortint
.
For interrupt-driven data transfer to happen successfully, the hardware should be able to generate interrupts with the following semantics:
For input, the device interrupts the processor when new data has arrived and is ready to be retrieved by the system processor. The actual actions to perform depend on whether the device uses I/O ports, memory mapping, or DMA.
For output, the device delivers an interrupt either when it is ready to accept new data or to acknowledge a successful data transfer. Memory-mapped and DMA-capable devices usually generate interrupts to tell the system they are done with the buffer.
The timing relationships between a read or write and the actual arrival of data were introduced in Section 5.2.4, in Chapter 5. But interrupt-driven I/O introduces the problem of synchronizing concurrent access to shared data items and all the issues related to race conditions. The next section covers this related topic in some depth.
Get Linux Device Drivers, Second Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.