~ 2 min read

Device drivers migration in Linux

share this story on
Moving from linux 2.4 to 2.6 by recompiling linux kernel device drivers

Migrating drivers is always a fun thing to do.

All most all migrations of device drivers from a 2.4 kernel to a 2.6 kernel has one thing in common and that’s handling of device node registration. If the 2.6 kernel supports devfs (CONFIG_DEVFS_FS) then it may be possible that API changes are very small if any although if the 2.6 version of the kernel you’re running doesn’t support DEVFS and requires manually allocating major and minor numbers to the new /dev structure then you’re up to some work, nothing too serious of course.

So this is really just the basics of things, starting with the includes it is possible to add backward compatibility for the driver to compile on a 2.4 kernel as well with something along the lines of:

#ifdef CONFIG_DEVFS_FS
#include

#else
#include
#endif

Then we need to deal with major and minor numbers, specifically if this is some third party, vendor owned driver then it is common that they make up major/minor pairs of their own imagination, thus:

#ifndef CONFIG_DEVFS_FS
#define DRV_MAJOR 200
#define DRV_MINOR 99
#define DRV_COUNT 1
char dev_name_DRV[] = "sample_drv";
#endif

when defining the driver’s structure there’s also a distinction that has to be made in how the device node is approached, and so:

typedef struct gpio_dev_stc {
int device_id;
char drvif_name[80];
#ifdef CONFIG_DEVFS_FS
devfs_handle_t handle;
#else
int major;
#endif
struct proc_dir_entry *procfs_entry;
} DRV_DEV;

And we continue on with these distinctions:

#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_dir_handle = NULL;
#else
static char devname[]="0";
static struct cdev drv_cdev;
#endif

Then we can jump right away to the __init module function and make appropriate changes for device registration, starting by defining 2 new variables:

int retval;
dev_t dev_id;

and then, for the actual device registration code

drv_dev->major = DRV_MAJOR;
if (drv_dev->major) {
dev_id = MKDEV(drv_dev->major, DRV_MINOR);
retval = register_chrdev_region(dev_id, DRV_COUNT, devname);
} else {
retval = alloc_chrdev_region(&dev_id, DRV_MINOR, DRV_COUNT, devname);
drv_dev->major = MAJOR(dev_id);
}

if (retval) {
printk(KERN_ERR "%s: can't get drivers major! %d\n", devname, drv_dev->major);
return -1;
}

cdev_init(&drv_dev, &drv_fops);
cdev_add(&drv_cdev, dev_id, DRV_COUNT);

and of course unregistering the driver is also required, so adding to __exit the following:

dev_t dev_id = MKDEV(drv_dev->major, 0);

cdev_del(&drv_cdev);
unregister_chrdev_region(dev_id, DRV_COUNT);

And we’re mostly done.

Don’t make of it a template, it’s simple an overview to give some general idea of how the API changes in 2.6 and how you can deal with device drivers migration.