Linux设备驱动程序 之 主次设备号
主设备号和次设备号
对字符设备的访问是通过文件系统内的设备名称进行的,这些名称被称为特殊文件、设备文件、或者简单称之为文件系统树的节点,它们通常位于/dev目录。字符设备驱动程序的设备文件可以通过ls -l命令输出的第一列中的c字符来识别,块设备也出现在/dev下,但它们由字符b来标识;
通过执行ls -l 命令,可以看到在修改日期之前,有两个用逗号分隔的数字,分别为主设备号和次设备号。
主设备号标识设备对应的驱动程序;linux设备内核允许多个驱动程序共享主设备号;
次设备号由内核使用,用用户正确确定设备文件所指的设备。依赖驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可以将次设备号当做设备本地数组的索引。不管哪种方式,除了知道次设备号用来指向驱动程序所实现的设备之外,内核本身不关心关于此设备号的其他信息;
crw-rw----. root video , Nov : agpgart
crw-------. root root , Nov : autofs
drwxr-xr-x. root root Nov : block
drwxr-xr-x. root root Nov : bsg
crw-------. root root , Nov : btrfs-control
drwxr-xr-x. root root Nov : bus
lrwxrwxrwx. root root Nov : cdrom -> sr0
drwxr-xr-x. root root Nov : char
crw-------. root root , Nov : console
lrwxrwxrwx. root root Nov : core -> /proc/kcore
drwxr-xr-x. root root Nov : cpu
crw-------. root root , Nov : cpu_dma_latency
crw-------. root root , Nov : cuse
drwxr-xr-x. root root Nov : disk
crw-rw----+ root audio , Nov : dmmidi
设备编号的内部表达
内核中,dev_t类型(位于<linux/types.h>)用来保存设备编号,包括主设备号和次设备号;
typedef __u32 __kernel_dev_t; typedef __kernel_dev_t dev_t;
可见dev_t类型是个32位的无符号整数,其中12位用来表示主设备号,其余20位表示次设备号;我们不应该对设备编号的组织做假定,而应该始终使用如下两个宏(位于linux/kdev_t.h)来获取主次设备号;
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1) #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
如果需要将主次设备号转换成dev_t类型,则使用下面宏(位于linux/kdev_t.h):
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
分配和释放设备编号
指定范围分配编号:
在建立一个字符设备之前,我们的驱动程序首先要做的事情就是获取一个或者多个设备编号,完成该工作的必要函数是register_chrdev_region,该函数在<linux/fs.h>中声明:
int register_chrdev_region(dev_t from, unsigned count, const char *name)
参数from标识要分配的设备号范围的起始值,次设备号经常设置为0,但对该函数不是必须的;
参数count标识分配设备号的个数,如果count非常大,则所请求的范围可能和下一个主设备号重叠,但是只要我们所请求的编号范围是可用的,则不会带来问题;
参数name是和该编号范围关联的设备名称,它将出现在/proc/devices和sysfs中;
动态分配设备编号:
在不知道要分配的设备号的时候,可以使用动态分配的方式,函数如下:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
参数dev是仅用于输出的参数,在成功完成调用后将保存已分配范围的第一个编号;
参数baseminor是要使用的被请求的第一个次设备号,通常是0;
参数count标识分配设备号的个数;
参数name是和该编号范围关联的设备名称;
始终使用动态分配设备编号:
对于新的驱动程序,强烈建议不要随便选择一个当前设备未使用的设备号作为主设备号,而应该使用动态分配机制获取主设备号;驱动程序应该使用使用alloc_chrdev_region而不是register_chrdev_region函数;
动态分配的缺点:由于分配的主设备号不能始终保持一致,素以无法预先创建设备节点;对于驱动程序的一般做法是,为了加载一个使用动态主设备号的设备驱动程序,对insmod的调用可替换成一个简单的脚本,该脚本在调用insmod之后读取/proc/devices以获得新分配的主设备号,然后创建对应的设备文件;
释放设备编号:
在不使用设备编号的时候需要进行释放,函数如下:
void unregister_chrdev_region(dev_t from, unsigned count)
Linux设备驱动程序 之 主次设备号的更多相关文章
- Linux设备驱动程序学习----1.设备驱动程序简介
设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介 Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...
- Linux设备驱动程序 之 字符设备的注册
内核内部使用struct cdev结构来标识字符设备,在内核调用设备的操作之前,必须分配并注册一个或者多个上述结构,为此,我们的代码需要包含<linux/cdev.h>,其中定义了这个结构 ...
- Linux串口驱动程序(3)-打开设备
先来分析一下串口打开的过程: 1.用户调用open函数打开串口设备文件:2.在内核中通过tty子系统,把open操作层层传递到串口驱动程序中:3.在串口驱动程序中的xx_open最终实现这个操作.这里 ...
- ARM Linux字符设备驱动程序
1.主设备号和次设备号(二者一起为设备号): 一个字符设备或块设备都有一个主设备号和一个次设备号.主设备号用来标识与设备文件相连的驱动程序,用来反 映设备类型.次设备号被驱动程序用来辨别操作的是哪个 ...
- 如何编写Linux设备驱动程序
一.Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看 ...
- Linux内核入门到放弃-设备驱动程序-《深入Linux内核架构》笔记
I/O体系结构 总线系统 PCI(Peripheral Component Interconnect) ISA(Industrial Standard Architecture) SBus IEEE1 ...
- 深入理解Linux内核-I/O体系结构和设备驱动程序
系统总线:1.链接CPU.RAM.I/O设备之间的数据流动.例如:PCI.ISA.EISA.MCA.SCSI.USB2.任何I\O设备有且仅能链接一条总线. I\O端口:1.每个连接到I\O总线上的设 ...
- linux设备驱动程序-i2c(0)-i2c设备驱动源码实现
(基于4.14内核版本) 为了梳理清楚linux内核中的i2c实现框架,从本文开始,博主将分几个章节分别解析i2c总线在linux内核中的形成过程.匹配过程.以及设备驱动程序源码实现. 在介绍linu ...
- Linux设备驱动程序学习----目录
目录 设备驱动程序简介 1.设备驱动程序简介 构造和运行模块 2.内核模块和应用程序的对比 3.模块编译和装载 4.模块的内核符号表 5.模块初始化和关闭 6.模块参数 7.用户空间编写驱动程序 ...
随机推荐
- arcgis js之调用wms服务
arcgis js之调用wms服务 定义: export const tdtlayer = async () => { let WMSLayer = await arcgisPackage.WM ...
- 四款免费好用的Bootstrap ui编辑器
Bootstrap带来了设计革命,本文介绍的四种免费Bootstrap在线设计工具,可视化所见所得设计网页,然后输出Html/CSS代码,其中有些甚至可以实现拖曳,也有可以设定自己的主题模板Theme ...
- 5.Servlet 对象(request-response)
/*ServletResponse*/ /*responese常见应用*/ 1.向客户端输出中文数据 (分别以OutputStream 和 PrintWriter输出) 2.文件下载和中文文件的下载 ...
- Oracle面试题及答案整理
一下题目根据此表变换 1.表:table1(FId,Fclass,Fscore),用最高效最简单的SQL列出各班成绩最高的列表,显示班级,成绩两个字段. select stu_class, max(s ...
- JavaSpring【七、AspectJ】
AspectJ 概念 @AspectJ类似纯Java注解的普通Java类 Spring可以使用AspectJ来作为切入点 AOP在运行时仍是纯SpringAOP,对AspectJ无依赖 配置: 对@A ...
- scrapy 增量采集
在做新闻或者其它文章采集到时候,只想采集最新发布的信息,之前采集过得就不要再采集了,从而达到增量采集到需求 scrapy-deltafetch,是一个用于解决爬虫去重问题的第三方插件. scrapy- ...
- MySQL无法启动:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
1 详细异常 ct 11 17:31:51 bd02.getngo.com mysqld[20513]: 2019-10-11T09:31:51.187848Z 0 [Note] /usr/sbin/ ...
- 高级IO——文件锁
文件锁也被称为记录所,文件锁如果深讲的话,内容不少(比如文件锁最起码分为了建议锁和强制性锁,暂时挖坑,后面填). 文件锁作用 顾名思义,就是用来保护文件数据的.当多个进程共享读写同一个文件时,为了不让 ...
- java线程基础巩固---如何给你的应用程序注入钩子程序
这次做一个比较有意思的实验,我们知道当一个程序如果抛异常了其程序肯定会挂掉,那有木有可能在程序异常退出时能执行一段咱们自己的代码,比如说服务器在异常退出时需要做一些额外的资源清理,像这种场景就正好是这 ...
- golang多维数组的切片
通过for循环来取多维数组的切片 package main import ( "fmt" ) func main() { a := [...]string{"USA&qu ...