Skip to content

Driver Lifecycle

The lifecycle of a character device driver in the Linux kernel involves three critical phases: module initialization, device registration, and cleanup. Properly managing these stages ensures the driver operates reliably and avoids resource leaks. This section outlines the steps and best practices for each phase.

Module Initialization

When a module is loaded, the kernel invokes the module_init-marked function. This function must allocate resources, initialize data structures, and register the device. Global variables class and dev are used to ensure accessibility across both module_init and module_exit.

Example:

struct class *class;
dev_t dev;

static int __init my_init(void) {
    struct cdev my_cdev;
    struct file_operations fops = {
        .owner = THIS_MODULE,
        .open = my_open,
        .read = my_read,
        .write = my_write,
    };

    // Allocate a dynamic major number
    if (alloc_chrdev_region(&dev, 0, 1, "my_device") < 0) {
        return -ENOMEM;
    }

    // Initialize the cdev structure
    cdev_init(&my_cdev, &fops);
    if (cdev_add(&my_cdev, dev, 1) < 0) {
        unregister_chrdev_region(dev, 1);
        return -EFAULT;
    }

    // Create a device class and device node
    class = class_create(THIS_MODULE, "my_class");
    device_create(class, NULL, dev, NULL, "my_device");

    return 0;
}

Key steps:
1. Allocate a major number with alloc_chrdev_region.
2. Initialize the cdev structure with cdev_init.
3. Register the device with cdev_add.
4. Create a sysfs entry using device_create.

Cleanup Procedures

On module removal, the module_exit-marked function must un-register the device, release resources, and clean up allocated structures.

Example:

static void __exit my_exit(void) {
    // Destroy the device and class
    device_destroy(class, dev);
    class_destroy(class);

    // Remove the cdev and unregister the major number
    cdev_del(&my_cdev);
    unregister_chrdev_region(dev, 1);
}

Key takeaways

  • Module initialization uses module_init to allocate resources and register the device. Global variables class and dev ensure accessibility across both module_init and module_exit.
  • Device registration requires dynamic major number allocation (alloc_chrdev_region) and cdev_add for modern drivers.
  • Cleanup in module_exit must un-register the device, destroy sysfs entries, and release all allocated resources to avoid leaks.