blueDonkey.org

Books.VxWorksToLinuxDeviceDrivers

Device Drivers


Checking for Existing Driver

For the vast majority of devices you are likely to encounter, a Linux driver will already exist. As was noted in the preface, there are many more Linux drivers than VxWorks drivers available, and most hardware manufacturers these days are providing Linux drivers for their devices. That said, you might find some newer devices do not have drivers yet, or have binary-only drivers for specific versions of the kernel (often only for x86 kernels too). Before spending the time writing your own driver, or porting one you wrote for VxWorks, it is worth spending an hour or so searching for an existing driver. Even if it is does not fully meet your needs, it will provide a good head start on the porting work.

Good places to look are:

  • The drivers directory of the kernel source tree you are using.

  • The device manufacturer's web site.

  • Archives of the Linux mailing lists and usenet forums; others may already be using the same device on their Linux system and provided information on driver location(s) and configuration.

Writing/Porting Drivers

Linux vs VxWorks Drivers

Since both Linux and VxWorks model their I/O systems on the Unix system, both have similar requirements when it comes to device drivers. Both operating systems split the driver space into character devices, block devices and network interface devices.

  • Differences
    • Major & Minor numbers
    • /proc file system
    • Supporting select(), and for Linux poll()

Character Devices

The table below shows the functions that can be implemented in a VxWorks character, and those from a Linux one. As can be seen, many are common, and those that are new to Linux devices need not be implemented.

VxWorks Linux Description
close release Indicate that the process no longer needs access to the device.
create   Creates a new file under the device. Not used for many true character devices, and not supported in Linux. For cases where this is used to create a new instance of a virtual device, e.g. a new VxWorks pipe in pipeDrv, a new device node with an unused minor number should be created in Linux.
delete   Delete a file under the device. See comments for create.
ioctl ioctl I/O control interface.
open open Indicate to the device driver that a process wishes to use the device.
read read Read bytes from the device.
write write Write bytes to the device.
  llseek Seek in the device's data stream.
  readdir Should not be implemented for character devices.
  poll Backend to select() and poll() functions.
  mmap Memory mapped access to the device's data. For most character devices this will not be implemented, and the driver should simply return -ENODEV.
  flush Wait for outstanding file operations. Most drivers will simply not implement this.
  fsync Flush any data in buffers to the device. Drivers should return -EINVAL if they do not support this.
  fasync Part of the asynchronous notification mechanism in Linux. For most drivers being ported from VxWorks this can be left unimplemented.
  lock File locking support. Not usually needed for devices.
  readv Scatter-gather read support. Need not be implemented.
  writev Scatter-gather write support. Need not be implemented.

Two important functions are not shown in the table: those that initialise and terminate the driver. These are discussed in the section about loadable kernel modules later.

Block Devices

TBD

Network Interface Devices

TBD

Debugging Drivers

TBD

Loadable Kernel Modules

Simple Modules

Many microcontroller CPUs have general purpose I/O pins, or GPIO pins. These can often be configured in a number of different modes, usually on a per-pin basis. Often the architecture support code for the CPU will provide routines for manipulating these pins that may be called by kernel code. In the case of devices that need to be configured and/or enabled at initialisation time and then left alone, a simple loadable module with an appropriate init routine may be all that is needed. The sample code below shows how a simple module could be used to set up some status LEDs during system initialisation.

#ifndef EXPORT_SYMTAB
#define EXPORT_SYMTAB
#endif

#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <asm/arch/gpio.h>

static int __init leds_init (void)
{
        // Configure LEDs for output & set initial state
        gpio_line_config (LED_0, GPIO_OUT);
        gpio_line_set    (LED_0, GPIO_HIGH);
        gpio_line_config (LED_1, GPIO_OUT);
        gpio_line_set    (LED_1, GPIO_HIGH);
        return 0;
}

static void __exit leds_exit (void)
{
        // Nothing to do on exit for now
        return;
}

module_init(leds_init);
module_exit(leds_exit);

This simple module could be enhanced to add more complex initialisation, a user-space interface (/dev/led0 and /dev/led1) or even a kernel thread that allows the LEDs to be flashed automatically.

Implementing a User-Space Interface

Kernel Threads

Handling Interrupts

More Information

The Linux Device Drivers book contains detailed instructions on writing any of the three types of driver, as well as examples which can be downloaded from http://examples.oreilly.com/linuxdrive2/ or from ftp://ar.linux.it/pub/ldd2/.

The Linux Device Drivers Dos and Don'ts document which can be found at http://kernel-janitor.sourceforge.net/ is another useful reference for those just starting to write device drivers for Linux.

For those writing their drivers as loadable kernel modules, the HOWTO for loadable kernel modules will be essential reading. The most up-to-date version of it can always be obtained from http://www.tldp.org/HOWTO/Module-HOWTO/index.html.

There are some example drivers for PowerPC MPC8xx based systems available from ftp://ftp.denx.de/pub/LinuxPPC/usr/src/drivers.tar.gz. These are still useful for anybody starting to work on their own simple device drivers.

-- JohnGordon - 16 Dec 2003

 
 
© 2003-5 blueDonkey.org, except where otherwise noted. All rights reserved.