Linux drivers (modules)
Linux provides a mechanism so that a properly written driver may be inserted into a running kernel and, when it is no longer needed, it may even be removed. Unlike some other operating systems, there is no need to re–boot the system or affect its normal operation in any harmful way. This capability makes it quite easy for a software engineer to learn to write a driver by actually doing it. As long as the software engineer is careful not to destroy any protected data or code within the kernel, the driver may be coded in part, installed, tested, removed, then more code added. This successive approximation technique is normally how most software is written anyway, even though many software engineers do not readily admit it.
The Linux kernel development source–code contains many kernel drivers (called modules) which may be used as templates. However, to demonstrate the capability of readily developing a driver, I wrote some source–code for a driver which allocates kernel pages which are DMA–capable, and then provides them to user–mode software using the POSIX standard memory–mapping convention. Using this means, hardware may write data directly to user–mode code using DMA, something that has been declared “impossible” by some other operating systems. One may download a copy of this software here.
The user to kernel interface
Linux normally connects to user–mode code through its ‘C’ runtime library. The actual mechanism by which software requests the kernel to perform tasks on its behalf is therefore hidden from view. However, it is possible to write software in other languages besides ‘C.’ For instance, one may write in machine language, commonly called “assembly–language.” This exposes the kernel interface directly to such user–mode code.
Basically, the kernel interface works by software putting a function–code and other variables into registers, then generating an exception or “trap” which forces the kernel to find out what caused the trap. If the trap was caused by a valid request for kernel services based upon the function code, then the kernel code will perform those services on behalf of the caller. If not, the kernel may take other steps up to and including the dissolution (killing) of the caller.
Devices, except for network devices, are initially accessed as files. The files are usually put in the “/dev” directory, but they may be anywhere. The sample code provided, simply creates such a device file in the “/tmp” directory which all “Sys–V” systems are supposed to have. Embedded systems often have unusual file structures so the device files may be anywhere that the designer chooses. Device files are simply a mechanism, a trick, to associate a major and minor number to control access. Once the device is opened for access, the device–file is never accessed again, so its presence does not slow down anything.
There are two basic kinds of devices, character devices and block devices. Character devices access the underlying hardware using strings of bytes (characters). Block devices access the hardware using fixed–length groups (blocks) of data. Character devices are normally used for access to memory devices and I/O terminals. Block devices are normally used to access disk drives and other devices that are accessed using file pointers and similar file–access objects. The designer is free to use either mechanism because the kernel does not interfere. It is the driver’s functionality that is important, not the device–file naming conventions. For instance, the kernel’s interface to the real–time clock chip normally available in PC/AT platforms uses a character device even though characters are not used in the access software.
In UNIX and Linux, devices are opened by calling the kernel open function to obtain a handle for subsequent access. The handle is simply an integer that the kernel provides to keep track of the device that has been opened. All subsequent access to that device uses that handle to tell the kernel the device being accessed. Once access is no longer required, the handle may be closed by calling the kernel close function. Typically, one or more additional kernel functions are called to handle specific access to the device.
Kernel device access functions
In principle, it is possible to use memory–mapping to make all the device registers accessible to user–mode code. Naïve programmers have sometimes done this with other operating systems, exposing the hardware to unauthorized or otherwise unwarranted access. Such software is said to produce a layering violation. Device drivers are supposed to provide the complete software solution to control the hardware, providing a transparent mechanism so that user–mode code does not have to handle the details of possibly very complex interaction with the hardware. Such layering has many advantages including the fact that hardware changes are isolated to their drivers. If one changes the hardware, including complete redesigns, only the driver needs to be changed. Other advantages include instant access to the interrupt mechanism and atomic operation of the device being controlled by the driver.
This webpage copyright © 2009, Route 495 Software, LLC