介绍
如果我们为面向字节的操作编写驱动程序,那么我们将它们称为字符驱动程序。由于大多数设备都是面向字节的,因此大多数设备驱动程序都是字符设备驱动程序。例如,串行驱动程序、音频驱动程序、视频驱动程序、相机驱动程序和基本I/O驱动程序。事实上,所有既不是存储设备驱动程序也不是网络设备驱动程序的设备驱动程序都是某种类型的字符驱动程序。
应用程序如何与硬件设备通信?
applications -> device file or device Node -> Majaor and Minor Number -> \
device Driver -> Hardware
- 应用程序将打开设备文件。此设备文件由设备驱动程序创建。
- 然后这个设备文件将使用主次号找到相应的设备驱动程序。
- 然后该设备驱动程序将与硬件设备对话。
字符设备驱动的主次设备号
Linux 内核的基本特性之一是它抽象了设备的处理。所有硬件设备看起来都像普通文件;可以使用用于操作文件的相同标准系统调用来打开、关闭、读取和写入它们。对于Linux,一切皆文件。写硬盘时候是在写文件。读键盘数据的时候是在读文件。即使从内存中读取数据时也是从文件中读取。如果你尝试读取或尝试写入的文件是“普通”文件,则该过程很容易理解:先打开文件,然后对文件进行读取或者写入。所以,设备驱动也像文件一样,驱动程序会将每个硬件程序映射成一个特殊文件。然后就可以通过文件与硬件设备进行通信。
如果想要创建一个设备文件,我们需要了解主从设备号。
Linux内核将字符设备和块设备表示为一对数字 :。
主设备号(major)
主设备号用于标识与设备相关联的驱动程序。一个主设备号可以对应多个设备驱动程序。在linux主机上,使用cat /proc/devices命令可以看到设备号的分配情况
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
5 ttyprintk
...
Block devices:
7 loop
8 sd
9 md
11 sr
65 sd
...
次设备号(minor)
主设备号用于标识对应的驱动程序。许多设备可能使用相同的主设备号。所以我们需要为每个使用相同主设备号的设备再进行分配编号。所以就有了次设备号。换句话说,设备驱动程序使用次设备号 来区分具体的单个物理或逻辑设备。
分配主从设备号
用两种方式可以分配主从设备号
- 静态分配
- 动态分配
代码接口分析是基于Linux4.15.0,因为我装了基于该内核版本的Ubuntu18.04发行版系统
静态分配
如果要为驱动程序设置特定的主编号,可以使用此方法。
int register_chrdev_region(dev_t first, unsigned int count,cgar *name);
first参数是要分配的范围的起始设备号。
count是申请的连续设备编号的总数,请注意,如果count很大,申请的范围可能会溢出到下一个主设备号;但只要申请的号码范围可用,就不会存在什么问题。
name是与设备号相关联的设备名称,就像是保存在/proc/devices文件中的"tty","sd"等设备名称。
dev_t 类型(在 <linux/types.h> 中定义)用于保存设备号。其实就是一个32位整型数,其中12位用于主编号,20位用于次编号。
typedef __kernel_dev_t dev_t;
typedef __u32 __kernel_dev_t;
如果你想要使用主从设备号生成dev_t变量,你可以使用
#define MKDEV(ma,mi) ((