Come distinguere tra identici adattatori da USB a seriale?


26

Uso un numero di adattatori USB-seriale identici con il mio laptop (Ubuntu 9.10). Gli adattatori sono prodotti da Sabrent e sono costruiti attorno a un Prolific PL2303 IC, come mostrato da 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  

Nessuno degli attributi visualizzati udevadmsembra essere univoco per un adattatore specifico:

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>

Tutti gli adattatori sono collegati a un singolo hub USB. Dal momento che non riesco a distinguere tra gli adattatori stessi, c'è un modo in cui posso scrivere una regola udev che ripari il nome di ciascun adattatore in base a quale porta fisica sull'hub in cui è collegato l'adattatore?

Risposte:


24

c'è un modo in cui posso scrivere una regola udev che ripari il nome di ciascun adattatore in base a quale porta fisica sull'hub a cui è collegato l'adattatore?

Sì, c'è, a quanto pare. Considera l'ultima parte della gerarchia dei dispositivi mostrata nel secondo esempio sopra:

guardando il dispositivo genitore '/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"
ATTRIBUTI {} idProduct == "2303"
ATTRIBUTI {} bcdDevice == "0300"
ATTRIBUTI {} bDeviceClass == "00"
ATTRIBUTI {bDeviceSubClass} == "00"
ATTRIBUTI {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 {autorizzati} == "1"
ATTRS {produttore} = = "Prolific Technology Inc."
ATTRS {product} == "Controller seriale USB"

Il nome assegnato a questo dispositivo dal kernel (KERNELS == "1-4.5") indica che questo dispositivo è collegato alla quinta porta di un hub collegato alla porta quattro sul bus 1 (vedere queste FAQ per ulteriori informazioni su come decodificare la gerarchia dei dispositivi USB sysfs). Con un po 'di aiuto da questa guida alla stesura delle regole udev, ho ideato il seguente set di regole udev per i miei convertitori da porta USB a seriale:

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"

Queste regole hanno un evidente svantaggio: presumono che tutti i convertitori da USB a seriale saranno collegati allo stesso hub ("1-8.1. *"). Se un convertitore da USB a seriale fosse inserito in un'altra porta USB, potrebbe essere assegnato il nome "ttyUSB0" che sarebbe in conflitto con lo schema di denominazione sopra descritto. Tuttavia, dal momento che lascio tutti i convertitori collegati all'hub posso vivere con questo vincolo.


1
Grazie per aver citato quelle fonti. Le domande frequenti su Linux USB erano esattamente ciò di cui avevo bisogno.
Lucas,

16

Anche se non sarebbe utile in questo caso specifico, ad alcuni adattatori sono assegnati ID seriali univoci:

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

Un ID seriale dell'adattatore di esempio:

  ATTRS{serial}=="A6008isP"`

e le regole udev conterrebbero quindi:

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

fonte


7
Purtroppo, la maggior parte degli adattatori seriali cheapo là fuori non hanno serial univoci :(
portforwardpodcast

7

Hai visto il contenuto di /dev/serial/by-id/? In una situazione simile a ciascun dispositivo è stato assegnato un ID persistente univoco lì (ammetto di non sapere cosa rappresenta effettivamente).


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

3

Poiché la domanda originale è stata posta 3 anni fa, questo potrebbe non essere indirizzato al richiedente, ma lo posterò per riferimento futuro.

C'è un modo per riprogrammare il numero di serie accedendo alla EEPROM dei chip FTDI, i laboratori di silicio forniscono uno strumento, ma è solo Windows:

Pagina del prodotto -> Strumenti-> Utilità di personalizzazione delle funzioni fisse

Collegamento diretto

È possibile trovare un'istruzione su remotehq:

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

C'è anche una libreria Unix su Sourceforge. È stato testato solo con CP2101 / CP2102 / CP2103 e non l'ho provato personalmente.

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


1

Utilizzo di una risposta anziché di un commento in quanto ho bisogno di formattazione.

Queste regole hanno un evidente svantaggio: presumono che tutti i convertitori da USB a seriale saranno collegati allo stesso hub ("1-8.1. *"). Se un convertitore da USB a seriale fosse inserito in un'altra porta USB, potrebbe essere assegnato il nome "ttyUSB0" che sarebbe in conflitto con lo schema di denominazione sopra descritto. Tuttavia, dal momento che lascio tutti i convertitori collegati all'hub posso vivere con questo vincolo.

Ho avuto questo problema ed è stato facilmente risolto utilizzando un piccolo programma C per manipolare il testo di% devpath o qualche altro attributo USB di tua scelta.

Quindi si chiama quel programma in questo modo:

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"

dove multiusbserial-id è il programma C compilato.

Il programma deve solo stampare il testo dopo un punto particolare, quindi non è complesso

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

Ho scritto un articolo sul blog con maggiori dettagli. Fa parte di una serie nella creazione di un ambiente di programmazione per team di sistemi embedded.


0

È possibile elencare i dispositivi seriali USB in questo modo

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

Le due linee stanno finendo con

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

Questo è su un Raspberry Pi. Ora lascerò il dispositivo ttyUSB1collegato, estrarrò l'adattatore ttyUSB0e lo collegherò a un'altra porta, quindi a un'altra, e quindi di nuovo alla porta iniziale

inserisci qui la descrizione dell'immagine

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

Non so perché 1-1.3:1.0non venga ripulito al momento della disconnessione, ma posso convivere con questo, dal momento che raramente cambio gli adattatori da una porta USB a un'altra.


Il mio problema era che su un Raspberry Pi che controlla i relè dell'otturatore tramite un Arduino collegato tramite cavo USB e legge i dati del sensore ambientale attraverso un altro Arduino (stesso produttore, stesso modello), di tanto in tanto, quando le persiane venivano attivate, i dati del sensore Arduino venivano espulsi fuori dalla scheda e riassegnato da ttyUSB0 a ttyUSB2 (ttyUSB1 è l'otturatore). Ho finito con questo script Python per non dover scoprire per tentativi ed errori su quale dispositivo erano ora i dati del sensore.

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

che mi dà il seguente risultato

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

Eseguo questo controllo solo quando si verificano timeout a causa di un errore di connessione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.