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

26

J'utilise un certain nombre d'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 circuit intégré Prolific PL2303, comme illustré 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 ne udevadmsemble ê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 branchés sur un seul concentrateur USB. Étant donné que je ne peux pas distinguer les adaptateurs eux-mêmes, existe-t-il un moyen d'écrire une règle udev qui fixe le nom de chaque adaptateur en fonction du port physique sur le concentrateur auquel l'adaptateur est branché?

Chris OBrien
la source

Réponses:

24

est-il possible d'écrire une règle udev qui fixe 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 des 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-SYSTEMES == "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 {bizarreries} == "0x0"
ATTRS {autorisé} == "1"
ATTRS {fabricant} = = "Prolific Technology Inc."
ATTRS {produit} == "Contrôleur USB-Série"

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 sur le bus 1 (voir cette FAQ pour plus d'informations sur la façon de décoder la hiérarchie des périphériques USB sysfs). Avec l'aide de ce guide pour écrire des règles udev, j'ai trouvé l'ensemble de règles udev suivant pour mes convertisseurs USB vers port série:

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"

Ces règles ont un inconvénient évident: elles supposent que tous les convertisseurs USB-série seront branchés sur le même concentrateur ("1-8.1. *"). Si un convertisseur USB vers série était branché sur un autre port USB, le nom "ttyUSB0" pourrait lui ê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 concentrateur, je peux vivre avec cette contrainte.

Chris OBrien
la source
1
Merci d'avoir cité ces sources. La foire aux questions Linux USB était exactement ce dont j'avais besoin.
Lucas
16

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

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

Un exemple d'ID 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"

La source

Cas
la source
7
Malheureusement, la plupart des adaptateurs série cheapo là-bas n'ont pas de publications en série uniques :(
portforwardpodcast
7

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

Rob Tirrell
la source
<VENDOR><delimeter><MODEL><delimeter><SERIAL>
Pithikos
3

Étant donné que la question d'origine a été posée il y a 3 ans, cela pourrait ne pas s'adresser au demandeur, mais je la posterai pour référence future.

Il existe un moyen de reprogrammer le numéro de série en accédant à l'EEPROM des puces FTDI, Silicon labs fournit un outil, mais c'est uniquement Windows:

Page produit -> Outils-> Utilitaire de personnalisation des fonctions fixes

Lien direct

Une instruction peut être trouvée sur remotehq:

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

Il existe également une bibliothèque Unix sur Sourceforge. Il n'est testé qu'avec CP2101 / CP2102 / CP2103 et je ne l'ai pas essayé personnellement.

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

Smundo
la source
1

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

Ces règles ont un inconvénient évident: elles supposent que tous les convertisseurs USB-série seront branchés sur le même concentrateur ("1-8.1. *"). Si un convertisseur USB vers série était branché sur un autre port USB, le nom "ttyUSB0" pourrait lui ê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 concentrateur, je peux vivre avec cette contrainte.

J'ai eu ce problème et il est facilement résolu 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 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. Il fait partie d'une série de mise en place d'un environnement de programmation d'équipe de systèmes embarqués.

vk5tu
la source
0

Vous pouvez répertorier les périphériques série USB comme celui-ci

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

C'est sur un Raspberry Pi. Je vais maintenant laisser l'appareil ttyUSB1connecté, retirer l'adaptateur ttyUSB0et le brancher sur un autre port, puis un autre, puis de nouveau sur le port initial

entrez la description de l'image ici

# 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.0ne se nettoie pas lors de la déconnexion, mais je peux vivre avec cela, car je change rarement les adaptateurs d'un port USB à un autre.


Mon problème était que sur un Raspberry Pi qui contrôle les relais de l'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 volets ont été activés, les données du capteur Arduino se sont déclenchées hors de la carte et réaffecté de ttyUSB0 à ttyUSB2 (ttyUSB1 est l'obturateur). Je me suis retrouvé avec ce script Python pour ne pas avoir à découvrir par essais et erreurs sur quel appareil les données du capteur étaient maintenant.

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 se produisent.

Daniel F
la source