【IMX6ULL驱动开发学习】07.cdev注册驱动设备_设置次设备号范围

news2025/6/23 12:16:43

一、register_chrdev

在之前的hello驱动中,注册驱动设备的方式如下

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

使用 register_chrdev 分配设备号的方式比较简单直接,但是会导致设备占用所有的次设备号

举个例子:
比如我的hello驱动主设备号是240,次设备号是0,
如果我使用 mknod 创建一个 /dev/abc 设备,主设备号也是240,次设备号 设置为1,
当我操作 /dev/abc 设备时,同样会调用我的hello驱动程序,
因为 register_chrdev 函数使得分配的主设备号下的所有次设备号都对应到hello驱动上了
效果如下图所示

在这里插入图片描述
linux内核提供的主设备号是有限的,如果设备很多的情况下主设备号就可能不够用了
那怎么办呢?
解决办法:可以在注册驱动设备的时候,给设备分配好固定的次设备号

二、alloc_chrdev_region、cdev_init、cdev_add

1. alloc_chrdev_region:注册一系列字符设备编号

/**
 * 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)
参数含义
dev分配的设备号(高12位是主设备号)
baseminor请求的起始次设备号
count请求的次设备号的数量
name自定义驱动程序名称

2. cdev_init:初始化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)
参数含义
cdevcdev结构体
file_operations关联应用程序和驱动程序的结构体(包含驱动读写函数指针等)

cdev结构体(file_operations 成员、dev_t成员等)

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:将字符设备添加到系统中

/**
 * 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)
参数含义
pcdev结构体
dev分配的设备号(高12位是主设备号)
count请求的次设备号数量

三、注册驱动设备,并分配驱动设备次设备号

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

四、hello驱动程序

在博客【IMX6ULL驱动开发学习】06.APP与驱动程序传输数据_自动创建设备节点(hello驱动) 的基础上修改,
注册驱动设备时,采用cdev函数注册,分配两个次设备号0、1

hello驱动程序代码:

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

hello应用程序代码:

#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;
}

五、实验效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/640752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从玩具到工具|社畜程序员用AI提效的神仙操作

&#x1f449;腾小云导读 随着 AI 技术的日益发展&#xff0c;前端开发模式和提效工具也在不断地变化。作为一名前端工程师&#xff0c;如何应对 AI 带来的挑战和机遇&#xff1f;在这篇文章中&#xff0c;作者将介绍什么是 AIGC&#xff0c;并深入探讨 AI 在低代码平台的应用。…

【数据结构】顺序表及其实现

目录 1.线性表 2.顺序表 2.1顺序表的概念及结构 2.2顺序表的实现 1.线性表 线性表&#xff1a;是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表&#xff0c;链表&#xff0c;栈&#xff0c;队…

Parallels Desktop 18 18.3.1激活攻略

如果说虚拟机领域有一位王者&#xff0c;非Parallels不能领袖群伦&#xff0c;毕竟大厂背书&#xff0c;功能满格&#xff0c;美中不足之处就是价格略高&#xff0c;但这也并非是Parallels的错&#xff0c;因为市场上没有任何一款虚拟机产品在产品力层面能和Parallels抗衡&…

使用Typora+PicGo+阿里云搭建图床

1.为什么要使用图床 不知道大家有没有遇到过这样的问题&#xff1f; 在使用Typora的时候&#xff0c;我们传到typora上面的图片&#xff0c;在转到其他地方时&#xff0c;总是加载不出来&#xff0c;造成图片丢失现象或者是在将markdown笔记上传到博客时&#xff0c;总是需要一…

华为OD机试真题 JavaScript 实现【静态代码扫描服务】【2023Q1 100分】

一、题目描述 静态扫描快速识别源代码的缺陷&#xff0c;静态扫描的结果以扫描报告作为输出&#xff1a; 文件扫描的成本和文件大小相关&#xff0c;如果文件大小为N&#xff0c;则扫描成本为N个金币&#xff1b;扫描报告的缓存成本和文件大小无关&#xff0c;每缓存一个报告…

(二)安装 Kafka

文章目录 1.选择操作系统2.配置 Java 环境3.安装 ZooKeeper4.安装 broker&#xff08;1&#xff09;安装 broker&#xff08;2&#xff09;验证是否安装正确 5.配置 broker&#xff08;1&#xff09;常规配置&#xff08;2&#xff09;主题的默认配置 6.配置 Kafka 集群&#x…

Netty之协议设计

目录 为什么需要协议 redis协议示例 http协议举例 自定义协议 要素 编解码器 测试 为什么需要协议 TCP/IP 中消息传输基于流的方式&#xff0c;没有边界。 协议的目的就是划定消息的边界&#xff0c;制定通信双方要共同遵守的通信规则 例如&#xff1a;在网络上传输 …

c++11 标准模板(STL)(std::ios_base)(三)

定义于头文件 <ios> class ios_base; 类 ios_base 是作为所有 I/O 流类的基类工作的多用途类。它维护数种数据&#xff1a; 1) 状态信息&#xff1a;流状态标志&#xff1b; 2) 控制信息&#xff1a;控制输入和输出序列格式化和感染的本地环境的标志&#xff1b; 3)…

(一)Flask简介和快速使用

关于Python三大Web框架浅谈一嘴&#xff1a; Django、Flask和Tornado三个框架都是Python Web应用的开发框架&#xff0c;虽然它们都能够开发Web应用&#xff0c;但在使用方式、适用领域和处理方式上还是有很多不同的。 Django Django是一个高层次&#xff08;大而全&#xff0…

Flutter自定义系列之折线波动图,心率图,价格走势图

随着前两篇文章的学习&#xff0c;我今天继续给大家演示下简单的自定义之折线波动图&#xff0c;心率图&#xff0c;价格走势图。 这里&#xff0c;我们创建一个自定义的StatefulWidget&#xff0c;用于显示动态的价格线。 我们将使用CustomPaint和CustomPainter来绘制价格线…

chatgpt赋能python:Python中如何截断字符串

Python中如何截断字符串 Python是一种简单易学、高效的编程语言&#xff0c;旨在让开发人员更快、更方便地完成任务。然而&#xff0c;在实际开发过程中&#xff0c;我们常常需要对字符串进行截断操作。那么&#xff0c;Python中怎么截断字符串呢&#xff1f;接下来就让我们来…

如何最大限度地利用ChatGPT、Bard和其他聊天机器人

作者&#xff1a;Hayden Field 译者&#xff1a;明明如月 当下&#xff0c;随着生成式人工智能的发展&#xff0c;面向消费者的聊天机器人能够处理不同领域的需求&#xff0c;并提供相应的帮助和建议&#xff0c;如制定商业战略、设计数学学习指南、提供薪资谈判建议&#xff…

chatgpt赋能python:Python字符串截断-解决方式及实现方法

Python字符串截断-解决方式及实现方法 在Python编程中&#xff0c;处理字符串是一个非常常见的任务。其中&#xff0c;字符串截断也是在许多场景下必不可少的功能之一。Python不仅提供了许多内置函数来处理字符串&#xff0c;而且还有许多方法来截断字符串。 什么是字符串截断…

chatgpt赋能python:Python怎么截图速度快?

Python怎么截图速度快&#xff1f; 在现在这个数字时代&#xff0c;我们所有人都需要进行屏幕截图。无论是用于记录重要笔记&#xff0c;制作教程&#xff0c;或是用于软件质量控制&#xff0c;高速、高质量、高效的屏幕截图工具都非常必要。 在Python编程领域中&#xff0c;…

S3C2440A的ARM工作模式以及寄存器种类

文章目录 前言一、ARM的工作模式二、寄存器的种类&#xff08;注意特殊寄存器的使用&#xff09;总结 前言 本期和大家主要分享的是ARM工作模式以及寄存器种类&#xff0c;不同系列的ARM的工作模式以及寄存器的种类大同小异&#xff0c;所以针对于S3C2440A&#xff0c;一定得通…

【题目解析】第六届字节后端青训营结营小测试全解析

前言 &#x1f44f; Hi! 我是 Yumuing&#xff0c;一个技术的敲钟人 &#x1f468;‍&#x1f4bb; 每天分享技术文章&#xff0c;永远做技术的朝拜者 &#x1f4da; 欢迎关注我的博客&#xff1a;Yumuing’s blog 由于官方答案没有出来&#xff0c;所以&#xff0c;这部分都是…

03.填充中断向量表IDT,使用中断

填充中断描述符表IDT&#xff0c;使用中断 通过初始化中断控制芯片&#xff0c;编码中断函数&#xff0c;实现BIOS中断 操作系统的中断是一种异步事件&#xff0c;用于通知 CPU 某个事件已经发生&#xff0c;例如硬件设备完成数据传输、发生错误或用户发起的系统调用。当操作系…

栈和队列(栈的应用)[二]

文章目录 栈的应用一、栈在系统中的应用简化路径(leetcode. 71) 二、扩号匹配问题有效的括号(leetcode. 20) 三、字符串去重删除字符串中的所有相邻重复项(leetcode. 1047) 四、逆波兰表达式问题逆波兰表达式求值(leetcode. 150) 总结 栈的应用 递归的实现是栈&#xff1a;每一…

使用腾讯手游助手作为开发测试模拟器的方案---以及部分问题的解决方案-1

目录 前言: 一.目录结构 二.注册表研究 1.HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Tencent\MobileGamePC 2.HKEY_CURRENT_USER\Software\Tencent\MobileGamePC 三.模拟器快捷启动 1.快捷启动命令: 2.启动命令如何放入桌面: 3.adb端口,目前测试均可以使用: 前言: 此…

PyTorch深度学习实战(3)——使用PyTorch构建神经网络

PyTorch深度学习实战&#xff08;3&#xff09;——使用PyTorch构建神经网络 0. 前言1. PyTorch 构建神经网络初体验1.1 使用 PyTorch 构建神经网络1.2 神经网络数据加载1.3 模型测试1.4 获取中间层的值 2. 使用 Sequential 类构建神经网络3. PyTorch 模型的保存和加载3.1 模型…