[Desarrollo y aprendizaje del controlador IMX6ULL] 07.cdev registra el dispositivo del controlador_establece el rango del número del dispositivo secundario

1. registrarse_chrdev

En el controlador hello anterior, la forma de registrar el dispositivo controlador es la siguiente

/*初始化设备方法1:自动分配设备号,占用所有次设备号*/
major = register_chrdev(0,"hello_drv",&hello_fops);

El método de asignación de números de dispositivo usando register_chrdev es relativamente simple y directo, pero hará que el dispositivo ocupe todos los números de dispositivo menores.

Por ejemplo: Por
ejemplo, el número de dispositivo principal de mi controlador hello es 240 y el número de dispositivo secundario es 0.
Si uso mknod para crear un dispositivo /dev/abc, el número de dispositivo principal también es 240 y el dispositivo secundario número se establece en 1.
Cuando opero el dispositivo / dev/abc, también se llamará a mi controlador hello,
porque la función register_chrdev hace que todos los números de dispositivos menores debajo del número de dispositivo principal asignado correspondan al controlador hello.
la figura de abajo

inserte la descripción de la imagen aquí
El número de dispositivo principal proporcionado por el kernel de Linux es limitado. Si hay muchos dispositivos, el número de dispositivo principal puede no ser suficiente. ¿
Qué debo hacer? Solución: puede asignar un número de dispositivo secundario fijo
al dispositivo al registrar el dispositivo de accionamiento

Ejemplo, alloc_chrdev_region, cdev_init, cdev_add

1. alloc_chrdev_region: Registre una serie de números de dispositivos de caracteres

/**
 * alloc_chrdev_region() - register a range of char device numbers
 * @dev: output parameter for first assigned number
 * @baseminor: first of the requested range of minor numbers
 * @count: the number of minor numbers required
 * @name: the name of the associated device or driver
 *
 * Allocates a range of char device numbers.  The major number will be
 * chosen dynamically, and returned (along with the first minor number)
 * in @dev.  Returns zero or a negative error code.
 */
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
parámetro significado
desarrollador El número de dispositivo asignado (los 12 bits superiores son el número de dispositivo principal)
base menor El número menor inicial de la solicitud.
contar El número de números de dispositivos menores solicitados
nombre nombre de controlador personalizado

2. cdev_init: inicializa la estructura de cdev

/**
 * cdev_init() - initialize a cdev structure
 * @cdev: the structure to initialize
 * @fops: the file_operations for this device
 *
 * Initializes @cdev, remembering @fops, making it ready to add to the
 * system with cdev_add().
 */
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
parámetro significado
cdv estructura cdv
operaciones_archivo La estructura de la aplicación y el controlador asociados (incluidos los punteros de función de lectura y escritura del controlador, etc.)

estructura cdev (miembros file_operations, miembros dev_t, etc.)

struct cdev {
    
    
	struct kobject kobj;
	struct module *owner;
	const struct file_operations *ops;
	struct list_head list;
	dev_t dev;
	unsigned int count;
};

3. cdev_add: agrega un dispositivo de caracteres al sistema

/**
 * cdev_add() - add a char device to the system
 * @p: the cdev structure for the device
 * @dev: the first device number for which this device is responsible
 * @count: the number of consecutive minor numbers corresponding to this
 *         device
 *
 * cdev_add() adds the device represented by @p to the system, making it
 * live immediately.  A negative error code is returned on failure.
 */
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
parámetro significado
pag estructura cdv
desarrollador El número de dispositivo asignado (los 12 bits superiores son el número de dispositivo principal)
contar El número de números de dispositivos menores solicitados

3. Registre el dispositivo del controlador y asigne el número de dispositivo menor del dispositivo del controlador

/*初始化设备方法2:自动分配设备号,设置次设备号占用区域*/
//1.自动分配设备号(起始次设备号0,次设备数量 2,设备名称“hello_drv”)
alloc_chrdev_region(&hello_dev, 0, 2,"hello_drv");
//2.initialize a cdev structure
cdev_init(&hello_cdev, &hello_fops);
//3.add a char device to the system
cdev_add(&hello_cdev, hello_dev, 2);
//4.register a range of device numbers
register_chrdev_region(hello_dev, 2, "hello_drv");

Cuatro, hola conductor

Basado en el blog [Desarrollo y aprendizaje del controlador IMX6ULL] 06. La aplicación y la transferencia de datos del controlador_crean automáticamente nodos de dispositivo (hola controlador), modifíquelo.
Al registrar el dispositivo del controlador, use la función cdev para registrar y asignar dos números de dispositivo menores 0 y 1

hola código de conductor:

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/capability.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <asm/therm.h>
#include <linux/string.h>


static unsigned char buff[100];
static struct class *hello_class;

//static int major;       		//主设备号
dev_t hello_dev;          		//保存分配的设备号
unsigned baseminor; 	  		//分配设备号的起始次设备号
static struct cdev hello_cdev;  //定义struct cdev 类型全局变量
unsigned char minor_count = 2; 	//指定次设备号个数


static int hello_open (struct inode *node, struct file *filp)
{
    
    
	printk("hello_open\n");
	printk("%s %s %d\n",__FILE__, __FUNCTION__, __LINE__);

	return 0;
}

static ssize_t hello_read (struct file *filp, char *buf, size_t size, loff_t *offset)
{
    
    
	size_t len = size > 100 ? 100 : size;
	printk("hello_read\n");
	copy_to_user(buf, buff, len);
	return len;
}

static ssize_t hello_write (struct file *filp, const char *buf, size_t size, loff_t *offset)
{
    
    
	size_t len = size > 100 ? 100 : size;
	memset(buff, 0 ,sizeof(buff));
	printk("hello_write\n");
	copy_from_user(buff, buf, len);
	return len;
}

static int hello_release (struct inode *node, struct file *filp)
{
    
    
	printk("hello_release\n");
	return 0;
}

/*1.定义 file_operations 结构体*/
static const struct file_operations hello_fops = {
    
    
    .owner 		= THIS_MODULE,
	.read		= hello_read,
	.write		= hello_write,
	.open		= hello_open,
	.release    = hello_release,
};


/*2.register_chrdev*/

/*3.入口函数*/
static int hello_init(void)
{
    
    
	struct device *dev;

	/*初始化设备方法1:自动分配设备号,占用所有次设备号*/
	//设备号
//	major = register_chrdev(0,"hello_drv",&hello_fops);

	/*初始化设备方法2:自动分配设备号,设置次设备号占用区域*/
	//1.自动分配设备号(起始次设备号baseminor,次设备数量 2)
	if(alloc_chrdev_region(&hello_dev, baseminor, minor_count,"hello_drv") < 0)
    {
    
    
        printk(KERN_ERR"Unable to alloc_chrdev_region.\n");
        return -EINVAL;
    }

	//2.initialize a cdev structure
	cdev_init(&hello_cdev, &hello_fops);
	
	//3.add a char device to the system
    if(cdev_add(&hello_cdev, hello_dev, minor_count) < 0)
    {
    
    
        printk(KERN_ERR "Unable to cdev_add.\n");
        return -EINVAL;
    }

	//4.register a range of device numbers
	register_chrdev_region(hello_dev, minor_count, "hello_drv");

	/*自动创建设备节点*/
	/*在内核中创建设备*/
	hello_class = class_create(THIS_MODULE, "hello_class");
	if (IS_ERR(hello_class)) {
    
    
		printk("hello class create failed!\n");
	}

	/*在/dev下面创建设备节点*/
	device_create(hello_class, NULL, hello_dev, NULL, "hello");
	if (IS_ERR(dev)) {
    
    
		printk("hello device_create  failed!\n");
	}
	
	return 0;
}


/*4.退出函数*/
static int hello_exit(void)
{
    
    
	//销毁设备
	device_destroy(hello_class, hello_dev);
	//删除设备类
	class_destroy(hello_class);

	/*对应初始化设备方法1:自动分配设备号,占用所有次设备号*/
//	unregister_chrdev(major,"hello_fops");

	/*对应初始化设备方法2:自动分配设备号,设置次设备号占用区域*/
	unregister_chrdev_region(hello_dev, minor_count);
	cdev_del(&hello_cdev);

	return 0;
}	

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

hola codigo de aplicacion:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
    
    
    int len;
    char read_buf[10];

    if(argc < 2){
    
    
        printf("please input  at least 2 args\n");
        printf("%s <dev> [string]\n", argv[0]);
        return -1;
    }

    /*open*/
    int fd;
    fd = open(argv[1], O_RDWR);
    if(fd < 0){
    
    
        printf("open failed\n");
        return -2;
    }

    /*read*/
    if(argc == 2){
    
      
        read(fd, read_buf, 10);    //调用read函数,只为了触发系统调用hello驱动的read函数
        printf("read operation : %s\n", read_buf);
    }

    /*write*/
    if(argc == 3){
    
    
        len = write(fd, argv[2], strlen(argv[2]));   //调用write函数,只为了触发系统调用hello驱动的write函数
        printf("write length = %d \n", len);
    }

    close(fd);

    return 0;
}

5. Resultados experimentales

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/HuangChen666/article/details/131166202
Recomendado
Clasificación