Linux Device Drivers

Linux Device Drivers

Character drivers
IO & Memory
Linux Kernel
Process Management
Process Address space

Linux Scheduler
Memory Management
System Calls
Kernel Synchronization
Linux Inter Process Communications

Serial Ports
Parallel Ports
Introduction to Hardware
Linux Timers
DMA in Linux
Linux Threads
Linux Thread Synchronization

Linux Multi Threading
Debugging in Linux
GDB GNU Debugger
KDB Kernel Debugger
KGDB Kernel GNU Debugger
Example Ethernet Driver

Hardware Basics

Hardware Basics


How to use the devices control and status registers

What causes the device to generate interrupt

How the device transfers data

Whether the device uses any dedicated memory

Whether the device can be auto configured



     Device Registers: command, status and data buffer

     Accessing device Registers: (i) address of the devices first register (ii) address space where these registers live

     I/O Space Registers: (i) inb() Read a single value from I/O Port (ii) outb() Write a single value to I/O Port

     Memory-mapped registers: (i) readb() Read a single value from I/O register (ii) writeb() Write a single value to I/O register


Memory-mapped device registers and I/O space portsMemoryRegister




     Device Interrupts-device interrupts for (i)has completed I/O operation (ii) A buffer or FIFO is full (iii) encounters some kind of error

     Interrupt priorities

     Interrupt vectors

     Signalling mechanism: edge triggered(or latched) interrupts and level-sensitive (or level triggered(level-triggered) interrupt

     Processor affinity: multiprocessor platform contains special interrupt routing hardware


Data transfer mechanisms


     Three basic options: Programmed I/O, Direct memory access, Shared buffers

     PIO -need help of CPU for each byte transfer

     DMA-special hardware DMA Controller, System DMA and Bus Master DMA

     Device Dedicated Memory -such as video adapter board


Paths followed by data in DMA and programmed I/O transfers




Auto configuration


     Ports, IRQs and DMA channel assignment

     Device resource lists: Manufacturer id, device type id, I/O space, interrupt requirement, DMA channels, device memory

     No jumpers or switches -change resource dynamically

     Change Notification




     Bus is a collection of data, address and control lines that allows a peripheral device to communicate with memory and CPU

     ISA -Industry Standard Architecture

     MCA -Micro Channel Architecture

     EISA -Extended Industry Standard Architecture

     PCI -Peripheral component Interconnect


Layout of an ISA system




     The ISA bus clock rate is 8.33 MHz, the maximum transfer rate is about 8MB/sec.

     The I/O Address range is 0x0000 to 0x03FF.

     ISA Bus supports 16 interrupts. Multiple cards can not share the interrupt.

     Upto8 DMA channels, Can access below 16 MB of memory.

     Any device dedicated memory must live with in 16 MB space.

     No Auto-Configuration facility, set by DIP switches and jumpers




Fast Transfer


     Fast bus clock (33MHz), the PCI architecture can hit 132 megabytes/sec for 32 bit transfers.

     Every transfer is a burst operation

     Supports multiple bus masters and permits direct device to device transfers. Overlap between I/O and CPU operation.

     A central bus arbiter reduces latency by overlapping arbitration with data transfer.

     An intelligent bridge between the host CPU and PCI bus performs caching and read-ahead functions.


Register Access

I/O register access is still limited to 64 kilo bytes in x86 architecture


Interrupt Mechanisms


The PCI has four equal-priority interrupt request lines (INTA-INTD)which are active-low, level-triggered, and shareable.


DMA capabilities


The native PCI functions are either bus masters doing their ownDMA or they use programmed I/O.


Device Memory


Dedicated memory used by PCI functions can live anywhere in a32-bit address space.




Each function on the PCI bus has 256 byte storage space for configuration data.


The PCI Interface


The PCI architecture was designed as a replacement for the ISA standard, with three main goals:


     To get better performance when transferring data between the computer and its peripherals,

     To be as platform independent as possible,

     To simplify adding and removing peripherals to the system



PCI Addressing


     Each PCI peripheral is identified by a Bus-number, a device-number, a function- number.

     PCI specification permits a system to host upto 256 buses, each bus hosts upto 32 devices and each device can be a multifunction board within a maximum of eight functions.

     Thus each PCI peripheral can be identified by a 16-bit ( 8 + 5 + 3 ) address


The 16 bit hardware addresses associated with PCI peripherals are visible as output of lspci and the layout of information in/proc/pci and /proc/bus/pci.


When the hardware address is displayed, it can either be shown as a 16-bit value, as two values (an 8-bit bus number and an 8-bitdevice and function number) or as three values (bus, device, andfunction).


For example, /proc/bus/pci/devices uses a single 16-bit field,while /proc/bus/busnumbersplits the address into three fields.


#lspci| cut -d: -f1-2

#cat /proc/bus/pci/devices | cut -d\-f1,3


The hardware implements the three address spaces: memory location, I/O ports and configuration space. The first two address spaces are shared by all the devices on a PCI bus. Configuration transactions address only one slot at a time.

The memory and I/O regions are accessed in the usual ways via inb, readb etc. Configuration transactions are performed by calling specific kernel functions to access configuration registers. Every PCI slot has 4 interrupts pins, and each device function can use one of them.

The I/O space in a PCI bus uses 32-bit address bus while the memory space can be accessed with either 32-bit or 64-bit addresses.

Every memory and I/O address region offered by interface board can be remapped by means of configuration transactions.


Boot time address assignment


When the power is applied to a PCI device, the hardware remains inactive. That is device has no memory and no I/O ports mapped in the computers address space. Interrupt reporting is disabled as well.

The firmware (BIOS) offers access to the device configuration address space by reading and writing registers in the PCI controller. At system boot, the firmware performs configuration transactions with every PCI peripheral in order to allocate at safe place for any address regions it offers. By the time a device driver accesses the device, its memory and I/O regions have already been mapped into the processor's address space.


     The PCI configuration space consists of 256 bytes for each device function.

     First 64 bytes are standardized and device independent

     Always little endian


PCI Configuration space




Some of the PCI configuration registers are required and some areoptional.

Three or five PCI registers identify a device: vendorID, deviceIDand class are always used. Every PCI manufacturer assigns propervalues to these read only registers. The driver can use them to lookfor the device. The fields subsystem vendorIDand subsystem deviceIDare sometimes set by vendor to further differentiatesimilar devices.


vendorID: The 16 bit register identifies the hardware manufacturer.

deviceID: Selected by vendor to identify the device.

class: Every peripheral device belongs to a class. This is a 16-bitvalue whose top 8 bits identify the "base class" (or group). For example, "ethernet" and "token ring" are two classes belonging to the network group.


Detecting the device


Using vendor-id and device-id, you can detect and get info of your device.


This macro is defined if the kernel includes support for PCI calls.


#include <linux/pci.h>

Declares all prototypes

int pci_present(void);

Check if PCI functionality is available or not.


struct pci_dev;

This data structure is used as a software object to represent a PCI device.


struct pci_dev *pci_find_device (UINT vendor, UINT device, const struct pci_dev *from ) ;


struct pci_dev *pci_find_class ( UINT class, const struct pci_dev *from);



Accessing PCI configuration space


After the driver has detected the device, it usually needs to read from or write to the three address spaces: memory, port and configuration. This is the only way to find out where the device is mapped in memory and in the I/O space. To access the configuration space, the CPU must write and read registers in the PCI controller. The Linux offers a standard interface to access the configuration space.


int pci_read_config_byte ( struct pci_dev *dev, int where, u8 *ptr);

int pci_read_config_word (struct pci_dev *dev, int where , u16 *ptr);

int pci_read_config_dword (struct pci_dev *dev, int where, u32 *ptr);

int pci_write_config_byte (struct pci_dev *dev, int where , u8 *ptr);

int pci_write_config_word (struct pci_dev *dev, int where, u16 *ptr);

int pci_write_config_dword(struct pci_dev *dev, int where, u32 *ptr);


Accessing the I/O and Memory Spaces


A PCI device implements up to six I/O address regions. Each region consists of either memory or I/O locations. Most devices implement their I/O registers in memory regions. An interface board reports the size and current location of its regions using configuration registers -the six 32-bit registers, whose symbolic names are PCI_BASE_ADDRESS_0 throughPCI_BASE_ADDRESS_5.

The lower bits of returned base address have different meanings depending if the address is I/O or memory mapped. On an I/O address bit 0 is always 1 and bit 1 is always 0. On a memory mapped address the lower 4 bits have following meaning:


Bit 0 always 0

1-2                                                                       address type

00 = arbitrary 32-bits

01 = below 1M

10 = arbitrary 64-bits

3 prefetchable



Base Address register for Memory



Base Address register for I/O



I/O resources in Linux 2.4


The I/O regions of PCI devices have been integrated in the generic resource management. The following functions are used to get region information:


unsigned long pci_resource_start (struct pci_dev *dev, int bar);

unsigned long pci_resource_end (struct pci_dev *dev, int bar);

unsigned long pci_resource_flags (struct pci_dev *dev, int bar);


All resource flags are defined in <linux/ioport.h>, the most important are:


If the associated I/O region exists, only one flag is set.


The flags tell whether a memory region is prefetchable and/or write protected.


PCI Interrupts


By the time Linux boots, the computers firmware has already assigned a unique interrupt number to the device, and the driver just needs to use it. The interrupt number is stored in configuration register 0x3c (PCI_INTERRUPT_LINE).


If the device does not support interrupts, register 0x3d (PCI_INTERRUPT_PIN) is 0.


Thus the PCI specific code for dealing with interrupts just needsto read the configuration byte to obtain the interrupt number.


Res = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &myirq);



Handling Hot-Pluggable Devices


The kernel version 2.4 supports hot pluggable devices, that is those devices that can be added to or removed from the system while the system runs (such as CardBus devices).The hot pluggable device driver must register an object with the kernel, and the probe function for the object will be asked to check any device the system to take hold of it or leave it alone. The design is built around struct pci_driver defined in <linux/pci.h> The structure defines operations it implements, and also includes a list of devices it supports.


How initialization and cleanup are handled, for a hypothetical

hot plug PCI module (HPPM):


struct pci_driverhppm_driver= { /* .. */};


int hppm_init_module(void)


return pci_module_init(&hppm_driver);



int hppm_cleanup_module(void)





int pci_register_driver (struct pci_driver *drv);

This function inserts the driver in a linked list maintained by the system.


int pci_module_init (struct pci_driver *drv);

This function is meant to be called by modularized initialization code. It returns 0 for success and ENODEVif no device has been found.


void pci_unregister_driver (struct pci_driver *drv);


This function removes the driver from liked list of known drivers.


The pci_driver structure


The pci_driver data structure is the core of hot-plug support. It is made of just a few methods and a device ID list.


struct list_head node;

Used to manage a list of drivers


char *name;

The name of the driver, it has informational value.


const struct pci_device_id *id_table;

An array that lists which devices are supported by this driver


int (*probe) (struct pci_dev*dev, const struct pci_device_id *id);

The function must initialize the device it is passed and return 0 in case of success or a negative error code.


int (*remove) (struct pci_dev*dev);

Is used to tell the device driver that it should shut down