Creating an interactive char driver is surprisingly simple, but there are a few traps along the way.
Exposing it to the File System
This is by far the hardest part to understand, but honestly a full understanding isn't really necessary. The new intro_init function looks like this:
#defineDEVICE_NAME"intro"#defineCLASS_NAME"intro"// setting up the deviceint major;staticstruct class* my_class =NULL;staticstruct device* my_device =NULL;staticint __init intro_init(void) { major =register_chrdev(0, DEVICE_NAME,&fops); // explained laterif ( major <0 )printk(KERN_ALERT "[Intro] Error assigning Major Number!");// Register device class my_class =class_create(THIS_MODULE, CLASS_NAME);if (IS_ERR(my_class)) {unregister_chrdev(major, DEVICE_NAME);printk(KERN_ALERT "[Intro] Failed to register device class\n"); }// Register the device driver my_device =device_create(my_class,NULL, MKDEV(major,0),NULL, DEVICE_NAME);if (IS_ERR(my_device)) {class_destroy(my_class);unregister_chrdev(major, DEVICE_NAME);printk(KERN_ALERT "[Intro] Failed to create the device\n"); }return0;}
A major number is essentially the unique identifier to the kernel module. You can specify it using the first parameter of register_chrdev, but if you pass 0 it is automatically assigned an unused major number.
We then have to register the class and the device. In complete honesty, I don't quite understand what they do, but this code exposes the module to /dev/intro.
Note that on an error it calls class_destroy and unregister_chrdev:
Cleaning it Up
These additional classes and devices have to be cleaned up in the intro_exit function, and we mark the major number as available:
staticvoid __exit intro_exit(void) {device_destroy(my_class, MKDEV(major,0)); // remove the deviceclass_unregister(my_class); // unregister the device classclass_destroy(my_class); // remove the device classunregister_chrdev(major, DEVICE_NAME); // unregister the major numberprintk(KERN_INFO "[Intro] Closing!\n");}
Controlling I/O
In intro_init, the first line may have been confusing:
major =register_chrdev(0, DEVICE_NAME,&fops);
The third parameter fops is where all the magic happens, allowing us to create handlers for operations such as read and write. A really simple one would look something like: