【问题标题】:Why do I have multiple product and vendor id's?为什么我有多个产品和供应商 ID?
【发布时间】:2018-10-17 05:12:57
【问题描述】:

目标: 我正在尝试将 4 个 RFID 阅读器连接到一个 Pi,我需要区分每个端口。

我做了什么: 我在终端中输入了lsusb,只插入了一个阅读器。它返回:

Bus 001 Device 004: ID 0c27:232a RFIDeas, Inc

这是我的读者。 所以我的供应商 ID 应该是 0c27 而我的产品 ID 应该是 232a 现在我需要序列号,因为我所有的读者都显示相同的供应商和产品 ID。

我的设备在端口ttyACM0 上,所以在终端中我搜索序列属性并通过输入验证我的产品 ID 和供应商 ID:

udevadm info --name=ttyACM0 --attribute-walk | grep -i "serial" -e "product" -e "vendor"

这会返回:

ATTRS{idProduct}=="232a"
ATTRS{idVendor}=="0c27"
ATTRS{product}=="USB Serial"
ATTRS{idProduct}=="9514"
ATTRS{idVendor}=="0424"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{product}=="DWC OTG Controller"
ATTRS{serial}=="3f980000.usb"

问题: 返回 3 个产品 ID 和 3 个供应商 ID。虽然只有一个序列号返回。

问题:

  1. 为什么只连接一个设备时返回 3 个产品 ID 和 3 个供应商 ID?

  2. 我应该在我的 udev 规则中使用哪些来创建永久设备名称?

如果我遗漏了什么,请告诉我,以便我更新问题。

编辑: 我已经使用第一个提到的产品 ID 和供应商 ID 成功创建了一个 udev 规则:

SUBSYSTEM=="tty", ATTRS{idVendor}=="0c27", ATTRS{idProduct}=="232a", SYMLINK+="reader1"

这会创建一个有效的 udev 规则,但是当我添加序列号 #ATTRS{serial}=="3f980000.usb" 时它会停止工作。我需要一个唯一的标识符。

【问题讨论】:

标签: linux usb udev


【解决方案1】:

虽然从您的角度来看,您只是将一台设备插入计算机,但 Linux 内核对正在发生的事情有更复杂的看法。内核跟踪设备的层次结构,每个设备都有自己的属性、驱动程序和子设备。层次结构的根通常是代表您的 CPU 的某种根设备,然后(可能间接)连接到 USB 控制器设备,该设备连接到“根集线器”,然后连接到您的物理 USB 设备插入,而 USB 设备公开的每个功能/接口可能都有子设备。

您可以运行man udevadm 以了解有关该命令作用的更多信息。它说:

   -a, --attribute-walk
       Print all sysfs properties of the specified device that can be used
       in udev rules to match the specified device. It prints all devices
       along the chain, up to the root of sysfs that can be used in udev
       rules.

所以有这个设备链,从 ttyACM0(USB 设备的一个函数)开始,一直到物理 USB 设备,然后是根集线器,然后是 USB 控制器,直到它到达等级制度。 --attribute-walk 选项沿着该链向上走,并沿途打印出每个设备的属性。

您将该命令的输出通过管道传输到grep,因此您看不到完整的输出,这可能是您感到困惑的原因。该命令的完整输出实际上是非常有用的:它打印出一个很好的段落来解释它的作用,并且当它从打印一个设备的属性切换到打印其父设备的属性时,还有一些有用的句子可以清楚地说明。以下是我在 Raspberry Pi 上检查 USB 设备时得到的一些输出:

$ udevadm info --name=sda2 --attribute-walk

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2':
    KERNEL=="sda2"
    SUBSYSTEM=="block"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda':
    KERNELS=="sda"
    SUBSYSTEMS=="block"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0':
    KERNELS=="target0:0:0"
    SUBSYSTEMS=="scsi"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0':
    KERNELS=="1-1.2.1:1.0"
    SUBSYSTEMS=="usb"
    [snip]

  looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1':
    KERNELS=="1-1.2.1"
    SUBSYSTEMS=="usb"
    [snip]

  [... and so on, up to the root device]

不幸的是,从您的udevadm 命令的输出来看,您的 RFID 适配器似乎没有 USB 序列号,因此将其与相同型号的其他设备区分开来可能会很棘手。要确认它没有序列号,我建议您运行lsusb -v -d 0c27:232a | grep iSerial。如果iSerial后面的数字为0,则表示没有序列号。

我建议查看 Linux 在/dev/serial/by-id 中为您创建的符号链接;也许这些符号链接的名称中将包含足够的详细信息,因此您无需创建新的 udev 规则。 (提示:运行ls -lR /dev/serial/by-id。)

如果您仍然需要更多帮助来查找或创建稳定的符号链接,我认为您应该插入所有四个 RFID 阅读器,然后发布每个命令的完整输出:

ls -lR /dev/serial/by-id
ls /dev/ttyACM*
udevadm info --name=ttyACM0 --attribute-walk

【讨论】:

    【解决方案2】:

    我可以通过输入以下内容来创建 udev 规则:

    SUBSYSTEM=="tty", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0002", ATTRS{serial}=="3f980000.usb", SYMLINK+="reader1"
    

    下面引用的 David Grayson 的回答解释了多个产品和供应商 ID 的原因。这就是导致我找到解决方案的原因。

    虽然从您的角度来看,您只是将一台设备插入计算机,但 Linux 内核对正在发生的事情有更复杂的看法。内核跟踪设备的层次结构,每个设备都有自己的属性、驱动程序和子设备。层次结构的根通常是代表您的 CPU 的某种根设备,然后(可能间接)连接到 USB 控制器设备,该设备连接到“根集线器”,然后连接到您的物理 USB 设备插入,而 USB 设备公开的每个功能/接口可能都有子设备。

    您可以运行 man udevadm 来详细了解该命令的作用。它说:

    -a, --attribute-walk 打印指定设备的所有可以使用的 sysfs 属性 在 udev 规则中匹配指定的设备。它打印所有设备 沿着链,直到可以在 udev 中使用的 sysfs 的根 规则。 所以有这个设备链,从 ttyACM0(USB 设备的一个函数)开始,一直到物理 USB 设备,然后是根集线器,然后是 USB 控制器,直到它到达层次结构的根。 --attribute-walk 选项沿着该链向上走,并沿途打印出每个设备的属性。

    您将该命令的输出通过管道传输到 grep 中,因此您看不到完整的输出,这可能是您感到困惑的原因。该命令的完整输出实际上是非常有用的:它打印出一个很好的段落来解释它的作用,并且当它从打印一个设备的属性切换到打印其父设备的属性时,还有一些有用的句子可以清楚地说明。以下是我在 Raspberry Pi 上检查 USB 设备时得到的一些输出:

    $ udevadm info --name=sda2 --attribute-walk

    udevadm 信息从 devpath 指定的设备开始,然后向上遍历父设备链。它以 udev 规则键格式为找到的每个设备打印所有可能的属性。要匹配的规则,可以由设备的属性和单个父设备的属性组成。

    查看设备'/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/ 0:0:0:0/block/sda/sda2': KERNEL=="sda2" SUBSYSTEM=="block" [snip]

    查看父设备 '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0 /0:0:0:0/block/sda': KERNELS=="sda" SUBSYSTEMS=="block" [snip]

    查看父设备 '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0 ': KERNELS=="target0:0:0" SUBSYSTEMS=="scsi" [snip]

    查看父设备'/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0':KERNELS=="1- 1.2.1:1.0" SUBSYSTEMS=="usb" [snip]

    查看父设备'/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1':KERNELS=="1-1.2.1" SUBSYSTEMS==" usb" [剪辑]

    [...等等,直到根设备]"

    【讨论】:

    • 您确定3f980000.usb 是您的RFID USB 设备的序列号吗?根据它在udevadm 输出中的显示位置,它似乎是您的 Raspberry Pi 的 USB 控制器的序列号。当您将不同的 RFID 阅读器插入同一个端口时,您可能会在其中看到相同的序列号,而您的 udev 规则将过于笼统。
    • 我明白了我的错误。在那种情况下,我的设备没有序列号是正确的。我试过lsusb -v -d 0c27:232a | grep iSerial。事实上,它确实返回 0。
    • 我也试过ls -lR /dev/serial/by-id。我从来没有听说过创建符号链接,所以我不确定如何处理这些信息。我正在调查。
    • 编辑:我没有听说过为此应用程序创建不是 udev 规则的符号链接。
    • ls -lR /dev/serial/by-id 的返回是total 0,然后是lrwxrwxrwx root root 13 Mar 14 00:52 usb-RFIDeas_USB_Serial-if00 -> ../../ttyACM0。不幸的是,我现在只能访问一个阅读器,所以我无法寻找这 4 个阅读器之间的差异。当它们到达时我会再次发布。再次感谢您的帮助。现在开始有意义了。
    猜你喜欢
    • 1970-01-01
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多