如何从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() ):

  1. 调用alloc_chrdev_region()来获得一个主数字和一系列小数字来处理。
  2. class_create()为你的设备创build设备类。
  3. 对于每个设备,调用cdev_init()cdev_add()将字符设备添加到系统中。
  4. 对于每个设备,调用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");