主设备号、次设备号和驱动程序加载

5
我是一名初学者,对于与设备驱动程序相关的主要号码和次要号码有一些了解。我知道大多数可以插入Linux系统的设备都有一个主要号码。并且基于这个主要号码,相应的驱动程序会被加载。
我有这个疑问,请告诉我内核如何从设备中读取主要号码,当它被插入时?
请尽可能简单地解释从设备插入到驱动程序加载的步骤。
先行致谢。
2个回答

18

主/次号适用于块设备和字符设备。

你不能从设备中“检测”出一个主号。也许你认为USB设备可以通信设备号码,Linux使用这些号码,但USB供应商/产品ID与主要号码无关。如果你将一个完全愚笨的串行设备插入串口,内核无法知道你插入/拔下了什么。

因此,例如,如果你想要一个字符设备的主号,那么要么你使用

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);

像NKamrath所说的那样,或者您可以使用绝对路径。但要注意,许多已被保留

据我所知,这里是您所要求的步骤:

  1. 将某个块/字符设备插入某个总线中。
  2. 根据总线类型(USB、PCI、PCI Express、SCSI、I²C等),总线(可能)会发送一个中断信号,它迟早会传递到CPU,从而传递到Linux。
  3. 中断例程根据总线类型及其内部机制执行必要的操作,为此设备加载适当的驱动程序(如果存在,则肯定存在)并执行其初始化函数。
  4. 设备驱动程序的初始化函数会注册(例如register_chrdev_region)一个主设备号,如果它已经被保留了(请参阅这个著名的保留列表);否则,它会请求内核为其分配一个(例如alloc_chrdev_region);驱动程序还将为该驱动程序保留一个次设备区域。
  5. 驱动程序设置一些回调函数(打开/关闭/读取/写入),并要求内核将它们与设备号关联起来。

此时,您可以使用该驱动程序的设备号进行通信,但是如何呢?在/dev中还没有任何内容……一种方法是在您知道要进行通信的主/次设备号对时使用mknod。您会发出:

# mknod /dev/mydevice c 232 4

这是要求:请在路径/dev/mydevice下创建一个设备节点,它与主设备号为232、次设备号为4的字符(c)设备相连。但是你怎么知道这些数字呢?它们可能是绝对值(保留列表),或者驱动程序printk输出它们以使您可以手动完成。

这里有更好的方法。

仍然在设备驱动程序的初始化函数中:驱动程序将设备注册为Sysfs设备(请参阅device_create)。这将把设备放入/sys树中,其节点(一个目录)将具有名为uevent的文件。如果您运行cat命令,它将输出类似以下内容:

MAJOR=232
MINOR=4
DEVNAME=whatever

试一试:

$ cat /sys/class/tty/console/uevent

是否匹配

$ ls -l /dev/console

现在,udev 是负责管理/dev的用户空间程序。总体而言,它简单地扫描/sys树来自动填充/dev。您还可以像这样查看所有字符和块设备的主/次编号:

$ ls /sys/dev/char
$ ls /sys/dev/block

大概就是这样了。如果你想更好地理解这一切,可以开发一个虚拟驱动程序,尝试让它自动出现在/dev中。


3
如果您提前知道主要编号,您可以使用
int register_chrdev_region(dev_t first, unsigned int count);

为了让内核动态分配设备的主设备号,请使用:
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, 
                    char *name);

要读取主要编号,请使用

int MAJOR(dev_t dev);

要插入设备或驱动程序,您必须使用insmod命令。然后,内核尝试使用您给出的编号,或者如果您使用了alloc函数,则动态分配一个空闲主编号。正确解释内核和驱动程序设计的内部工作需要大量的解释。但是,有一本非常好的免费书籍(对于编程书籍来说)叫做《Linux Device Drivers 3rd Edition》,它很容易阅读,可以为驱动程序提供很好的介绍,即使您只阅读前三章(大约100页),您也将对我认为您正在查找的内容有所了解。此外,所有示例的源代码都可用,因此您可以修改其演示文稿并更快地开始编写驱动程序!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接