Énoncé du problème
Linux a une interface standard pour travailler avec GPIO via sysfs. La documentation pour cela peut être trouvée
ici .
En bref, il y a des fichiers "export" et "unxport" dans le dossier "/ sys / class / gpio". En écrivant le numéro X dans le fichier d'exportation, vous pouvez ouvrir l'interface dans l'espace utilisateur pour contrôler GPIOX
Après avoir ouvert l'interface, le dossier / sys / class / gpio / gpioX / apparaîtra dans lequel il y aura des fichiers tels que "value" ou "direction", et en écrivant "in" ou "out" dans le fichier "direction" et en écrivant 1 ou 0 dans le fichier "Value" peut contrôler la sortie GPIO directement depuis la ligne de commande.
Pour que la commande «echo X> / sys / class / gpio / export» crée le dossier «gpioX», le pilote du contrôleur GPIO doit être enregistré dans le noyau, ce qui ouvre l'interface aux lignes GPIO.
Il se trouve que je travaille sur le portage de coreboot pour une carte personnalisée basée sur le processeur Intel Haswell i7 [Pour ceux qui ne le savent pas, coreboot est un projet open source de BIOS open source (
https://www.coreboot.org/ ) ]. Le pont sud LynxpointLP dans lequel il y a 94 lignes GPIO est intégré à mon processeur. Et je voulais les ouvrir dans sysfs ...
Résolution de problèmes (communication des pilotes et des périphériques sous Linux)
Après une courte recherche sur le code du noyau, j'ai constaté que ce pilote a déjà été écrit, se trouve dans le fichier "drivers \ gpio \ gpio-lynxpoint.c" et est activé à l'aide de Kconfig
config GPIO_LYNXPOINT tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 select GPIOLIB_IRQCHIP help driver for GPIO functionality on Intel Lynxpoint PCH chipset Requires ACPI device enumeration code to set up a platform device.
L'option GPIO_LYNXPOINT a été activée dans le noyau avec lequel je travaillais, cependant, il n'y avait pas un seul dossier «gpiochipN» pour le contrôleur GPIO dans le dossier «/ sys / class / gpio /» (qui devrait l'être), et même un tel script n'a pas conduit à l'exportation de tout lignes.
$ for i in {0..255}; do echo $i > /sys/class/gpio/export; done
En regardant le code coreboot ou en consultant la documentation de ce pont sud, vous pouvez voir que le contrôleur GPIO n'est pas un périphérique PCI distinct. Il fait partie d'un autre périphérique PCI: le pont d'interface LPC. À l'aide des registres d'espace de configuration PCI de ce périphérique, vous devez activer le contrôleur GPIO et lui affecter BASE_ADDRESS dans l'espace d'E / S. Cela ouvrira une fenêtre dans l'espace d'E / S 1KV. En écrivant / lisant des octets dans cette fenêtre, vous pouvez contrôler les lignes GPIO.
Ce que nous pouvons voir dans le code coreboot:
southbridge \ intel \ lynxpoint \ pch.h:
#define DEFAULT_GPIOBASE 0x1400 #define DEFAULT_GPIOSIZE 0x400 ... #define GPIO_BASE 0x48 #define GPIO_CNTL 0x4C ... #define PCH_LPC_DEV PCI_DEV(0, 0x1f, 0)
southbridge \ intel \ lynxpoint \ early_pch.c:
pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE|1); pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10);
Si nous regardons les registres de périphériques LPC sous Linux via «lspci -xxx», nous verrons que les données enregistrées par nous se trouvent dans ces registres. Donc, tout semble être configuré comme il se doit.
En continuant à regarder le code du pilote, j'ai remarqué que le pilote Linux communique avec le périphérique via le champ .acpi_match_table. Étant donné que notre périphérique ne peut pas être énuméré (il ne se trouve ni sur le PCI ni sur le bus USB), un pilote de plate-forme est requis pour cela, et la connexion de ce pilote avec le périphérique se fait via des tables ACPI. Le cas habituel pour x86, dans le cas d'ARM, nous enregistrerions notre appareil dans DeviceTree, ou utiliserions les anciens codes durs dans le noyau.
drivers \ gpio \ gpio-lynxpoint.c:
static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { { "INT33C7", 0 }, { "INT3437", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); static struct platform_driver lp_gpio_driver = { .probe = lp_gpio_probe, .remove = lp_gpio_remove, .driver = { .name = "lp_gpio", .pm = &lp_gpio_pm_ops, .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), }, };
Cela fonctionne comme ceci: si le noyau, lors de l'analyse de la table ACPI, y voit un périphérique avec l'identifiant _HID "INT33C7", il essaiera de trouver le pilote de plate-forme correspondant avec les identifiants correspondants dans les champs de la structure ".driver-> acpi_match_table".
Lorsqu'une correspondance est trouvée, Linux exécute la fonction de pilote .probe.
Il s'est avéré que le code ACPI de cet appareil a été présenté dans coreboot, je viens de le commenter. Commenté en raison du fait que pour ce périphérique, Windows n'a pas pu trouver le pilote et affiché «périphérique inconnu» dans le gestionnaire de périphériques. Plus d'informations ci-dessous.
Nous sommes donc intéressés par les informations du fichier
src \ southbridge \ intel \ lynxpoint \ acpi \ serialio.asl (le code est un peu simplifié):
Scope (\_SB) { Device (PCI0) { ... Device (GPIO) {
Pour comprendre ce code en détail, vous devez vous familiariser avec la syntaxe ASL dans
la spécification ACPI .
Mais en bref, ce code crée un appareil avec l'identifiant "INT33C7" qui dispose de 2 ressources:
I/O memory: 1400-17ff; IRQ: 14;
Dans sa fonction Linux .probe, le pilote reçoit les ressources de périphérique ci-dessus comme suit:
io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
Sur la base de ces données, le code du pilote remplira la structure gpio_chip et enregistrera le contrôleur gpio dans le système, ce qui le rendra accessible via l'interface sysfs.
Après avoir renvoyé le code ASL de l'appareil et recompilé l'image du BIOS, le système a réussi à accéder au GPIO via sysfs.
Pour commencer, le dossier «gpiochip162» est apparu dans / sys / class / gpio. Ce dossier contient les fichiers "base" et "ngpio". Le fichier de base est responsable du numéro du premier GPIO de ce contrôleur, ngpio pour leur numéro.
$ cat /sys/class/gpio/gpiochip162/base 162 $ cat /sys/class/gpio/gpiochip162/ngpio 94
Ainsi, tout a été exporté comme il se doit. Nous exécutons le script:
$ for i in {162..255}; do echo $i > /sys/class/gpio/export; done
Après cela, les sous-dossiers gpioN apparaîtront dans le dossier / sys / class / gpio /, dans lequel il y aura des fichiers pour contrôler l'état de la ligne.
Quelques commentaires:
- Le dossier / sys / class / gpio162 / est responsable de la gestion de GPIO0, le dossier / sys / class / gpio163 / est responsable de GPIO1 Ce décalage est dû au fait que le pilote lors de l'initialisation de la structure de contrôle "struct gpio_chip" a attribué "gc-> base = -1;". Autrement dit, j'ai quitté le noyau pour choisir les numéros moi-même. Ce n'est généralement pas critique, mais il convient de s'en souvenir.
- L'accès n'est accordé qu'aux lignes GPIO configurées en tant que GPIO et non en tant que fonctionnalités natives de Southbridge. Pour ces lignes, le pilote affiche les informations dans dmesg: "gpio% d réservé à ACPI". Dans le cas de coreboot, le GPIO est configuré dans le fichier «gpio.h» du dossier avec la carte mère.
- Le périphérique et le pilote peuvent également être mappés à l'aide de la méthode _CID (Compatible ID), et la documentation de notre rubrique dans le noyau est présentée dans le document «Énumération des périphériques basés sur ACPI»
Il est à noter que le périphérique INT33C7 n'a pas 2 cartes mères propriétaires sur le même chipset dans les tables ACPI (d'IBASE et DFI). Certes, il n'y a probablement pas de sortie de lignes GPIO (je n'ai pas regardé la documentation à ce moment en détail).
Identifiant "INT33C7"
Après avoir augmenté la fonctionnalité sysfs, j'avais une question, d'où venait le numéro d'identification «INT33C7»?
Après avoir examiné la documentation de la méthode _HID, il est devenu clair qu'il valait la peine de consulter
http://www.uefi.org/PNP_ACPI_Registry_HID (ID matériel)_HID (ID matériel)Cet objet est utilisé pour fournir à OSPM l'ID PNP ou l'ID ACPI de l'appareil *
Lors de la description d'une plate-forme, l'utilisation de tout objet _HID est facultative. Cependant, un objet _HID doit être
utilisé pour décrire tout périphérique qui sera énuméré par OSPM. OSPM énumère uniquement un périphérique
quand aucun énumérateur de bus ne peut détecter l'ID de périphérique. Par exemple, les périphériques sur un bus ISA sont
énumérés par OSPM. Utilisez l'objet _ADR pour décrire les périphériques énumérés par les énumérateurs de bus
autre que OSPM.
Arguments:Aucun
Valeur de retour:Un entier ou une chaîne contenant le HID
Un objet _HID est évalué comme un ID de type EISA compressé numérique 32 bits ou une chaîne. Si un
chaîne, le format doit être un PNP alphanumérique ou un ID ACPI sans astérisque ni autre
caractères.
Un ID PNP valide doit être de la forme "AAA ####" où A est une lettre majuscule et # est un hex
chiffre. Un ID ACPI valide doit être au format "NNNN ####" où N est une lettre majuscule ou un
chiffre ('0' - '9') et # est un chiffre hexadécimal. Cette spécification réserve la chaîne "ACPI" pour une utilisation uniquement
avec liste des appareils définis. Il réserve en outre toutes les chaînes représentant 4 chiffres HEX pour
utilisation exclusive avec les ID de fournisseur attribués par PCI.
* -PNP ID and ACPI ID Registry est à
http://www.uefi.org/PNP_ACPI_Registry Il y a 3 points sur ce lien:
- tous les types d'identifiants à 3 lettres (PNP ID) sont indiqués ici
- Les ID PNP commençant par «PNP» réservés par Microsoft sont indiqués ici.
- toutes sortes d'identifiants à 4 lettres (ACPI ID) sont indiqués ici
On ne sait pas très bien pourquoi, mais à partir de la liste des identifiants PNP, vous pouvez trouver que les identifiants «INT» sont réservés sur INTERPHASE CORPORATION:
INTERPHASE CORPORATION INT 11/29/1996
Apparemment, une seule liste d'identifiants complets des appareils (partie lettre + numérique) n'est pas publiée. Mais avec l'aide de Google, il était possible de trouver des listes d'appareils et leur _HID par exemple
ici ou
ici .
Ils indiquent:
INT33C7=Intel Serial I/O GPIO Host Controller
Et à en juger par le reste des lignes de cette liste, tous les périphériques INTxxxx sont des périphériques Intel (maintenant cela semble assez évident, mais la connexion avec INTERPHASE CORPORATION n'est toujours pas claire; il est également difficile de comprendre pourquoi la numérotation commence avec des nombres aussi grands, mais elle est visible sur Discrétion Intel).
Pilote de communication et périphérique sous Windows
Ayant satisfait ma curiosité, j'ai décidé de télécharger Windows sur ma carte. Comme prévu, le système n'a pas pu trouver de pilote pour le périphérique. Il n'y avait aucune aide des pilotes pour les cartes IBASE et DFI, ce qui est compréhensible, car dans le BIOS de ces cartes, ce périphérique n'est pas indiqué.
J'ai réussi à trouver un pilote
sur le site Web de MicrosoftCependant, ce pilote n'est présenté que pour Windows 8.1 et supérieur. Je travaille toujours avec Windows 7.
Néanmoins, j'ai essayé de télécharger l'un des pilotes et de spécifier son dossier lors de la recherche d'un pilote pour mon périphérique inconnu.
Cependant, le répartiteur n'a pas pu mapper le pilote sur le périphérique. Bien que le fichier inf contienne clairement des informations sur le périphérique INT33C7.
[Manufacturer] %INTEL%=Intel,NTamd64.6.3 [Intel.NTamd64.6.3] %iaLPSS_GPIO.DeviceDesc_LPT%=iaLPSS_GPIO_Device, ACPI\INT33C7 %iaLPSS_GPIO.DeviceDesc_WPT%=iaLPSS_GPIO_Device, ACPI\INT3437
Lors de l'analyse du fichier INF, il s'est avéré que la section [Fabricant] indiquait clairement qu'il n'était pas destiné à mon système:
Ce que signifie Intel.NTamd64.6.3 peut être compris à
partir de la description :
nt[Architecture][.[OSMajorVersion][.[OSMinorVersion] OSMajorVersion=6 => Windows 7/Windows 8.1/Windows Server 2012 R2/... OSMinorVersion=3 => Windows 8.1/Windows Server 2012 R2
Essayer de pousser le pilote Windows 7 en remplaçant Intel.NTamd64.6.3 par Intel.NTamd64.6.1, pour le dire légèrement, a échoué, car cela m'a donné un écran bleu de la mort et un système d'exploitation non amorçable, et j'ai donc dû faire une récupération.
Le pilote pour Win7 n'a été trouvé que sur un site Web incompréhensible sur Internet, puis le périphérique dans le gestionnaire de périphériques s'affiche avec un point d'exclamation.
Réalisant son impuissance, j'ai décidé de tester la fonctionnalité sur Windows 10. Il y a eu une agréable surprise.
Le logiciel Intel Chipset Device (INF Update Utility) a installé le pilote de mon contrôleur sans aucun problème.

Comme vous pouvez le voir, cet appareil dispose des ressources indiquées par nous.

En théorie, après avoir installé le pilote avec le contrôleur GPIO, il sera très probablement possible de travailler via les fonctions IOCTL (
comme dans ce document) .
Cependant, il n'y avait pas de tâche de programmation GPIO à partir de Windows, donc la recherche d'un document similaire pour mon chipset a été reportée.
Conclusion:
Cet article a examiné la connexion entre le pilote et le périphérique à l'aide de la méthode _HID ACPI. Une telle communication peut être requise sur un système x86 pour les périphériques qui ne peuvent pas être énumérés.
- Dans le cas de Linux, la communication avec le pilote se fait via .acpi_match_table
- Dans le cas de Windows, la communication avec le pilote se fait via un fichier INF