Oct 31, 2008

writing the linux device driver

Does the idea of writing a Linux device driver sound difficult? If you have some basic programming experience, the task issimpler than you think. Get started with this quick primer ondevice driver programming 

What do I need to know about writing drivers? 
Basic knowledge of kernel compilation, a good deal of programmingexperience in C under Linux and lastly, the right techniques of datastructures, like linked list is essential along with their data types. 
The first thing a programmer must know before attempting to write adriver, is to know how the Linux kernel source compiles, paying attentionto the compilation process (the gcc compiler flags).



Choosing the device type 



a) Block drivers 
A block device is something that can host a filesystem such as a disk. Ablock 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 chardriver is in charge of implementing this behaviour. This driver implementsthe open, close, read and write system calls. The console and parallelports are examples of char devices.
Device drivers in Linux are known as modules and can be loaded dynamicallyinto the kernel using the insmod command.A single module can be compiled alone, and also can be linked to thekernel (here, care has to be taken on the type of driver). 


eg: A simple module 
#define MODULE#include 
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 runsthe module's init function. 
The module image begins with a module structure and is followed by codeand data as appropriate. 
The module structure is defined as follows: 
struct module 
{ 
unsigned long size_of_struct; 
struct module *next;const char *name; 
unsigned long size; 
long usecount; 
unsigned long flags; 
unsigned int nsyms; 
unsigned int ndeps; 
struct module_symbol *syms;struct module_ref *deps;struct module_ref *refs; 
int (*init)(void); 
void (*cleanup)(void); 
const struct exception_table_entry *ex_table_start; 
const struct exception_table_entry *ex_table_end; 
#ifdef __alpha__unsigned long gp; 
#endif 
} 
; 
All of the pointer fields, with the exception of next and refs, areexpected to point within the module body and be initialized as appropriatefor kernel space, i.e. relocated with the rest of the module. 

Return Values 
On success, zero is returned. On error, -1 is returnedand 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->namedoes 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 accessibleaddress space. 

How cleanup_module works? 
cleanup_module attempts to remove an unused loadable module entry. Ifname 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 isset 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 addressspace.This simple module is called skull, short for Simple Kernel Utility ForLoading Localities. 

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 itwill be linked to. Each module defines a symbol called kernel_versionwhich is defined in . In case of a version mismatch, usethe insmod -f (force) option to load the module.