(本章基于:linux-4.4.0-37)
Linux中设备编号分为主、次两种。主设备编号表示设备相连的驱动。次设备号决定引用哪个设备,这个由驱动自行定义。
在内核中,设备编号类型为dev_t,本质就是一个32位无符号整型的量,在linux/types.h中定义。其中主编号占12位,次编号占20位。通过下面的宏可以获取主次编号:
MAJOR(dev_t dev);
MINOR(dev_t dev);
相反,通过主次编号获取设备编号使用:
MKDEV(int major, int minor);
以上宏在linux/kdev_t.h中定义
静态注册设备编号:
int register_chrdev_region(dev_t, unsigned, const char *);
1)需要注册的设备编号
2)连续编号个数
3)设备名,会出现在/proc/devices中
注册成功返回0,失败返回一个错误码
静态注册需要实现准备好一个设备号,但必须去其他的驱动模块区分开来,不能重复,因此静态注册并不常用,更通用的方法是让内核动态为你分配一个设备编号。
动态注册设备编号:
int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
1)设备编号
2)第一个次设备号,常用0
3)连续编号个数
4)设备名
成功注册返回0,失败返回一个错误码
无论用哪种方式注册设备编号,当不再使用的时候需要注销此设备号,以防止不必要的资源占用。
注销设备编号:
void unregister_chrdev_region(dev_t, unsigned);
1)待注销的设备号
2)连续的设备号个数
以上函数均在linux/fs.h中定义
例:
hello.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
dev_t devId;
static __init int hello_init(void)
{
int result;
#if 0
//静态
if(( result = register_chrdev_region(MKDEV(888, 0), 10, "stone-dev") ) != 0) {
printk(KERN_WARNING "register dev id error:%d\n", result);
} else {
printk(KERN_WARNING "register dev id success!\n");
}
#else
//动态
if(( result = alloc_chrdev_region(&devId, 0, 1, "stone-alloc-dev") ) != 0) {
printk(KERN_WARNING "register dev id error:%d\n", result);
} else {
printk(KERN_WARNING "register dev id success!\n");
}
#endif
printk(KERN_ALERT "hello init success!\n");
return 0;
}
static __exit void hello_exit(void)
{
//unregister_chrdev_region(MKDEV(888, 0), 10);
unregister_chrdev_region(devId, 1);
printk(KERN_WARNING "helloworld exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
成功加载模块后可在/proc/devices中查看
# cat /proc/devices | grep stone
247 stone-alloc-dev