什么是设备号:
Linux 规定 每个字符设备或者块设备必须有一个专属的设备号;一个设备号由主设备号 和次设备号组成;
主设备号和次设备号是什么?
主设备号 在Linux是唯一的,次设备号不一定;
设备号是计算机识别设备的一种方式,主设备相同就被视为同一类的设备;
查看主设备号命令:
cat /proc/devices
设备号类型
Linux使用dev_tde数据类型表示设备号,定义在 include/linux/types.h 头文件里面;
其中 dev_t 是一个u32类型,其中高12bit是主设备号,低20bit是次设备号;
设备号操作宏
- MINORBITS:表示次设备号的位数,通常为20位。这个宏定义了次设备号在
dev_t
类型中所占的位数。 - MINORMASK:用于计算次设备号使用的掩码,其值为
(1U << MINORBITS) - 1
。 - MAJOR(dev):从
dev_t
类型的设备号中提取主设备号。其实现通常是将设备号右移MINORBITS
位。 - MINOR(dev):从
dev_t
类型的设备号中提取次设备号。其实现通常是取设备号与MINORMASK
进行位与操作。 - MKDEV(ma, mi):由主设备号(
ma
)和次设备号(mi
)合成一个dev_t
类型的设备号。其实现通常是将主设备号左移MINORBITS
位后与次设备号进行位或操作。
设备号相关函数
设备号申请
编写字符设备驱动代码时候,可以静态分配设备号也可以动态分配设备号
有两个函数实现这两种功能
/* 静态申请 */
int register_chrdev_region(dev_t from, unsigned count, const char *name);
//from:要申请的起始设备号,通常是通过MKDEV(major, 0)宏计算得到的,其中major是已知的主设备号。
//count:要申请的设备号数量。
//name:设备名,这个名称将出现在/proc/devices文件中。
//成功时返回0,失败时返回负数错误码。
/* 动态申请 */
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
//dev:用于接收分配到的起始设备号的指针。
//baseminor:起始次设备号,如果不需要特别指定,可以设为0。
//count:要申请的设备号数量。
//name:设备名,这个名称将出现在/proc/devices文件中。
//成功时返回0,并将分配到的起始设备号存储在*dev中;失败时返回负数错误码。
释放设备号
/* 释放设备号 */
void unregister_chrdev_region(dev_t first, unsigned int count);
//first:要注销的起始设备号。对于unregister_chrdev_region函数来说,这个参数是设备号范围的起始
//值,通常是通过MKDEV(major, 0)宏计算得到的,其中major是之前申请到的主设备号。
//count:要注销的设备号数量。这个参数指定了要注销的设备号范围中的设备号数量。
例程
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/modulepram.h>
#include<linux/kdev_t.h>
static int major;
static int minor;
module_param(major,int,S_IRUGO);
MODULE_PARAM_DESC(major,"e.g:major=1");
module_param(minor,int,S_IRUGO);
MODULE_PARAM_DESC(minor,"e.g:minor=1");
static int hello_init(void)
{
dev_t dev_num;
int ret;
printk("input major=%d minor=%d \n",major,minor);
if(major == 0)
{
//静态申请
dev_num=MKDEV(major,minor);
ret=register_chrdev_region(dev_num,1,"chrdev_num");
if(0 != ret)
{
printk("register_chrdev_region err %d\n",ret);
return ret;
}
}
else
{
//动态申请
ret=alloc_chrdev_region(&dev_num,0,1,"chrdev_num");
if(0 != ret)
{
printk("alloc_chrdev_regionerr %d\n",ret);
return ret;
}
printk("dev_num=%d \n",dev_num);
major = MAJOR(dev_num);
minor = MINOR(dev_num);
printk("input major=%d minor=%d \n",major,minor);
}
printk("hello word init\n");
return 0;
}
static void hello_exit(void)
{
//释放设备号
unregister_chrdev_region(dev_num,1);
printk("hello word exit\n");
return 0;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SONG");
MODULE_VERSION("v1.0");
编译生成.ko文件 加载到目标板
查看打印是否正确,也可以通过命令查看
cat /proc/devices