~ 2 min read
Device drivers migration in Linux
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.