#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
static dev_t dev_nr;
static struct cdev my_cdev;
static struct class *my_class;
static ssize_t my_read(struct file *f, char __user *u, size_t l, loff_t *o)
{
pr_info("hello_cdev - Read is called\n");
return 0;
}
static struct file_operations fops = {
.read = my_read
};
static int __init my_init(void)
{
int status;
#ifdef STATIC_DEVNR
dev_nr = STATIC_DEVNR;
status = register_chrdev_region(dev_nr, MINORMASK + 1, "hello_cdev");
#else
status = alloc_chrdev_region(&dev_nr, 0, MINORMASK + 1, "hello_cdev");
#endif
if (status) {
pr_err("hello_cdev - Error reserving the region of device numbers\n");
return status;
}
cdev_init(&my_cdev, &fops);
my_cdev.owner = THIS_MODULE;
status = cdev_add(&my_cdev, dev_nr, MINORMASK + 1);
if (status) {
pr_err("hello_cdev - Error adding cdev\n");
goto free_devnr;
}
pr_info("hello_cdev - Registered a character device for Major %d starting with Minor %d\n", MAJOR(dev_nr), MINOR(dev_nr));
my_class = class_create("my_class");
if (!my_class) {
pr_err("hello_cdev - Could not create class my_class\n");
status = ENOMEM;
goto delete_cdev;
}
if (!device_create(my_class, NULL, dev_nr, NULL, "hello%d", 0)) {
pr_err("hello_cdev - Could not create device hello0\n");
status = ENOMEM;
goto delete_class;
}
pr_info("hello_cdev - Created device under /sys/class/my_class/hello0\n");
return 0;
delete_class:
class_unregister(my_class);
class_destroy(my_class);
delete_cdev:
cdev_del(&my_cdev);
free_devnr:
unregister_chrdev_region(dev_nr, MINORMASK + 1);
return status;
}
static void __exit my_exit(void)
{
device_destroy(my_class, dev_nr);
class_unregister(my_class);
class_destroy(my_class);
cdev_del(&my_cdev);
unregister_chrdev_region(dev_nr, MINORMASK + 1);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Johannes 4Linux");
MODULE_DESCRIPTION("A sample driver for manually registering a character device");
和lesson9 相比就添加了如下代码:
static struct class *my_class;
添加了一个叫my_class 的静态结构。class 在c++中很常见,有公有私有保护数据(public/private/protected),但是c里面是没有类这个数据结构的,在c中最类似的是结构(strcut),但是struct 中都是公有数据。这里等于C++中给了一个全局变量的公共类。
my_class = class_create("my_class");
if (!my_class) {
pr_err("hello_cdev - Could not create class my_class\n");
status = ENOMEM;
goto delete_cdev;
}
if (!device_create(my_class, NULL, dev_nr, NULL, "hello%d", 0)) {
pr_err("hello_cdev - Could not create device hello0\n");
status = ENOMEM;
goto delete_class;
}
class_create():
dynamically creates a device class in the Linux kernel, allowing automatic management of device nodes and integration with sysfs.
device_create():
To create a device in Linux using the device_create function, follow these steps:
-
Include the necessary header file in your kernel module:#include <linux/device.h>
-
Ensure that a class has been created using the class_create function. This class will be associated with the device:
my_class = class_create("my_class");
- Use the device_create function to dynamically create the device: struct device *my_device = device_create(my_class, NULL, dev_t, NULL, "device_name"); Replace my_class with the pointer to your class. Use NULL for the parent device if there is no parent. Provide the dev_t (device number) for the device. Use NULL for driver-specific data if not needed. Specify the name of the device (e.g., "device_name").
- Verify that the device is successfully created by checking the return value of device_create . It should return a valid pointer to the struct device:
if (!device_create(my_class, NULL, dev_nr, NULL, "hello%d", 0)) {
pr_err("hello_cdev - Could not create device hello0\n");
status = ENOMEM;
goto delete_class;
}
- The device will now appear in /sys/devices/virtual and /dev directories.
这样在device_create()/class_create()之后就直接添加了设备,不需要mknod来执行,这无疑更方便。