diff --git a/fr_FR.ISO8859-1/articles/ddwg/Makefile b/fr_FR.ISO8859-1/articles/ddwg/Makefile
new file mode 100644
index 0000000000..68714b471c
--- /dev/null
+++ b/fr_FR.ISO8859-1/articles/ddwg/Makefile
@@ -0,0 +1,20 @@
+#
+# The FreeBSD Documentation Project
+# The FreeBSD French Documentation Project
+#
+# $Id: Makefile,v 1.1 2000-06-01 19:14:23 gioria Exp $
+# Original revision: 1.4
+#
+
+DOC?= article
+
+FORMATS?= html
+
+INSTALL_COMPRESSED?=gz
+INSTALL_ONLY_COMPRESSED?=
+
+SRCS= article.sgml
+
+DOC_PREFIX?= ${.CURDIR}/../../..
+
+.include "${DOC_PREFIX}/share/mk/doc.project.mk"
diff --git a/fr_FR.ISO8859-1/articles/ddwg/article.sgml b/fr_FR.ISO8859-1/articles/ddwg/article.sgml
new file mode 100644
index 0000000000..012e35654a
--- /dev/null
+++ b/fr_FR.ISO8859-1/articles/ddwg/article.sgml
@@ -0,0 +1,1861 @@
+
+
+ %man;
+ %urls;
+ %abstract;
+ %artheader;
+ %translators;
+
+ %authors;
+ %mailing-lists;
+
+]>
+
+
+
+
+ Le guide de l'auteur de pilotes de périphériques pour FreeBSD
+
+
+ Eric L.
+ Hernes
+
+
+ &artheader.copyright;
+
+ erich@rrnet.com
+ 29 Mai 1996
+ Ce document décrit comment ajouter un module de gestion de
+périphérique à FreeBSD. Il n'est pas destiné pour être un
+cours d'instruction sur des modules de gestion de périphérique
+d'Unix en général. Il est destiné pour les auteurs de module de
+gestion de périphérique, au courant du modèle de module de gestion
+de périphérique d'Unix, pour travailler sur FreeBSD.
+
+ &abstract.license;
+ &abstract.disclaimer;
+ &trans.a.dntt;
+
+
+
+
+
+Spécificité de FreeBSD2.x
+
+Dû aux changements de FreeBSD avec le temps, ce guide est
+seulement précis en ce qui concerne FreeBSD 2.x. Un guide de
+rechange pour FreeBSD 3.x et au-delà est en train d'être écrit.
+Contactez Jeroen Ruigrok asmodai@wxs.nl si
+vous voulez l'aider à ce sujet.
+
+
+
+
+
+Généralité
+
+ Le noyau de FreeBSD est très bien
+documenté, malheureusement il est entièrement écrit en `C'.
+
+
+
+
+Types de pilotes de module de périphériques.
+
+
+Caractère
+
+
+Structures de données
+
+Structure cdevsw
+
+
+
+Points d'entrée
+
+
+d_open()
+
+d_open() prend plusieurs arguments, la liste formelle ressemble à
+quelque chose comme :
+
+
+
+int
+d_open(dev_t dev, int flag, int mode, struct proc *p)
+
+
+d_open() est appelé à chaque ouverture du périphérique.
+
+L'argument dev contient le nombre majeur et mineur du
+périphérique ouvert. Ils sont disponibles par les macros
+major() et minor()
+
+
+Les arguments flag et mode sont comme décrits sur
+la page de manuel de
+open.
+Il est recommandé que vous examiniez
+ces derniers pour vous assurer des droits d'accès dans <sys/fcntl.h>
+et faire ce qui est exigé. Par exemple si flag est
+(O_NONBLOCK | O_EXLOCK) l'ouverture échouerait si il bloquait ou
+si l'accès exclusif ne pouvait pas être accordé.
+
+
+
+L'argument p contient toutes les informations à propos du
+processus actuel.
+
+
+
+
+d_close()
+ d_close() prend la même liste d'argument que d_open():
+
+
+
+int
+d_close(dev_t dev , int flag , int mode , struct proc *p)
+
+
+d_close() est seulement appelé à la dernière fermeture de votre
+périphérique (par périphérique mineur). Par exemple dans le fragment
+suivant de code, d_open() est appelé 3 fois, mais d_close()
+seulement une fois.
+
+
+
+ ...
+ fd1=open("/dev/mydev", O_RDONLY);
+ fd2=open("/dev/mydev", O_RDONLY);
+ fd3=open("/dev/mydev", O_RDONLY);
+ ...
+ <useful stuff with fd1, fd2, fd3 here>
+ ...
+ close(fd1);
+ close(fd2);
+ close(fd3);
+ ...
+
+
+Les arguments sont semblables à ceux décrits ci-dessus pour
+d_open().
+
+
+
+
+d_read() et d_write()
+
+d_read() et d_write prennent les listes suivantes d'argument:
+
+
+
+int
+d_read(dev_t dev, struct uio *uio, int flat)
+int
+d_write(dev_t dev, struct uio *uio, int flat)
+
+
+
+Les points d'entrée de d_read() et de d_write() sont appelés quand
+read et
+write
+sont appelés sur votre périphérique depuis l'espace utilisateur. Le transfert
+des données peut être manipulé par la routine du noyau uiomove().
+
+
+
+
+d_ioctl()
+
+ Sa liste d'argument est comme suit:
+
+
+int
+d_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *p)
+
+
+
+d_ioctl() est un fourre-tout pour les exécutions qui ne semblent
+pas raisonnable dans un paradigme lecture/écriture. Le plus
+célèbre de tout les ioctl est probablement celui sur des périphériques
+tty, par le
+stty.
+
+Le point d'entrée d'ioctl est appelé depuis l'ioctl() de
+sys/kern/sys_generic.c
+
+
+Il y a quatre types différents d'ioctl qui peuvent être implémentés.
+
+<sys/ioccom.h> contient des macros pratiques de
+pour définir ces ioctls.
+
+
+
+
+_IO(g, n) pour les opérations de type contrôle.
+
+
+
+
+
+_IOR(g, n, t) pour des opérations lisant des données d'un
+périphérique.
+
+
+
+
+
+_IOW(g, n, t) pour les opérations écrivant des données
+sur un périphérique.
+
+
+
+
+
+_IOWR(g,n,t) pour les opérations écrivant sur un périphérique
+puis lisent les données.
+
+
+
+
+
+
+Ici g se rapporte à un groupe /. C'est une valeur
+de 8 bits, en général indicative du périphérique ; par exemple, 't'
+est utilisé dans des ioctls de tty. n se
+rapporte au nombre de l'ioctl dans le groupe. Sur SCO, ce seul nombre
+dénote l'ioctl. t est le type de données qui sera
+passé au pilote de périphérique; ceci est alors remis à un opérateur
+sizeof() du noyau. L'appel système ioctl() fera soit un copyin()
+soit un copyout() ou les deux à votre pilote, puis vous
+renverra un pointeur à la structure de données dans l'argument
+arg de l'appel d'd_ioctl. Actuellement la taille de
+données est limitée à une page (4k sur l'i386).
+
+
+
+
+d_stop()
+
+
+
+
+d_reset()
+
+
+
+
+d_devtotty()
+
+
+
+
+d_poll() (3.0 et plus) ou d_select() (2.2)
+
+la liste d'argument de d_poll() est comme suit :
+
+
+
+void
+d_poll(dev_t dev, int events, struct proc *p)
+
+
+ d_poll() est employé pour découvrir si un périphérique
+est prêt pour les E/S. Par exemple, attendre que des données du réseau
+soient dispnibles, ou que l'utilisateur presse une touche.
+Cela correspond à un appel de poll() dans l'espace utilisateur.
+
+
+L'appel à d_poll() devrait vérifier les événements
+indiqués dans le masque d'évènement. Si aucun des événements demandés n'est
+en activité, mais qu'elles pourraient devenir actif plus tard, il
+devrait enregistrer ceci pour les actions futures du noyau.
+d_poll() fait ceci en appelant selrecord() avec une structure
+selinfo pour ce périphérique. La somme de toutes ces activités
+ressemblent à quelque chose comme ceci:
+
+
+
+static struct my_softc {
+ struct queue rx_queue; /* As example only - not required */
+ struct queue tx_queue; /* As example only - not required */
+ struct selinfo selp; /* Required */
+} my_softc[NMYDEV];
+
+...
+
+static int
+mydevpoll(dev_t dev, int events, struct proc *p)
+{
+ int revents = 0; /* Events we found */
+ int s;
+ struct my_softc *sc = &my_softc[dev];
+
+ /* We can only check for IN and OUT */
+ if ((events & (POLLIN|POLLOUT)) == 0)
+ return(POLLNVAL);
+
+ s = splhigh();
+ /* Writes are if the transmit queue can take them */
+ if ((events & POLLOUT) &&
+ !IF_QFULL(sc->tx_queue))
+ revents |= POLLOUT;
+ /* ... while reads are OK if we have any data */
+ if ((events & POLLIN) &&
+ !IF_QEMPTY(sc->rx_queue))
+ revents |= POLLIN;
+ if (revents == 0)
+ selrecord(p, &sc->selp);
+ splx(s);
+ return revents;
+}
+
+
+ d_select() est utilisé dans la version 2.2 et
+précédentes de FreeBSD. Au lieu de 'events', il prend un simple
+entier 'rw', qui peut être FREAD pour la lecture (comme dans
+POLLIN ci-dessus), FWRITE pour l'écriture (comme dans POLLOUT ci-dessus),
+et 0 pour 'exception' - lorsque quelque chose d'exceptionnel se produit,
+comme une carte étant insérée ou retirée pour le pilote de
+pccard.
+
+Pour 'select', le fragment correspondant à la description
+ci-dessus ressembleraient à ceci:
+
+
+static int
+mydevselect(dev_t dev, int rw, struct proc *p)
+{
+ int ret = 0;
+ int s;
+ struct my_softc *sc = &my_softc[dev];
+
+ s = splhigh();
+ switch (rw) {
+ case FWRITE:
+ /* Writes are if the transmit queue can take them */
+ if (!IF_QFULL(sc->tx_queue))
+ ret = 1;
+ break;
+ case FREAD:
+ /* ... while reads are OK if we have any data */
+ if (!IF_QEMPTY(sc->rx_queue))
+ ret = 1;
+ break;
+ case 0:
+ /* This driver never get any exceptions */
+ break;
+ }
+ if(ret == 0)
+ selrecord(p, &sc->selp);
+ splx(s);
+ return(revents);
+}
+
+
+
+
+d_mmap()
+
+
+
+
+d_strategy()
+
+
+La liste d'argument de d_strategy() est comme suit :
+
+
+
+void
+d_strategy(struct buf *bp)
+
+
+d_strategy() est utilisé pour les périphériques utilisant
+des E/S de type disperser-regrouper (scatter-gather).
+C'est ce qu'il y a de plus courant dans un périphérique de bloc.
+C'est sensiblement différent du modèle de système V, où seulement
+le pilote de bloc fait une E/S de type disperser-regrouper.
+Sous BSD, les périphériques de caractère sont parfois sommé d'exécuter
+une E/S de type disperser-regrouper par l'intermédiaire des appels
+systèmes readv() et writev().
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+Bloc
+
+
+Structures de données
+ Structure struct bdevsw
+
+
+ Structure struct buf
+
+
+
+
+Points d'entrée
+
+
+d_open()
+ Décrit dans la section périphérique de caractère.
+
+
+
+
+d_close()
+Décrit dans la section périphérique de caractère.
+
+
+
+
+d_strategy()
+Décrit dans la section périphérique de caractère.
+
+
+
+
+d_ioctl()
+Décrit dans la section périphérique de caractère.
+
+
+
+
+d_dump()
+
+
+
+
+d_psize()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+Réseau
+Structure struct ifnet
+
+
+
+Points d'entrée
+
+
+if_init()
+
+
+
+
+if_output()
+
+
+
+
+if_start()
+
+
+
+
+if_done()
+
+
+
+
+if_ioctl()
+
+
+
+
+if_watchdog()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+Protocole de communication
+
+
+Structures de données
+Structure struct linesw
+
+
+
+
+Points d'entrée
+
+
+l_open()
+
+
+
+
+l_close()
+
+
+
+
+l_read()
+
+
+
+
+l_write()
+
+
+
+
+l_ioctl()
+
+
+
+
+l_rint()
+
+
+
+
+l_start()
+
+
+
+
+l_modem()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+
+Bus Supportés
+
+
+ISA -- Architecture Standard d'Industrie (Industry Standard
+Architecture
+
+
+Structures de données
+
+
+Structure struct isa_device
+
+Cette structure est obligatoire, mais généralement elle est créée par
+config à partir du fichier de configuration de noyau.
+Elle est requise pour chaque périphérique, c'est à dire que si vous avez
+un pilote de périphérique contrôlant deux "serial boards", vous
+aurez deux structures isa_device. Si vous construisez un périphérique
+comme un LKM, vous devrez créer votre propre structure isa_device afin
+de refléter votre configuration (lignes 85 - 131 de pcaudio_lkm.c).
+Il y a un équivalence directe ebtre le fichier de configuration et la
+structureisa_device. La définition de
+/usr/src/sys/i386/isa/isa_device.h
+est :
+
+
+
+struct isa_device {
+ int id_id; /* device id */
+ struct isa_driver *id_driver;
+ int id_iobase; /* base i/o address */
+ u_short id_irq; /* interrupt request */
+ short id_drq; /* DMA request */
+ caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
+ int id_msize; /* size of i/o memory */
+ inthand2_t *id_intr; /* interrupt interface routine */
+ int id_unit; /* unit number */
+ int id_flags; /* flags */
+ int id_scsiid; /* scsi id if needed */
+ int id_alive; /* device is present */
+#define RI_FAST 1 /* fast interrupt handler */
+ u_int id_ri_flags; /* flags for register_intr() */
+ int id_reconfig; /* hot eject device support (such as PCMCIA) */
+ int id_enabled; /* is device enabled */
+ int id_conflicts; /* we're allowed to conflict with things */
+ struct isa_device *id_next; /* used in isa_devlist in userconfig() */
+};
+
+
+
+
+Structure struct isa_driver
+
+Cette structure est définie dans
+/usr/src/sys/i386/isa/isa_device.h,
+est est requise pour chaque pilote de périphérique. La définition
+est :
+
+
+
+struct isa_driver {
+ int (*probe) __P((struct isa_device *idp));
+ /* test whether device is present */
+ int (*attach) __P((struct isa_device *idp));
+ /* setup driver for a device */
+ char *name; /* device name */
+ int sensitive_hw; /* true if other probes confuse us */
+};
+
+
+
+C'est la structure employée par le code sondage/attachement
+(probe/attach) pour
+détecter et initialiser votre périphérique. Le membre probe
+est un pointeur à votre fonction permettant de sonder les périphériques.
+Le membre attach est un pointeur vers votre fonction d'attache.
+Le membre name est un pointeur de caractère sur le nom de deux
+ou trois lettres de votre pilote.
+C'est le nom enregistré pendant le processus de
+sondage/attachement (et probablement aussi dans
+lsdev).
+Le membre sensitive_hw est un
+indicateur qui aide le code de sondage à déterminer l'ordre du sondage.
+
+
+
+Un instantiation typique est:
+
+
+
+struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" };
+
+
+
+
+
+Points d'entrée
+
+
+probe()
+probe() prend un pointeur sur une structure isa_device
+comme argument et renvoie un int. La valeur de retour est ``zéro'' ou
+``non-zéro '' quant à l'absence ou à la présence de votre périphérique.
+Ce point d'entrée peut être déclaré comme
+static parce qu'il
+est accessible par l'intermédiaire du membre
+probe de la structre
+isa_driver. Cette fonction est destinée à
+détecter la présence de votre périphérique seulement et ne devrait
+faire aucune configuration du périphérique elle-même.
+
+
+
+
+attach()
+
+attach() prend également un pointeur sur une structure
+isa_device comme argument et
+renvoie un int. La valeur de retour est également ``zéro'' ou
+``non-zéro'' indiquant si l'attache a réussie. Cette fonction
+est destinée pour faire n'importe quelle initialisation spéciale du
+périphérique aussi bien que pour confirmer que le périphérique est utilisable.
+Il devrait aussi être déclaré static parce qu'il est accesible
+par le membre attach de la structure isa_driver .
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+EISA -- Architecture Étendue de Standard industriel (Extended Industry Standard Architecture)
+
+
+
+Structures de données
+
+Structure struct eisa_dev
+Structure struct isa_driver
+
+
+
+Points d'entrée
+
+
+probe()
+Décrit dans la section de périphérique ISA.
+
+
+
+attach()
+Décrit dans la section de périphérique ISA.
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+PCI -- Bus d'interconnexion Périphérique (Peripheral Computer
+Interconnect)
+
+
+Structures de données
+
+ Structure struct pci_device
+
+
+
+
+nom : Le nom abrégé du périphérique.
+
+
+
+
+ sonde: Contrôle si le pilote peut supporter un périphérique avec
+ce type. L'étiquette peut être employée pour obtenir plus
+d'information avec pci_read_conf(). Voir ci-dessous. Elle renvoie
+une chaîne de caractères avec le nom du périphérique, ou un pointeur
+NULL si le pilote ne peut pas supporter ce périphérique.
+
+
+
+
+ attache: Assigne une structure de contrôle et la prépare. Cette
+fonction peut utiliser les fonctions de mapping PCI. Voir
+ci-dessous. (identification de configuration) ou type.
+
+
+
+
+ compte: Un pointeur sur un compteur d'unité. Il est
+employé par le configurateur de PCI pour assigner des numéros.
+
+
+
+
+
+
+
+Points d'entrée
+
+
+probe()
+
+
+
+
+attach()
+
+
+
+
+shutdown()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+SCSI -- Small Computer Systems Interface
+
+
+Structure de données
+
+Structure struct scsi_adapter
+Structure struct scsi_device
+Structure struct scsi_ctlr_config
+Structure struct scsi_device_config
+Structure struct scsi_link
+
+
+
+Points d'entrée
+
+
+attach()
+
+
+
+
+init()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+
+PCCARD (PCMCIA)
+
+
+Structure de données
+
+Structure struct slot_cont
+Structure struct pccard_drv
+Structure struct pccard_dev
+Structure struct slot
+
+
+
+Points d'entrée
+
+
+handler()
+
+
+
+
+unload()
+
+
+
+
+suspend()
+
+
+
+
+init()
+
+
+
+
+
+Fichiers d'en-tête
+
+<pccard/slot.h>
+
+
+
+
+
+
+
+Incorporation dans le noyau
+
+Dans FreeBSD, le support des bus d'ISA et EISA est spécifique à
+i386. Tandis que FreeBSD lui-même est actuellement
+disponible sur la plateforme i386, un certain effort a été fait pour
+faire du code portable pour PCI, PCCARD, et SCSI. Le code
+spécifique à ISA et EISA réside dans
+/usr/src/sys/i386/isa et
+/usr/src/sys/i386/eisa respectivement. Le code indépendant de la
+machine de PCI, de PCCARD, et de SCSI réside dans
+/usr/src/sys/{pci,pccard,scsi}. Le code spécifique i386 quand à lui
+réside dans /usr/src/sys/i386/{pci, pccard, scsi}.
+
+
+
+ Dans FreeBSD, un module de gestion de périphérique peut
+être soit sous forme binaire soit sous forme de sources.
+Il n'y a aucun endroit ``officiel'' pour mettre les binaires des
+pilotes de périphériques. les systèmes BSD utilise quelque
+chose comme sys/i386/OBJ. Puisque la plupart des pilotes sont
+distribués dans les sources, la discussion suivante se rapporte à un
+source pilote de périphérique.
+Des binaires de pilotes de périphériques sont
+parfois fournis par les constructeurs de matériel qui souhaitent
+maintenir les sources de manière propriétaire.
+
+
+ Un pilote typique a son code source sous forme de fichier C,
+comme dev.c. Le pilote peut également inclure des
+fichiers; devreg.h contient typiquement des déclarations publiques
+de registre de périphérique, des macros, et d'autres
+déclarations spécifique au pilote de périphérique.
+Quelques pilotes appellent parfois ce fichier devvar.h.
+Quelques pilotes, tels que
+le dgb (pour le Digiboard PC/Xe), exigent que du microcode soit chargé
+sur la carte. Pour le pilote de dgb le microcode est compilé
+et reporté dans un fichier d'en-tête par
+file2c.
+
+
+ Si le pilote de périphérique a des structures de données et des
+ioctl qui sont spécifiques au pilote de périphérique ou
+périphérique, et
+doivent être accessibles de l'espace-utilisateur, elles devraient
+être mises dans un fichier d'en-tête séparé qui résidera dans
+/usr/include/machine/ (certaines de ces derniers résident dans
+/usr/include/sys/). Ceux-ci est typiquement nommé quelque chose comme
+ioctl_dev.h ou devio.h.
+
+
+ Si un pilote écrit depuis l'espace
+d'utilisateur est identique à un périphérique qui existe déjà, il faut
+prendre garde à utiliser les mêmes
+interfaces ioctl et structures de données. Par exemple, de l'espace
+utilisateur, un lecteur de SCSI CDROM devrait être identique à un
+lecteur de cdrom IDE; ou une ligne série sur une carte
+intelligente multiport (Digiboard, Cyclades...) devrait être identique
+à un périphérique sio. Ces périphériques ont une interface définie
+relativement bonne et devraient être utilisées.
+
+
+ Il y a deux méthodes pour lier un pilote dans le
+noyau, statiquement et le modèle LKM. La première méthode
+est assez standard à travers la famille *BSD. L'autre
+méthode a été initialement développée par Sun (je crois), et a
+été mis en application dans BSD en utilisant le modèle de Sun.
+Je ne crois pas que l'implémentation actuelle utilise encore le moindre
+code de Sun.
+
+
+
+Modèle Standard
+
+ Les étapes exigées pour ajouter votre pilote au
+noyau standard de FreeBSD sont
+
+
+
+
+Ajout à la liste des pilotes de périphérique
+
+
+
+
+Ajout d'une entrée au [bc]devsw
+
+
+
+
+Ajout d'une entrée du pilote de périphérique au fichier de
+configuration du noyau
+
+
+
+
+config,
+compilation et installation du noyau
+
+
+
+
+créer les fichiers spéciaux requis
+
+
+
+
+redémarrage
+
+
+
+
+
+Ajout à la liste des pilotes de périphérique
+
+Le modèle standard pour ajouter un module de gestion de périphérique
+au noyau de Berkeley est d'ajouter votre pilote à la liste des
+périphériques connus. Cette liste dépend de l'architecture du CPU.
+Si le périphérique n'est pas spécifique i386
+(PCCARD, PCI, SCSI), le fichier est dans
+/usr/src/sys/conf/files.
+Si le périphérique est spécifique i386, utilisez
+/usr/src/sys/i386/conf/files.i386. Une ligne typique ressemblerait
+à :
+
+
+
+i386/isa/joy.c optional joy device-driver
+
+
+Le premier champ relatif est le chemin du module de pilote
+par rapport à /usr/src/sys.
+Pour le cas d'un pilote binaire, le chemin d'accès serait quelque
+chose comme i386/OBJ/joy.o.
+
+
+Le deuxième champ indique à
+config(8)
+que c'est un pilote facultatif. Quelques
+périphériques sont obligatoires pour que le noyau puisse être construit.
+
+
+
+Le troisième champ est le nom du périphérique.
+
+
+Le quatrième champ indique à config que c'est un
+pilote de périphérique (par opposition à juste facultatif). Ceci
+dit à config de créer des entrées pour le périphérique dans dans
+des structures de /usr/src/sys/compile/KERNEL/ioconf.c.
+
+
+Il est également possible de créer un fichier
+/usr/src/sys/i386/conf/files.KERNEL dont le contenu ignorera le
+fichier par défaut files.i386, mais seulement pour le noyau ``KERNEL''.
+
+
+
+
+Faire de la place dans conf.c
+
+Maintenant vous devez éditer /usr/src/sys/i386/i386/conf.c
+pour faire une entrée pour votre pilote. Quelque part au début,
+vous devez déclarer vos points d'entrée. L'entrée pour
+le pilote du joystick est:
+
+
+#include "joy.h"
+#if NJOY > 0
+d_open_t joyopen;
+d_close_t joyclose;
+d_rdwr_t joyread;
+d_ioctl_t joyioctl;
+#else
+#define joyopen nxopen
+#define joyclose nxclose
+#define joyread nxread
+#define joyioctl nxioctl
+#endif
+
+
+
+Cela définit vos points d'entrée, ou points d'entrée nuls qui
+renverront ENXIO quand appelé (clause #else).
+
+
+
+Le fichier d'en-tête ``joy.h'' est automatiquement produit par
+config
+quand l'arborescence de construction du noyau est
+créé. Cela se réduit habituellement à une seule ligne comme :
+
+
+
+#define NJOY 1
+
+
+
+ou
+
+
+#define NJOY 0
+
+
+ ce qui définit le nombre de vos périphériques dans votre noyau.
+
+
+
+Vous devez additionnellement ajouter un slot au cdevsw[&rsqb, ou
+au bdevsw[&rsqb, selon que ce soit un périphérique caractère,
+périphérique bloc, ou les deux si c'est un périphérique bloc
+avec une interface brute. L'entrée pour le pilote du joystick
+est:
+
+
+
+/* open, close, read, write, ioctl, stop, reset, ttys, select, mmap, strat */
+struct cdevsw cdevsw[] =
+{
+ ...
+ { joyopen, joyclose, joyread, nowrite, /*51*/
+ joyioctl, nostop, nullreset, nodevtotty,/*joystick */
+ seltrue, nommap, NULL},
+ ...
+}
+
+
+
+ L'ordre est ce qui détermine le nombre majeur de votre
+périphérique. C'est pourquoi il y aura toujours une entrée
+pour votre pilote, que ce soit des points d'entrée nuls,
+ou des points d'entrée actuels. Il est probablement intéressant de
+noter que c'est
+sensiblement différent de SCO et d'autres dérivés du système V, où
+n'importe quel périphérique (dans la théorie) peut avoir n'importe
+quel nombre majeur. C'est en grande partie un avantage sur FreeBSD,
+sur la manière dont les fichiers spéciaux de périphérique sont créés.
+Nous reviendrons en détail sur ceci plus tard.
+
+
+
+
+Ajout de votre périphérique dans le fichier de configuration.
+
+ Ceci ajoute simplement une ligne décrivant votre périphérique. La
+ligne de description du joystick est :
+
+device joy0 at isa? port "IO_GAME"
+
+Ceci indique que nous avons un
+périphérique appelé ``joy0'' sur le bus ISA en utilisant
+le port E/S ``IO_GAME'' (IO_GAME est une macro définie dans
+/usr/src/sys/i386/isa/isa.h).
+
+
+
+Une entrée légèrement plus compliquée est pour le pilote ``ix'' :
+
+
+device ix0 at isa? port 0x300 net irq 10 iomem 0xd0000 iosiz 32768
+vector ixintr
+
+
+Ceci indique que nous avons un périphérique appelé
+`ix0 ' sur le bus ISA. Il utilise le port E/S 0x300. Son
+interruption sera masqué par d'autres périphériques dans la classe
+réseau. Il utilise l'interruption 10. Il utilise 32k de mémoire
+partagée à l'adresse physique 0xd0000. Il le définit également
+son pilote d'interruption comme étant ``ixintr()''
+
+
+
+
+config
+du noyau.
+
+ Maintenant avec notre fichier de configuration en main,
+nous pouvons créer un répertoire de compilation du noyau. Cela peut être
+fait en tapant :
+
+# config KERNEL
+
+
+où KERNEL est le nom de votre fichier de configuration.
+La configuration crée un arbre de compilation
+pour votre noyau dans /usr/src/sys/compile/KERNEL. Elle crée le fichier
+makefile, quelques fichiers C, et quelques fichiers H avec des
+macros définissant le nombre de chaque périphérique à inclure dans votre
+votre noyau.
+
+
+
+Maintenant vous pouvez aller dans le répertoire de compilation et
+construire votre noyau. À chaque fois que vous lancerez config, votre
+arbre de construction précédent sera retiré, à moins que vous ne lancez
+config avec un -n. Si vous avez configuré et compilé un noyau GENERIC,
+vous pouvez faire un ``make links'' afin d'éviter de compiler certains
+fichiers à chaque itération. Typiquement, je lance :
+
+# make depend links all
+
+suivi d'un ``make install'' quand le noyau me convient.
+
+
+
+
+Créer les fichiers spéciaux de périphériques
+
+ Sur FreeBSD, vous avez la responsabilité de faire vos propres fichiers
+spéciaux
+de périphérique. Le
+nombre majeur de votre périphérique est déterminé par le nombre de
+slots dans le commutateur de périphérique. Le nombre mineur est
+dépendant du pilote, naturellement. Vous pouvez
+soit exécuter mknod depuis la ligne de commande, soit liasser faire le
+travail à /dev/MAKEDEV.local, ou même
+/dev/MAKEDEV.
+Je crée parfois un script MAKEDEV.dev qui peut être soit lancé
+de manière autonome soit collé dans /dev/MAKEDEV.local.
+
+
+
+
+Redémarrage
+ C'est la partie facile. Il y a un
+certain nombre de méthodes pour faire ceci, reboot, fastboot,
+shutdown - r, couper le courant, etc. Au démarrage, vous
+devriez voir votre XXprobe() appelé, et si tout marche,
+votre attach() aussi.
+
+
+
+
+
+Module du noyau à chargement dynamique (LKM)
+
+Il n'y a vraiment aucune procédure définie pour écrire un pilote de
+LKM. Ce qui suit est ma propre conception après expérimentation
+avec l'interface de périphérique LKM et en regardant le modèle standard
+de module de gestion de périphérique, c'est une manière d'ajouter une
+interface LKM à un pilote existant sans toucher aux sources (ou binaire)
+initiaux de pilote . On recommande cependant,
+que si vous projetez de distribuer les sources de votre pilote,
+que les parties spécifiques LKM devraient faire partie du pilote
+lui-même, compilé de manière conditionnelle par la macro LKM
+(c.-à-d. #ifdef LKM).
+
+
+
+Cette section se concentrera sur la manière d'écrire la partie spécifique
+LKM du pilote. Nous supposerons que nous avons écrit un
+pilote qui atterrira dans le modèle standard de
+gestion de périphérique, que nous voudrions maintenant mettre en
+application comme étant LKM. Nous utiliserons le pilote de pcaudio
+comme pilote d'exemple, et développerons une entrée LKM. La
+source et le fichier makefile pour le LKM pcaudio , ``pcaudio_lkm.c''
+et ``Makefile'', devraient être dans placé /usr/src/lkm/pcaudio.
+Ce qui suit est le code commenté de pcaudio_lkm.c.
+
+
+
+Lignes 17 - 26
+
+
+
+Ceci inclut le fichier ``pca.h'' et fait une compilation conditionnelle
+du reste de LKM suivant que vous avez défini ou non le pilote de
+périphérique pcaudio.
+Cela imite le comportement de config. Dans un pilote de
+périphérique standard,
+config
+produit le fichier pca.h depuis le nombre de périphériques pca
+le fichier de config.
+
+
+ 17 /*
+ 18 * figure out how many devices we have..
+ 19 */
+ 20
+ 21 #include "pca.h"
+ 22
+ 23 /*
+ 24 * if we have at least one ...
+ 25 */
+ 26 #if NPCA > 0
+
+
+
+Lignes 27 - 37
+
+
+
+Les fichiers d'en-tête requis depuis divers répertoire d'inclusion.
+
+
+
+ 27 #include <sys/param.h>
+ 28 #include <sys/systm.h>
+ 29 #include <sys/exec.h>
+ 30 #include <sys/conf.h>
+ 31 #include <sys/sysent.h>
+ 32 #include <sys/lkm.h>
+ 33 #include <sys/errno.h>
+ 34 #include <i386/isa/isa_device.h>
+ 35 #include <i386/isa/isa.h>
+ 36
+ 37
+
+
+
+Lignes 38 - 51
+
+
+déclarent vos points d'entrée comme externs .
+
+
+
+ 38 /*
+ 39 * declare your entry points as externs
+ 40 */
+ 41
+ 42 extern int pcaprobe(struct isa_device *);
+ 43 extern int pcaattach(struct isa_device *);
+ 44 extern int pcaopen(dev_t, int, int, struct proc *);
+ 45 extern int pcaclose(dev_t, int, int, struct proc *);
+ 46 extern int pcawrite(dev_t, struct uio *, int);
+ 47 extern int pcaioctl(dev_t, int, caddr_t);
+ 48 extern int pcaselect(dev_t, int, struct proc *);
+ 49 extern void pcaintr(struct clockframe *);
+ 50 extern struct isa_driver pcadriver;
+ 51
+
+
+
+Lignes 52 - 70
+
+
+
+Cela crée la table d'entrée de commutateur de périphérique pour
+votre pilote. Cette table est en gros entièrement mise dans le
+système de commutation de périphériques à l'emplacement indiqué par
+votre nombre majeur. Dans le modèle standard, c'est dans
+/usr/src/sys/i386/i386/conf.c.
+NOTE: vous ne pouvez pas sélectionner
+un nombre majeur de périphérique plus grand que ce qui existe dans
+conf.c, par exemple
+il y a 67 slots pour des périphériques caractère, vous ne popuvez pas
+utiliser un périphérique (caractère) de numéro majeur 67 ou
+plus, sans avoir d'abord réservé de l'espace dans conf.c.
+
+
+
+ 52 /*
+ 53 * build your device switch entry table
+ 54 */
+ 55
+ 56 static struct cdevsw pcacdevsw = {
+ 57 (d_open_t *) pcaopen, /* open */
+ 58 (d_close_t *) pcaclose, /* close */
+ 59 (d_rdwr_t *) enodev, /* read */
+ 60 (d_rdwr_t *) pcawrite, /* write */
+ 61 (d_ioctl_t *) pcaioctl, /* ioctl */
+ 62 (d_stop_t *) enodev, /* stop?? */
+ 63 (d_reset_t *) enodev, /* reset */
+ 64 (d_ttycv_t *) enodev, /* ttys */
+ 65 (d_select_t *) pcaselect, /* select */
+ 66 (d_mmap_t *) enodev, /* mmap */
+ 67 (d_strategy_t *) enodev /* strategy */
+ 68 };
+ 69
+ 70
+
+
+
+Lignes 71 - 131
+
+
+cette section est analogue à la déclaration de fichier de configuration
+de votre périphérique. Les membres de la structure isa_device sont
+remplis grace à ce qu'il connait de votre périphérique,
+port E/S, segment partagé de mémoire, etc...
+Nous n'aurons probablement jamais un besoin de deux périphériques
+pcaudio dans le noyau, mais cet exemple montre comment
+périphériques multiples peuvent être supportés.
+
+
+
+ 71 /*
+ 72 * this lkm arbitrarily supports two
+ 73 * instantiations of the pc-audio device.
+ 74 *
+ 75 * this is for illustration purposes
+ 76 * only, it doesn't make much sense
+ 77 * to have two of these beasts...
+ 78 */
+ 79
+ 80
+ 81 /*
+ 82 * these have a direct correlation to the
+ 83 * config file entries...
+ 84 */
+ 85 struct isa_device pcadev[NPCA] = {
+ 86 {
+ 87 11, /* device id */
+ 88 &pcadriver, /* driver pointer */
+ 89 IO_TIMER1, /* base io address */
+ 90 -1, /* interrupt */
+ 91 -1, /* dma channel */
+ 92 (caddr_t)-1, /* physical io memory */
+ 93 0, /* size of io memory */
+ 94 pcaintr , /* interrupt interface */
+ 95 0, /* unit number */
+ 96 0, /* flags */
+ 97 0, /* scsi id */
+ 98 0, /* is alive */
+ 99 0, /* flags for register_intr */
+ 100 0, /* hot eject device support */
+ 101 1 /* is device enabled */
+ 102 },
+ 103 #if NPCA >1
+ 104 {
+ 105
+ 106 /*
+ 107 * these are all zeros, because it doesn't make
+ 108 * much sense to be here
+ 109 * but it may make sense for your device
+ 110 */
+ 111
+ 112 0, /* device id */
+ 113 &pcadriver, /* driver pointer */
+ 114 0, /* base io address */
+ 115 -1, /* interrupt */
+ 116 -1, /* dma channel */
+ 117 -1, /* physical io memory */
+ 118 0, /* size of io memory */
+ 119 NULL, /* interrupt interface */
+ 120 1, /* unit number */
+ 121 0, /* flags */
+ 122 0, /* scsi id */
+ 123 0, /* is alive */
+ 124 0, /* flags for register_intr */
+ 125 0, /* hot eject device support */
+ 126 1 /* is device enabled */
+ 127 },
+ 128 #endif
+ 129
+ 130 };
+ 131
+
+
+
+Lignes 132 - 139
+
+
+
+Ceci appelle la macro MOD_DEV du préprocesseur C, qui
+installe un module de gestion de périphérique de LKM, par
+opposition à un système de fichiers LKM, ou un appel système de LKM.
+
+
+
+ 132 /*
+ 133 * this macro maps to a function which
+ 134 * sets the LKM up for a driver
+ 135 * as opposed to a filesystem, system call, or misc
+ 136 * LKM.
+ 137 */
+ 138 MOD_DEV("pcaudio_mod", LM_DT_CHAR, 24, &pcacdevsw);
+ 139
+
+
+
+Lignes 140 - 168
+
+
+
+c'est la fonction qui sera appelée lorsque le pilote sera
+chargé. Cette fonction essaye de fonctionner comme
+/sys/i386/isa/isa.c qui fait les appels de probe/attach pour un
+pilote au moment du redémarrage. La plus grande astuce ici est qu'il
+met en correspondance l'adresse physique du segment partagé de mémoire, qui est
+indiqué dans la structure isa_device à une adresse virtuelle du noyau.
+Normalement, l'adresse physique est mise dans le fichier de configuration
+qui construit la structure isa_device dans
+/usr/src/sys/compile/KERNEL/ioconf.c. La séquence probe/attach de
+/usr/src/sys/isa/isa.c traduit l'adresse physique en une virtuelle de
+sorte que dans les sous-programmes de probe/attach vous puissiez
+faire des choses comme
+
+
+(int *)id->id_maddr = something;
+
+ et se réfère juste au segment partagé de mémoire
+par l'intermédiaire de pointeurs.
+
+
+
+ 140 /*
+ 141 * this function is called when the module is
+ 142 * loaded; it tries to mimic the behavior
+ 143 * of the standard probe/attach stuff from
+ 144 * isa.c
+ 145 */
+ 146 int
+ 147 pcaload(){
+ 148 int i;
+ 149 uprintf("PC Audio Driver Loaded\n");
+ 150 for (i=0; i<NPCA; i++){
+ 151 /*
+ 152 * this maps the shared memory address
+ 153 * from physical to virtual, to be
+ 154 * consistent with the way
+ 155 * /usr/src/sys/i386/isa.c handles it.
+ 156 */
+ 157 pcadev[i].id_maddr -=0xa0000;
+ 158 pcadev[i].id_maddr += atdevbase;
+ 159 if ((*pcadriver.probe)(pcadev+i)) {
+ 160 (*(pcadriver.attach))(pcadev+i);
+ 161 } else {
+ 162 uprintf("PC Audio Probe Failed\n");
+ 163 return(1);
+ 164 }
+ 165 }
+ 166 return 0;
+ 167 }
+ 168
+
+
+Lignes 169 - 179
+
+
+c'est la fonction appelée quand votre pilote n'est pas
+chargé; il affiche juste un message à cet effet.
+
+
+
+ 169 /*
+ 170 * this function is called
+ 171 * when the module is unloaded
+ 172 */
+ 173
+ 174 int
+ 175 pcaunload(){
+ 176 uprintf("PC Audio Driver Unloaded\n");
+ 177 return 0;
+ 178 }
+ 179
+
+
+Lignes 180 - 190
+
+
+c'est le point d'entrée qui est indiqué sur la ligne de commande
+de modload. Par convention il est nommé <dev>_mod. C'est
+ainsi qu'il est défini dans bsd.lkm.mk, le makefile qui
+construit le LKM. Si vous nommez votre module suivant cette
+convention, vous pouvez faire ``make load'' et ``make unload''
+de /usr/src/lkm/pcaudio.
+
+Note : Il y a eu tellement de révisions entre la version 2.0 et
+2.1. Il peut ou ne peut ne pas être possible d'écrire
+un module qui est portable pour chacune des trois versions.
+
+
+
+
+ 180 /*
+ 181 * this is the entry point specified
+ 182 * on the modload command line
+ 183 */
+ 184
+ 185 int
+ 186 pcaudio_mod(struct lkm_table *lkmtp, int cmd, int ver)
+ 187 {
+ 188 DISPATCH(lkmtp, cmd, ver, pcaload, pcaunload, nosys);
+ 189 }
+ 190
+ 191 #endif /* NICP > 0 */
+
+
+
+
+Idiosyncrasies du type périphérique
+
+
+Caractère
+
+
+
+
+Bloc
+
+
+
+
+Réseau
+
+
+
+
+Line discipline
+
+
+
+
+
+Idiosyncrasies du type bus
+
+
+ISA
+
+
+
+
+EISA
+
+
+
+
+PCI
+
+
+
+
+SCSI
+
+
+
+
+PCCARD
+
+
+
+
+
+
+
+Support du noyau
+
+
+Structures de données
+
+
+Structure struct kern_devconf
+
+Cette structure contient quelques informations sur l'état du
+périphérique et de son pilote. Elle est définie dans
+/usr/src/sys/sys/devconf.h comme ci-dessous :
+
+
+
+struct devconf {
+ char dc_name[MAXDEVNAME]; /* name */
+ char dc_descr[MAXDEVDESCR]; /* description */
+ int dc_unit; /* unit number */
+ int dc_number; /* unique id */
+ char dc_pname[MAXDEVNAME]; /* name of the parent device */
+ int dc_punit; /* unit number of the parent */
+ int dc_pnumber; /* unique id of the parent */
+ struct machdep_devconf dc_md; /* machine-dependent stuff */
+ enum dc_state dc_state; /* state of the device (see above) */
+ enum dc_class dc_class; /* type of device (see above) */
+ size_t dc_datalen; /* length of data */
+ char dc_data[1]; /* variable-length data */
+};
+
+
+
+
+Structure struct proc
+
+ Cette structure contient toutes les informations sur un processus.
+Elle est dans définie /usr/src/sys/sys/proc.h:
+
+
+
+/*
+ * Description of a process.
+ *
+ * This structure contains the information needed to manage a thread of
+ * control, known in UN*X as a process; it has references to
+substructures
+ * containing descriptions of things that the process uses, but may
+share
+ * with related processes. The process structure and the substructures
+ * are always addressable except for those marked "(PROC ONLY)" below,
+ * which might be addressable only on a processor on which the process
+ * is running.
+ */
+struct proc {
+ struct proc *p_forw; /* Doubly-linked run/sleep queue. */
+ struct proc *p_back;
+ struct proc *p_next; /* Linked list of active procs */
+ struct proc **p_prev; /* and zombies. */
+
+ /* substructures: */
+ struct pcred *p_cred; /* Process owner's identity. */
+ struct filedesc *p_fd; /* Ptr to open files structure. */
+ struct pstats *p_stats; /* Accounting/statistics (PROC ONLY). */
+ struct plimit *p_limit; /* Process limits. */
+ struct vmspace *p_vmspace; /* Address space. */
+ struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */
+
+#define p_ucred p_cred->pc_ucred
+#define p_rlimit p_limit->pl_rlimit
+
+ int p_flag; /* P_* flags. */
+ char p_stat; /* S* process status. */
+ char p_pad1[3];
+
+ pid_t p_pid; /* Process identifier. */
+ struct proc *p_hash; /* Hashed based on p_pid for kill+exit+... */
+ struct proc *p_pgrpnxt; /* Pointer to next process in process group. */
+ struct proc *p_pptr; /* Pointer to process structure of parent. */
+ struct proc *p_osptr; /* Pointer to older sibling processes. */
+
+/* The following fields are all zeroed upon creation in fork. */
+#define p_startzero p_ysptr
+ struct proc *p_ysptr; /* Pointer to younger siblings. */
+ struct proc *p_cptr; /* Pointer to youngest living child. */
+ pid_t p_oppid; /* Save parent pid during ptrace. XXX */
+ int p_dupfd; /* Sideways return value from fdopen. XXX */
+
+ /* scheduling */
+ u_int p_estcpu; /* Time averaged value of p_cpticks. */
+ int p_cpticks; /* Ticks of cpu time. */
+ fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */
+ void *p_wchan; /* Sleep address. */
+ char *p_wmesg; /* Reason for sleep. */
+ u_int p_swtime; /* Time swapped in or out. */
+ u_int p_slptime; /* Time since last blocked. */
+
+ struct itimerval p_realtimer; /* Alarm timer. */
+ struct timeval p_rtime; /* Real time. */
+ u_quad_t p_uticks; /* Statclock hits in user mode. */
+ u_quad_t p_sticks; /* Statclock hits in system mode. */
+ u_quad_t p_iticks; /* Statclock hits processing intr. */
+
+ int p_traceflag; /* Kernel trace points. */
+ struct vnode *p_tracep; /* Trace to vnode. */
+
+ int p_siglist; /* Signals arrived but not delivered. */
+
+ struct vnode *p_textvp; /* Vnode of executable. */
+
+ char p_lock; /* Process lock (prevent swap) count. */
+ char p_pad2[3]; /* alignment */
+
+/* End area that is zeroed on creation. */
+#define p_endzero p_startcopy
+
+/* The following fields are all copied upon creation in fork. */
+#define p_startcopy p_sigmask
+
+ sigset_t p_sigmask; /* Current signal mask. */
+ sigset_t p_sigignore; /* Signals being ignored. */
+ sigset_t p_sigcatch; /* Signals being caught by user. */
+
+ u_char p_priority; /* Process priority. */
+ u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */
+ char p_nice; /* Process "nice" value. */
+ char p_comm[MAXCOMLEN+1];
+
+ struct pgrp *p_pgrp; /* Pointer to process group. */
+
+ struct sysentvec *p_sysent; /* System call dispatch information. */
+
+ struct rtprio p_rtprio; /* Realtime priority. */
+/* End area that is copied on creation. */
+#define p_endcopy p_addr
+ struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */
+ struct mdproc p_md; /* Any machine-dependent fields. */
+
+ u_short p_xstat; /* Exit status for wait; also stop signal. */
+ u_short p_acflag; /* Accounting flags. */
+ struct rusage *p_ru; /* Exit information. XXX */
+};
+
+
+
+
+Structure struct buf
+La structure struct buf est employée pour s'interfacer
+avec le cache de la mémoire tampon. Elle est dans
+définie /usr/src/sys/sys/buf.h :
+
+
+
+/*
+ * The buffer header describes an I/O operation in the kernel.
+ */
+struct buf {
+ LIST_ENTRY(buf) b_hash; /* Hash chain. */
+ LIST_ENTRY(buf) b_vnbufs; /* Buffer's associated vnode. */
+ TAILQ_ENTRY(buf) b_freelist; /* Free list position if not active. */
+ struct buf *b_actf, **b_actb; /* Device driver queue when active. */
+ struct proc *b_proc; /* Associated proc; NULL if kernel. */
+ volatile long b_flags; /* B_* flags. */
+ int b_qindex; /* buffer queue index */
+ int b_error; /* Errno value. */
+ long b_bufsize; /* Allocated buffer size. */
+ long b_bcount; /* Valid bytes in buffer. */
+ long b_resid; /* Remaining I/O. */
+ dev_t b_dev; /* Device associated with buffer. */
+ struct {
+ caddr_t b_addr; /* Memory, superblocks, indirect etc. */
+ } b_un;
+ void *b_saveaddr; /* Original b_addr for physio. */
+ daddr_t b_lblkno; /* Logical block number. */
+ daddr_t b_blkno; /* Underlying physical block number. */
+ /* Function to call upon completion. */
+ void (*b_iodone) __P((struct buf *));
+ /* For nested b_iodone's. */
+ struct iodone_chain *b_iodone_chain;
+ struct vnode *b_vp; /* Device vnode. */
+ int b_pfcent; /* Center page when swapping cluster. */
+ int b_dirtyoff; /* Offset in buffer of dirty region. */
+ int b_dirtyend; /* Offset of end of dirty region. */
+ struct ucred *b_rcred; /* Read credentials reference. */
+ struct ucred *b_wcred; /* Write credentials reference. */
+ int b_validoff; /* Offset in buffer of valid region. */
+ int b_validend; /* Offset of end of valid region. */
+ daddr_t b_pblkno; /* physical block number */
+ caddr_t b_savekva; /* saved kva for transfer while bouncing */
+ void *b_driver1; /* for private use by the driver */
+ void *b_driver2; /* for private use by the driver */
+ void *b_spc;
+ struct vm_page *b_pages[(MAXPHYS + PAGE_SIZE - 1)/PAGE_SIZE];
+ int b_npages;
+};
+
+
+
+
+
+Structure struct uio
+
+Cette structure est utilisée pour déplacer des données entre le noyau et
+les espaces utilisateur par les appels système de read() et de write().
+Il est dans défini /usr/src/sys/sys/uio.h :
+
+
+
+struct uio {
+ struct iovec *uio_iov;
+ int uio_iovcnt;
+ off_t uio_offset;
+ int uio_resid;
+ enum uio_seg uio_segflg;
+ enum uio_rw uio_rw;
+ struct proc *uio_procp;
+};
+
+
+
+
+
+
+Fonctions
+plein
+
+
+
+Références.
+
+ FreeBSD Kernel Sources http://www.freebsd.org
+
+
+ NetBSD Kernel Sources http://www.netbsd.org
+
+
+ Writing Device Drivers: Tutorial and Reference;
+Tim Burke, Mark A. Parenti, Al, Wojtas;
+Digital Press, ISBN 1-55558-141-2.
+
+
+ Writing A Unix Device Driver;
+Janet I. Egan, Thomas J. Teixeira;
+John Wiley & Sons, ISBN 0-471-62859-X.
+
+
+ Writing Device Drivers for SCO Unix;
+Peter Kettle;
+
+
+
+
diff --git a/fr_FR.ISO_8859-1/articles/ddwg/Makefile b/fr_FR.ISO_8859-1/articles/ddwg/Makefile
new file mode 100644
index 0000000000..68714b471c
--- /dev/null
+++ b/fr_FR.ISO_8859-1/articles/ddwg/Makefile
@@ -0,0 +1,20 @@
+#
+# The FreeBSD Documentation Project
+# The FreeBSD French Documentation Project
+#
+# $Id: Makefile,v 1.1 2000-06-01 19:14:23 gioria Exp $
+# Original revision: 1.4
+#
+
+DOC?= article
+
+FORMATS?= html
+
+INSTALL_COMPRESSED?=gz
+INSTALL_ONLY_COMPRESSED?=
+
+SRCS= article.sgml
+
+DOC_PREFIX?= ${.CURDIR}/../../..
+
+.include "${DOC_PREFIX}/share/mk/doc.project.mk"
diff --git a/fr_FR.ISO_8859-1/articles/ddwg/article.sgml b/fr_FR.ISO_8859-1/articles/ddwg/article.sgml
new file mode 100644
index 0000000000..012e35654a
--- /dev/null
+++ b/fr_FR.ISO_8859-1/articles/ddwg/article.sgml
@@ -0,0 +1,1861 @@
+
+
+ %man;
+ %urls;
+ %abstract;
+ %artheader;
+ %translators;
+
+ %authors;
+ %mailing-lists;
+
+]>
+
+
+
+
+ Le guide de l'auteur de pilotes de périphériques pour FreeBSD
+
+
+ Eric L.
+ Hernes
+
+
+ &artheader.copyright;
+
+ erich@rrnet.com
+ 29 Mai 1996
+ Ce document décrit comment ajouter un module de gestion de
+périphérique à FreeBSD. Il n'est pas destiné pour être un
+cours d'instruction sur des modules de gestion de périphérique
+d'Unix en général. Il est destiné pour les auteurs de module de
+gestion de périphérique, au courant du modèle de module de gestion
+de périphérique d'Unix, pour travailler sur FreeBSD.
+
+ &abstract.license;
+ &abstract.disclaimer;
+ &trans.a.dntt;
+
+
+
+
+
+Spécificité de FreeBSD2.x
+
+Dû aux changements de FreeBSD avec le temps, ce guide est
+seulement précis en ce qui concerne FreeBSD 2.x. Un guide de
+rechange pour FreeBSD 3.x et au-delà est en train d'être écrit.
+Contactez Jeroen Ruigrok asmodai@wxs.nl si
+vous voulez l'aider à ce sujet.
+
+
+
+
+
+Généralité
+
+ Le noyau de FreeBSD est très bien
+documenté, malheureusement il est entièrement écrit en `C'.
+
+
+
+
+Types de pilotes de module de périphériques.
+
+
+Caractère
+
+
+Structures de données
+
+Structure cdevsw
+
+
+
+Points d'entrée
+
+
+d_open()
+
+d_open() prend plusieurs arguments, la liste formelle ressemble à
+quelque chose comme :
+
+
+
+int
+d_open(dev_t dev, int flag, int mode, struct proc *p)
+
+
+d_open() est appelé à chaque ouverture du périphérique.
+
+L'argument dev contient le nombre majeur et mineur du
+périphérique ouvert. Ils sont disponibles par les macros
+major() et minor()
+
+
+Les arguments flag et mode sont comme décrits sur
+la page de manuel de
+open.
+Il est recommandé que vous examiniez
+ces derniers pour vous assurer des droits d'accès dans <sys/fcntl.h>
+et faire ce qui est exigé. Par exemple si flag est
+(O_NONBLOCK | O_EXLOCK) l'ouverture échouerait si il bloquait ou
+si l'accès exclusif ne pouvait pas être accordé.
+
+
+
+L'argument p contient toutes les informations à propos du
+processus actuel.
+
+
+
+
+d_close()
+ d_close() prend la même liste d'argument que d_open():
+
+
+
+int
+d_close(dev_t dev , int flag , int mode , struct proc *p)
+
+
+d_close() est seulement appelé à la dernière fermeture de votre
+périphérique (par périphérique mineur). Par exemple dans le fragment
+suivant de code, d_open() est appelé 3 fois, mais d_close()
+seulement une fois.
+
+
+
+ ...
+ fd1=open("/dev/mydev", O_RDONLY);
+ fd2=open("/dev/mydev", O_RDONLY);
+ fd3=open("/dev/mydev", O_RDONLY);
+ ...
+ <useful stuff with fd1, fd2, fd3 here>
+ ...
+ close(fd1);
+ close(fd2);
+ close(fd3);
+ ...
+
+
+Les arguments sont semblables à ceux décrits ci-dessus pour
+d_open().
+
+
+
+
+d_read() et d_write()
+
+d_read() et d_write prennent les listes suivantes d'argument:
+
+
+
+int
+d_read(dev_t dev, struct uio *uio, int flat)
+int
+d_write(dev_t dev, struct uio *uio, int flat)
+
+
+
+Les points d'entrée de d_read() et de d_write() sont appelés quand
+read et
+write
+sont appelés sur votre périphérique depuis l'espace utilisateur. Le transfert
+des données peut être manipulé par la routine du noyau uiomove().
+
+
+
+
+d_ioctl()
+
+ Sa liste d'argument est comme suit:
+
+
+int
+d_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *p)
+
+
+
+d_ioctl() est un fourre-tout pour les exécutions qui ne semblent
+pas raisonnable dans un paradigme lecture/écriture. Le plus
+célèbre de tout les ioctl est probablement celui sur des périphériques
+tty, par le
+stty.
+
+Le point d'entrée d'ioctl est appelé depuis l'ioctl() de
+sys/kern/sys_generic.c
+
+
+Il y a quatre types différents d'ioctl qui peuvent être implémentés.
+
+<sys/ioccom.h> contient des macros pratiques de
+pour définir ces ioctls.
+
+
+
+
+_IO(g, n) pour les opérations de type contrôle.
+
+
+
+
+
+_IOR(g, n, t) pour des opérations lisant des données d'un
+périphérique.
+
+
+
+
+
+_IOW(g, n, t) pour les opérations écrivant des données
+sur un périphérique.
+
+
+
+
+
+_IOWR(g,n,t) pour les opérations écrivant sur un périphérique
+puis lisent les données.
+
+
+
+
+
+
+Ici g se rapporte à un groupe /. C'est une valeur
+de 8 bits, en général indicative du périphérique ; par exemple, 't'
+est utilisé dans des ioctls de tty. n se
+rapporte au nombre de l'ioctl dans le groupe. Sur SCO, ce seul nombre
+dénote l'ioctl. t est le type de données qui sera
+passé au pilote de périphérique; ceci est alors remis à un opérateur
+sizeof() du noyau. L'appel système ioctl() fera soit un copyin()
+soit un copyout() ou les deux à votre pilote, puis vous
+renverra un pointeur à la structure de données dans l'argument
+arg de l'appel d'd_ioctl. Actuellement la taille de
+données est limitée à une page (4k sur l'i386).
+
+
+
+
+d_stop()
+
+
+
+
+d_reset()
+
+
+
+
+d_devtotty()
+
+
+
+
+d_poll() (3.0 et plus) ou d_select() (2.2)
+
+la liste d'argument de d_poll() est comme suit :
+
+
+
+void
+d_poll(dev_t dev, int events, struct proc *p)
+
+
+ d_poll() est employé pour découvrir si un périphérique
+est prêt pour les E/S. Par exemple, attendre que des données du réseau
+soient dispnibles, ou que l'utilisateur presse une touche.
+Cela correspond à un appel de poll() dans l'espace utilisateur.
+
+
+L'appel à d_poll() devrait vérifier les événements
+indiqués dans le masque d'évènement. Si aucun des événements demandés n'est
+en activité, mais qu'elles pourraient devenir actif plus tard, il
+devrait enregistrer ceci pour les actions futures du noyau.
+d_poll() fait ceci en appelant selrecord() avec une structure
+selinfo pour ce périphérique. La somme de toutes ces activités
+ressemblent à quelque chose comme ceci:
+
+
+
+static struct my_softc {
+ struct queue rx_queue; /* As example only - not required */
+ struct queue tx_queue; /* As example only - not required */
+ struct selinfo selp; /* Required */
+} my_softc[NMYDEV];
+
+...
+
+static int
+mydevpoll(dev_t dev, int events, struct proc *p)
+{
+ int revents = 0; /* Events we found */
+ int s;
+ struct my_softc *sc = &my_softc[dev];
+
+ /* We can only check for IN and OUT */
+ if ((events & (POLLIN|POLLOUT)) == 0)
+ return(POLLNVAL);
+
+ s = splhigh();
+ /* Writes are if the transmit queue can take them */
+ if ((events & POLLOUT) &&
+ !IF_QFULL(sc->tx_queue))
+ revents |= POLLOUT;
+ /* ... while reads are OK if we have any data */
+ if ((events & POLLIN) &&
+ !IF_QEMPTY(sc->rx_queue))
+ revents |= POLLIN;
+ if (revents == 0)
+ selrecord(p, &sc->selp);
+ splx(s);
+ return revents;
+}
+
+
+ d_select() est utilisé dans la version 2.2 et
+précédentes de FreeBSD. Au lieu de 'events', il prend un simple
+entier 'rw', qui peut être FREAD pour la lecture (comme dans
+POLLIN ci-dessus), FWRITE pour l'écriture (comme dans POLLOUT ci-dessus),
+et 0 pour 'exception' - lorsque quelque chose d'exceptionnel se produit,
+comme une carte étant insérée ou retirée pour le pilote de
+pccard.
+
+Pour 'select', le fragment correspondant à la description
+ci-dessus ressembleraient à ceci:
+
+
+static int
+mydevselect(dev_t dev, int rw, struct proc *p)
+{
+ int ret = 0;
+ int s;
+ struct my_softc *sc = &my_softc[dev];
+
+ s = splhigh();
+ switch (rw) {
+ case FWRITE:
+ /* Writes are if the transmit queue can take them */
+ if (!IF_QFULL(sc->tx_queue))
+ ret = 1;
+ break;
+ case FREAD:
+ /* ... while reads are OK if we have any data */
+ if (!IF_QEMPTY(sc->rx_queue))
+ ret = 1;
+ break;
+ case 0:
+ /* This driver never get any exceptions */
+ break;
+ }
+ if(ret == 0)
+ selrecord(p, &sc->selp);
+ splx(s);
+ return(revents);
+}
+
+
+
+
+d_mmap()
+
+
+
+
+d_strategy()
+
+
+La liste d'argument de d_strategy() est comme suit :
+
+
+
+void
+d_strategy(struct buf *bp)
+
+
+d_strategy() est utilisé pour les périphériques utilisant
+des E/S de type disperser-regrouper (scatter-gather).
+C'est ce qu'il y a de plus courant dans un périphérique de bloc.
+C'est sensiblement différent du modèle de système V, où seulement
+le pilote de bloc fait une E/S de type disperser-regrouper.
+Sous BSD, les périphériques de caractère sont parfois sommé d'exécuter
+une E/S de type disperser-regrouper par l'intermédiaire des appels
+systèmes readv() et writev().
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+Bloc
+
+
+Structures de données
+ Structure struct bdevsw
+
+
+ Structure struct buf
+
+
+
+
+Points d'entrée
+
+
+d_open()
+ Décrit dans la section périphérique de caractère.
+
+
+
+
+d_close()
+Décrit dans la section périphérique de caractère.
+
+
+
+
+d_strategy()
+Décrit dans la section périphérique de caractère.
+
+
+
+
+d_ioctl()
+Décrit dans la section périphérique de caractère.
+
+
+
+
+d_dump()
+
+
+
+
+d_psize()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+Réseau
+Structure struct ifnet
+
+
+
+Points d'entrée
+
+
+if_init()
+
+
+
+
+if_output()
+
+
+
+
+if_start()
+
+
+
+
+if_done()
+
+
+
+
+if_ioctl()
+
+
+
+
+if_watchdog()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+Protocole de communication
+
+
+Structures de données
+Structure struct linesw
+
+
+
+
+Points d'entrée
+
+
+l_open()
+
+
+
+
+l_close()
+
+
+
+
+l_read()
+
+
+
+
+l_write()
+
+
+
+
+l_ioctl()
+
+
+
+
+l_rint()
+
+
+
+
+l_start()
+
+
+
+
+l_modem()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+
+Bus Supportés
+
+
+ISA -- Architecture Standard d'Industrie (Industry Standard
+Architecture
+
+
+Structures de données
+
+
+Structure struct isa_device
+
+Cette structure est obligatoire, mais généralement elle est créée par
+config à partir du fichier de configuration de noyau.
+Elle est requise pour chaque périphérique, c'est à dire que si vous avez
+un pilote de périphérique contrôlant deux "serial boards", vous
+aurez deux structures isa_device. Si vous construisez un périphérique
+comme un LKM, vous devrez créer votre propre structure isa_device afin
+de refléter votre configuration (lignes 85 - 131 de pcaudio_lkm.c).
+Il y a un équivalence directe ebtre le fichier de configuration et la
+structureisa_device. La définition de
+/usr/src/sys/i386/isa/isa_device.h
+est :
+
+
+
+struct isa_device {
+ int id_id; /* device id */
+ struct isa_driver *id_driver;
+ int id_iobase; /* base i/o address */
+ u_short id_irq; /* interrupt request */
+ short id_drq; /* DMA request */
+ caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
+ int id_msize; /* size of i/o memory */
+ inthand2_t *id_intr; /* interrupt interface routine */
+ int id_unit; /* unit number */
+ int id_flags; /* flags */
+ int id_scsiid; /* scsi id if needed */
+ int id_alive; /* device is present */
+#define RI_FAST 1 /* fast interrupt handler */
+ u_int id_ri_flags; /* flags for register_intr() */
+ int id_reconfig; /* hot eject device support (such as PCMCIA) */
+ int id_enabled; /* is device enabled */
+ int id_conflicts; /* we're allowed to conflict with things */
+ struct isa_device *id_next; /* used in isa_devlist in userconfig() */
+};
+
+
+
+
+Structure struct isa_driver
+
+Cette structure est définie dans
+/usr/src/sys/i386/isa/isa_device.h,
+est est requise pour chaque pilote de périphérique. La définition
+est :
+
+
+
+struct isa_driver {
+ int (*probe) __P((struct isa_device *idp));
+ /* test whether device is present */
+ int (*attach) __P((struct isa_device *idp));
+ /* setup driver for a device */
+ char *name; /* device name */
+ int sensitive_hw; /* true if other probes confuse us */
+};
+
+
+
+C'est la structure employée par le code sondage/attachement
+(probe/attach) pour
+détecter et initialiser votre périphérique. Le membre probe
+est un pointeur à votre fonction permettant de sonder les périphériques.
+Le membre attach est un pointeur vers votre fonction d'attache.
+Le membre name est un pointeur de caractère sur le nom de deux
+ou trois lettres de votre pilote.
+C'est le nom enregistré pendant le processus de
+sondage/attachement (et probablement aussi dans
+lsdev).
+Le membre sensitive_hw est un
+indicateur qui aide le code de sondage à déterminer l'ordre du sondage.
+
+
+
+Un instantiation typique est:
+
+
+
+struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" };
+
+
+
+
+
+Points d'entrée
+
+
+probe()
+probe() prend un pointeur sur une structure isa_device
+comme argument et renvoie un int. La valeur de retour est ``zéro'' ou
+``non-zéro '' quant à l'absence ou à la présence de votre périphérique.
+Ce point d'entrée peut être déclaré comme
+static parce qu'il
+est accessible par l'intermédiaire du membre
+probe de la structre
+isa_driver. Cette fonction est destinée à
+détecter la présence de votre périphérique seulement et ne devrait
+faire aucune configuration du périphérique elle-même.
+
+
+
+
+attach()
+
+attach() prend également un pointeur sur une structure
+isa_device comme argument et
+renvoie un int. La valeur de retour est également ``zéro'' ou
+``non-zéro'' indiquant si l'attache a réussie. Cette fonction
+est destinée pour faire n'importe quelle initialisation spéciale du
+périphérique aussi bien que pour confirmer que le périphérique est utilisable.
+Il devrait aussi être déclaré static parce qu'il est accesible
+par le membre attach de la structure isa_driver .
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+EISA -- Architecture Étendue de Standard industriel (Extended Industry Standard Architecture)
+
+
+
+Structures de données
+
+Structure struct eisa_dev
+Structure struct isa_driver
+
+
+
+Points d'entrée
+
+
+probe()
+Décrit dans la section de périphérique ISA.
+
+
+
+attach()
+Décrit dans la section de périphérique ISA.
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+PCI -- Bus d'interconnexion Périphérique (Peripheral Computer
+Interconnect)
+
+
+Structures de données
+
+ Structure struct pci_device
+
+
+
+
+nom : Le nom abrégé du périphérique.
+
+
+
+
+ sonde: Contrôle si le pilote peut supporter un périphérique avec
+ce type. L'étiquette peut être employée pour obtenir plus
+d'information avec pci_read_conf(). Voir ci-dessous. Elle renvoie
+une chaîne de caractères avec le nom du périphérique, ou un pointeur
+NULL si le pilote ne peut pas supporter ce périphérique.
+
+
+
+
+ attache: Assigne une structure de contrôle et la prépare. Cette
+fonction peut utiliser les fonctions de mapping PCI. Voir
+ci-dessous. (identification de configuration) ou type.
+
+
+
+
+ compte: Un pointeur sur un compteur d'unité. Il est
+employé par le configurateur de PCI pour assigner des numéros.
+
+
+
+
+
+
+
+Points d'entrée
+
+
+probe()
+
+
+
+
+attach()
+
+
+
+
+shutdown()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+SCSI -- Small Computer Systems Interface
+
+
+Structure de données
+
+Structure struct scsi_adapter
+Structure struct scsi_device
+Structure struct scsi_ctlr_config
+Structure struct scsi_device_config
+Structure struct scsi_link
+
+
+
+Points d'entrée
+
+
+attach()
+
+
+
+
+init()
+
+
+
+
+
+Fichiers d'en-tête
+
+
+
+
+
+
+PCCARD (PCMCIA)
+
+
+Structure de données
+
+Structure struct slot_cont
+Structure struct pccard_drv
+Structure struct pccard_dev
+Structure struct slot
+
+
+
+Points d'entrée
+
+
+handler()
+
+
+
+
+unload()
+
+
+
+
+suspend()
+
+
+
+
+init()
+
+
+
+
+
+Fichiers d'en-tête
+
+<pccard/slot.h>
+
+
+
+
+
+
+
+Incorporation dans le noyau
+
+Dans FreeBSD, le support des bus d'ISA et EISA est spécifique à
+i386. Tandis que FreeBSD lui-même est actuellement
+disponible sur la plateforme i386, un certain effort a été fait pour
+faire du code portable pour PCI, PCCARD, et SCSI. Le code
+spécifique à ISA et EISA réside dans
+/usr/src/sys/i386/isa et
+/usr/src/sys/i386/eisa respectivement. Le code indépendant de la
+machine de PCI, de PCCARD, et de SCSI réside dans
+/usr/src/sys/{pci,pccard,scsi}. Le code spécifique i386 quand à lui
+réside dans /usr/src/sys/i386/{pci, pccard, scsi}.
+
+
+
+ Dans FreeBSD, un module de gestion de périphérique peut
+être soit sous forme binaire soit sous forme de sources.
+Il n'y a aucun endroit ``officiel'' pour mettre les binaires des
+pilotes de périphériques. les systèmes BSD utilise quelque
+chose comme sys/i386/OBJ. Puisque la plupart des pilotes sont
+distribués dans les sources, la discussion suivante se rapporte à un
+source pilote de périphérique.
+Des binaires de pilotes de périphériques sont
+parfois fournis par les constructeurs de matériel qui souhaitent
+maintenir les sources de manière propriétaire.
+
+
+ Un pilote typique a son code source sous forme de fichier C,
+comme dev.c. Le pilote peut également inclure des
+fichiers; devreg.h contient typiquement des déclarations publiques
+de registre de périphérique, des macros, et d'autres
+déclarations spécifique au pilote de périphérique.
+Quelques pilotes appellent parfois ce fichier devvar.h.
+Quelques pilotes, tels que
+le dgb (pour le Digiboard PC/Xe), exigent que du microcode soit chargé
+sur la carte. Pour le pilote de dgb le microcode est compilé
+et reporté dans un fichier d'en-tête par
+file2c.
+
+
+ Si le pilote de périphérique a des structures de données et des
+ioctl qui sont spécifiques au pilote de périphérique ou
+périphérique, et
+doivent être accessibles de l'espace-utilisateur, elles devraient
+être mises dans un fichier d'en-tête séparé qui résidera dans
+/usr/include/machine/ (certaines de ces derniers résident dans
+/usr/include/sys/). Ceux-ci est typiquement nommé quelque chose comme
+ioctl_dev.h ou devio.h.
+
+
+ Si un pilote écrit depuis l'espace
+d'utilisateur est identique à un périphérique qui existe déjà, il faut
+prendre garde à utiliser les mêmes
+interfaces ioctl et structures de données. Par exemple, de l'espace
+utilisateur, un lecteur de SCSI CDROM devrait être identique à un
+lecteur de cdrom IDE; ou une ligne série sur une carte
+intelligente multiport (Digiboard, Cyclades...) devrait être identique
+à un périphérique sio. Ces périphériques ont une interface définie
+relativement bonne et devraient être utilisées.
+
+
+ Il y a deux méthodes pour lier un pilote dans le
+noyau, statiquement et le modèle LKM. La première méthode
+est assez standard à travers la famille *BSD. L'autre
+méthode a été initialement développée par Sun (je crois), et a
+été mis en application dans BSD en utilisant le modèle de Sun.
+Je ne crois pas que l'implémentation actuelle utilise encore le moindre
+code de Sun.
+
+
+
+Modèle Standard
+
+ Les étapes exigées pour ajouter votre pilote au
+noyau standard de FreeBSD sont
+
+
+
+
+Ajout à la liste des pilotes de périphérique
+
+
+
+
+Ajout d'une entrée au [bc]devsw
+
+
+
+
+Ajout d'une entrée du pilote de périphérique au fichier de
+configuration du noyau
+
+
+
+
+config,
+compilation et installation du noyau
+
+
+
+
+créer les fichiers spéciaux requis
+
+
+
+
+redémarrage
+
+
+
+
+
+Ajout à la liste des pilotes de périphérique
+
+Le modèle standard pour ajouter un module de gestion de périphérique
+au noyau de Berkeley est d'ajouter votre pilote à la liste des
+périphériques connus. Cette liste dépend de l'architecture du CPU.
+Si le périphérique n'est pas spécifique i386
+(PCCARD, PCI, SCSI), le fichier est dans
+/usr/src/sys/conf/files.
+Si le périphérique est spécifique i386, utilisez
+/usr/src/sys/i386/conf/files.i386. Une ligne typique ressemblerait
+à :
+
+
+
+i386/isa/joy.c optional joy device-driver
+
+
+Le premier champ relatif est le chemin du module de pilote
+par rapport à /usr/src/sys.
+Pour le cas d'un pilote binaire, le chemin d'accès serait quelque
+chose comme i386/OBJ/joy.o.
+
+
+Le deuxième champ indique à
+config(8)
+que c'est un pilote facultatif. Quelques
+périphériques sont obligatoires pour que le noyau puisse être construit.
+
+
+
+Le troisième champ est le nom du périphérique.
+
+
+Le quatrième champ indique à config que c'est un
+pilote de périphérique (par opposition à juste facultatif). Ceci
+dit à config de créer des entrées pour le périphérique dans dans
+des structures de /usr/src/sys/compile/KERNEL/ioconf.c.
+
+
+Il est également possible de créer un fichier
+/usr/src/sys/i386/conf/files.KERNEL dont le contenu ignorera le
+fichier par défaut files.i386, mais seulement pour le noyau ``KERNEL''.
+
+
+
+
+Faire de la place dans conf.c
+
+Maintenant vous devez éditer /usr/src/sys/i386/i386/conf.c
+pour faire une entrée pour votre pilote. Quelque part au début,
+vous devez déclarer vos points d'entrée. L'entrée pour
+le pilote du joystick est:
+
+
+#include "joy.h"
+#if NJOY > 0
+d_open_t joyopen;
+d_close_t joyclose;
+d_rdwr_t joyread;
+d_ioctl_t joyioctl;
+#else
+#define joyopen nxopen
+#define joyclose nxclose
+#define joyread nxread
+#define joyioctl nxioctl
+#endif
+
+
+
+Cela définit vos points d'entrée, ou points d'entrée nuls qui
+renverront ENXIO quand appelé (clause #else).
+
+
+
+Le fichier d'en-tête ``joy.h'' est automatiquement produit par
+config
+quand l'arborescence de construction du noyau est
+créé. Cela se réduit habituellement à une seule ligne comme :
+
+
+
+#define NJOY 1
+
+
+
+ou
+
+
+#define NJOY 0
+
+
+ ce qui définit le nombre de vos périphériques dans votre noyau.
+
+
+
+Vous devez additionnellement ajouter un slot au cdevsw[&rsqb, ou
+au bdevsw[&rsqb, selon que ce soit un périphérique caractère,
+périphérique bloc, ou les deux si c'est un périphérique bloc
+avec une interface brute. L'entrée pour le pilote du joystick
+est:
+
+
+
+/* open, close, read, write, ioctl, stop, reset, ttys, select, mmap, strat */
+struct cdevsw cdevsw[] =
+{
+ ...
+ { joyopen, joyclose, joyread, nowrite, /*51*/
+ joyioctl, nostop, nullreset, nodevtotty,/*joystick */
+ seltrue, nommap, NULL},
+ ...
+}
+
+
+
+ L'ordre est ce qui détermine le nombre majeur de votre
+périphérique. C'est pourquoi il y aura toujours une entrée
+pour votre pilote, que ce soit des points d'entrée nuls,
+ou des points d'entrée actuels. Il est probablement intéressant de
+noter que c'est
+sensiblement différent de SCO et d'autres dérivés du système V, où
+n'importe quel périphérique (dans la théorie) peut avoir n'importe
+quel nombre majeur. C'est en grande partie un avantage sur FreeBSD,
+sur la manière dont les fichiers spéciaux de périphérique sont créés.
+Nous reviendrons en détail sur ceci plus tard.
+
+
+
+
+Ajout de votre périphérique dans le fichier de configuration.
+
+ Ceci ajoute simplement une ligne décrivant votre périphérique. La
+ligne de description du joystick est :
+
+device joy0 at isa? port "IO_GAME"
+
+Ceci indique que nous avons un
+périphérique appelé ``joy0'' sur le bus ISA en utilisant
+le port E/S ``IO_GAME'' (IO_GAME est une macro définie dans
+/usr/src/sys/i386/isa/isa.h).
+
+
+
+Une entrée légèrement plus compliquée est pour le pilote ``ix'' :
+
+
+device ix0 at isa? port 0x300 net irq 10 iomem 0xd0000 iosiz 32768
+vector ixintr
+
+
+Ceci indique que nous avons un périphérique appelé
+`ix0 ' sur le bus ISA. Il utilise le port E/S 0x300. Son
+interruption sera masqué par d'autres périphériques dans la classe
+réseau. Il utilise l'interruption 10. Il utilise 32k de mémoire
+partagée à l'adresse physique 0xd0000. Il le définit également
+son pilote d'interruption comme étant ``ixintr()''
+
+
+
+
+config
+du noyau.
+
+ Maintenant avec notre fichier de configuration en main,
+nous pouvons créer un répertoire de compilation du noyau. Cela peut être
+fait en tapant :
+
+# config KERNEL
+
+
+où KERNEL est le nom de votre fichier de configuration.
+La configuration crée un arbre de compilation
+pour votre noyau dans /usr/src/sys/compile/KERNEL. Elle crée le fichier
+makefile, quelques fichiers C, et quelques fichiers H avec des
+macros définissant le nombre de chaque périphérique à inclure dans votre
+votre noyau.
+
+
+
+Maintenant vous pouvez aller dans le répertoire de compilation et
+construire votre noyau. À chaque fois que vous lancerez config, votre
+arbre de construction précédent sera retiré, à moins que vous ne lancez
+config avec un -n. Si vous avez configuré et compilé un noyau GENERIC,
+vous pouvez faire un ``make links'' afin d'éviter de compiler certains
+fichiers à chaque itération. Typiquement, je lance :
+
+# make depend links all
+
+suivi d'un ``make install'' quand le noyau me convient.
+
+
+
+
+Créer les fichiers spéciaux de périphériques
+
+ Sur FreeBSD, vous avez la responsabilité de faire vos propres fichiers
+spéciaux
+de périphérique. Le
+nombre majeur de votre périphérique est déterminé par le nombre de
+slots dans le commutateur de périphérique. Le nombre mineur est
+dépendant du pilote, naturellement. Vous pouvez
+soit exécuter mknod depuis la ligne de commande, soit liasser faire le
+travail à /dev/MAKEDEV.local, ou même
+/dev/MAKEDEV.
+Je crée parfois un script MAKEDEV.dev qui peut être soit lancé
+de manière autonome soit collé dans /dev/MAKEDEV.local.
+
+
+
+
+Redémarrage
+ C'est la partie facile. Il y a un
+certain nombre de méthodes pour faire ceci, reboot, fastboot,
+shutdown - r, couper le courant, etc. Au démarrage, vous
+devriez voir votre XXprobe() appelé, et si tout marche,
+votre attach() aussi.
+
+
+
+
+
+Module du noyau à chargement dynamique (LKM)
+
+Il n'y a vraiment aucune procédure définie pour écrire un pilote de
+LKM. Ce qui suit est ma propre conception après expérimentation
+avec l'interface de périphérique LKM et en regardant le modèle standard
+de module de gestion de périphérique, c'est une manière d'ajouter une
+interface LKM à un pilote existant sans toucher aux sources (ou binaire)
+initiaux de pilote . On recommande cependant,
+que si vous projetez de distribuer les sources de votre pilote,
+que les parties spécifiques LKM devraient faire partie du pilote
+lui-même, compilé de manière conditionnelle par la macro LKM
+(c.-à-d. #ifdef LKM).
+
+
+
+Cette section se concentrera sur la manière d'écrire la partie spécifique
+LKM du pilote. Nous supposerons que nous avons écrit un
+pilote qui atterrira dans le modèle standard de
+gestion de périphérique, que nous voudrions maintenant mettre en
+application comme étant LKM. Nous utiliserons le pilote de pcaudio
+comme pilote d'exemple, et développerons une entrée LKM. La
+source et le fichier makefile pour le LKM pcaudio , ``pcaudio_lkm.c''
+et ``Makefile'', devraient être dans placé /usr/src/lkm/pcaudio.
+Ce qui suit est le code commenté de pcaudio_lkm.c.
+
+
+
+Lignes 17 - 26
+
+
+
+Ceci inclut le fichier ``pca.h'' et fait une compilation conditionnelle
+du reste de LKM suivant que vous avez défini ou non le pilote de
+périphérique pcaudio.
+Cela imite le comportement de config. Dans un pilote de
+périphérique standard,
+config
+produit le fichier pca.h depuis le nombre de périphériques pca
+le fichier de config.
+
+
+ 17 /*
+ 18 * figure out how many devices we have..
+ 19 */
+ 20
+ 21 #include "pca.h"
+ 22
+ 23 /*
+ 24 * if we have at least one ...
+ 25 */
+ 26 #if NPCA > 0
+
+
+
+Lignes 27 - 37
+
+
+
+Les fichiers d'en-tête requis depuis divers répertoire d'inclusion.
+
+
+
+ 27 #include <sys/param.h>
+ 28 #include <sys/systm.h>
+ 29 #include <sys/exec.h>
+ 30 #include <sys/conf.h>
+ 31 #include <sys/sysent.h>
+ 32 #include <sys/lkm.h>
+ 33 #include <sys/errno.h>
+ 34 #include <i386/isa/isa_device.h>
+ 35 #include <i386/isa/isa.h>
+ 36
+ 37
+
+
+
+Lignes 38 - 51
+
+
+déclarent vos points d'entrée comme externs .
+
+
+
+ 38 /*
+ 39 * declare your entry points as externs
+ 40 */
+ 41
+ 42 extern int pcaprobe(struct isa_device *);
+ 43 extern int pcaattach(struct isa_device *);
+ 44 extern int pcaopen(dev_t, int, int, struct proc *);
+ 45 extern int pcaclose(dev_t, int, int, struct proc *);
+ 46 extern int pcawrite(dev_t, struct uio *, int);
+ 47 extern int pcaioctl(dev_t, int, caddr_t);
+ 48 extern int pcaselect(dev_t, int, struct proc *);
+ 49 extern void pcaintr(struct clockframe *);
+ 50 extern struct isa_driver pcadriver;
+ 51
+
+
+
+Lignes 52 - 70
+
+
+
+Cela crée la table d'entrée de commutateur de périphérique pour
+votre pilote. Cette table est en gros entièrement mise dans le
+système de commutation de périphériques à l'emplacement indiqué par
+votre nombre majeur. Dans le modèle standard, c'est dans
+/usr/src/sys/i386/i386/conf.c.
+NOTE: vous ne pouvez pas sélectionner
+un nombre majeur de périphérique plus grand que ce qui existe dans
+conf.c, par exemple
+il y a 67 slots pour des périphériques caractère, vous ne popuvez pas
+utiliser un périphérique (caractère) de numéro majeur 67 ou
+plus, sans avoir d'abord réservé de l'espace dans conf.c.
+
+
+
+ 52 /*
+ 53 * build your device switch entry table
+ 54 */
+ 55
+ 56 static struct cdevsw pcacdevsw = {
+ 57 (d_open_t *) pcaopen, /* open */
+ 58 (d_close_t *) pcaclose, /* close */
+ 59 (d_rdwr_t *) enodev, /* read */
+ 60 (d_rdwr_t *) pcawrite, /* write */
+ 61 (d_ioctl_t *) pcaioctl, /* ioctl */
+ 62 (d_stop_t *) enodev, /* stop?? */
+ 63 (d_reset_t *) enodev, /* reset */
+ 64 (d_ttycv_t *) enodev, /* ttys */
+ 65 (d_select_t *) pcaselect, /* select */
+ 66 (d_mmap_t *) enodev, /* mmap */
+ 67 (d_strategy_t *) enodev /* strategy */
+ 68 };
+ 69
+ 70
+
+
+
+Lignes 71 - 131
+
+
+cette section est analogue à la déclaration de fichier de configuration
+de votre périphérique. Les membres de la structure isa_device sont
+remplis grace à ce qu'il connait de votre périphérique,
+port E/S, segment partagé de mémoire, etc...
+Nous n'aurons probablement jamais un besoin de deux périphériques
+pcaudio dans le noyau, mais cet exemple montre comment
+périphériques multiples peuvent être supportés.
+
+
+
+ 71 /*
+ 72 * this lkm arbitrarily supports two
+ 73 * instantiations of the pc-audio device.
+ 74 *
+ 75 * this is for illustration purposes
+ 76 * only, it doesn't make much sense
+ 77 * to have two of these beasts...
+ 78 */
+ 79
+ 80
+ 81 /*
+ 82 * these have a direct correlation to the
+ 83 * config file entries...
+ 84 */
+ 85 struct isa_device pcadev[NPCA] = {
+ 86 {
+ 87 11, /* device id */
+ 88 &pcadriver, /* driver pointer */
+ 89 IO_TIMER1, /* base io address */
+ 90 -1, /* interrupt */
+ 91 -1, /* dma channel */
+ 92 (caddr_t)-1, /* physical io memory */
+ 93 0, /* size of io memory */
+ 94 pcaintr , /* interrupt interface */
+ 95 0, /* unit number */
+ 96 0, /* flags */
+ 97 0, /* scsi id */
+ 98 0, /* is alive */
+ 99 0, /* flags for register_intr */
+ 100 0, /* hot eject device support */
+ 101 1 /* is device enabled */
+ 102 },
+ 103 #if NPCA >1
+ 104 {
+ 105
+ 106 /*
+ 107 * these are all zeros, because it doesn't make
+ 108 * much sense to be here
+ 109 * but it may make sense for your device
+ 110 */
+ 111
+ 112 0, /* device id */
+ 113 &pcadriver, /* driver pointer */
+ 114 0, /* base io address */
+ 115 -1, /* interrupt */
+ 116 -1, /* dma channel */
+ 117 -1, /* physical io memory */
+ 118 0, /* size of io memory */
+ 119 NULL, /* interrupt interface */
+ 120 1, /* unit number */
+ 121 0, /* flags */
+ 122 0, /* scsi id */
+ 123 0, /* is alive */
+ 124 0, /* flags for register_intr */
+ 125 0, /* hot eject device support */
+ 126 1 /* is device enabled */
+ 127 },
+ 128 #endif
+ 129
+ 130 };
+ 131
+
+
+
+Lignes 132 - 139
+
+
+
+Ceci appelle la macro MOD_DEV du préprocesseur C, qui
+installe un module de gestion de périphérique de LKM, par
+opposition à un système de fichiers LKM, ou un appel système de LKM.
+
+
+
+ 132 /*
+ 133 * this macro maps to a function which
+ 134 * sets the LKM up for a driver
+ 135 * as opposed to a filesystem, system call, or misc
+ 136 * LKM.
+ 137 */
+ 138 MOD_DEV("pcaudio_mod", LM_DT_CHAR, 24, &pcacdevsw);
+ 139
+
+
+
+Lignes 140 - 168
+
+
+
+c'est la fonction qui sera appelée lorsque le pilote sera
+chargé. Cette fonction essaye de fonctionner comme
+/sys/i386/isa/isa.c qui fait les appels de probe/attach pour un
+pilote au moment du redémarrage. La plus grande astuce ici est qu'il
+met en correspondance l'adresse physique du segment partagé de mémoire, qui est
+indiqué dans la structure isa_device à une adresse virtuelle du noyau.
+Normalement, l'adresse physique est mise dans le fichier de configuration
+qui construit la structure isa_device dans
+/usr/src/sys/compile/KERNEL/ioconf.c. La séquence probe/attach de
+/usr/src/sys/isa/isa.c traduit l'adresse physique en une virtuelle de
+sorte que dans les sous-programmes de probe/attach vous puissiez
+faire des choses comme
+
+
+(int *)id->id_maddr = something;
+
+ et se réfère juste au segment partagé de mémoire
+par l'intermédiaire de pointeurs.
+
+
+
+ 140 /*
+ 141 * this function is called when the module is
+ 142 * loaded; it tries to mimic the behavior
+ 143 * of the standard probe/attach stuff from
+ 144 * isa.c
+ 145 */
+ 146 int
+ 147 pcaload(){
+ 148 int i;
+ 149 uprintf("PC Audio Driver Loaded\n");
+ 150 for (i=0; i<NPCA; i++){
+ 151 /*
+ 152 * this maps the shared memory address
+ 153 * from physical to virtual, to be
+ 154 * consistent with the way
+ 155 * /usr/src/sys/i386/isa.c handles it.
+ 156 */
+ 157 pcadev[i].id_maddr -=0xa0000;
+ 158 pcadev[i].id_maddr += atdevbase;
+ 159 if ((*pcadriver.probe)(pcadev+i)) {
+ 160 (*(pcadriver.attach))(pcadev+i);
+ 161 } else {
+ 162 uprintf("PC Audio Probe Failed\n");
+ 163 return(1);
+ 164 }
+ 165 }
+ 166 return 0;
+ 167 }
+ 168
+
+
+Lignes 169 - 179
+
+
+c'est la fonction appelée quand votre pilote n'est pas
+chargé; il affiche juste un message à cet effet.
+
+
+
+ 169 /*
+ 170 * this function is called
+ 171 * when the module is unloaded
+ 172 */
+ 173
+ 174 int
+ 175 pcaunload(){
+ 176 uprintf("PC Audio Driver Unloaded\n");
+ 177 return 0;
+ 178 }
+ 179
+
+
+Lignes 180 - 190
+
+
+c'est le point d'entrée qui est indiqué sur la ligne de commande
+de modload. Par convention il est nommé <dev>_mod. C'est
+ainsi qu'il est défini dans bsd.lkm.mk, le makefile qui
+construit le LKM. Si vous nommez votre module suivant cette
+convention, vous pouvez faire ``make load'' et ``make unload''
+de /usr/src/lkm/pcaudio.
+
+Note : Il y a eu tellement de révisions entre la version 2.0 et
+2.1. Il peut ou ne peut ne pas être possible d'écrire
+un module qui est portable pour chacune des trois versions.
+
+
+
+
+ 180 /*
+ 181 * this is the entry point specified
+ 182 * on the modload command line
+ 183 */
+ 184
+ 185 int
+ 186 pcaudio_mod(struct lkm_table *lkmtp, int cmd, int ver)
+ 187 {
+ 188 DISPATCH(lkmtp, cmd, ver, pcaload, pcaunload, nosys);
+ 189 }
+ 190
+ 191 #endif /* NICP > 0 */
+
+
+
+
+Idiosyncrasies du type périphérique
+
+
+Caractère
+
+
+
+
+Bloc
+
+
+
+
+Réseau
+
+
+
+
+Line discipline
+
+
+
+
+
+Idiosyncrasies du type bus
+
+
+ISA
+
+
+
+
+EISA
+
+
+
+
+PCI
+
+
+
+
+SCSI
+
+
+
+
+PCCARD
+
+
+
+
+
+
+
+Support du noyau
+
+
+Structures de données
+
+
+Structure struct kern_devconf
+
+Cette structure contient quelques informations sur l'état du
+périphérique et de son pilote. Elle est définie dans
+/usr/src/sys/sys/devconf.h comme ci-dessous :
+
+
+
+struct devconf {
+ char dc_name[MAXDEVNAME]; /* name */
+ char dc_descr[MAXDEVDESCR]; /* description */
+ int dc_unit; /* unit number */
+ int dc_number; /* unique id */
+ char dc_pname[MAXDEVNAME]; /* name of the parent device */
+ int dc_punit; /* unit number of the parent */
+ int dc_pnumber; /* unique id of the parent */
+ struct machdep_devconf dc_md; /* machine-dependent stuff */
+ enum dc_state dc_state; /* state of the device (see above) */
+ enum dc_class dc_class; /* type of device (see above) */
+ size_t dc_datalen; /* length of data */
+ char dc_data[1]; /* variable-length data */
+};
+
+
+
+
+Structure struct proc
+
+ Cette structure contient toutes les informations sur un processus.
+Elle est dans définie /usr/src/sys/sys/proc.h:
+
+
+
+/*
+ * Description of a process.
+ *
+ * This structure contains the information needed to manage a thread of
+ * control, known in UN*X as a process; it has references to
+substructures
+ * containing descriptions of things that the process uses, but may
+share
+ * with related processes. The process structure and the substructures
+ * are always addressable except for those marked "(PROC ONLY)" below,
+ * which might be addressable only on a processor on which the process
+ * is running.
+ */
+struct proc {
+ struct proc *p_forw; /* Doubly-linked run/sleep queue. */
+ struct proc *p_back;
+ struct proc *p_next; /* Linked list of active procs */
+ struct proc **p_prev; /* and zombies. */
+
+ /* substructures: */
+ struct pcred *p_cred; /* Process owner's identity. */
+ struct filedesc *p_fd; /* Ptr to open files structure. */
+ struct pstats *p_stats; /* Accounting/statistics (PROC ONLY). */
+ struct plimit *p_limit; /* Process limits. */
+ struct vmspace *p_vmspace; /* Address space. */
+ struct sigacts *p_sigacts; /* Signal actions, state (PROC ONLY). */
+
+#define p_ucred p_cred->pc_ucred
+#define p_rlimit p_limit->pl_rlimit
+
+ int p_flag; /* P_* flags. */
+ char p_stat; /* S* process status. */
+ char p_pad1[3];
+
+ pid_t p_pid; /* Process identifier. */
+ struct proc *p_hash; /* Hashed based on p_pid for kill+exit+... */
+ struct proc *p_pgrpnxt; /* Pointer to next process in process group. */
+ struct proc *p_pptr; /* Pointer to process structure of parent. */
+ struct proc *p_osptr; /* Pointer to older sibling processes. */
+
+/* The following fields are all zeroed upon creation in fork. */
+#define p_startzero p_ysptr
+ struct proc *p_ysptr; /* Pointer to younger siblings. */
+ struct proc *p_cptr; /* Pointer to youngest living child. */
+ pid_t p_oppid; /* Save parent pid during ptrace. XXX */
+ int p_dupfd; /* Sideways return value from fdopen. XXX */
+
+ /* scheduling */
+ u_int p_estcpu; /* Time averaged value of p_cpticks. */
+ int p_cpticks; /* Ticks of cpu time. */
+ fixpt_t p_pctcpu; /* %cpu for this process during p_swtime */
+ void *p_wchan; /* Sleep address. */
+ char *p_wmesg; /* Reason for sleep. */
+ u_int p_swtime; /* Time swapped in or out. */
+ u_int p_slptime; /* Time since last blocked. */
+
+ struct itimerval p_realtimer; /* Alarm timer. */
+ struct timeval p_rtime; /* Real time. */
+ u_quad_t p_uticks; /* Statclock hits in user mode. */
+ u_quad_t p_sticks; /* Statclock hits in system mode. */
+ u_quad_t p_iticks; /* Statclock hits processing intr. */
+
+ int p_traceflag; /* Kernel trace points. */
+ struct vnode *p_tracep; /* Trace to vnode. */
+
+ int p_siglist; /* Signals arrived but not delivered. */
+
+ struct vnode *p_textvp; /* Vnode of executable. */
+
+ char p_lock; /* Process lock (prevent swap) count. */
+ char p_pad2[3]; /* alignment */
+
+/* End area that is zeroed on creation. */
+#define p_endzero p_startcopy
+
+/* The following fields are all copied upon creation in fork. */
+#define p_startcopy p_sigmask
+
+ sigset_t p_sigmask; /* Current signal mask. */
+ sigset_t p_sigignore; /* Signals being ignored. */
+ sigset_t p_sigcatch; /* Signals being caught by user. */
+
+ u_char p_priority; /* Process priority. */
+ u_char p_usrpri; /* User-priority based on p_cpu and p_nice. */
+ char p_nice; /* Process "nice" value. */
+ char p_comm[MAXCOMLEN+1];
+
+ struct pgrp *p_pgrp; /* Pointer to process group. */
+
+ struct sysentvec *p_sysent; /* System call dispatch information. */
+
+ struct rtprio p_rtprio; /* Realtime priority. */
+/* End area that is copied on creation. */
+#define p_endcopy p_addr
+ struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */
+ struct mdproc p_md; /* Any machine-dependent fields. */
+
+ u_short p_xstat; /* Exit status for wait; also stop signal. */
+ u_short p_acflag; /* Accounting flags. */
+ struct rusage *p_ru; /* Exit information. XXX */
+};
+
+
+
+
+Structure struct buf
+La structure struct buf est employée pour s'interfacer
+avec le cache de la mémoire tampon. Elle est dans
+définie /usr/src/sys/sys/buf.h :
+
+
+
+/*
+ * The buffer header describes an I/O operation in the kernel.
+ */
+struct buf {
+ LIST_ENTRY(buf) b_hash; /* Hash chain. */
+ LIST_ENTRY(buf) b_vnbufs; /* Buffer's associated vnode. */
+ TAILQ_ENTRY(buf) b_freelist; /* Free list position if not active. */
+ struct buf *b_actf, **b_actb; /* Device driver queue when active. */
+ struct proc *b_proc; /* Associated proc; NULL if kernel. */
+ volatile long b_flags; /* B_* flags. */
+ int b_qindex; /* buffer queue index */
+ int b_error; /* Errno value. */
+ long b_bufsize; /* Allocated buffer size. */
+ long b_bcount; /* Valid bytes in buffer. */
+ long b_resid; /* Remaining I/O. */
+ dev_t b_dev; /* Device associated with buffer. */
+ struct {
+ caddr_t b_addr; /* Memory, superblocks, indirect etc. */
+ } b_un;
+ void *b_saveaddr; /* Original b_addr for physio. */
+ daddr_t b_lblkno; /* Logical block number. */
+ daddr_t b_blkno; /* Underlying physical block number. */
+ /* Function to call upon completion. */
+ void (*b_iodone) __P((struct buf *));
+ /* For nested b_iodone's. */
+ struct iodone_chain *b_iodone_chain;
+ struct vnode *b_vp; /* Device vnode. */
+ int b_pfcent; /* Center page when swapping cluster. */
+ int b_dirtyoff; /* Offset in buffer of dirty region. */
+ int b_dirtyend; /* Offset of end of dirty region. */
+ struct ucred *b_rcred; /* Read credentials reference. */
+ struct ucred *b_wcred; /* Write credentials reference. */
+ int b_validoff; /* Offset in buffer of valid region. */
+ int b_validend; /* Offset of end of valid region. */
+ daddr_t b_pblkno; /* physical block number */
+ caddr_t b_savekva; /* saved kva for transfer while bouncing */
+ void *b_driver1; /* for private use by the driver */
+ void *b_driver2; /* for private use by the driver */
+ void *b_spc;
+ struct vm_page *b_pages[(MAXPHYS + PAGE_SIZE - 1)/PAGE_SIZE];
+ int b_npages;
+};
+
+
+
+
+
+Structure struct uio
+
+Cette structure est utilisée pour déplacer des données entre le noyau et
+les espaces utilisateur par les appels système de read() et de write().
+Il est dans défini /usr/src/sys/sys/uio.h :
+
+
+
+struct uio {
+ struct iovec *uio_iov;
+ int uio_iovcnt;
+ off_t uio_offset;
+ int uio_resid;
+ enum uio_seg uio_segflg;
+ enum uio_rw uio_rw;
+ struct proc *uio_procp;
+};
+
+
+
+
+
+
+Fonctions
+plein
+
+
+
+Références.
+
+ FreeBSD Kernel Sources http://www.freebsd.org
+
+
+ NetBSD Kernel Sources http://www.netbsd.org
+
+
+ Writing Device Drivers: Tutorial and Reference;
+Tim Burke, Mark A. Parenti, Al, Wojtas;
+Digital Press, ISBN 1-55558-141-2.
+
+
+ Writing A Unix Device Driver;
+Janet I. Egan, Thomas J. Teixeira;
+John Wiley & Sons, ISBN 0-471-62859-X.
+
+
+ Writing Device Drivers for SCO Unix;
+Peter Kettle;
+
+
+
+