scull
字符设备驱动程序适合于大多数简单的硬件设备,它们都依赖于一个真正的设备驱动程序:scull,即Simple Character Utility for Loading Localities(区域装载的简单字符工具),scull是一个操作内存区域的字符设备驱动程序,这片区域就相当于一个设备
主设备号和次设备号
对字符设备的访问是通过文件系统内的设备名称进行的,这些名称被称为特殊文件、设备文件、或者为文件系统树的节点,他们通常位于/dev目录下 使用ls -l命令可以查看
第一列中的“c”用来表明这是一个字符设备
‘b’块设备
‘d’是目录
第一个数字“10” ‘“7”是主设备号,第二个数字是“175” “235”是次设备号 最后的时间是最后修改日期以及设备名称
主设备号:标识设备对应的驱动程序
例如,/dev/null和/dev/zero由驱动程序1管理 串口终端由驱动程序4管理,由此可见Linux内核允许多个驱动程序共享主设备号,但是通常来说大多数设备依然按照一个设备号对应一个驱动程序的原则
次设备号:由内核使用,用于确定设备文件所指的设备。我们可以通过次设备号获得指向内核设备的直接指针,也可以将次设备号当做设备本地数组的索引--即引导驱动程序( 主设备号标识)所实现的设备
设备编号的内部表达
在内核中,dev_t类型(<linux/type.h>中定义)用来保存设备编号--包括主设备号和次设备号,dev_t是一个32位的数,其中12位用来表示主设备号,其余20位用来表示次设备号
若想获得dev_t 的主设备号或次设备号,应使用<linux/kdev_t.h>中定义的宏
获得主设备号:MAJOR(dev_t dev);
获得次设备号:MINOR(dev_t dev);
若想将主设备号和次设备号转换成dev_t类型
MKDEV(int major,int minor);
分配和释放设备编号
在建立一个字符设备之间,我们的驱动程序首先要做的事情就是获得一个或者多个设备编号,此工作是通过register_chrdev_region函数完成的(在<linux/fs.h>中声明)
int register_chrdev_region(dev_t first,unsigned int count,char *name);
first:要分配设备编号范围的起始值
count:所请求的连续设备编号的个数
name:与该编号范围关联的设备名称(出现在/proc/devices 和sysfs中)
返回值:分配成功时为0,错误返回负的错误码
若是我们不知道所需要的设备编号,则需要动态的分配设备编号
int alloc_chrdev_region(dev_t dev,unsigned int firstminor,unsigned int count,char *name);
dev:用于在成功完成调用后保存已分配范围的第一个编号
firstminor:要使用的被请求的第一个次设备号,通常是0
使用该函数,内核会为我们恰当分配所需要的主设备号
不管采用哪种方法分配设备编号,都应该在不使用它们时释放这些设备编号
void unregister_chrdev_region(dev_t first,unsigned int count);
上面的函数为驱动程序分配设备编号,但并没有告诉内核拿这些编号做什么工作,在用户空间程序可访问上述设备编号之前,驱动程序需要将设备编号和内部函数连接起来,这些内部函数用来实现设备的操作
对于一个新的驱动程序,应该始终使用alloc_chrdev_region而不是register_chrdev_region来动态的分配主设备号