作者:世至其美
原文地址:https://hqber.com
字符设备驱动程序scull
scull设备是一个操作内存的字符设备,不是真正的设备,只是向内核注册为字符设备,并使用内存来存取数据。
1. scull的设计
- scull0~scull3:分别是由一个全局且持久的内存区域组成。
- scullpip0 ~ sullpip3:多个进程读取同一个设备,可能发生数据竞争,在不借助中断的条件下,实现阻塞式和非阻塞式读/写操作。
- scullsingle:一次只允许一个进程使用该驱动程序。
- scullpriv:对每个虚拟控制台(或X终端会话)是私有,每个控制台/终端上的进程将获取不同的内存区
- sculluid:每次只能由一个用户打开,如果另一个用户锁定该设备,sculluid将返回"Device Busy"。
- scullwuid:每次只能由一个用户打开,如果另一个用户锁定该设备,sullwuid实现了阻塞式的open。
2. 主设备号和次设备号
主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。内核由次设备号确定当前所指向的是哪个设备。根据所编写的驱动程序,可以从内核那里得到一个直接指向设备的指针,或者使用次设备号作为一个设备本地数组的索引。
主设备号:标识与设备关联的驱动程序。
次设备号:由内核使用,用于确定设备文件所指的设备。
3. 设备编号的内部表达
在内核中,dev_t类型(<linux types.h>)用来保存设备编号--包括主设备号和次设备号。在内核Linux2.6.0版本中,dev_t是一个32位的数,其中的12位用来表示主设备号,其余20位用来表示次设备号,设备编号应该使用<linux kdev_t.h>中定义的宏。
3.1 获取dev_t的主设备号或次设备号:
MAJOR(dev_t dev);
MINOR(dev_t dev);
3.2 将主设备号和次设备号转换成dev_t类型:
MKDEV(int major, int minor);
4. 分配和释放设备编号
在建立一个字符设备之前,驱动程序需要获得一个或多个设备编号。
4.1 静态申请设备编号
如果提前确定所需要的设备编号,可以通过register_chrdev_region()函数注册设备编号:
#include <linux fs.h>
int register_chrdev_region(dev_t first, unsigned int count, char *name);
4.2 动态申请设备编号
如果不知道设备将要使用的设备编号,可以通过alloc_chrdev_region()函数注册设备编号:
#include <linux fs.h>
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
5. 释放设备编号
在不使用申请的设备编号时,要释放这些设备编号,通常在模块的清除函数中释放申请的设备编号;设备编号的释放需要使用以下函数实现:
#include <linux fs.h>
void unregister_chrdev_region(dev_t first, unsigned int count);
在scull驱动中获取主设备号的代码
if (scull_major) {
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, scull_nr, "scull");
} else {
result = alloc_chrdev_region(&dev, scull_minor, scull_nr, "scull");
scull_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
return result;
}
作者:世至其美
原文地址:https://hqber.com