Automatically creating device nodes without the need of user using mknod
In our previous post, we have created a null device which acts a block hole. We will add logic in our driver code to avoid user using mknod to create /dev/my_null, instead allow driver to automatically create it on loading the module.
Code:
Output:
Notes:
Automatic creating/deleting of device nodes is handled by udev. For udev to work properly, device driver should expose major and minor number to sysfs, that is done by below API's
1. device_create — creates a device and registers it with sysfs. Verify it with (find /sys -name 'my_null')
2. class_create — create a struct class structure (ls -l /sys/class/my_driver_class)
Code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/kdev_t.h> | |
#include <linux/types.h> | |
#include <linux/fs.h> | |
#include <linux/cdev.h> | |
MODULE_LICENSE("GPL"); | |
dev_t device_number; | |
bool dynamic = true; | |
struct class *my_class; | |
static struct cdev my_cdev; | |
static int mydevice_open(struct inode *inode, struct file *file) | |
{ | |
pr_info("%s\n", __func__); | |
return 0; | |
} | |
static int mydevice_release(struct inode *inode, struct file *file) | |
{ | |
pr_info("%s\n", __func__); | |
return 0; | |
} | |
ssize_t mydevice_read(struct file *file, char __user *user_buffer, | |
size_t count, loff_t *offset) | |
{ | |
pr_info("%s\n", __func__); | |
return 0; | |
} | |
ssize_t mydevice_write(struct file *file, const char __user *user_buffer, | |
size_t count, loff_t *offset) | |
{ | |
pr_info("%s\n", __func__); | |
return count; | |
} | |
struct file_operations fops = { | |
.owner = THIS_MODULE, | |
.open = mydevice_open, | |
.release = mydevice_release, | |
.read = mydevice_read, | |
.write = mydevice_write | |
}; | |
static int mynull_device_init(void) | |
{ | |
int retval; | |
pr_info("%s: In init\n", __func__); | |
if (dynamic) { | |
retval = alloc_chrdev_region(&device_number, 0, 1, "embedded"); | |
} | |
else { | |
device_number = MKDEV(180, 0); | |
retval = register_chrdev_region(device_number, 1, "embedded"); | |
} | |
if (!retval) { | |
pr_info("%s: Major Number:%d\t Minor Number:%d\n", | |
__func__, MAJOR(device_number), MINOR(device_number)); | |
my_class = class_create(THIS_MODULE, "my_driver_class"); | |
cdev_init(&my_cdev, &fops); | |
retval = cdev_add(&my_cdev, device_number, 1); | |
if (retval) { | |
pr_info("%s: Failed in adding cdev to subsystem " | |
"retval:%d\n", __func__, retval); | |
} | |
else { | |
device_create(my_class, NULL, device_number, NULL, "my_null"); | |
} | |
} | |
else | |
pr_err("%s: Failed in allocating device number " | |
"Error:%d\n", __func__, retval); | |
return retval; | |
} | |
static void mynull_device_exit(void) | |
{ | |
cdev_del(&my_cdev); | |
device_destroy(my_class, device_number); | |
class_destroy(my_class); | |
unregister_chrdev_region(device_number, 5); | |
pr_info("%s: In exit\n", __func__); | |
} | |
module_init(mynull_device_init); | |
module_exit(mynull_device_exit); |
Output:
Notes:
Automatic creating/deleting of device nodes is handled by udev. For udev to work properly, device driver should expose major and minor number to sysfs, that is done by below API's
1. device_create — creates a device and registers it with sysfs. Verify it with (find /sys -name 'my_null')
2. class_create — create a struct class structure (ls -l /sys/class/my_driver_class)
Comments
Post a Comment