Nommage udev en fonction de l’interface (bInterfaceNumber)

Je viens tout juste de recevoir un nouveau programmeur AVR sur port USB. Bonne nouvelle, celui-ci propose non pas un port série de type ttyACM* mais deux (le second fournissant un port USB/TTL simple). Mauvaise nouvelle, une règle udev classique (voir ce billet) ne fonctionne pas. En effet, la règle match les deux interfaces et on se retrouve systématiquement avec un lien symbolique pointant sur la seconde interface. Le programmeur est inaccessible proprement via un Makefile.

Le problème ici est de mixer des attributs provenants à la fois du périphérique (product) et du périphérique parent (bInterfaceNumber). Ceci ne fonctionne donc pas :

SUBSYSTEMS=="usb", KERNEL=="ttyACM*", ATTRS{product}=="Pololu USB AVR Programmer", SYMLINK+="POLOLU"

Pas plus que :

SUBSYSTEMS=="usb", KERNEL=="ttyACM*", ATTRS{product}=="Pololu USB AVR Programmer", ATTRS{bInterfaceNumber}==02, SYMLINK+="POLOLU_SERIAL"

Il faut être plus tordu et réutiliser le nom d’un attribut du périphérique pour nommer le lien symbolique avec :

SUBSYSTEMS=="usb", KERNEL=="ttyACM*", ATTRS{product}=="Pololu USB AVR Programmer",  SYMLINK+="POLOLU%s{bInterfaceNumber}"

Ce qui nous donne :

% ls -l /dev/POL*
13099267 lrwxrwxrwx 1 root root 7 jui 21 21:01 /dev/POLOLU00 -> ttyACM0
13099249 lrwxrwxrwx 1 root root 7 jui 21 21:01 /dev/POLOLU02 -> ttyACM1
Pareil en présence d'un autre programmeur ttyACM* :
13105697 lrwxrwxrwx 1 root root 7 jui 21 21:10 /dev/POLOLU00 -> ttyACM1
13105715 lrwxrwxrwx 1 root root 7 jui 21 21:10 /dev/POLOLU02 -> ttyACM2

Ça n’est pas exactement ce que je voulais (POLOLU0 et POLOLU1) mais c’est fixe et clair. On va pas chercher la petite bête…

ttyUSB0 ? ttyUSB2 ? Non, ttyUSB1… Graaaahh ! udev !

J’ai acheté il y a quelque temps plusieurs de ces petites choses :

Des convertisseurs USB/Série en TTL (0-5V). Ceci permet de connecter directement, sans max232, un adaptateur USB/Série à un montage à base de microcontrôleur (genre Atmel AVR) ou un système embarqué (genre Fonera, remarquez le cavalier permettant de choisir 5V ou 3.3V, convitude). Seulement, voilà :
je branche un adaptateur, il est accessible via /dev/ttyUSB0
j’en branche un autre qui devient /dev/ttyUSB1
je débranche le premier et en branche deux autres et ça devient la fête aux ttyUSB*

Où est ma Fonera 1, où est mon Attiny2313, où est ma Fonera 2… etc…  ?

On trouve dans /sys/bus/usb-serial/devices plein de choses intéressantes avec udevinfo -a -p. Parmi lesquelles :
ATTRS{manufacturer}== »FTDI »
ATTRS{product}== »FT232R USB UART »
ATTRS{serial}== »A90066ai »
Du coup, il ne reste plus qu’à se construire des petites règles sympathiques dans un fichier placé dans /etc/udev/rules.d :
SUBSYSTEMS== »usb », KERNEL== »ttyUSB* », ATTRS{product}== »FT232R USB UART »,
SYSFS{serial}== »A90066j7″, SYMLINK+= »TTYUSB0″
SUBSYSTEMS== »usb », KERNEL== »ttyUSB* », ATTRS{product}== »FT232R USB UART »,
SYSFS{serial}== »A90066ac », SYMLINK+= »TTYUSB1″
SUBSYSTEMS== »usb », KERNEL== »ttyUSB* », ATTRS{product}== »FT232R USB UART »,
SYSFS{serial}== »A900669W », SYMLINK+= »TTYUSB2″
SUBSYSTEMS== »usb », KERNEL== »ttyUSB* », ATTRS{product}== »FT232R USB UART »,
SYSFS{serial}== »A90066ai », SYMLINK+= »TTYUSB3″
On redémarre udev avec un petit /etc/init.d/udev restart et on marque des petits chiffres au feutre indélébile sur les adaptateurs. A la connexion du périphérique identifié par son numéro de série, un lien symbolique est créé dans /dev. Peu importe le /dev/ttyUSB*, le lien symbolique donne toujours accès au bon périphérique.

Done.

PS : ça marche pour plein de périphériques. Ceci inclus les clef USB par exemple :
BUS== »usb », SYSFS{serial}== »123456789ABCDEF », NAME= »%k », SYMLINK= »usbkey1″

ASRock 4CoreDual-SATA2, VT6102, eth1, eth2, eth3…

Nouvelle carte mère, nouveaux problèmes… Bon d’accord j’abuse. GNU/Linux n’est pas windows, pas de réinstallation système à chaque changement de périphérique. Mais on aimerai tout de même bien que tout marche du premier coup au premier boot suivant un changement de carte mère…

La ASRock 4CoreDual-Sata2 comporte un contrôleur ethernet VT6102 supporté par le module via-rhine. Premier boot après upgrade matérielle et…. tiens pas de réseau… tiens eth1 ? Aurai-je une autre NIC ? Bin… non. Késsésséssa ?

Après avoir penché pour un problème de pilote et quelques essais de rmmod/modprobe, voici arriver un troupeau de eth1, eth2, eth3, eth4… amusant… ou pas.

Mais le problème ne vient pas du pilote mais d’udev et des règles. Plus exactement du persistent-net-generator.rules. On retrouve ainsi dans z25_persistent-net.rules :
# PCI device 0x1106:0x3065 (via-rhine)
SUBSYSTEM== »net », DRIVERS== »?* », ATTRS{address}== »00:19:66:2e:b2:13″, NAME= »eth1″
Une petite correction en :
# PCI device 0x1106:0x3065 (via-rhine)
SUBSYSTEM== »net », DRIVERS== »?* », ATTRS{address}== »00:19:66:2e:b2:13″, NAME= »eth0″
Un reboot pour vérifier et voilà.

PS : merci iMil pour le tuyau.