Linux Device Drivers (3rd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Linux Device Drivers (3rd Edition) [Electronic resources] - نسخه متنی

Jonathan Corbet, Greg Kroah-Hartman, Alessandro Rubini

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








10.6. Interrupt-Driven I/O


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/shortprint.

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 6.2.3 in Chapter 6.


10.6.1. A Write-Buffering Example


We have mentioned the shortprint
driver a couple of times; now it is time to actually take a look.
This module
implements a very simple,
output-oriented driver for the parallel port; it is sufficient,
however, to enable the printing of files. If you chose to test this
driver out, however, remember that you must pass the printer a file
in a format it understands; not all printers respond well when given
a stream of arbitrary data.

The shortprint driver maintains a one-page
circular output buffer. When a user-space process writes data to the
device, that data is fed into the buffer, but the
write method does not actually perform any I/O.
Instead, the core of shortp_write looks like
this:

    while (written < count) {
/* Hang out until some buffer space is available. */
space = shortp_out_space( );
if (space <= 0) {
if (wait_event_interruptible(shortp_out_queue,
(space = shortp_out_space( )) > 0))
goto out;
}
/* Move data into the buffer. */
if ((space + written) > count)
space = count - written;
if (copy_from_user((char *) shortp_out_head, buf, space)) {
up(&shortp_out_sem);
return -EFAULT;
}
shortp_incr_out_bp(&shortp_out_head, space);
buf += space;
written += space;
/* If no output is active, make it active. */
spin_lock_irqsave(&shortp_out_lock, flags);
if (! shortp_output_active)
shortp_start_output( );
spin_unlock_irqrestore(&shortp_out_lock, flags);
}
out:
*f_pos += written;

A semaphore (shortp_out_sem) controls access to
the circular buffer; shortp_write obtains that
semaphore just prior to the code fragment above. While holding the
semaphore, it attempts to feed data into the circular buffer. The
function shortp_out_space returns the amount of
contiguous space available (so there is no need to worry about buffer
wraps); if that amount is 0, the driver waits
until some space is freed. It then copies as much data as it can into
the buffer.

Once there is data to output, shortp_write must
ensure that the data is written to the device. The actual writing is
done by way of a workqueue function;
shortp_write must kick that function off if it
is not already running. After obtaining a separate spinlock that
controls access to variables used on the consumer side of the output
buffer (including shortp_output_active), it calls
shortp_start_output if need be. Then
it's just a matter of noting how much data was
"written" to the buffer and
returning.

The function that starts the output process looks like the following:

static void shortp_start_output(void)
{
if (shortp_output_active) /* Should never happen */
return;
/* Set up our 'missed interrupt' timer */
shortp_output_active = 1;
shortp_timer.expires = jiffies + TIMEOUT;
add_timer(&shortp_timer);
/* And get the process going. */
queue_work(shortp_workqueue, &shortp_work);
}

The reality of dealing with hardware is that you can, occasiona

/ 202