Como distinguir entre adaptadores USB-serial idênticos?

26

Eu uso vários adaptadores USB-serial idênticos com o meu laptop (Ubuntu 9.10). Os adaptadores são fabricados pela Sabrent e são construídos em torno de um Prolific PL2303 IC, conforme mostrado por 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  

Nenhum dos atributos exibidos por udevadmparece ser exclusivo para um adaptador específico:

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 os adaptadores estão conectados a um único hub USB. Como não posso distinguir entre os adaptadores, existe alguma maneira de escrever uma regra do udev que corrige o nome de cada adaptador com base na porta física do hub em que o adaptador está conectado?

Chris OBrien
fonte

Respostas:

24

existe alguma maneira de escrever uma regra do udev que corrige o nome de cada adaptador com base em qual porta física no hub em que o adaptador está conectado?

Sim, existe, como se vê. Considere a última parte da hierarquia de dispositivos mostrada no segundo exemplo acima:

olhando para o dispositivo pai '/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 {versão} == "1,10" ATTRS {maxchild} == "0" ATTRS {peculiaridades} == "0x0"
ATTRS {autorizado} == "1"
ATTRS {fabricante} = = "Prolific Technology Inc."
ATTRS {product} == "Controlador serial USB"

O nome dado a este dispositivo pelo kernel (KERNELS == "1-4.5") indica que este dispositivo está conectado à quinta porta de um hub conectado à porta quatro no barramento 1 (consulte esta FAQ para obter mais informações sobre como decodificar a hierarquia do dispositivo usb sysfs). Com alguma ajuda deste guia para escrever regras do udev, criei o seguinte conjunto de regras do udev para os conversores de porta USB para porta serial:

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", NOME = "ttyUSB2"
KERNEL == "ttyUSB *", KERNELS == "1-8.1.2", NAME = "ttyUSB3"

Essas regras têm uma desvantagem óbvia: elas assumem que todos os conversores de USB para serial serão conectados ao mesmo hub ("1-8.1. *"). Se um conversor USB para serial estiver conectado a outra porta USB, poderá ser atribuído o nome "ttyUSB0", que entraria em conflito com o esquema de nomeação descrito acima. No entanto, como deixo todos os conversores conectados ao hub, posso conviver com essa restrição.

Chris OBrien
fonte
1
Obrigado por citar essas fontes. As perguntas freqüentes sobre o Linux USB eram exatamente o que eu precisava.
Lucas
16

Embora não ajude nesse caso específico, alguns adaptadores recebem IDs de série exclusivos:

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

Um exemplo de identificação serial do adaptador:

  ATTRS{serial}=="A6008isP"`

e as regras do udev conteriam:

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

Fonte

Cas
fonte
7
Infelizmente, a maioria dos adaptadores de série cheapo lá fora não têm números de série únicos :(
portforwardpodcast
7

Você já olhou o conteúdo de /dev/serial/by-id/? Em uma situação semelhante, a cada dispositivo foi atribuído um ID persistente exclusivo lá (eu admito que não sei o que ele realmente representa).

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

Como a pergunta original foi feita há 3 anos, isso talvez não atenda ao solicitante, mas eu a publicarei para referência futura.

Existe uma maneira de reprogramar o número de série acessando a EEPROM dos chips FTDI, o Silicon labs fornece uma ferramenta, mas é apenas o Windows:

Página do produto -> Ferramentas-> Utilitário de Customização de Função Fixa

Link direto

Uma instrução pode ser encontrada em remotehq:

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

Há também uma biblioteca Unix no Sourceforge. Ele foi testado apenas com o CP2101 / CP2102 / CP2103 e eu não o testei pessoalmente.

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

Smundo
fonte
1

Usando uma resposta em vez de um comentário, pois preciso de formatação.

Essas regras têm uma desvantagem óbvia: elas assumem que todos os conversores de USB para serial serão conectados ao mesmo hub ("1-8.1. *"). Se um conversor USB para serial estiver conectado a outra porta USB, poderá ser atribuído o nome "ttyUSB0", que entraria em conflito com o esquema de nomeação descrito acima. No entanto, como deixo todos os conversores conectados ao hub, posso conviver com essa restrição.

Eu tive esse problema e é facilmente corrigido usando um pequeno programa C para manipular o texto de% devpath ou algum outro atributo USB de sua escolha.

Você chama esse programa assim:

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"

onde multiusbserial-id é o programa C compilado.

O programa só precisa imprimir texto após um determinado ponto, para que não seja complexo

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

Eu escrevi um artigo de blog com mais detalhes. É uma de uma série na configuração de um ambiente de programação de equipe de sistemas embarcados.

vk5tu
fonte
0

Você pode listar os dispositivos seriais 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

As duas linhas estão terminando com

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

Isso é em um Raspberry Pi. Vou agora deixar o dispositivo ttyUSB1conectado, puxar o adaptador ttyUSB0e conectá-lo a outra porta, depois a outra e depois voltar à porta inicial

insira a descrição da imagem aqui

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

Não sei por que não estou 1-1.3:1.0sendo limpo após a desconexão, mas posso conviver com isso, pois raramente troco os adaptadores de uma porta USB para outra.


Meu problema era que, em um Raspberry Pi que controla os relés do obturador por meio de um Arduino conectado via cabo USB e lê os dados do sensor do ambiente por outro Arduino (mesmo fabricante, mesmo modelo), ocasionalmente, quando as persianas eram ativadas, os dados do sensor do Arduino eram chutados. fora da placa e transferido de ttyUSB0 para ttyUSB2 (ttyUSB1 é o obturador). Eu terminei com este script Python para não precisar descobrir por tentativa e erro em qual dispositivo os dados do sensor estavam ativados.

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

o que me dá a seguinte saída

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

Realizo essa verificação apenas quando ocorrem tempos limite devido a um erro de conexão.

Daniel F
fonte