¿Cómo distinguir entre adaptadores USB a serie idénticos?

26

Utilizo varios adaptadores USB a serie idénticos con mi computadora portátil (Ubuntu 9.10). Los adaptadores son fabricados por Sabrent y están construidos alrededor de un Prolific PL2303 IC, como se muestra en 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  

Ninguno de los atributos mostrados por udevadmparece ser exclusivo de un adaptador en particular:

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>

Todos los adaptadores están conectados a un solo concentrador USB. Dado que no puedo distinguir entre los adaptadores, ¿hay alguna forma de escribir una regla udev que corrija el nombre de cada adaptador según el puerto físico en el que está conectado el adaptador?

Chris OBrien
fuente

Respuestas:

24

¿Hay alguna forma de escribir una regla udev que corrija el nombre de cada adaptador según el puerto físico en el que está conectado el adaptador?

Sí lo hay, como resulta. Considere la última parte de la jerarquía de dispositivos que se muestra en el segundo ejemplo anterior:

mirando el dispositivo principal '/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 {velocidad} == "12"
ATTRS {busnum} == "1"
ATTRS {devnum} == "7" ATTRS {versión} == "1.10" ATTRS {maxchild} == "0" ATTRS {quirks} == "0x0"
ATTRS {autorizado} == "1"
ATTRS {fabricante} = = "Tecnología prolífica Inc."
ATTRS {product} == "Controlador en serie USB"

El nombre dado a este dispositivo por el núcleo (KERNELS == "1-4.5") indica que este dispositivo está enchufado en el quinto puerto de un concentrador conectado al puerto cuatro en el bus 1 (consulte estas Preguntas frecuentes para obtener más información sobre cómo decodificar la jerarquía de dispositivos usb sysfs). Con algo de ayuda de esta guía para escribir reglas de udev, se me ocurrió el siguiente conjunto de reglas de udev para mis convertidores de puerto USB a puerto serie:

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"

Estas reglas tienen una desventaja obvia: suponen que todos los convertidores de USB a serie se conectarán al mismo concentrador ("1-8.1. *"). Si se conectó un convertidor de USB a serie a otro puerto USB, se le podría asignar el nombre "ttyUSB0", lo que entraría en conflicto con el esquema de nomenclatura descrito anteriormente. Sin embargo, como dejo todos los convertidores conectados al concentrador, puedo vivir con esta restricción.

Chris OBrien
fuente
1
Gracias por citar esas fuentes. Las preguntas frecuentes sobre Linux USB eran exactamente lo que necesitaba.
Lucas
16

Aunque no ayudaría en este caso específico, algunos adaptadores tienen identificadores de serie únicos:

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

Un ejemplo de id. De serie del adaptador:

  ATTRS{serial}=="A6008isP"`

y las reglas de udev contendrían entonces:

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

Fuente

Cas
fuente
77
Lamentablemente, la mayoría de los adaptadores seriales de cheapo no tienen series únicas :(
portforwardpodcast
7

¿Has mirado el contenido de /dev/serial/by-id/? En una situación similar, a cada dispositivo se le asignó una identificación persistente única allí (admito que no sé lo que realmente representa).

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

Dado que la pregunta original se hizo hace 3 años, esto podría no responder al autor de la pregunta, pero lo publicaré para referencia futura.

Hay una manera de reprogramar el número de serie accediendo a la EEPROM de los chips FTDI, Silicon labs proporciona una herramienta, pero es solo Windows:

Página del producto -> Herramientas-> Utilidad de personalización de funciones fijas

Enlace directo

Se puede encontrar una instrucción en remotehq:

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

También hay una biblioteca Unix en Sourceforge. Solo se probó con CP2101 / CP2102 / CP2103 y no lo probé personalmente.

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

Smundo
fuente
1

Usando una respuesta en lugar de un comentario ya que necesito formatear.

Estas reglas tienen una desventaja obvia: suponen que todos los convertidores de USB a serie se conectarán al mismo concentrador ("1-8.1. *"). Si se conectó un convertidor de USB a serie a otro puerto USB, se le podría asignar el nombre "ttyUSB0", lo que entraría en conflicto con el esquema de nomenclatura descrito anteriormente. Sin embargo, como dejo todos los convertidores conectados al concentrador, puedo vivir con esta restricción.

Tuve este problema y se soluciona fácilmente usando un pequeño programa en C para manipular el texto de% devpath o algún otro atributo USB de su elección.

Luego llama a ese programa así:

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"

donde multiusbserial-id es el programa C compilado.

El programa solo necesita imprimir texto después de un punto en particular, por lo que no es complejo

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

Escribí un artículo de blog con más detalles. Es una de una serie en la configuración de un entorno de programación de equipo de sistemas integrados.

vk5tu
fuente
0

Puede enumerar los dispositivos serie USB como este

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

Las dos líneas terminan con

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

Esto está en una Raspberry Pi. Ahora dejaré el dispositivo ttyUSB1conectado, sacaré el adaptador ttyUSB0y lo enchufaré a otro puerto, luego a otro y luego de vuelta al puerto inicial

ingrese la descripción de la imagen aquí

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

No sé por qué 1-1.3:1.0no se limpia después de la desconexión, pero puedo vivir con eso, ya que rara vez cambio los adaptadores de un puerto USB a otro.


Mi problema fue que en una Raspberry Pi que controla los obturadores a través de un Arduino conectado a través de un cable USB y lee los datos del sensor de entorno a través de otro Arduino (mismo fabricante, mismo modelo), ocasionalmente, cuando se activaron los obturadores, los datos del sensor Arduino fueron pateados fuera del tablero y reasignado de ttyUSB0 a ttyUSB2 (ttyUSB1 es el obturador). Terminé con este script de Python para no tener que averiguar por prueba y error en qué dispositivo estaban ahora los datos del sensor.

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

lo que me da el siguiente resultado

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

Solo realizo esta comprobación cuando se producen tiempos de espera debido a un error de conexión.

Daniel F
fuente