Global Sources
EE Times-India
Stay in touch with EE Times India
EE Times-India > Embedded

Developing embedded Linux device drivers for a system-on-chip device

Posted: 22 Apr 2004     Print Version  Bookmark and Share

Keywords:embedded Linux device drivers 

Developing embedded

Linux device drivers for a

System-on-Chip device

Tanya Ortega

Systems Software Engineer

Cirrus Logic, Inc.

/PDF document

IIC-China/ESC-China 2004 7 Conference Proceedings 139

Developing embedded

Linux device drivers for a

System-on-Chip device

Tanya Ortega

Systems Software Engineer

Cirrus Logic, Inc.

The fundamental components of an operating system in-

clude a resource manager, a scheduler, an interface between

hardware and applications, a networking manager, a file sys-

tem manager. Linux operating system includes these com-

ponents and much more. This document focuses on the in-

terface between hardware and applications - device drivers.

Figure 1 illustrates the distinction between user applica-

tions, the operating system kernel, and the hardware platform.

Device Driver Types

Device drivers can be divided into two types, hardware de-

vice drivers and software device drivers. Hardware device

drivers are associated with a physical hardware device, such

as a UART device or an IDE device. While software device

drivers act as interfaces between low level data structures,

or hardware device drivers and higher level data structures.

An example of a software device driver is a graphicalconsole

driver. In this case an LCD controller driver sets up and

manages the display device hardware while the graphical


Writing a Linux device driver can be a complex undertak-

ing, the details of which cannot fully covered in a 45 minute

presentation. However, I'm going to pass over some of the

higher level details of writing device drivers and refer read-

ers to the excellent reference materials already available.

Instead, this document will focus on aspects of writing de-

vice drivers for non-standard hardware, exploring the hard-

ware APIs, with examples taken from the work done add-

ing device driver support for the Cirrus Logic EP9312 Sys-

tem On Chip Embedded Platform.

If some aspect of writing a device driver is not covered

in this document, the next option is to review the code of

similar device drivers to see how the issue is handled in that

implementation. In most cases the issue at hand has been

encountered previously. Another option, and one used by

most device driver developers, is to review the archives of,

or post an inquiry to one of the linux-kernel mailing lists or

a list specific to the type of device driver being developed.

Linux Overview

Linux is a clone of the UNIX operating system developed

initially by Linus Torvalds in 1991, with continued devel-

opment and improvement by the open source community

via the open source development model. Linux requires no

royalties to be paid for use.

Only the kernel, Linux is typically bundled with some

type of windowing environment, a windows manager, and

applications, which run on the kernel. However, with an

embedded platform, a windowing environment is not al-

ways required. Unlike a Microsoft Windows type of oper-

ating system, Linux does not require a fixed set of applica-

tions or utilities that must be used with it, therefore making

it quite customizable for end solutions in the embedded



IIC-China/ESC-China 2004 7 Conference Proceedings140

console renders characters to be displayed on the console

and accepts input from a keyboard device.Another example

of a software device driver is a file system implementation,

where the file system driver uses a hard disk driver to store

data, and the hard disk driver interfaces directly to the physi-

cal hard disk device.

Device Driver Classes

Linux device drivers are broken down into classes includ-

ing character, block, network, and others. Typically the driv-

ers are classified based on how the device is accessed. How-

ever, there are some devices, which don't fall into a specific

class and are grouped in a miscellaneous class.

Character devices include those devices that stream data.

Devices are accessed like a file through a file system spe-

cial file. File system special files are discussed in a later

section of this document. Because of the nature of charac-

ter devices, this class of devices can access data sequen-

tially only, meaning there can be no seeking forward or back

through the data. Serial ports and audio devices are ex-

amples of character devices. Figure 2 shows the the Cirrus

Logic EP9312 SOC layout with devices classified as Linux

character devices highlighted in green.

Block devices are devices, which can host a file system.

Devices of this class are accessed in the same way a charac-

ter device is accessed, through a file system special file.

However, block devices differ from character devices in that

they can be accessed randomly. This means that a calling

application can seek to a random location within the de-

vice. Examples of block devices are hard disk drives and

CD drives. In both cases a file pointer within the device can

point to any location within the device, limited only by the

device itself. While block devices are accessed via a file

system special file, making the application interface the same

as a character device, the device interface to the kernel dif-

fers from that of a character device. Figure 2 shows the Cir-

rus Logic EP9312 SOC layout with devices classified as

Linux block devices highlighted in red.

Network interface devices can be either hardware de-

vices or software devices. An example of a hardware de-

vice is an Ethernet card, and an example of a software de-

vice is a low level networking protocol stack. In this docu-

ment this type of interface is termed a software device. These

types of software devices are sometimes referred to as

middleware or protocol stacks. Network interface devices

are communication devices, with packet-oriented data.

Devices of this class have unique names, and are not ac-

cessed via a file system special file. Instead, the devices are

exposed only the kernel's networking stacks. Typically a

user level application would access the kernel's networking

stack, and not the device directly. Figure 2 shows the Cirrus

Logic EP9312 SOC layout with devices classified as Linux

network interface devices highlighted in blue.

Other types of device drivers include data bus drivers

(USB, I2C, AMBA, etc.), /proc interface, and video driv-

ers. These types of devices don't necessarily fall into one

of the above-mentioned classes, but have a device driver

type of interface to the Linux kernel.

File System Special Files

File system special files provide access to hardware devices

from the file system. These access points are created in the

/dev directory of the file system using the mknod utility.

The command looks like this:


Where is the name given to the hard-

ware device, for example, /dev/hda1 is a common name

given to a hard disk drive. is one of the de-

vice driver class types - char for character, block, etc. jor number> represents the device type and the driver asso-

ciated with that device. represents one

instance of the device type, and is used only by the device

driver. An example of this would be two hard disk drives

used in one system. Both drives would have the same ma-

jor number and use the same device driver software, but

internally the device driver software would use the minor

number to differentiate between the two hard drives.

Not all device classes implement the devices special file

interface. As discussed previously in this document, the

class of networking device drivers does not use this type of

interface to access devices.

Alternatively, the device file system, devfs may be used

to generated file system device special files. devfs is gain-

ing popularity, but is still not a default feature of the kernel.

If the devfs file system is used, mknod is not needed to gen-

erate special file. Instead, device driver software uses a

direct devfs file system interface to generate the special file

on the fly or as the device is initialized.

Overview of Coding Examples

To demonstrate the most common classes of Linux device

drivers, three device drivers implemented for the EP9312

will be examined in detail. An example of a block device is

the EP9312 IDE device driver, the character device example

will be the EP9312 touch screen device driver, and for a

network interface device the EP9312 Ethernet device driver

is examined. For each coding example, high levelAPI, hard-

ware interface, initialization sequence and application code

are examined

EP9312 System On Chip Layout

Figure 2 - EP9312 SOC hardware devices classified as Character devices highlighted

in Green, Block devices in Red, and Networking Interface devices in Blue

IIC-China/ESC-China 2004 7 Conference Proceedings 141

Character Device Driver Example:

Touch Screen Device Driver

The EP9312 touch screen controller is classified as a Linux

character device type due to the nature of data access through

this device, which is sequential only. The touch screen char-

acter driver is straightforward in its implementation - the

device is registered with the operating system and accessed

via a file system special file. The hardware specific code is

contained within a set of functions mapped to a table of file

operations. The implementation of this driver is traced in

this section starting with kernel initialization.

The function used to initialize the EP9312 touch screen


int __init ep93xx_ts_init(void)

This function performs two specific tasks - acquires the

device IRQ if the device is interrupt driven and registers the

touch screen device with the operating system.

The function request_irq() is called to request an IRQ

and register an interrupt handler function to handle any tasks

needed when the device causes a system interrupt.

Typically the function register_chrdev() is used to reg-

ister a character device. The function looks like this:

int register_chrdev(unsigned int major,

const char * name,

struct file_operations *fops)

This function sets up the kernel interface to the charac-

ter device hardware. The major number is used in mapping

the driver to the file system special file in the /dev direc-

tory. The device is given a name, which the kernel will use

to identify that device. And, the file_operations structure

holds a pointer to a table of function pointers. This table

points to hardware specific functions.

However, there are some character devices that don't fit

into a predefined category of character device. This group

of devices falls under the category of miscellaneous, grouped

together with major number 10, and registering devices with

the following function:

int misc_register(struct miscdevice * misc)

misc_register() calls register_chrdev() with the major

number 10, a device name and table of function pointers

passed in through the miscdevice data structure. The

miscdevice data structure also holds the minor number, used

by the device driver.

The following is the function call used to register to the

EP9312 touch screen in the device driver code:


The data structure ep93xx_ts_miscdev is the kernel ac-

cess to the touch screen hardware, and is defined as fol-


static struct miscdevice ep93xx_ts_miscdev =


EP93XX_TS_MINOR,/* device minor number */

"ep93xx_ts", /* name of the device */

&ep93xx_ts_fops /* device file operations */

/* table pointer */


The minor number is used by the miscellaneous device

driver to differentiate amongst devices.

Hardware interface functions are defined statically within

device driver and are accessed by the kernel through the

table of file operation function pointers passed to the OS

when the device is registered. The table of pointers is de-

fined as follows:

static struct file_operations ep93xx_ts_fops =



read: ep93xx_ts_read,

write: ep93xx_ts_write,

poll: ep93xx_ts_poll,

open: ep93xx_ts_open,

release: ep93xx_ts_release,

fasync: ep93xx_ts_fasync,


The next step after initializing the touch screen device

is to create the file system special file, enabling application

code to access the device. The call to the mknod utility to

create the special file for the EP9312 touch screen looks

like this:

mknod /dev/misc/ep93xx_ts c 10 240

This step is performed either during the Linux initial-

ization by an init file in the root file system. Or this can be

done manually from the command prompt.

The following is an example of user level application

code, which accesses the touch screen device via the file

system special file.

#define TS_DEV "/dev/misc/ep93xx_ts"

int read_ts()


int fd, nbytes;

short data[3];

fd = open("/dev/misc/ep93xx_ts", O_NONBLOCK);

if ( fd < 0 )


printf("Unable to open touch screen device %s!\n",




nbytes = read(pd_fd, data, sizeof(data));


if (nbytes != sizeof(data))

return 0;

return 1;


IIC-China/ESC-China 2004 7 Conference Proceedings142

Block Device Driver Example: IDE Device Drive

IDE devices that interface the EP9312 IDE controller are

classified as Linux block devices. These devices include

hard disk drives and CDROM drives. Random access of

data on these devices is the main reason for the classifica-

tion as block devices.

Compared to the simple interface implemented for the

touch screen, an IDE block device driver is quite complex.

The device driver is separated into several parts including

the kernel interface to the IDE block device, an internal

driver hardware interface which is setup for the IDE con-

troller with up to 4 individual IDE devices attached, a mod-

ule for the specific IDE device type (hard disk, floppy, etc),

and the architecture specific interface. Function pointers held

in the IDE device type data structure allows non-standard

architectures flexibility and extendibility by allowing hard-

ware/architecture specific functions to be called. Figure 3

shows the IDE block device driver organization. The imple-

mentation of this driver is traced in this section starting with

device driver initialization.

The high level IDE driver is initialized during Linux

kernel initialization or during module installation if the driver

is configured as a module. This document won't go into the

detail of the high level IDE driver initialization or setup.

Instead the focus is on the pieces of the driver, which are

customized to initialize and interface to the hardware. Dur-

ing high level IDE driver initialization, the following func-

tion is called to setup the IDE controller:

static __inline__ void ide_init_default_hwifs(void)

This function, defined in the file include/asm/mach/ide.h,

configures the hardware interface data structure for the non-

standard IDE controller, registers the EP9312 IDE interface

with the high level IDE driver, and sets up the IRQ for the


The IRQ setup done in the architecture specific initial-

ization code is merely to set a field in the hardware inter-

face data structure with platform IRQ number to be used by

the IDE interface. The call to request_irq() is taken care of

by the high level IDE driver.

Figure 3 - EP9312 IDE Device Driver Organization

The IDE hardware interface data structure is configured

by calling the following function, also defined in include/


static __inline__ void

ide_init_hwif_ports(hw_regs_t *hw,

int data_port,

int ctrl_port,

int *irq)

This function configures the non-standard EP9312 IDE

interface by setting up command and control register ad-

dresses in the hardware interface data structure and setting

up and enabling the interface on the EP9312.

After the function ide_init_default_hwifs (void) config-

ures the IDE controller and registers the hardware interface

with the high level IDE driver, the architecture specific in-

terface is further initialized with a call to the following func-


void ep93xx_ide_init(unsigned int * pointer)

This function is defined in the file drivers/ide/ide-

ep93xx.c and performs several tasks - maps the architec-

ture specific functions to function pointers held in the hard-

ware interface data structure and sets up the DMA interface

if DMA is enabled for the platform.

The architecture specific function pointer fields of the

IDE hardware interface data structure are shown:

typedef struct hwif_s


ide_rw_proc_t *rwproc;

ide_ideproc_t *ideproc;

ide_dmaproc_t *dmaproc;


} ide_hwif_t;

Where ideproc handles the PIO mode transfers, and is

mapped to the architecture specific function

ep93xx_ideproc(). Both rwproc and dmaproc handle the

DMA mode transfers. rwproc is mapped to

ep93xx_rwproc(), and dmaproc is mapped

ep93xx_dmaproc(). The high level IDE driver checks if

these pointers are null, if they are found to be null, then

default functions are used instead of the architecture spe-

cific functions. Both ideproc() and dmaproc() are IOCTL

based functions with implementing a set of ioctls defined

by the high level IDE driver. The rwproc() function sets up

IDE controller for a particular transfer speed and direction.

These EP9312 architecture specific functions are defined

in the file drivers/ide/ide-ep93xx.c. The function prototypes

look like this:

static void ep93xx_ideproc(ide_ide_action_t action,

ide_drive_t * drive, void * buffer, unsigned int count)

static void ep93xx_dmaproc(ide_dma_action_t action,

ide_drive_t *drive)

static void ep93xx_rwproc(ide_drive_t * drive,

ide_dma_action_t action)

IIC-China/ESC-China 2004 7 Conference Proceedings 143

Also a part of the architecture specific implementation

is a redefinition of several IDE generic macros. These are

the macros used to read/write directly to the IDE device.

The file /include/asm/mach/ide.h holds the macro mappings

to the EP9312 definitions.

#define OUT_BYTE(b, p) ep93xx_ide_outb((b), (p))

#define OUT_WORD(w, p) ep93xx_ide_outw((w), (p))

#define IN_BYTE(p) ep93xx_ide_inb((p))

#define IN_WORD(p) ep93xx_ide_inw((p))

Once the hardware interface (EP9312 IDE controller

interface) is initialized and registered with the high level

IDE driver, the high level IDE driver continues initializa-

tion by probing the hardware interface for IDE devices con-

nected. If a device is found, it is registered with the operat-

ing system. Registering the device with the operating sys-

tem maps the device with a table of operations that can be

performed on the device. This also gives the OS additional

information about the device needed to manage the device

as a resource. Additional information includes size, num-

ber of partitions, etc. The following is the function call used

to register an IDE hard disk:

register_disk (struct gendisk *gd, int drive,

unsigned minors,

struct block_device_operations *ops,

long size)

The high level IDE driver calls this function with values

for the function parameter gathered as the device is probed.

The first parameter, gd, is a data structure which describes

the layout of the disk. The second parameter, drive, is the

device number. For the EP9312, that device number is go-

ing to be either 0 or 1 as a maximum of two devices are

supported by the hardware. The third parameter, minors, is

the number of partitions on the disk, found when the device

is probed. The fourth parameter, block_device_operations,

is a table of function pointers, which is defined by the IDE

driver hard disk implementation. The functions mapped

into this table use the architecture specific functions to per-

form the various tasks. The final parameter, size, is the size

of device in sectors, also retrieved from the device directly.

The table of function pointers includes the following

operations for block devices:

7 open - initialization of device and driver instance.

7 release - shut down device and clean up driver instance.

7 ioctl - fill in the gaps, a form of message passing through

the kernel to the device driver.

7 check media change - deals with devices that support

removable media.

7 revalidate - deals with devices which support remov-

able media, usually device specific

The table of device operations for a block device does

not include any I/O operations. For block devices the re-

quest method is used to handle device I/O, and is associated

with a queue of pending I/O operations, thus further differ-

entiating this type of device from a character device. De-

fined by the high level IDE device driver, the request method

and queue are registered with the operating system and as-

sociated with the device major number.

In addition to registering the device with the operating

system, the high level IDE device driver also manages this

device locally using a data structure, which includes func-

tion pointers mapped to functions specific to the type of

IDE device. Shown below is the a portion of this data struc-

ture mapped to function specific to IDE hard disks:

static ide_driver_t idedisk_driver = {


cleanup: idedisk_cleanup,

standby: do_idedisk_standby,

flushcache: do_idedisk_flushcache,

do_request: do_rw_disk,

end_request: NULL,

ioctl: NULL,

open: idedisk_open,

release: idedisk_release,

media_change: idedisk_media_change,

revalidate: idedisk_revalidate,

pre_reset: idedisk_pre_reset,

capacity: idedisk_capacity,

special: idedisk_special,

proc: idedisk_proc,

reinit: idedisk_reinit,



Notice that some of the function pointers map directly

to the function pointers found in the table of file operations

registered with the OS, while the IDE device driver uses

others internally. The function pointers do_request and

end_request, for example, are used internally by the high

level device driver to handle the request method I/O.

That covers the architecture specific API of the IDE de-

vice driver. The next step is to create the file system special

file, thereby enabling user level applications access to this

device. To generate a special file for an IDE hard drive the

following command is used:

mknod /dev/hda1 b 3 1

As mentioned for the touch screen special file creation,

an init script can perform this step hduring system initial-

ization or a user can manually execute the command from a

command prompt once the system is up and running.

Block devices are rarely directly called from user level

applications. Typically block devices are accessed directly

via kernel level file system implementations. User level

applications usually access block devices with OS utilities

to perform file system operations, such as creating file sys-

tems, mounting devices to access file systems, etc. Com-

mand line tools are available for partitioning, formatting,

mounting, and verifying block devices. An example of a

command to mount the device created with the example

mnknod command is:

mount -t ext3 -o rw /dev/hda1 /mnt/drive

IIC-China/ESC-China 2004 7 Conference Proceedings144

where -t ext3 indicates that the device is configured with

an Extended 3 file system. -o rw indicates the device should

have read/write permissions, /dev/hda1 is the file system

special file for the device being mounted, and /mnt/drive is

the mount point where users access the contents of the file

system stored on the device

Adding New Device Driver Support to the Linux Kernel

The Linux kernel is built in three commands

make menuconfig (config, xconfig, oldconfig, etc.)

make dep


During the first step the Linux kernel is configured for

the target run environement. The user also has the option to

add in support for various devicdes, support for various file

systems, configure boot parameters, etc. When a new de-

vice driver is implemented in the Linux kernel, configura-

tion support for that new device must be added. This is

done by first updating the Makefile within the appropriate

device type subdirectory within the drivers directory. In

the Makefile an option must be added to build the device

driver binary and either link directly to the Linux kernel or

create as a module. The second task needed is to update the file within the device type subdirectory within

the drivers directory. Configuration options for this new

device must be added to


This document is not intended to fully break down Linux

device drivers in general. There are plenty of resources avail-

able to do that, including the Linux source code itself. In-

stead, this document explored the hardware APIs used to

implement device drivers for embedded, non-standard de-

vices. Using the EP9312 System on Chip platform as an

example, several device drivers, of different types are bro-

ken down to examine those APIs that are customized for

the hardware interface. Understanding how these APIs are

designed and implemented is the first step in writing a de-

vice driver for a new device.

Further Information

For further information the following resources are recom-


7 Linux Device Drivers by O'Reilly Press

7 General Linux reference

7 General embedded

Linux reference



Rubini, Alessandro, and Corbet, Jonathan. Linux Device

Drivers, Second Edition. O'Reilly. 2001

Linux kernel source code, version 2.4.19-test11

About the author

Tanya Ortega

Cirrus Logic, Inc.

2901 Via Fortuna, Austin, TX 78746, USA

Phone: (+1-512) 851 4956

Fax: (+1-512) 851 4898



Tanya Ortega is a Systems Software Engineer with Cirrus

Logic, Inc, where she develops embedded software forARM

based System on Chip devices. Projects include embedded

Linux board support packages and device drivers. Tanya

has been with Cirrus Logic since 2000. Prior to Cirrus, she

developed embedded application software for PowerPC plat-

forms with the Xerox Corporation. Tanya has been in the

industry since 1996, after earning her BS in Computer Sci-

ence at Northwestern University.

Comment on "Developing embedded Linux device dri..."
*  You can enter [0] more charecters.
*Verify code:


Visit Asia Webinars to learn about the latest in technology and get practical design tips.


Go to top             Connect on Facebook      Follow us on Twitter      Follow us on Orkut

Back to Top