如何在不打开 Linux 的情况下找到所有串行设备(ttyS、ttyUSB、..)?

新手上路,请多包涵

获取 Linux 系统上所有可用串行端口/设备列表的正确方法是什么?

换句话说,当我遍历 /dev/ 中的所有设备时,我如何以经典方式判断哪些是串行端口,即通常支持波特率和 RTS/CTS 流控制的那些?

解决方案将用 C 编码。

我问是因为我使用的第三方库明显错误:它似乎只迭代 /dev/ttyS* 。问题在于,例如,USB 上的串行端口(由 USB-RS232 适配器提供),这些端口列在 /dev/ttyUSB* 下。阅读 Linux.org 上的 Serial-HOWTO 后,我了解到随着时间的推移,还会有其他名称空间。

所以我需要找到检测串口设备的官方方法。问题是似乎没有记录,或者我找不到它。

我想一种方法是从 /dev/tty* 打开所有文件并在它们上调用特定的 ioctl() 仅在串行设备上可用。不过,这会是一个好的解决方案吗?

更新

hrickards 建议查看“setserial”的来源。它的代码完全符合我的想法:

首先,它打开一个设备:

 fd = open (path, O_RDWR | O_NONBLOCK)

然后它调用:

 ioctl (fd, TIOCGSERIAL, &serinfo)

如果该调用没有返回错误,那么它显然是一个串行设备。

我在 _Serial Programming/termios_ 中发现了类似的代码,它建议还添加 O_NOCTTY 选项。

但是,这种方法存在一个问题:

当我在 BSD Unix(即 Mac OS X)上测试这段代码时,它运行良好。 但是,通过蓝牙提供的串行设备会导致系统(驱动程序)尝试连接到蓝牙设备,这需要一段时间才能返回超时错误。这是由于刚刚打开设备造成的。我可以想象类似的事情也会发生在 Linux 上——理想情况下,我不需要打开设备来确定它的类型。我想知道是否还有一种方法可以在没有打开的情况下调用 ioctl 函数,或者以不会导致建立连接的方式打开设备?

我应该怎么办?

原文由 Thomas Tempelmann 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 924
2 个回答

/sys 文件系统应该包含大量信息用于您的任务。我的系统(2.6.32-40-generic #87-Ubuntu)建议:

 /sys/class/tty

它为您提供了系统已知的所有 TTY 设备的描述。一个精简的例子:

 # ll /sys/class/tty/ttyUSB*
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 /sys/class/tty/ttyUSB0 -> ../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.0/ttyUSB0/tty/ttyUSB0/
lrwxrwxrwx 1 root root 0 2012-03-28 20:44 /sys/class/tty/ttyUSB1 -> ../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/ttyUSB1/tty/ttyUSB1/

以下链接之一:

 # ll /sys/class/tty/ttyUSB0/
insgesamt 0
drwxr-xr-x 3 root root    0 2012-03-28 20:43 ./
drwxr-xr-x 3 root root    0 2012-03-28 20:43 ../
-r--r--r-- 1 root root 4096 2012-03-28 20:49 dev
lrwxrwxrwx 1 root root    0 2012-03-28 20:43 device -> ../../../ttyUSB0/
drwxr-xr-x 2 root root    0 2012-03-28 20:49 power/
lrwxrwxrwx 1 root root    0 2012-03-28 20:43 subsystem -> ../../../../../../../../../../class/tty/
-rw-r--r-- 1 root root 4096 2012-03-28 20:43 uevent

此处 dev 文件包含以下信息:

 # cat /sys/class/tty/ttyUSB0/dev
188:0

这是主要/次要节点。这些可以在 /dev 目录中搜索以获得用户友好的名称:

 # ll -R /dev |grep "188, *0"
crw-rw----   1 root dialout 188,   0 2012-03-28 20:44 ttyUSB0

/sys/class/tty 目录包含所有 TTY 设备,但您可能希望排除那些讨厌的虚拟终端和伪终端。我建议您仅检查具有 device/driver 条目的那些:

 # ll /sys/class/tty/*/device/driver
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS0/device/driver -> ../../../bus/pnp/drivers/serial/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS1/device/driver -> ../../../bus/pnp/drivers/serial/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS2/device/driver -> ../../../bus/platform/drivers/serial8250/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS3/device/driver -> ../../../bus/platform/drivers/serial8250/
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 /sys/class/tty/ttyUSB0/device/driver -> ../../../../../../../../bus/usb-serial/drivers/ftdi_sio/
lrwxrwxrwx 1 root root 0 2012-03-28 21:15 /sys/class/tty/ttyUSB1/device/driver -> ../../../../../../../../bus/usb-serial/drivers/ftdi_sio/

原文由 A.H. 发布,翻译遵循 CC BY-SA 3.0 许可协议

在最近的内核中(不确定从什么时候开始),您可以列出 /dev/serial 的内容以获取系统上的串行端口列表。它们实际上是指向正确 /dev/ 节点的符号链接:

 flu0@laptop:~$ ls /dev/serial/
total 0
drwxr-xr-x 2 root root 60 2011-07-20 17:12 by-id/
drwxr-xr-x 2 root root 60 2011-07-20 17:12 by-path/
flu0@laptop:~$ ls /dev/serial/by-id/
total 0
lrwxrwxrwx 1 root root 13 2011-07-20 17:12 usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0 -> ../../ttyUSB0
flu0@laptop:~$ ls /dev/serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 2011-07-20 17:12 pci-0000:00:0b.0-usb-0:3:1.0-port0 -> ../../ttyUSB0

如您所见,这是一个 USB 串行适配器。注意,当系统上没有串口时,/dev/serial/目录不存在。希望这可以帮助 :)。

原文由 flu0 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题