如何区分相同的USB转串口适配器?


26

我在笔记本电脑(Ubuntu 9.10)上使用了许多相同的USB到串行适配器。适配器由Sabrent制造,并围绕Prolific PL2303 IC构建,如下所示lsusb

Bus 001 Device 008: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port  
Bus 001 Device 007: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port  
Bus 001 Device 006: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port  

显示的所有属性udevadm似乎都不是特定适配器唯一的:

foo@bar:~$ udevadm info --attribute-walk --path=/sys/bus/usb-serial/devices/ttyUSB0

   looking at device
 '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.1/1-4.1:1.0/ttyUSB0':  
     KERNEL=="ttyUSB0"  
     SUBSYSTEM=="usb-serial"  
     DRIVER=="pl2303"   
     ATTR{port_number}=="0"  

   looking at parent device
 '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.1/1-4.1:1.0':
     KERNELS=="1-4.1:1.0"  
     SUBSYSTEMS=="usb"  
     DRIVERS=="pl2303"  
     ATTRS{bInterfaceNumber}=="00"  
     ATTRS{bAlternateSetting}==" 0"  
     ATTRS{bNumEndpoints}=="03"  
     ATTRS{bInterfaceClass}=="ff"  
     ATTRS{bInterfaceSubClass}=="00"  
     ATTRS{bInterfaceProtocol}=="00"  
     ATTRS{modalias}=="usb:v067Bp2303d0300dc00dsc00dp00icFFisc00ip00"  
     ATTRS{supports_autosuspend}=="1"  

   looking at parent device
 '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.1':
     KERNELS=="1-4.1"   
     SUBSYSTEMS=="usb"  
     DRIVERS=="usb"   
     ATTRS{configuration}==""  
     ATTRS{bNumInterfaces}==" 1"  
     ATTRS{bConfigurationValue}=="1"  
     ATTRS{bmAttributes}=="80"  
     ATTRS{bMaxPower}=="100mA"  
     ATTRS{urbnum}=="538"  
     ATTRS{idVendor}=="067b"  
     ATTRS{idProduct}=="2303"  
     ATTRS{bcdDevice}=="0300"  
     ATTRS{bDeviceClass}=="00"  
     ATTRS{bDeviceSubClass}=="00"  
     ATTRS{bDeviceProtocol}=="00"  
     ATTRS{bNumConfigurations}=="1"  
     ATTRS{bMaxPacketSize0}=="64"  
     ATTRS{speed}=="12"  
     ATTRS{busnum}=="1"  
     ATTRS{devnum}=="6"  
     ATTRS{version}==" 1.10"  
     ATTRS{maxchild}=="0"  
     ATTRS{quirks}=="0x0"  
     ATTRS{authorized}=="1"  
     ATTRS{manufacturer}=="Prolific Technology Inc."  
     ATTRS{product}=="USB-Serial Controller"  

     <snip>

 foo@bar:~$ udevadm info --attribute-walk --path=/sys/bus/usb-serial/devices/ttyUSB1

   looking at device
 '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.5/1-4.5:1.0/ttyUSB1':
     KERNEL=="ttyUSB1"  
     SUBSYSTEM=="usb-serial"  
     DRIVER=="pl2303"  
     ATTR{port_number}=="0"  

   looking at parent device
 '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.5/1-4.5:1.0':
     KERNELS=="1-4.5:1.0"  
     SUBSYSTEMS=="usb"  
     DRIVERS=="pl2303"  
     ATTRS{bInterfaceNumber}=="00"  
     ATTRS{bAlternateSetting}==" 0"  
     ATTRS{bNumEndpoints}=="03"  
     ATTRS{bInterfaceClass}=="ff"  
     ATTRS{bInterfaceSubClass}=="00"  
     ATTRS{bInterfaceProtocol}=="00"  
     ATTRS{modalias}=="usb:v067Bp2303d0300dc00dsc00dp00icFFisc00ip00"  
     ATTRS{supports_autosuspend}=="1"  

   looking at parent device
 '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.5':
     KERNELS=="1-4.5"  
     SUBSYSTEMS=="usb"  
     DRIVERS=="usb"  
     ATTRS{configuration}==""  
     ATTRS{bNumInterfaces}==" 1"  
     ATTRS{bConfigurationValue}=="1"  
     ATTRS{bmAttributes}=="80"  
     ATTRS{bMaxPower}=="100mA"  
     ATTRS{urbnum}=="69"  
     ATTRS{idVendor}=="067b"  
     ATTRS{idProduct}=="2303"  
     ATTRS{bcdDevice}=="0300"  
     ATTRS{bDeviceClass}=="00"  
     ATTRS{bDeviceSubClass}=="00"  
     ATTRS{bDeviceProtocol}=="00"  
     ATTRS{bNumConfigurations}=="1"  
     ATTRS{bMaxPacketSize0}=="64"  
     ATTRS{speed}=="12"  
     ATTRS{busnum}=="1"  
     ATTRS{devnum}=="7"  
     ATTRS{version}==" 1.10"  
     ATTRS{maxchild}=="0"  
     ATTRS{quirks}=="0x0"  
     ATTRS{authorized}=="1"  
     ATTRS{manufacturer}=="Prolific Technology Inc."  
     ATTRS{product}=="USB-Serial Controller"  

     <snip>

所有适配器均插入单个USB集线器中。由于我无法区分适配器本身,因此我有什么办法可以编写udev规则,根据插入适配器的集线器上的哪个物理端口来固定每个适配器的名称?

Answers:


24

有什么办法可以编写一个udev规则,根据插入适配器的集线器上的哪个物理端口来固定每个适配器的名称?

是的,事实证明它是存在的。考虑上面第二个示例中显示的设备层次结构的最后一部分:

查看父设备'/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.5':KERNELS ==“ 1-4.5”
SUBSYSTEMS ==“ usb”
DRIVERS ==“ usb “
ATTRS {configuration} ==”“
ATTRS {bNumInterfaces} ==” 1“
ATTRS {bConfigurationValue} ==” 1“
ATTRS {bmAttributes} ==” 80“
ATTRS {bMaxPower} ==” 100mA“
ATTRS {urbnum} = =“ 69”
ATTRS {idVendor} ==“ 067b”
ATTRS {idProduct} ==“ 2303”
ATTRS {bcdDevice} ==“ 0300”
ATTRS {bDeviceClass} ==“ 00”
ATTRS {bDeviceSubClass} ==“ 00”
ATTRS {bDeviceProtocol} ==“ 00”
ATTRS {bNumConfigurations} ==“ 1”
ATTRS {bMaxPacketSize0} ==“ 64”
ATTRS {speed} ==“ 12”
ATTRS {busnum} ==“ 1”
ATTRS {devnum} ==“ 7” ATTRS {version} ==“ 1.10” ATTRS {maxchild} ==“ 0” ATTRS {quirks} ==“ 0x0”
ATTRS {authorized} ==“ 1”
ATTRS {manufacturer} = =“ Prolific Technology Inc.”
ATTRS {product} ==“ USB串行控制器”

内核为此设备指定的名称(KERNELS ==“ 1-4.5”)表示此设备已插入连接到总线1上端口4的集线器的第五个端口中(有关如何解码的更多信息,请参阅此FAQ) sysfs usb设备层次结构)。在该指南的帮助下,我为udev到USB串行端口转换器编写了以下udev规则集:

KERNEL ==“ ttyUSB *”,KERNELS ==“ 1-8.1.5”,NAME =“ ttyUSB0”
KERNEL ==“ ttyUSB *”,KERNELS ==“ 1-8.1.6”,NAME =“ ttyUSB1”
KERNEL = =“ ttyUSB *”,KERNELS ==“ 1-8.1.1”,NAME =“ ttyUSB2”
KERNEL ==“ ttyUSB *”,KERNELS ==“ 1-8.1.2”,NAME =“ ttyUSB3”

这些规则有一个明显的缺点:它们假定所有USB到串行转换器都将插入同一集线器(“ 1-8.1。*”)。如果将USB到串行转换器插入另一个USB端口,则可以为其指定名称“ ttyUSB0”,这将与上述命名方案冲突。但是,由于我将所有转换器都插入了集线器,因此我可以忍受这种约束。


1
感谢您引用这些来源。在Linux的USB常见问题是我需要什么。
卢卡斯

16

尽管在这种特定情况下无济于事,但为某些适配器分配了唯一的序列ID:

udevadm info -a -n /dev/ttyUSB1 | grep '{serial}'

适配器序列号示例:

  ATTRS{serial}=="A6008isP"`

然后udev规则将包含:

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A6008isP", SYMLINK+="arduino"

资源


7
可悲的是,大部分的小气鬼串行适配器在那里不具备唯一连续:(
portforwardpodcast

7

您看过其中的内容了/dev/serial/by-id/吗?在类似的情况下,每个设备在此都被分配了唯一的永久性ID(我承认不知道它实际代表什么)。


<VENDOR><delimeter><MODEL><delimeter><SERIAL>
Pithikos

3

由于最初的问题是3年前提出的,因此可能无法解决这个问题,但是我会将其发布以供将来参考。

有一种方法可以通过访问FTDI-Chips的EEPROM重新编程序列号,Silicon实验室提供了一种工具,但仅Windows:

产品页面 ->工具->固定功能自定义实用程序

直接链接

可以在remotehq上找到说明:

http://remoteqth.com/wiki/index.php?page=How+to+set+usb+device+SerialNumber

Sourceforge上还有一个Unix库。仅在CP2101 / CP2102 / CP2103上进行过测试,我没有亲自尝试过。

http://sourceforge.net/projects/cp210x-program/


1

我需要格式化时使用答案而不是评论。

这些规则有一个明显的缺点:它们假定所有USB到串行转换器都将插入同一集线器(“ 1-8.1。*”)。如果将USB到串行转换器插入另一个USB端口,则可以为其指定名称“ ttyUSB0”,这将与上述命名方案冲突。但是,由于我将所有转换器都插入了集线器,因此我可以忍受这种约束。

我遇到了这个问题,可以通过使用小型C程序来操纵%devpath或您选择的其他USB属性的文本来轻松解决。

然后,您可以像这样调用该程序:

ACTION!="add|change", GOTO="99-local-end

SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6001", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", GOTO="99-local-tty-ftdi"
GOTO="99-local-end"

LABEL="99-local-tty-ftdi"
IMPORT{program}="/usr/local/lib/udev/multiusbserial-id %s{devpath}"
# Hayes-style Modem
ENV{ID_MULTIUSBSERIAL_DEVNAME_MINOR}=="1", GROUP="dialout", MODE="0660", SYMLINK+="modem"
# Console for network device
ENV{ID_MULTIUSBSERIAL_DEVNAME_MINOR}=="2", GROUP="wheel", MODE="0660", SYMLINK+="ttyswitch"
# Serial port for software development
ENV{ID_MULTIUSBSERIAL_DEVNAME_MINOR}=="3", GROUP="eng", MODE="0660", SYMLINK+="ttyrouter"
# Unused
ENV{ID_MULTIUSBSERIAL_DEVNAME_MINOR}=="4", GROUP="wheel", MODE="0660"

LABEL="99-local-end"

其中multiusbserial-id是已编译的C程序。

该程序仅需在特定点之后打印文本,因此并不复杂

/* multiusbserial.c */
#include <stdio.h>
#include <stdlib.h>

#define PROGRAM_NAME "multiusbserial-id"
#define VARIABLE_PREFIX "ID_MULTIUSBSERIAL_"

int main(int argc, char *argv[])
{
  char *p;
  int found = 0;

  if (argc != 2) {
    fprintf(stderr, "Usage: " PROGRAM_NAME " ATTRS{devpath}\n");
    exit(1);
  }

  for (p = argv[1]; *p != '\0'; p++) {
    if (*p == '.') {
      p++;
      found = (*p != '\0');
      break;
    }
  }

  if (!found) {
    fprintf(stderr, PROGRAM_NAME ": unexpected format\n");
    exit(1);
  }

  printf(VARIABLE_PREFIX "DEVNAME_MINOR=%s\n", p);
  return 0;
}

我写了一篇博客文章,提供更多详细信息。这是设置嵌入式系统团队编程环境的系列之一。


0

您可以像这样列出USB串行设备

ls -l /sys/bus/usb-serial/devices
total 0
lrwxrwxrwx 1 root root 0 Oct  9 09:10 ttyUSB0 -> ../../../devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3/1-1.3:1.0/ttyUSB0
lrwxrwxrwx 1 root root 0 Oct  9 09:10 ttyUSB1 -> ../../../devices/platform/soc/3f980000.usb/usb1/1-1/1-1.5/1-1.5:1.0/ttyUSB1

这两行以

1-1.3:1.0/ttyUSB0
1-1.5:1.0/ttyUSB1

这是在Raspberry Pi上。我现在将使设备保持ttyUSB1连接状态,拔出适配器ttyUSB0并将其插入另一个端口,然后再插入另一个端口,然后再回到初始端口

在此处输入图片说明

# original setup
['1-1.3:1.0', 'ttyUSB0'] --
['1-1.5:1.0', 'ttyUSB1']

# move it to port above 1.3
['1-1.3:1.0', 'ttyUSB0']
['1-1.5:1.0', 'ttyUSB1']
['1-1.2:1.0', 'ttyUSB2'] --

# move it to port above 1.5
['1-1.3:1.0', 'ttyUSB0']
['1-1.5:1.0', 'ttyUSB1']
['1-1.4:1.0', 'ttyUSB2'] --

# move it back to the original port
['1-1.3:1.0', 'ttyUSB0'] --
['1-1.5:1.0', 'ttyUSB1']

我不知道1-1.3:1.0断开连接后为什么不清理,但我可以忍受,因为我很少将适配器从一个USB端口更改为另一个USB端口。


我的问题是在Raspberry Pi上,它通过USB电缆通过连接的Arduino控制快门继电器,并通过另一个Arduino(相同制造商,相同型号)读取环境传感器数据,偶尔,当快门被激活时,传感器数据Arduino被踢开并从ttyUSB0重新分配给ttyUSB2(ttyUSB1是快门)。我最终得到了这个Python脚本,因为不必通过反复试验来找出传感器数据现在位于哪个设备上。

usb_devices = collections.OrderedDict()
usb_device_list = subprocess.check_output('ls -l /sys/bus/usb-serial/devices', shell=True, universal_newlines=True).split('\n')
for usb_device in usb_device_list:
  match = re.search("([^/]+)/([^/]+)$", usb_device)
  if match:
    usb_devices[match.group(1)] = match.group(2)

for key, value in usb_devices.items():
  print key, value

# I know that 1.3 is the environment sensor device
if '1-1.3:1.0' in usb_devices:
  print '1-1.3:1.0 -->', usb_devices['1-1.3:1.0'] # == ttyUSB0

这给了我以下输出

1-1.3:1.0 ttyUSB0
1-1.5:1.0 ttyUSB1
1-1.3:1.0 --> ttyUSB0

我仅在发生由于连接错误而导致的超时时执行此检查。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.