Simple Linux Device Driver (sysfs)

This will create a new folder called “driver” with any necessary parent directories if they don’t already exist.

2. Next, create a C file that contains your device driver code. Let’s call it `etx_driver.c`. Inside this file, add the following:

// This script is used to create a new folder called "driver" and a C file named "etx_driver.c" for device driver code.

// Include necessary libraries for the script to run
#include <linux/module.h> // This library contains functions for loading and unloading modules
#include <linux/kernel.h> // This library contains functions for kernel operations
#include <linux/init.h> // This library contains functions for module initialization and cleanup
#include <linux/fs.h> // This library contains functions for file system operations

#include <asm/io.h> // This library contains functions for input/output operations
#include <misc/printk.h> // This library contains functions for printing messages to the kernel log

// Module initialization function
static int __init etx_driver_init(void) {
    printk(KERN_INFO "ETX driver loaded"); // Print message to kernel log indicating module has been loaded
    return 0; // Return 0 to indicate successful initialization
}

// Module cleanup function
static void __exit etx_driver_exit(void) {
    printk(KERN_INFO "ETX driver unloaded"); // Print message to kernel log indicating module has been unloaded
}

// Register module initialization and cleanup functions
module_init(etx_driver_init); // Register module initialization function
module_exit(etx_driver_exit); // Register module cleanup function

MODULE_LICENSE("GPL"); // Specify the license for the module
MODULE_AUTHOR("Your Name"); // Specify the author of the module
MODULE_DESCRIPTION("ETX driver"); // Specify a description for the module

3. Add the following code to initialize your device driver:

// This function is used to initialize the device driver
static int __init etx_driver_init(void) {
    // Allocate major number for our device driver
    if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0) { // allocates a major number for the device driver
        printk("Cannot allocate major number\n"); // prints an error message if allocation fails
        return -1;
    }
    
    // Create cdev structure and add it to the system
    if ((cdev_add(&etx_cdev, dev, 1)) < 0) { // creates a cdev structure and adds it to the system
        printk("Cannot add the device to the system\n"); // prints an error message if adding fails
        goto r_class; // jumps to the r_class label if adding fails
    }
    
    // Create struct class for our driver
    if (IS_ERR(dev_class = class_create(THIS_MODULE, "etx_class"))) { // creates a struct class for the driver
        printk("Cannot create the struct class\n"); // prints an error message if creation fails
        goto r_class; // jumps to the r_class label if creation fails
    }
    
    // Create device inside /sys/kernel directory using sysfs
    if (IS_ERR(device_create(dev_class, NULL, dev, NULL, "etx_device"))) { // creates a device inside the /sys/kernel directory using sysfs
        printk("Cannot create the Device 1\n"); // prints an error message if creation fails
        goto r_device; // jumps to the r_device label if creation fails
    }
    
    // Create a directory in /sys/kernel/ using sysfs
    kobj_ref = kobject_create_and_add("etx_sysfs", kernel_kobj); // creates a directory in the /sys/kernel/ using sysfs
    
    // Create sysfs file for etx_value
    if (sysfs_create_file(kobj_ref, &etx_attr.attr)) { // creates a sysfs file for etx_value
        printk("Cannot create sysfs file......\n"); // prints an error message if creation fails
        goto r_sysfs; // jumps to the r_sysfs label if creation fails
    }
    
    // Print a message to indicate successful driver insertion
    pr_info("Device Driver Insert...Done!!!\n"); // prints a message to indicate successful insertion of the driver
    return 0; // returns 0 to indicate successful initialization
    
r_sysfs:
    kobject_put(kobj_ref); // releases the reference to the kobject
    sysfs_remove_file(kernel_kobj, &etx_attr.attr); // removes the sysfs file for etx_value
    device_destroy(dev_class, dev); // destroys the device created in the /sys/kernel directory
r_device:
    class_destroy(dev_class); // destroys the struct class for the driver
r_class:
    unregister_chrdev_region(dev, 1); // unregisters the allocated major number
    return -1; // returns -1 to indicate failure in initialization
}

4. Create a header file called `etx_driver.h`. Inside this file, add the following:

// This script is used to create a header file called `etx_driver.h` and define necessary variables and structures for the ETX driver.

// Include guard to prevent multiple inclusions of the header file
#ifndef _ETX_DRIVER_H_
#define _ETX_DRIVER_H_

// Define a structure for the ETX device
struct etx_dev {
    int value; // This variable will hold the value of the device
};

// Declare external variables and structures that will be used in the driver
extern struct class *etx_class; // This variable will hold the class of the device
extern dev_t dev; // This variable will hold the device number
extern struct cdev etx_cdev; // This variable will hold the character device structure
extern struct device *etx_device; // This variable will hold the device structure
extern struct attribute *sysfs_attrs[]; // This array will hold the attributes for the sysfs
extern const struct attribute_group sysfs_attr_group; // This variable will hold the attribute group for the sysfs

#endif // _ETX_DRIVER_H_

5. Create a `Makefile`. Inside this file, add the following:

# This Makefile script is used to compile a driver module for the Linux kernel.

# The obj-m variable is used to specify the object files that will be linked to create the driver module.
obj-m += driver.o

# The KDIR variable is used to specify the location of the kernel source code.
KDIR := /lib/modules/$(shell uname -r)/build

# The all target is used to compile the driver module.
all:
    # The make command is used to compile the driver module.
    # The -C flag is used to specify the directory where the kernel source code is located.
    # The M flag is used to specify the directory where the driver source code is located.
    # The modules option is used to compile all modules in the specified directory.
    make -C $(KDIR) M=$(shell pwd) modules

# The clean target is used to remove any compiled files.
clean:
    # The make command is used to clean the compiled files.
    # The -C flag is used to specify the directory where the kernel source code is located.
    # The M flag is used to specify the directory where the driver source code is located.
    # The clean option is used to remove all compiled files in the specified directory.
    make -C $(KDIR) M=$(shell pwd) clean

6. Finally, create a `.config` file inside your driver directory with the following content:

# This Makefile script is used to compile a simple Linux device driver that utilizes the sysfs interface.

# The first line specifies the target of the Makefile, which is the driver module.
obj-m += driver.o

# The next line specifies the source file for the driver.
driver-objs := driver_main.o

# The following line specifies the location of the kernel source code.
KDIR := /lib/modules/$(shell uname -r)/build

# The next line specifies the target of the Makefile, which is the driver module.
all:
	# The command below uses the kernel source code to compile the driver module.
	make -C $(KDIR) M=$(PWD) modules

# The following line specifies the target of the Makefile, which is the driver module.
clean:
	# The command below removes any compiled files and temporary files.
	make -C $(KDIR) M=$(PWD) clean

# The following line specifies the target of the Makefile, which is the driver module.
install:
	# The command below installs the driver module to the appropriate directory.
	# The driver module is also loaded into the kernel.
	make -C $(KDIR) M=$(PWD) modules_install

# The following line specifies the target of the Makefile, which is the driver module.
uninstall:
	# The command below removes the driver module from the kernel.
	make -C $(KDIR) M=$(PWD) modules_uninstall

# The following line specifies the target of the Makefile, which is the driver module.
help:
	# The command below displays the available targets and their functions.
	@echo "Targets:"
	@echo "all - compile the driver module"
	@echo "clean - remove compiled files and temporary files"
	@echo "install - install the driver module to the appropriate directory"
	@echo "uninstall - remove the driver module from the kernel"
	@echo "help - display available targets and their functions"

7. Build and test your driver using the following commands:

– `make` to compile the code
– `sudo insmod driver.ko` to load the module into the kernel
– `ls -l /sys/kernel/etx_sysfs` to check if the sysfs file was created successfully.

SICORPS