在 Linux 中, '/dev' 目录中的文件如何匹配设备模型?

3
在文件读写中,我的理解是这样的:
在应用层,可以调用fopen()方法。
fwrite()方法会调用系统调用open()。
当操作系统接收到open()调用时,它将把命令传递给虚拟文件系统(VFS)。
VFS查找包括所需任何目录的文件名,并执行必要的访问检查。
如果在RAM缓存中,则不需要磁盘访问。如果没有,则VFS会向特定的文件系统发送读取请求,该文件系统可能是EXT4。
然后,EXT4文件系统驱动程序将确定该目录位于哪个磁盘块中。然后将向磁盘设备驱动程序发送读取命令。
现在假设我想读取连接到板上的i2c设备A。文件目录为/dev/i2c/A。
  • 所有设备是否都有一个主编号?例如,Linux OS设置USB的主编号为180.那么在设备端,每个USB设备是否都有180的主编号?

  • 如果第一题的答案是否定的,那么Linux OS如何确定device A的类型,只是根据文件目录吗?

  • 我认为第二个问题的答案可能是:在引导初始化阶段,已经有一些特定代码使用类似export()的东西将该端口挂载到文件系统中。所以事实上,在引导阶段之后,文件目录/dev/i2c/A会存在,并与i2c设备的主编号绑定。因此,当我想打开dev/i2c/A时,操作系统将为我找到正确的i2c驱动程序,而不是SPI或USB驱动程序。我对这部分不太确定,需要更多的信息。

  • 在设备挂载到文件系统之后,如果我有一个usb,它如何被挂载到文件系统并具有正确的180主编号?我猜在挂载阶段开始之前,插入usb时会发生中断?


1
这个问题的标题与内容不符。内容是关于“Linux如何确定在/dev/树中特定路径下将打开哪个驱动程序”。而关于“为设备选择哪个驱动程序”的问题完全不同:即通过启发式探测或借助“即插即用”系统来识别外围设备。 - Kaz
一个非常类似的问题,也被关闭了。 - artless noise
2个回答

9
请参考:热插拔文档。如果您运行示例代码,您会发现在向USB添加/删除设备时会发送一个netlink事件。这是驱动程序模型的一部分。每个驱动程序都应该连接到一个BUS;这可以是平台USBI2CSPIPCI等。此外,在sysfs中,将有条目标识特定设备。通常可以使用I2C地址来标识特定的客户端/从设备。驱动程序模型还支持挂起、恢复、有序关闭等功能。 /dev/文件是由udevmdev用户空间程序创建的。它们将名称与设备节点(major、minor、char/block)关联起来。您可以使用sysfs和/或您的udev脚本基于netlink信息创建所需的设备名称;大多数信息都可以在udev脚本中获取。 编辑:对于i2c总线主驱动程序,通过运行probe注1发现设备的地址。使用表格将设备与特定的驱动程序关联。例如,stargate机器文件有一个imote2_i2c_board_info,它将i2c地址与驱动程序关联。类似的表格也适用于SPI设备。使用platform_add_devices()添加Platform注2设备。USBPCI设备由设备的相应BUS特定ID识别。通常,一个机器文件(或最近的device tree)将这两个关联起来。
另请参见:Linux Journal - I2C Drivers pt1Linux Journal - I2C Drivers pt2

我认为混淆的来源是所有驱动程序/设备都在/dev/目录中。这是不正确的。只有顶级驱动程序对用户可见。许多Linux驱动程序/设备由主设备使用。它们可以形成设备层次结构。通常,只有顶级设备向用户公开。例如,存在函数spi_write(),高级别驱动程序可以使用该函数通过SPI进行通信,但SPI设备不会暴露给user space。声音和媒体/电视捕获卡通常使用SPI设备,但用户从不知道这个BUS的存在并被使用。通常,多个卡供应商将在底层使用相同的芯片组。而不是为每张卡编写驱动程序,只编写一些卡的glue。然后,使用chip驱动程序的通用集合与glue在层次结构的顶部将其全部连接起来;这是向user space公开的顶级驱动程序。这也允许smartTM芯片供应商创建系统集成商可以使用的良好驱动程序。

< p >< em>注1:通过探测,我指的是请求总线上所有注册地址的消息。我不确定probe 是否是正确的i2c 术语。

注2:平台 设备是 SOC 设备。它们没有关联的总线,因此平台是一个综合性的概念。通常,平台 设备都与 CPU 集成在一起(SOC 代表系统芯片)。


3
平台设备是指SOC(片上系统)设备。它们没有关联的总线,因此平台是这些设备的通用名称。通常,它们与CPU集成在一起(SOC代表“片上系统”)。您不需要一个 gpio 驱动程序,有一个库可以使用。您可以将 GPIO 引脚传递给驱动程序(也许以太网驱动程序想要闪烁LED灯)。在不同的板子上,使用不同的GPIO引脚,但以太网驱动程序不会关心哪个引脚,它只使用传递给它的一些 平台数据。通常只需传递函数指针,最终将使用GPIO,因为这样可以提供更大的灵活性。 - artless noise
2
@henryyao,如果驱动程序在某个地方维护一个文件(设备节点、debugfs 中的文件或其他任何地方),则它会在 struct file_operations 中指定回调函数,如 open() 等,并在创建文件时注册该结构。当应用程序打开文件、从中读取或写入数据、为其调用 ioctl() 等操作时,这些回调函数将被调用。一些驱动程序使用此功能来管理与用户空间之间的数据传输、调整参数等。 - Eugene
@Eugene,那么什么情况下应该使用像.prob这样的函数呢?难道驱动程序中包含.prob的设备也应该有.open函数吗?因为所有设备都需要作为文件打开,对吧? - henryyao
1
@Henryyao。有些驱动程序不对“用户空间”公开。大多数人不想直接使用“i2c”。通常,顶层设备是具有open()read()等功能的设备。例如,音频卡将具有SSI接口、编解码器芯片和许多GPIO。编解码器芯片可能使用SPII2C;这用于设置音量混音器等;用户空间使用ioctl()来完成此操作。实际的PCM音频数据通过SSI从主CPU内存传输到编解码器。在CPU侧有SSI驱动程序,这些必须连接到编解码器;这些是通用的。 - artless noise
1
@Henryyao。最后,有一个顶级机器驱动程序将所有这些东西组合在一起。sound/soc目录具有此类常见的基础结构用户空间可以通过此基础结构进行通信,但是顶级机器驱动程序会将数据/请求路由到不同的总线等。请参阅:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=sound/soc/soc-io.c;hb=HEAD 以获取对I2C/SPI声音抽象的了解。 - artless noise
显示剩余5条评论

1
每个设备都有一个主号和次号。您可以通过执行ls -n /dev来查看它们。对于某些驱动程序,如磁盘,主要数字是硬编码的。对于其他驱动程序,它是动态的。次要数字可以在运行时动态分配,而不仅仅是在启动时发现设备。内核维护一个内部设备转换表,将dev号映射到正确的驱动程序。

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