Vous avez sûrement plein d'idées d'applications intéressantes, mais envisager de contrôler une jonction série vous fait peur ? Voici quelques petites indications.
Sous Unix, donc sous Linux, les seuls objets manipulés lors des entrées/sorties sont les fichiers. (Tiens, au fait, on aurait peut-être dû commencer par là ! Bon, vous le saviez déjà, ce n'est pas un cours Unix). La jonction série n'échappe pas à cette règle et le pilote vous la présente ainsi. Ici, il s'agit d'un (ou plutôt deux comme on le verra plus loin) fichier particulier, bien sûr, puisque se cache derrière un pilote (driver) en mode caractère, mais la façon de réaliser les entrées sorties est la même : open, read, write, ioctl, close. Il y a quand même quelques petites choses à savoir.
Le pilote série s'est enregistré, à l'initialisation du noyau, comme un tty. Il est donc géré comme un tty classique. Il apporte bien entendu quelques caractéristiques supplémentaires que nous verrons rapidement dans la section concernant la commande ioctl. Toujours est-il que si vous savez gérer un tty sous Unix (commande stty), vous saurez sans problème gérer ce pilote.
La méthode d'ouverture et de fermeture d'un port série est classique. Néanmoins un mécanisme particulier se cache derrière la primitive open qui est rapidement décrit à la section Appels entrants (Dial-in) et appels sortants (Call-out) sous Linux.
Rien à signaler de particulier.
Le contrôle de tout système d'entrée/sortie se fait avec la commande système ioctl. Elle est souvent masquée par des commandes de haut niveau (setserial, stty, modemstat, ...), mais elle est leur moteur.
Selon que vous souhaitez vous adresser aux fonctionnalités
classiques d'un tty ou aux fonctions spécialisées du
pilote série, vous utiliserez deux sous-ensembles de commandes
différentes. Vous les retrouverez dans le fichier à inclure
linux/termios.h. Décrivons-les rapidement (on
déborde un tout petit peu du sujet :-)
) :
et quelques dérivés avec WAIT, FLUSH... Elles permettent de récupérer (resp. positionner) les attributs standard tty dans une structure termios (voir le fichier linux/termios.h)
permettent de définir (resp. annuler) une session d'utilisation du tty. Ceci est visible car, entre autres choses, une conséquence est le changement des droits du fichier correspondant
Avant:
crw-rw-rw- 1 root tty 4, 64 Nov 26 20:47 ttyS0
Apres:
crw--w--w- 1 root root 4, 64 Nov 26 20:49 ttyS0
positionnement d'indicateurs (voir la commande stty)
permettent de récupérer (resp. positionner) les informations générales dans une (resp. à partir d'une) structure serial_struct (voir le fichier linux/serial.h) : le type de port série, la ligne, le port, l'irq le port utilisé... ni plus ni moins ce que fait setserial.
permettent de récupérer (resp. positionner) les informations plus spécifiques à la jonction proprement dite (dans un entier, sous forme de bits positionnés selon que l'indicateur correspondant est vrai ou faux) :
+-------------------------------------------------------------------------------------------+
| // DSR RNG CAR CTS // // RTS DTR //|
| // (Data Set (Ring) (Carrier) (Clear To // // (Request (Data Terminal // |
| // Ready) Send) // // To Send) Ready) // |
+------+----------+-------+----------+-----------+----+----+-----------+---------------+----+
31 9 8 7 6 5 4 3 2 1 0
Le pilote série du noyau de Linux propose de gérer un même port série à la fois pour les appels entrants et pour les appels sortants exploitant ainsi pleinement leur caractéristique bi-directionnelle. Il offre donc à l'utilisateur deux types de fichiers :
/dev/ttyS<n>
: sont généralement
utilisés en entrée ;
/dev/cua<n>
: sont généralement
utilisés en sortie.
Chaque port série est enregistré deux fois auprès du gérant tty : une fois en mode entrée (ttyS, majeur 4) et une fois en mode sortie (cua, majeur 5). Voyons rapidement comment le pilote gère ensuite les "deux" ports :
/dev/cua
sont gérés en mode
non-bloquant. Leur ouverture n'est possible que si la ligne
/dev/ttyS
correspondante n'est pas ouverte et active (sinon
errno
retourne EBUSY) ;
/dev/ttyS
sont gérés en mode
bloquant ou non-bloquant, c'est donc un peu plus compliqué. Si
l'indicateur CLOCAL est positionné, l'ouverture en mode
bloquant est effective si la ligne /dev/cua
est libre. Si
l'indicateur CLOCAL n'est pas positionné, elle est effective si les
deux conditions suivantes sont réunies :
/dev/cua
correspondant n'est pas
utilisé),
L'ouverture en mode non-bloquant, quant à elle, est effective si le
port n'est pas déjà ouvert et actif (sinon errno
retourne EBUSY)
Les applications utilisent de plus le mécanisme des fichiers de verrouillage garantissant l'unicité d'utilisation de la ressource..
C'est le mode qu'utilisent beaucoup d'applications comme getty qui souhaitent dans un premier temps initialiser la ligne (pour éviter des instabilités liées aux connexions précédentes) voire ensuite pour initialiser l'équipement (modem). Elles ne s'intéressent qu'au fait que la ligne soit occupée, en fermeture ou libre. Si celle-ci n'est pas libre, l'application se termine et le mécanisme du respawn se charge de les relancer.
Pour la gestion de la connexion proprement dite, l'application getty (pour prendre un exemple courant) ouvre la ligne, soit en mode bloquant si vous laissez le modem en réponse automatique, soit en mode non-bloquant si vous souhaitez qu'elle gère activement la connexion. Elle est alors en attente bloquante en lecture (sur read).