【IMX6ULL驱动开发学习】07.注册驱动设备_分配固定的次设备号_cdev

news2024/9/28 7:16:15

一、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/637232.html

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

相关文章

【JAVA开发环境配置】 我也可以让JDK版本来去自由的切换了! 哈哈哈哈 舒服!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

单页面控制中心 vue-router

一、 路由的基本配置 1. 在router->index.js中&#xff0c;配置一个懒路由&#xff0c;定义页面加载哪个组件 import Vue from vue import VueRouter from vue-routerVue.use(VueRouter)const routes []// 配置一个懒路由,不然会加载页面下所有组件 const router new Vu…

基于微信小程序的失物招领系统设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

BI工具+方案:火速构建电商数据分析架构

电商数据分析该怎么做&#xff1f;谁都知道电商数据分析讲究效率和精细化&#xff0c;光是围绕电商销售分析&#xff0c;就需要制作包括管理驾驶舱、销售预算分析、店铺销售增长趋势、店铺排名分析、商品退货分析等近20种电商数据分析报表。怎么才能又快又好地完成智能数据分析…

java设计模式之:装饰器模式

前言 在软件设计中&#xff0c;我们也有一种类似新房装修的技术可以对已有对象&#xff08;新房&#xff09;的功能进行扩展&#xff08;装修&#xff09;&#xff0c;以获得更加符合用户需求的对象&#xff0c;使得对象具有更加强大的功能。这种技术对应于一种被称之为装饰模…

Bug序列——容器内给/root目录777权限后无法使用ssh免密登录

Linux——创建容器并将本地调试完全的前后端分离项目打包上传docker运行_北岭山脚鼠鼠的博客-CSDN博客 接着上一篇文章结尾出现403错误时通过赋予/root目录以777权限解决403错误。 chmod 777 /root 现在又出现新的问题&#xff0c;远程ssh无法免密登录了&#xff0c;即使通过…

准备了2个月,怒刷面试题,4面字节跳动,顺利拿到 offer

说到字节跳动的经历还是比较搞笑的。一开始我特别想去那个游戏测试部门&#xff0c;当然 data测试部门也是特别想去的&#xff0c;但是提前批只能投一个&#xff0c;于是投了游戏&#xff0c;结果第二天就给我挂了。。。中间北京的捞我&#xff0c;但是不想去北京所以拒绝了&am…

说透缓存击穿、穿透、雪崩及常用解决方案

文章目录 缓存击穿、穿透、雪崩及解决方案击穿、穿透、雪崩的意思缓存击穿缓存穿透缓存雪崩总结 系列文章目录 本文是系列文章&#xff0c;为了增强您的阅读体验&#xff0c;已将系列文章目录放入文章末尾。&#x1f44d;&#x1f44d;&#x1f44d; 缓存击穿、穿透、雪崩及解决…

我的内网渗透-metasploit基础

目录 MSF postgresql msf模块 永恒之蓝 木马下放 后渗透一些简单命令 MSF Msfconsole是Metasploit框架的主要控制台界面。 开源的渗透软件 postgresql 使用的是postgresql数据库&#xff08;metasploit所依载的数据库&#xff0c;没有他也可以运行metasploit框架&…

Vue中如何进行二维码生成与扫描?

Vue中如何进行二维码生成与扫描&#xff1f; 二维码是一种广泛应用于各种场合的编码方式&#xff0c;它可以将信息编码成一张二维图案&#xff0c;方便快捷地传递信息。在Vue.js中&#xff0c;我们可以使用一些库和组件来实现二维码的生成和扫描。本文将介绍如何在Vue中实现二…

高频RFID工业读写器在自动化产线上如何应用?

工业读写器在自动化生产上具有十分重要的作用&#xff0c;它可以对工业生产中的贴上RFID标签的各种零部件和产品&#xff0c;进行跟踪与识别。利用RFID技术进行非接触的物体识别和追踪&#xff0c;更好的掌握产线上的物料信息。 高频RFID工业读写器在自动化产线上如何应用&…

Android studio C++调试问题汇总

问题1&#xff1a;如下图所示&#xff0c;cpp目录不显示或cpp目录不显示C源文件。 此问题由由于abiFilter指定为armeabi&#xff0c;但armeabi架构已经不再支持的原因导致&#xff0c;将armeabi修改为armeabi-v7a或arm64等其他支持的架构即可&#xff0c;修改后如下图所示&…

致敬易语言,Excel衍生新型中文编程,Python用户:转折点到了

没有逃过被命运的捉弄 易语言作为中文编程里的老大&#xff0c;刚开始的时候&#xff0c;叫E语言。 创始人吴涛&#xff0c;地道的中国人&#xff0c;就是为了让中国人不再孜孜不倦的去追难懂的编程语言&#xff0c;降低开发门槛。 易语言的结局最终也没逃过被命运的捉弄&…

一款可以拿来做毕设的图书管理系统,简单易掌握,非常nice

项目介绍 项目简介 使用jsp、layui、mysql完成的图书馆系统&#xff0c;包含用户图书借阅、图书管理员、系统管理员界面&#xff0c;功能齐全。 项目详细介绍 本图书管理系统总体上分为前台页面显示和后台管理。 共包含三个大模块&#xff1a;用户、图书管理员、系统管理员…

全量程真空压力综合测量系统的高精度控制解决方案

摘要&#xff1a;针对工作范围在5~1.3Pa&#xff0c;控制精度在0.1%~0.5%读数的全量程真空压力综合测量系统技术要求&#xff0c;本文提出了稳压室真空压力精密控制的技术方案。为保证控制精度&#xff0c;基于动态平衡法&#xff0c;技术方案在高真空、低真空和正压三个区间内…

初识s3c2440A之ARM体系架构入门linux硬件

文章目录 前言一、环境平台的基本介绍二、ARM体系架构必备知识1. 计算机三大组成2. ARM的分类2.1 ARM Cortex-A系列2.2 ARM Cortex-R系列2.3 ARM Cortex-M系列 3. 2440ARM的系统架构 总结 前言 如果大家在前期学习了c语言&#xff0c;并且具备了一定的c语言功底&#xff0c;且学…

7 原子类

Java.util.concurrent.atomic 7.2 没有CAS之前 多线程环境中不使用原子类保证线程安全i&#xff08;基本数据类型&#xff09; class Test {private volatile int count 0;//若要线程安全执行执行count&#xff0c;需要加锁public synchronized void increment() {count;}pu…

二叉树前序遍历:在树叶掉落前,寻找根的方向

本篇博客会讲解力扣“144. 二叉树的前序遍历”的解题思路&#xff0c;这是题目链接。 先来审题&#xff1a; 由于本篇博客会使用C语言来实现这道题&#xff0c;最简单的解法自然是使用递归。所谓前序遍历&#xff0c;即按照“根、左子树、右子树”的顺序来遍历&#xff0c;当…

【新版】系统架构设计师 - 数据库系统

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 数据库系统考点摘要数据库系统模式数据库视图数据模型&#xff08;基本数据模型&#xff09;数据库完整性约束关系模型关系代数规范化理论候选键、主键、外键、主属性&#xff0c;非主属性求候选键…

【笔记】最优解人生

死前归零 如果在死亡之前没有将赚到的钱花完&#xff0c;那么剩下那些没花完的钱&#xff0c;就是你白白浪费的生命能量。 60岁以后&#xff0c;虽然医疗开支变大&#xff0c;但娱乐&#xff0c;衣物的开始会变小&#xff0c;总体上开销会越来越少。 如何“死前归零”呢&…