Labels

Friday, 29 May 2015

how to write a simple device driver program???

Prerequisites : Before proceeding further about device driver programming some prerequisites is needed.
  • User Space and Kernel Space
A module runs in kernel space, whereas applications run in user space.
  • supervisor mode and user mode
Under Unix, the kernel executes in the highest level (also called supervisor mode), where everything is allowed, whereas applications execute in the lowest level (the so-called user mode), where the processor regulates direct access to hardware and unauthorized access to memory.

  • Applications are laid out in virtual memory with a very large stack area. The stack, of course, is used to hold the function call history and all automatic variables created by currently active functions. 
  • The kernel, instead, has a very small stack; it can be as small as a single, 4096-byte page. Your functions must share that stack with the entire kernel-space call chain. Thus, it is never a good idea to declare large auto-matic variables; if you need larger structures, you should allocate them dynamically at call time.
  • Often, as you look at the kernel API, you will encounter function names starting with a double underscore ( __ ). Functions so marked are generally a low-level component of the interface and should be used with caution. Essentially, the double underscore says to the programmer: “If you call this function, be sure you know what you are doing”.
  • Kernel code cannot do floating point arithmetic. Enabling floating point would require that the kernel save and restore the floating point  processor’s state on each entry to, and exit from, kernel space—at least, on some architectures. Given that there really is no need for floating point in kernel code, the extra overhead is not worthwhile.

Introduction to character device drivers with sample program:

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);
This module defines two functions.
  • one to be invoked when the module is loaded into the kernel (hello_init
  • And one for when the module is removed (hello_exit).
The module_init and module_exit lines use special kernel macros to indicate the role of these two functions. 
Another special macro (MODULE_LICENSE) is used to tell the kernel that this module bears a free license; without such a declaration, the kernel complains when the module is loaded. 

The printk function is defined in the Linux kernel and made available to modules; it behaves similarly to the standard C library function printf. The kernel needs its own printing function because it runs by itself, without the help of the C library. The module can call printk because, after insmod has loaded it, the module is linked to the kernel and can access the kernel’s public symbols . The string KERN_ALERT is the priority of the message.

You can test the module with the insmod and rmmod utilities, as shown below. Note: Only the superuser can load and unload a module.

output:
root# insmod ./hello.ko
Hello, world
root# rmmod hello
Goodbye cruel world
root#
In particular, the previous screen dump was taken from a text console; if you are running insmod and rmmod from a terminal emulator running under the window system, you won’t see anything on your screen. The message goes to one of the system log files, such as /var/log/messages (the name of the actual file varies between Linux distributions), or you can see using dmesg command typing in linux terminal.

Compiling and Loading:

To compile and build the module there are two ways

1.directly compiling code by entering entire command.
2.write a simple make file, which is nothing but a kind of script file.

I recommend you to use make file. make file has lot of advantages. we can discuss in further posts regarding make file and its usage.

case 1 (with out make file):

Consider you have a module called module.ko that is generated from two source
files (called, say, file1.c and file2.c), the correct incantation would be:
obj-m := module.o
module-objs := file1.o file2.o

If your kernel source tree is located in, say,your ~/kernel-2.6 directory, the make command required to build your module (typed in the directory containing the module source and makefile) would be:
make -C ~/kernel-2.6 M=`pwd` modules
This command starts by changing its directory to the one provided with the -C option (that is, your kernel source directory). There it finds the kernel’s top-level
makefile. The M= option causes that makefile to move back into your module source directory before trying to build the modules target. This target, in turn, refers to the list of modules found in the obj-m variable, which we’ve set to module.o in our examples.

case 2 (with make file):

obj-m := hello.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
or
obj-m := hello.o
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
After the module is built, the next step is loading it into the kernel. insmod loads the module code and data into the kernel, which, in turn, performs a function similar to that of ld, in that it links any unresolved symbol in the module to the symbol table of the kernel. 

modprobe, like insmod, loads a module into the kernel. It differs in that it will look at the module to be loaded to see whether it references any symbols that are not currently defined in the kernel. If any such references are found, modprobe looks for other modules in the current module search path that define the relevant symbols. When modprobe finds those modules (which are needed by the module being loaded), it loads them into the kernel as well.
If you use insmod in this situation instead, the command fails with an “unresolved symbols” message left in the system logfile.

modules may be removed from the kernel with the rmmod utilty. Note that module removal fails if the kernel believes that the module is still in use (e.g., a program still has an open file for a device exported by the modules), or if the kernel has been configured to disallow module removal. It is possible to configure the kernel to allow “forced” removal of modules, even when they appear to be busy. If you reach a point where you are considering using this option, however, things are likely to have gone wrong badly enough that a reboot may well be the better course of action.

Version Dependency:
# insmod hello.ko
Error inserting './hello.ko': -1 Invalid module format
A look in the system log file (/var/log/messages or whatever your system is configured to use) will reveal the specific problem that caused the module to fail to load. If you need to compile a module for a specific kernel version, you will need to use the build system and source tree for that particular version. A simple change to the KERNELDIR variable in the example makefile shown previously does the trick.

Preliminaries:
#include <linux/module.h>
#include <linux/init.h>
module.h contains a great many definitions of symbols and functions needed by loadable modules. You need init.h to specify your initialization and cleanup functions, as we saw in the “hello world” example.

It is not strictly necessary, but your module really should specify which license
applies to its code. Doing so is just a matter of including a MODULE_LICENSE line:
MODULE_LICENSE("GPL");
Other descriptive definitions that can be contained within a module include
MODULE_AUTHOR (stating who wrote the module), MODULE_DESCRIPTION (a human-readable statement of what the module does), MODULE_VERSION (for a code revision number; see the comments in <linux/module.h> for the conventions to use in creating version strings), MODULE_ALIAS (another name by which this module can be known), and MODULE_DEVICE_TABLE (to tell user space about which devices the module supports).

example 2:

static int __init initialization_function(void)
{
/* Initialization code here */
}
module_init(initialization_function);
Initialization functions should be declared static , since they are not meant to be visible outside the specific file; there is no hard rule about this, though, as no function is exported to the rest of the kernel unless explicitly requested. 

The __init token in the definition may look a little strange; it is a hint to the kernel that the given function is used only at initialization time. The module loader drops the initialization function after the module is loaded, making its memory available for other uses.


static void __exit cleanup_function(void)
{
/* Cleanup code here */
}
module_exit(cleanup_function);
The cleanup function has no value to return, so it is declared void . The __exit modifier marks the code as being for module unload only (by causing the compiler to place it in a special ELF (Executable Linkable Format) section). If your module is built directly into the kernel, or if your kernel is configured to disallow the unloading of modules, functions marked __exit are simply discarded. For this reason, a function marked __exit can be called only at module unload or system shutdown time.

soooo you did it...
you learned how to write a simple kernel program...
thanks.

No comments:

Post a Comment