1. Linux 2.6 Device Drivers and LKM
Unified framework for device drivers.
Complete support for device plug and play, power management by
defining the interfaces that these subsystems can use when
communicating with individual driver.
Sysfs filesystem to provide a hierarchical view of each system’s
device tree (prevent loading of proc filesystem).
New naming convention for loadable kernel modules using the .ko
extension (kernel object).
2. Updating the basic structure of a device driver
You must use the module_init() and module_exit() macros to register
the names of your initialization and exit routines.
#define MODULE statement is no longer necessary, either in your
code or in your make file.
You need to add an instance of the MODULE_LICENSE() macro,
such as the following:
MODULE_LICENSE(“GPL”);
3. A generic template for a minimal 2.6 device driver would be the
following:
#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static int __init
name_of_initialization_routine(void) {
/* code goes here */
return 0;
}
static void __exit
name_of_cleanup_routine(void) {
/* code goes here */
}
module_init(name_of_initialization_routine);
module_exit(name_of_cleanup_routine);
4. Changes to the build process for the module
Under 2.4, to produce a LKM named testmod.o
gcc –D__KERNEL__ -DMODULE –I/usr/src/linux-2.4.21/include
-O2 –c testmod.c
In 2.6, you don’t have to specify MODULE oriented declarations
such as MODULE, __KERNEL__ or –O2 options.
The 2.6 compatible Makefile for the module testmod.ko
obj-m := testmod.o
A simple command line for building a module
#make –C /usr/src/linux-2.6.1 SUBDIRS=$PWD modules
assumes, your module’s source code and Makefile are located at the
same directory.
5. Other 2.6 related changes
- Kernel’s asynchronous I/O mechanism
- DMA support layer
- Memory and page allocation mechanism
- The block device driver, a new generic disk interface
Allowing and managing memory and pages using a new standard
interface, known as mempool.
Module reference counts, are managed and manipulated differently.
Task queues replaced with work queues.
6. Other 2.6 related changes…
MODULE_PARAM() macro replaced by explicit parameter
declaration using the new module_param() macro.
Enhanced preemptibility and SMP awareness of the 2.6 Linux kernel,
some concern for drivers. Should use spinlock or mutex to protect
data.
Use of devfs filesystem marked as obsolete during 2.6 Linux kernel
configuration. devfs is an intermediate steps between the hard coded
device nodes and the integration of udev, hot plug and the sysfs
file system.
7. Char Device Registration
Two ways to define cdev structure (represents the char device)
- struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
- void cdev_init(struct cdev *dev, struct file_operations *fops);
To resister a char device
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
To remove a char device from the system:
void cdev_del(struct cdev *dev);
8. The inode structure
inode structure is used by the kernel to represent files. Two fields of
this structure are:
dev_t i_rdev;
struct cdev *i_cdev; // represents char devices.
Two macros to obtain the major and minor number from an inode
unsigned int iminor(struct inode inode);
unsigned int imajor(struct inode *inode);
9. Work Queue
Two mechanism to implement bottom half processing: tasklets and
workqueue.
Tasklets are very fast, but all tasklet code must be atomic.
Workqueue higher latency, but allowed to sleep.
static struct work_struct short_wq;
INIT_WORK(&short_wq, (void (*) (void *))short_do_tasklet,
NULL);
/* in interrupt handler */
schedule_work(&short_wq);
Workqueue have a type of struct workqueue_struct defined in
<linux/workqueue.h>
11. Disk Registration
struct gendisk (<linux/gendisk.h>) is the kernel’s representation of
an individual disk driver.
Fields :
int major
int firstminor
int minors
char disk_name[32]
struct block_device_operations *fops
struct request_queue *queue
structure used by kernel to manage I/O
requests for this device
int flags
sector_t capacity
void *private_data
12. Disk Registration
A set of functions working with gendisk structure.
struct gendisk *alloc_disk(int minors);
When a disk is no longer need, it should be freed.
void del_gendisk(struct gendisk *gd);
You must initialize the structure and call add_disk
void add_disk(struct gendisk *gd);