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

news/2024/9/23 9:28:47/

一、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 structurecdev_init(&hello_cdev, &hello_fops);//3.add a char device to the systemif(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 numbersregister_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.ppmy.cn/news/357894.html

相关文章

教你如何下载抖音视频的背景音乐?是音乐不是视频哦

有时候遇到很喜欢的抖音视频音乐&#xff0c;想用来当做手机铃声却找不到好的剪辑&#xff0c;怎么办&#xff1f; 今天&#xff0c;豆豆来教你用飞狐视频下载器&#xff0c;轻松下载抖音音乐&#xff01; 首先&#xff0c;复制你喜欢音乐的那条抖音视频链接。 然后&#x…

截取音乐片段的计算机软件,电脑上剪辑音乐的软件

大家应该经常对着一些音频歌曲进行剪切&#xff0c;但是完成音频剪辑通常都是使用电脑来操作的&#xff0c;音频编辑的软件有很多&#xff0c;那么在电脑上剪辑音乐的软件有哪些呢&#xff1f;哪些好用呢&#xff1f;关于音频歌曲剪辑其实并没有这么的难&#xff0c;只要大家认…

手机音乐计算机软件,盘点适合手机音频剪辑软件

在接听电话时&#xff0c;我们常常希望手机铃声是自己喜欢的音乐&#xff0c;而对于自己歌单中的大部分歌曲&#xff0c;喜欢的部分往往在高潮&#xff0c;需要后期剪辑从而作为铃声。电脑上有许多专业的音频处理软件可以对音乐进行修剪编辑&#xff0c;但对于新手而言显得有些…

软件推荐:音乐剪辑器(magic music editor)V8.12

一、软件简介&#xff1a; 1.软件名称&#xff1a;音乐剪辑器(magic music editor)V8.12 2.软件大小&#xff1a;12MB 3.安装环境&#xff1a;win7/win8/win10 4.软件简介&#xff1a;音乐剪辑器(magic music editor)最新版是一款非常棒的录音以及音频编辑软件&#xff0c;…

常用的音频剪辑软件

对于普通用户来说&#xff0c;平时生活中想自己制作来电铃声和闹钟铃声&#xff0c;就需要一款对音频剪辑的辅助工具&#xff0c;对喜欢的音频进行简单的剪辑&#xff0c;市面上有免安装&#xff0c;免下载的在线剪辑工具&#xff0c;可以简单的满足需求&#xff0c;使用也很方…

mp3音频剪辑软件怎么使用?

电脑上剪辑音频是非常方便的&#xff0c;对于专业的剪辑音乐人员是非常简单的&#xff0c;但是对于一些只是想要简单的剪辑歌曲和音频新手来说是有点复杂的&#xff0c;那么如何选择一款适合我们剪辑需求的软件&#xff0c;大部分人获取剪辑工具都是通过搜索“音频剪辑工具”关…

在电脑上如何剪辑音乐?

电脑上怎么剪辑音乐&#xff1f;一般想要对音乐进行剪辑&#xff0c;在电脑上操作是比较方便的。音乐可以是一首歌曲&#xff0c;一段录音&#xff0c;剪辑音乐就是剪辑音频&#xff0c;剪辑的目的就是把需要的片段截取出来&#xff0c;那么如何截取音乐中的一段或者多段&#…

电脑上剪辑音乐的软件

大家应该经常对着一些音频歌曲进行剪切&#xff0c;但是完成音频剪辑通常都是使用电脑来操作的&#xff0c;音频编辑的软件有很多&#xff0c;那么在电脑上剪辑音乐的软件有哪些呢&#xff1f;哪些好用呢&#xff1f;关于音频歌曲剪辑其实并没有这么的难&#xff0c;只要大家认…