2.9. Doing It in User Space
A
Unix programmer who's addressing kernel issues for
the first time might be nervous about writing a module.
Writing a user program that reads and writes
directly to the device ports may be easier.
Indeed, there are some arguments in favor of user-space programming,
and sometimes writing a so-called user-space device driver is a wise
alternative to kernel hacking. In this section, we discuss some of
the reasons why you might write a driver in user space. This book is
about kernel-space drivers, however, so we do not go beyond this
introductory discussion.
The advantages of user-space drivers are:
The full C library can be linked in. The driver can perform many
exotic tasks without resorting to external programs (the utility
programs implementing usage policies that are usually distributed
along with the driver itself). The programmer can run a conventional debugger on the driver code
without having to go through contortions to debug a running kernel. If a user-space driver hangs, you can simply kill it. Problems with
the driver are unlikely to hang the entire system, unless the
hardware being controlled is really misbehaving. User memory is swappable, unlike kernel memory. An infrequently used
device with a huge driver won't occupy RAM that
other programs could be using, except when it is actually in use. A well-designed driver program can still, like kernel-space drivers,
allow concurrent access to a device. If you must write a closed-source driver, the user-space option makes
it easier for you to avoid ambiguous licensing situations and
problems with changing kernel interfaces.
For example, USB drivers can be written for user space; see the
(still young) libusb project at libusb.sourceforge.net and
"gadgetfs" in the kernel source.
Another example is the X server: it knows exactly what the hardware
can do and what it can't, and it offers the graphic
resources to all X clients. Note, however, that there is a slow but
steady drift toward frame-buffer-based graphics environments, where
the X server acts only as a server based on a real kernel-space
device driver for actual graphic manipulation.
Usually, the writer of a user-space driver implements a server
process, taking over from the kernel the task of being the single
agent in charge of hardware control. Client applications can then
connect to the server to perform actual communication with the
device; therefore, a smart driver process can allow concurrent access
to the device. This is exactly how the X server works.
But the user-space approach to device driving has a number of
drawbacks. The most important are:
Interrupts are not available in user space. There are workarounds for
this limitation on some platforms, such as the
vm86 system call on the IA32 architecture. Direct access to memory is possible only by
mmapping /dev/mem, and only
a privileged user can do that. Access to I/O ports is available only after calling
ioperm or iopl. Moreover,
not all platforms support these system calls, and access to
/dev/port can be too slow to be effective. Both
the system calls and the device file are reserved to a privileged
user. Response time is slower, because a context switch is required to
transfer information or actions between the client and the hardware. Worse yet,
if the driver has been swapped to disk, response time is unacceptably
long. Using the mlock system call might help,
but usually you'll need to lock many memory pages,
because a user-space program depends on a lot of library code.
mlock, too, is limited to privileged users. The most important devices can't be handled in user
space, including, but not limited to, network interfaces and block
devices.
As you see, user-space drivers can't do that much
after all. Interesting applications nonetheless exist: for example,
support for SCSI scanner devices (implemented by the
SANE package) and CD writers (implemented by
cdrecord and other tools). In both cases,
user-level device drivers rely on the "SCSI
generic" kernel driver, which exports low-level SCSI
functionality to user-space programs so they can drive their own
hardware.
One case in which working in user space might make sense is when you
are beginning to deal with new and unusual hardware. This way you can
learn to manage your hardware without the risk of hanging the whole
system. Once you've done that, encapsulating the
software in a kernel module should be a painless operation.
|