Wie kann man zwischen identischen USB-zu-Seriell-Adaptern unterscheiden?

26

Ich verwende eine Reihe identischer USB-zu-Seriell-Adapter für meinen Laptop (Ubuntu 9.10). Die Adapter werden von Sabrent hergestellt und sind um einen Prolific PL2303 IC gebaut, wie dargestellt durch 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  

Keines der von angezeigten Attribute udevadmscheint für einen bestimmten Adapter eindeutig zu sein:

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>

Alle Adapter werden an einen einzelnen USB-Hub angeschlossen. Da ich nicht zwischen den Adaptern selbst unterscheiden kann, gibt es eine Möglichkeit, eine udev-Regel zu schreiben, die den Namen jedes Adapters basierend auf dem physischen Port des Hubs festlegt, an den der Adapter angeschlossen ist.

Chris OBrien
quelle

Antworten:

24

Kann ich auf irgendeine Weise eine udev-Regel schreiben, die den Namen jedes Adapters basierend auf dem physischen Port des Hubs, an den der Adapter angeschlossen ist, festlegt?

Ja, wie sich herausstellt. Betrachten Sie den letzten Teil der Gerätehierarchie, der im zweiten Beispiel oben gezeigt wird:

Betrachten des übergeordneten Geräts '/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"

Der vom Kernel diesem Gerät zugewiesene Name (KERNELS == "1-4.5") zeigt an, dass dieses Gerät an den fünften Port eines Hubs angeschlossen ist, der an Port 4 von Bus 1 angeschlossen ist ( weitere Informationen zum Dekodieren finden Sie in dieser FAQ die sysfs-USB-Gerätehierarchie). Mit Hilfe dieser Anleitung zum Schreiben von udev-Regeln habe ich die folgenden udev-Regeln für meine USB-zu-Seriell-Port-Konverter entwickelt:

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"

Diese Regeln haben einen offensichtlichen Nachteil: Sie setzen voraus, dass alle USB-Seriell-Wandler an denselben Hub angeschlossen werden ("1-8.1. *"). Wenn ein USB-zu-Seriell-Konverter an einen anderen USB-Anschluss angeschlossen wird, kann ihm der Name "ttyUSB0" zugewiesen werden, der mit dem oben beschriebenen Benennungsschema in Konflikt steht. Da ich jedoch alle Konverter an den Hub angeschlossen lasse, kann ich mit dieser Einschränkung leben.

Chris OBrien
quelle
1
Vielen Dank für das Zitieren dieser Quellen. Die häufig gestellten Fragen zu Linux USB waren genau das, was ich brauchte.
Lucas
16

Obwohl dies in diesem speziellen Fall nicht helfen würde, werden einigen Adaptern eindeutige Seriennummern zugewiesen:

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

Eine beispielhafte Seriennummer des Adapters:

  ATTRS{serial}=="A6008isP"`

und udev Regeln würden dann enthalten:

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

Quelle

Cas
quelle
7
Leider haben die meisten billigen seriellen Adapter keine eindeutigen Seriennummern :(
portforwardpodcast
7

Haben Sie sich den Inhalt von angesehen /dev/serial/by-id/? In einer ähnlichen Situation wurde jedem Gerät eine eindeutige persistente ID zugewiesen (ich gebe zu, ich weiß nicht, was es tatsächlich darstellt).

Rob Tirrell
quelle
<VENDOR><delimeter><MODEL><delimeter><SERIAL>
Pithikos
3

Da die ursprüngliche Frage vor 3 Jahren gestellt wurde, richtet sich diese möglicherweise nicht an den Fragesteller, aber ich werde sie zur späteren Bezugnahme veröffentlichen.

Es gibt eine Möglichkeit, die Seriennummer neu zu programmieren, indem auf das EEPROM der FTDI-Chips zugegriffen wird. Silicon Labs bietet ein Tool an, das jedoch nur unter Windows ausgeführt wird:

Produktseite -> Tools-> Fixed Function Customization Utility

Direkte Verbindung

Eine Anleitung finden Sie bei remotehq:

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

Es gibt auch eine Unix-Bibliothek auf Sourceforge. Es wurde nur mit CP2101 / CP2102 / CP2103 getestet und ich habe es nicht persönlich ausprobiert.

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

Smundo
quelle
1

Verwenden Sie eine Antwort anstelle eines Kommentars, da ich eine Formatierung benötige.

Diese Regeln haben einen offensichtlichen Nachteil: Sie setzen voraus, dass alle USB-Seriell-Wandler an denselben Hub angeschlossen werden ("1-8.1. *"). Wenn ein USB-zu-Seriell-Konverter an einen anderen USB-Anschluss angeschlossen wird, kann ihm der Name "ttyUSB0" zugewiesen werden, der mit dem oben beschriebenen Benennungsschema in Konflikt steht. Da ich jedoch alle Konverter an den Hub angeschlossen lasse, kann ich mit dieser Einschränkung leben.

Ich hatte dieses Problem und es kann leicht mit einem kleinen C-Programm behoben werden, um den Text von% devpath oder ein anderes USB-Attribut Ihrer Wahl zu manipulieren.

Dann rufen Sie das Programm folgendermaßen auf:

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"

Dabei ist multiusbserial-id das kompilierte C-Programm.

Das Programm muss nur Text nach einem bestimmten Punkt drucken, damit es nicht komplex ist

/* 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;
}

Ich habe einen Blog-Artikel mit mehr Details geschrieben. Dies ist Teil einer Reihe von Schritten zum Einrichten einer Team-Programmierumgebung für eingebettete Systeme.

vk5tu
quelle
0

Sie können die seriellen USB-Geräte wie folgt auflisten

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

Die beiden Zeilen enden mit

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

Dies ist auf einem Himbeer-Pi. Jetzt lasse ich das Gerät ttyUSB1angeschlossen, ziehe den Adapter heraus ttyUSB0und schließe ihn an einen anderen Port an, dann an einen anderen und dann wieder an den ursprünglichen Port

Bildbeschreibung hier eingeben

# 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']

Ich weiß nicht, warum 1-1.3:1.0beim Trennen der Verbindung nicht aufgeräumt wird, aber ich kann damit leben, da ich selten die Adapter von einem USB-Anschluss auf einen anderen wechsle.


Mein Problem war, dass auf einem Himbeer-Pi, der die Verschlussrelais über ein per USB-Kabel angeschlossenes Arduino steuert und Umgebungssensordaten über ein anderes Arduino (gleicher Hersteller, gleiches Modell) liest, gelegentlich, wenn die Verschlüsse aktiviert wurden, die Sensordaten Arduino gekickt wurden vom Board entfernt und von ttyUSB0 zu ttyUSB2 neu zugewiesen (ttyUSB1 ist der Shutter). Ich endete mit diesem Python-Skript, um nicht durch Ausprobieren herausfinden zu müssen, auf welchem ​​Gerät sich die Sensordaten jetzt befanden.

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

Das gibt mir die folgende Ausgabe

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

Ich führe diese Überprüfung nur durch, wenn Zeitüberschreitungen aufgrund eines Verbindungsfehlers auftreten.

Daniel F
quelle