modprobe - ¿Cómo crear un nodo de dispositivo a partir del código init_module de un módulo del kernel de Linux?
como cargar un modulo en linux (3)
Para tener más control sobre los números de dispositivo y la creación del dispositivo, puede realizar los siguientes pasos (en lugar de register_chrdev()
):
- Llame a
alloc_chrdev_region()
para obtener un número mayor y un rango de números menores para trabajar. - Crea una clase de dispositivo para tus dispositivos con
class_create()
. - Para cada dispositivo, llame a
cdev_init()
ycdev_add()
para agregar el dispositivo de caracteres al sistema. - Para cada dispositivo, llame a
device_create()
. Como resultado, entre otras cosas, Udev creará nodos de dispositivo para sus dispositivos. No hay necesidad demknod
o similares.device_create()
también le permite controlar los nombres de los dispositivos.
Probablemente hay muchos ejemplos de esto en la Red, uno de ellos está aquí .
Estoy escribiendo un módulo para el kernel de Linux y quiero crear algunos nodos de dispositivo en la función init
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
// Now I want to create device nodes with the returned major number
}
También quiero que el kernel asigne un número menor para mi primer nodo, y luego asignaré los números menores de los otros nodos por mi cuenta.
¿Cómo puedo hacer esto en el código. No quiero crear dispositivos desde la shell usando mknod
Ejemplo ejecutable mínimo
Minimizado de otras respuestas. GitHub upstream con configuración de prueba.
#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");
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;
}