Writing Device Drivers in Linux

2 views
Skip to first unread message

achindra...@gmail.com

unread,
May 24, 2005, 7:04:57 AM5/24/05
to giGA...@googlegroups.com
Device drivers take on a special role in the Linux kernel. They are
distinct "black boxes" that make a particular piece of hardware respond
to a well-defined internal programming interface; they hide completely
the details of how the device works. User activities are performed by
means of a set of standardized calls that are independent of the
specific driver; mapping those calls to device-specific operations that
act on real hardware is then the role of the device driver. This
programming interface is such that drivers can be built separately from
the rest of the kernel, and "plugged in" at runtime when needed. This
modularity makes Linux drivers easy to write, to the point that there
are now hundreds of them available.

The distinction between mechanism and policy is one of the best ideas
behind the Unix design. Most programming problems can indeed be split
into two parts: "what capabilities are to be provided" (the mechanism)
and "how those capabilities can be used" (the policy). If the two
issues are addressed by different parts of the program, or even by
different programs altogether, the software package is much easier to
develop and to adapt to particular needs.

Many modern operating systems have a method for installing special
files to make hardware work. On the Apple Mac, for instance, the
drivers for the hardware devices are usually special files that go in
the System Extensions folder. Linux also has special files that it uses
to control the hardware.

Linux device drivers work through special kernel code that directly
accesses the hardware. To make the services that the card or other
device offers available to normal user programs, the kernel uses the
special files in /dev

One end of the file in /dev can be opened normally and the other end is
attached to the kernel. That is of course an oversimplification, but I
think you get the general idea: hardware, kernel, special file, user
program and the same path back from user program to hardware. There are
two forms of the kernel portion of this equation: compiled-in drivers
that are coded in permanently when the kernel is built, and modules.


There are basicly three types of device drivers in linux
Block, Character and mixed mode(hybrid)

a) Block drivers

A block device is something that can host a filesystem such as a disk.
A block device can only be accessed as multiples of a block, where a
blockis usually one kilobyte of data .

b) Character drivers

A character device is one that can be accessed like a file, and a char
driver is in charge of implementing this behaviour. This driver
implements the open, close, read and write system calls. The console
and parallelports are examples of char devices.

A single module can be compiled alone, and also can be linked to the
kernel (at the run time, when it is loaded).

eg: A simple module

#define MODULE
#include <linux/module.h>

int init_module (void) /* Loads a module in the kernel */
{
printk("Hello kernel n");
return 0;
}

void cleanup_module(void) /* Removes module from kernel */
{
printk("GoodBye Kerneln");
}

Compiling the module

# gcc -c hello.c
# insmod hello.o

The output is

Hello kernel

# rmmod hello.o

GoodBye Kernel


How init_module works?


init_module loads the relocated module image into kernel space and runs
the module's init function.

there is no user space library available to kernel code (device driver)
so we can't use printf(libc) or any other. Kernel has its own set of
libraries, where a kernel version of printf is available as printk.

there is no main module in module code, init_module is the entry point
to the device driver, where all initialization takes place.

The module image begins with a module structure and is followed by code
and data as appropriate.

Return Values

On success, zero is returned. On error, -1 is returned and errno is set
appropriately.

Errors

EPERM The user is not the superuser.

ENOENT No module by that name exists.

EINVAL Some image slot filled in incorrectly, image->name does not
correspond to the original module name, some image->deps entry does not
correspond to aloaded module, or some other similar inconsistency.

EBUSY The module's initialization routine failed.

EFAULT name or image is outside the program's accessible address space.


How cleanup_module works?


cleanup_module attempts to remove an unused loadable module entry. If
name is NULL, all unused modules marked auto clean will be removed.

Return Values

On success, zero is returned. On error, -1 is returned and errno is set
appropriately.

Errors

EPERM The user is not the superuser.

ENOENT No module by that name exists.

EINVAL name was the empty string.

EBUSY The module is in use.

EFAULT name is outside the program's accessible address space.


General flags used for compiling any driver are

-D__KERNEL__ _DMODULE -O -Wall -I$(INCLUDEDIR)

Note: The INCLUDEDIR should contain the header files of the kernel
source.


Module code has to be recompiled for each version of the kernel that it
will be linked to. Each module defines a symbol called kernel_version
which is defined in <linux/module.h>. In case of a version mismatch,
use the insmod -f (force) option to load the module.

Reply all
Reply to author
Forward
0 new messages