如何从Linux内核模块的init_module代码创build一个设备节点?
我正在为linux内核编写一个模块,我想在init函数中创build一些设备节点
int init_module(void) { Major = register_chrdev(0, DEVICE_NAME, &fops); // Now I want to create device nodes with the returned major number }
我也希望内核为我的第一个节点分配一个次要号码,然后我将自己分配其他节点的次要号码。
我怎样才能在代码中做到这一点。 我不想使用mknod从shell创build设备
要更好地控制设备号和创build设备,可以执行以下步骤(而不是register_chrdev()
):
- 调用
alloc_chrdev_region()
来获得一个主数字和一系列小数字来处理。 - 用
class_create()
为你的设备创build设备类。 - 对于每个设备,调用
cdev_init()
和cdev_add()
将字符设备添加到系统中。 - 对于每个设备,调用
device_create()
。 因此,除此之外, Udev将为您的设备创build设备节点。 不需要mknod
或类似的东西。device_create()
还允许您控制设备的名称。
网上可能有很多这样的例子, 其中之一就在这里 。
static int __init ofcd_init(void) /* Constructor */ { printk(KERN_INFO "Welcome!"); if (alloc_chrdev_region(&first, 0, 1, "char_dev") < 0) //$cat /proc/devices { return -1; } if ((cl = class_create(THIS_MODULE, "chardrv")) == NULL) //$ls /sys/class { unregister_chrdev_region(first, 1); return -1; } if (device_create(cl, NULL, first, NULL, "mynull") == NULL) //$ls /dev/ { class_destroy(cl); unregister_chrdev_region(first, 1); return -1; } cdev_init(&c_dev, &fops); if (cdev_add(&c_dev, first, 1) == -1) { device_destroy(cl, first); class_destroy(cl); unregister_chrdev_region(first, 1); return -1; } return 0; }
最小的可运行示例
最小化其他答案。 GitHub上游与testing设置。
#include <linux/cdev.h> #include <linux/device.h> #include <linux/fs.h> /* register_chrdev, unregister_chrdev */ #include <linux/module.h> #include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */ #define NAME "lkmc_character_device_create" static int major = -1; static struct cdev mycdev; static struct class *myclass = NULL; static int show(struct seq_file *m, void *v) { seq_printf(m, "abcd"); return 0; } static int open(struct inode *inode, struct file *file) { return single_open(file, show, NULL); } static const struct file_operations fops = { .llseek = seq_lseek, .open = open, .owner = THIS_MODULE, .read = seq_read, .release = single_release, }; static void cleanup(int device_created) { if (device_created) { device_destroy(myclass, major); cdev_del(&mycdev); } if (myclass) class_destroy(myclass); if (major != -1) unregister_chrdev_region(major, 1); } static int myinit(void) { int device_created = 0; /* cat /proc/devices */ if (alloc_chrdev_region(&major, 0, 1, NAME "_proc") < 0) goto error; /* ls /sys/class */ if ((myclass = class_create(THIS_MODULE, NAME "_sys")) == NULL) goto error; /* ls /dev/ */ if (device_create(myclass, NULL, major, NULL, NAME "_dev") == NULL) goto error; device_created = 1; cdev_init(&mycdev, &fops); if (cdev_add(&mycdev, major, 1) == -1) goto error; return 0; error: cleanup(device_created); return -1; } static void myexit(void) { cleanup(1); } module_init(myinit) module_exit(myexit) MODULE_LICENSE("GPL");