web-dev-qa-db-fra.com

Comment faire la distinction entre des adaptateurs USB / série identiques?

J'utilise plusieurs adaptateurs USB/série identiques avec mon ordinateur portable (Ubuntu 9.10). Les adaptateurs sont fabriqués par Sabrent et sont construits autour d’un CI Prolific PL2303, comme indiqué par 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  

Aucun des attributs affichés par udevadm ne semble être unique pour un adaptateur particulier:

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>

Tous les adaptateurs sont connectés à un seul concentrateur USB. Étant donné que je ne peux pas distinguer les adaptateurs eux-mêmes, puis-je écrire une règle udev qui corrige le nom de chaque adaptateur en fonction du port physique sur le concentrateur auquel l'adaptateur est branché?

25
Chris OBrien

est-il possible d'écrire une règle udev qui corrige le nom de chaque adaptateur en fonction du port physique sur le concentrateur auquel l'adaptateur est branché?

Oui, il se trouve. Considérez la dernière partie de la hiérarchie de périphériques illustrée dans le deuxième exemple ci-dessus:

en regardant le périphérique parent '/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.5': KERNELS == "1-4.5"
SOUS-SYSTÈMES == "usb"
PILOTES == "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 {authorisé} == "1"
ATTRS {fabricant} == "Prolific Technology Inc."
ATTRS {product} == "Contrôleur série USB"

Le nom donné à ce périphérique par le noyau (KERNELS == "1-4.5") indique que ce périphérique est branché sur le cinquième port d'un concentrateur connecté au port quatre du bus 1 (voir cette FAQ pour plus d’informations sur le décodage de la hiérarchie des périphériques sysfs usb). Avec l’aide de ce guide pour écrire des règles udev, j’ai créé le jeu de règles udev suivant pour mes convertisseurs USB/port série:

KERNEL == "ttyUSB *", KERNELS == "1-8.1.5", NOM = "ttyUSB0"
KERNEL == "ttyUSB *", KERNELS == "1-8.1.6", NOM = "ttyUSB1"
KERNEL == "ttyUSB *", KERNELS == "1-8.1.1", NOM = "ttyUSB2"
KERNEL == "ttyUSB *", KERNELS == "1-8.1.2", NOM = "ttyUSB3"

Ces règles présentent un inconvénient évident: elles supposent que tous les convertisseurs USB/série seront connectés au même concentrateur ("1-8.1. *"). Si un convertisseur USB vers série était connecté à un autre port USB, le nom "ttyUSB0" pourrait être attribué, ce qui entrerait en conflit avec le schéma de dénomination décrit ci-dessus. Cependant, puisque je laisse tous les convertisseurs branchés sur le hub, je peux vivre avec cette contrainte.

23
Chris OBrien

Bien que cela ne soit d'aucune utilité dans ce cas particulier, certains adaptateurs se voient attribuer des ID série uniques:

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

Un exemple d'identifiant de série d'adaptateur:

  ATTRS{serial}=="A6008isP"`

et les règles udev contiendraient alors:

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

Source

15
Cas

Avez-vous consulté le contenu de /dev/serial/by-id/? Dans une situation similaire, chaque appareil s'est vu attribuer un identifiant persistant unique (j'admets que je ne sais pas ce qu'il représente réellement).

7
Rob Tirrell

Étant donné que la question initiale a été posée il y a 3 ans, cela pourrait ne pas répondre au demandeur, mais je vais l'afficher pour référence future.

Il existe un moyen de reprogrammer le numéro de série en accédant à la mémoire EEPROM des puces FTDI. Silicon Labs fournit un outil, mais il ne concerne que Windows:

Page produit -> Outils-> Utilitaire de personnalisation de fonction fixe

lien direct

Une instruction peut être trouvée à remotehq:

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

Il existe également une bibliothèque Unix sur Sourceforge. Il a uniquement été testé avec CP2101/CP2102/CP2103 et je ne l’ai pas essayé personnellement.

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

3
Smundo

Utiliser une réponse plutôt qu'un commentaire car j'ai besoin d'un formatage.

Ces règles présentent un inconvénient évident: elles supposent que tous les convertisseurs USB/série seront connectés au même concentrateur ("1-8.1. *"). Si un convertisseur USB vers série était branché sur un autre port USB, le nom "ttyUSB0" pourrait être attribué, ce qui entrerait en conflit avec le schéma de dénomination décrit ci-dessus. Cependant, puisque je laisse tous les convertisseurs branchés sur le hub, je peux vivre avec cette contrainte.

J'ai eu ce problème et il est facilement corrigé en utilisant un petit programme C pour manipuler le texte de% devpath ou un autre attribut USB de votre choix.

Vous appelez ensuite ce programme comme ceci:

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"

où multiusbserial-id est le programme en C compilé.

Le programme a juste besoin d'imprimer du texte après un point particulier, donc ce n'est pas complexe

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

J'ai écrit un article de blog avec plus de détails. C’est l’une des séries de la configuration d’un environnement de programmation d’équipe de systèmes embarqués.

1
vk5tu

Vous pouvez lister les périphériques série USB comme ceci

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

Les deux lignes se terminent par

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

Ceci est sur un Raspberry Pi. Je vais maintenant laisser le périphérique ttyUSB1 connecté et retirer l'adaptateur ttyUSB0 et le brancher sur un autre port, puis sur un autre, puis sur le port initial.

enter image description here

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

Je ne sais pas pourquoi 1-1.3:1.0 n'est pas nettoyé lors de la déconnexion, mais je peux vivre avec cela, car je change rarement d'adaptateur d'un port USB à un autre.


Mon problème était que sur un Raspberry Pi qui contrôle les relais d'obturateur via un Arduino connecté via un câble USB et lit les données du capteur d'environnement via un autre Arduino (même fabricant, même modèle), parfois, lorsque les obturateurs ont été activés, les données du capteur Arduino ont été expulsées hors du tableau et réaffecté de ttyUSB0 à ttyUSB2 (ttyUSB1 est le déclencheur). Je me suis retrouvé avec ce script Python afin de ne pas avoir à rechercher par essais et erreurs le périphérique sur lequel les données du capteur étaient maintenant stockées.

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

ce qui me donne la sortie suivante

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

J'effectue cette vérification uniquement lorsque des délais d'attente dus à une erreur de connexion surviennent.

0
Daniel F