[Desenvolvimento e aprendizado do driver IMX6ULL] 07.cdev registra o driver device_sets o intervalo do número do dispositivo secundário

1. register_chrdev

No driver hello anterior, a maneira de registrar o dispositivo do driver é a seguinte

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

O método de atribuir números de dispositivo usando register_chrdev é relativamente simples e direto, mas fará com que o dispositivo ocupe todos os números de dispositivo secundários

Por exemplo: Por
exemplo, o número do dispositivo principal do meu driver hello é 240 e o número do dispositivo secundário é 0.
Se eu usar mknod para criar um dispositivo /dev/abc, o número do dispositivo principal também é 240 e o dispositivo secundário O número é definido como 1.
Quando eu opero o dispositivo /dev/abc, meu driver hello também será chamado,
porque a função register_chrdev faz com que todos os números de dispositivos secundários sob o número do dispositivo principal atribuído correspondam ao driver hello.
O efeito é mostrado em a figura abaixo

insira a descrição da imagem aqui
O número do dispositivo principal fornecido pelo kernel do Linux é limitado. Se houver muitos dispositivos, o número do dispositivo principal pode não ser suficiente.
O que devo fazer? Solução: você pode atribuir um número de dispositivo menor fixo
ao dispositivo ao registrar o dispositivo de acionamento

二、alloc_chrdev_region、cdev_init、cdev_add

1. alloc_chrdev_region: Registra uma série 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
desenvolvedor O número do dispositivo atribuído (os 12 bits superiores são o número do dispositivo principal)
básico menor O número menor inicial da solicitação
contar O número de números de dispositivos secundários solicitados
nome nome do driver personalizado

2. cdev_init: Inicializa a estrutura 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
cdev estrutura cdev
arquivo_operações A estrutura do aplicativo e driver associados (incluindo ponteiros de função de leitura e gravação do driver, etc.)

estrutura cdev (membros file_operations, membros 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: adiciona um dispositivo de caractere ao 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
p estrutura cdev
desenvolvedor O número do dispositivo atribuído (os 12 bits superiores são o número do dispositivo principal)
contar O número de números de dispositivos secundários solicitados

3. Registre o dispositivo do driver e atribua o número do dispositivo secundário do dispositivo do driver

/*初始化设备方法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");

Quatro, olá motorista

Com base no blog [IMX6ULL driver development and learning] 06. APP e driver program transfer data_automatically create device nodes (hello driver), modifique-o.
Ao registrar o driver device, use a função cdev para registrar e atribuir dois números de dispositivos menores 0 e 1

Olá código do driver:

#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");

Olá código do aplicativo:

#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 experimentais

insira a descrição da imagem aqui

Acho que você gosta

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