2011-05-11 8 views
36

Estoy escribiendo un módulo para el kernel de Linux y quiero crear algunos nodos de dispositivos en la función init¿Cómo crear un nodo de dispositivo a partir del código init_module de un módulo kernel de Linux?

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 quieren que el kernel para asignar un número menor para mi primer nodo y, a continuación, voy a asignar los números menores de los otros nodos por mí mismo.

¿Cómo puedo hacer esto en el código. No quiero crear dispositivos de la cáscara utilizando mknod

Respuesta

64

Para tener más control sobre los números de dispositivo y la creación de dispositivos que podría hacer los siguientes pasos (en lugar de register_chrdev()):

  1. llamada alloc_chrdev_region() para obtener una número principal y un rango de números menores para trabajar.
  2. Cree la clase de dispositivo para sus dispositivos con class_create().
  3. Para cada dispositivo, llame al cdev_init() y cdev_add() para agregar el dispositivo de caracteres al sistema.
  4. Para cada dispositivo, llame al device_create(). Como resultado, entre otras cosas, Udev creará nodos de dispositivos para sus dispositivos. Sin necesidad de mknod o similar. device_create() también le permite controlar los nombres de los dispositivos.

Probablemente haya muchos ejemplos de esto en la red, one of them is here.

+0

Gracias. Su respuesta y el código de ejemplo fueron muy útiles – Alptugay

+2

Perdón por excavar esto del pasado, pero ¿existe un método equivalente de hacerlo cuando la licencia no es GPL? class_create no se puede usar con licencias que no sean de GPL. – Piotr

+1

@Piotr: en realidad, no sé si existe. – Eugene

12
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; 
} 
+1

Quizás 'cdev_add()' se debería llamar antes de 'device_create()'. Ese parece ser el orden más común. –

+1

El código podría estar claro si usaría goto como los usos del kernel. – JagsVG

+0

Su limpieza falta 'cdev_del'. Ver: https://stackoverflow.com/a/45531867/895245 –

3

Mínimo ejemplo ejecutable

minimizadas 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"); 
+1

Santilli - +1 para el gran ejemplo. –

Cuestiones relacionadas