【迅为iTop4412学习笔记】17.静态方式申请主次设备号

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39057987/article/details/84668380

声明

以下都是我刚开始看驱动视频的个人强行解读,如果有误请指出,共同进步。

本节目标

静态方式申请主次设备号


申请主次设备号的函数(本节讲静态,下节动态)

我们打开 include/linux/fs.h 头文件可以看到以下三个函数(具体参数含义后面再说)
当然,写的时候要包含头文件 linux/fs.h

// 动态申请主次设备号(linux分配)
extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
// 静态申请主次设备号(自己指定主次设备号是多少)
extern int register_chrdev_region(dev_t, unsigned, const char *);
// 已被上面俩取代,这个过时了...
extern int __register_chrdev(太多懒得抄);

数据类型

就像文件IO操作有个fd一样,注册设备号也有一个类似的东西

申请主次设备号,必须要用dev_t(其实就是int)来作为数据类型。
其头文件为 linux/cdev.h

处理的宏定义

主次设备号一共32位,高12位用来表示主设备号,低20位用来表示次设备号。
当然,自己去移位也行,但是linux已经给我们封装好了一个宏定义叫MKDEV(ma,mi) ,参数1是主设备号,参数2是次设备号。
其头文件为 linux/kdev_t.h

正文

我们本次编写的模板参考上一节的模块传参,这样我们就可以直接把传入的参数当作主、次设备号。

如果我们insmod的时候,忘了传入参数怎么办?所以我们在声明主次设备号的时候,赋一个初值,如果没有传入参数,就用初值好了。

那么赋值多少好呢?

linux贴心的为我们提供了0,当传入0的时候,表示不指定设备号是多少,由linux去提供空闲的设备号(从大到小找,主设备号就255个,设备号255->1)。

当然,只是为了保险起见,如果不是我们指定多少,那静态还有啥意义,不如直接用动态申请的方式…

以下是模块传参部分的代码

// 初始化主次设备号
int device_major = 0;
int device_minor = 0;
// 模块传参
module_param(device_major, int, S_IRUSR);
module_param(device_minor, int, S_IRUSR);

我们在模块初始化的时候来申请主设备号。
首先要定义一个主次设备号,并把模块传参主、次设备号,合成后赋值给他

dev_t mryang_dev;
mryang_dev = MKDEV(device_major, device_minor);

有了主、次设备号mryang_dev(高12位是主,低20位是次,用MKDEV宏定义合成的)

我们就开始申请

先介绍一下申请函数的参数:

// 参数1:设备号的编号
// 参数2:连续设备编号个数
// 参数3:设备的名字
// 返回:申请状态
int register_chrdev_region(dev_t first,unsigned int count,char *name) 

设备编号就传入我们刚刚合成好的mryang_dev
连续设备编号个数传入2
设备的名字我们就叫"mryang_cdev"
我们再声明一个ret来查看是否申请成功

当然,申请了,你退出模块的时候同样要卸载释放,其函数是:

// 参数内容类似申请的函数
void unregister_chrdev_region(dev_t first, unsigned int count);

全部代码:

#include <linux/init.h>
#include <linux/module.h>

#include <linux/moduleparam.h>

// 字符设备申请函数
#include <linux/fs.h>
// 设备号数据类型 dev_t
#include <linux/cdev.h>
// 处理宏定义 MKDEV
#include <linux/kdev_t.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("MrYang");

// 初始化主次设备号
int device_major = 0;
int device_minor = 0;
// 模块传参
module_param(device_major, int, S_IRUSR);
module_param(device_minor, int, S_IRUSR);

static int mryang_init(void)
{
	int ret;
	dev_t mryang_dev;
	// 输出
	printk(KERN_EMERG "HELLO MrYang\n");
	printk(KERN_EMERG "major: %d, minor: %d\n", device_major, device_minor);
	
	// 申请主设备号
	mryang_dev = MKDEV(device_major, device_minor);
	ret = register_chrdev_region(mryang_dev, 2, "mryang_cdev");
	if(ret < 0)
		printk(KERN_EMERG "failed!\n");
	else
		printk(KERN_EMERG "success!\n");
	return 0;
}

static void mryang_exit(void)
{
	dev_t mryang_dev;
	// 输出
	printk(KERN_EMERG "Bye MrYang\n");
	// 注销
	mryang_dev = MKDEV(device_major, device_minor);
	unregister_chrdev_region(mryang_dev, 2);
	printk(KERN_EMERG "over!\n");
}

module_init(mryang_init);
module_exit(mryang_exit);

编译完成之后

我们先查看一下linux已经分配的主设备号

cat /proc/devices

我们随便挑一个没有的即可,比如主设备号叫9,次设备号本节不关心,所以设置为0让他自动分配吧。

我们输入:

insmod probe_linux_module.ko device_major=9 device_minor=0

返回:

[  176.009824] HELLO MrYang
[  176.010960] major: 9, minor: 0
[  176.013951] success!

查看主设备号发现编号是9,名字一致,全部正确。

我们还可以试一下不带参数

insmod probe_linux_module.ko

返回:

[  900.409599] HELLO MrYang
[  900.410692] major: 0, minor: 0
[  900.413702] success!

主、次设备号都是动态分配的号码,然后静态方式去申请它。
查看设备号发现被分配为248,也正确。

收尾

学到现在,感觉对于主次设备号大致有点概念了。
主设备号用于区分某一类的设备
次设备号用于区分这一类设备里的哪一个设备。
有了主+次,就可以具体定位到某一设备了。
以上就是我目前的见解。


猜你喜欢

转载自blog.csdn.net/qq_39057987/article/details/84668380
今日推荐