Declaración del problema.
Linux tiene una interfaz estándar para trabajar con GPIO a través de sysfs. La documentación para ello se puede encontrar
aquí .
En resumen, hay archivos "exportar" y "no exportar" en la carpeta "/ sys / class / gpio". Al escribir el número X en el archivo de exportación, puede abrir la interfaz en el espacio del usuario para controlar GPIOX
Después de abrir la interfaz, aparecerá la carpeta / sys / class / gpio / gpioX / en la que habrá archivos como "value" o "direction", y escribiendo "in" o "out" en el archivo "direction" y escribiendo 1 o 0 en el archivo El "valor" puede controlar la salida GPIO directamente desde la línea de comando.
Para que el comando "echo X> / sys / class / gpio / export" cree la carpeta "gpioX", el controlador del controlador GPIO debe estar registrado en el kernel, que abre la interfaz a las líneas GPIO.
Dio la casualidad de que estoy trabajando en portar coreboot para una placa personalizada basada en el procesador Intel Haswell i7 [Para aquellos que no lo saben, coreboot es un proyecto de código abierto de código abierto (
https://www.coreboot.org/ ) ] El puente sur LynxpointLP en el que hay 94 líneas GPIO está integrado en mi procesador. Y quería abrirlos en sysfs ...
Resolución de problemas (comunicación de controlador y dispositivo en Linux)
Después de una breve búsqueda en el código del kernel, descubrí que este controlador ya se ha escrito, se encuentra en el archivo "drivers \ gpio \ gpio-lynxpoint.c" y está habilitado con 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.
La opción GPIO_LYNXPOINT estaba habilitada en el kernel con el que estaba trabajando, sin embargo, no había una sola carpeta "gpiochipN" para el controlador GPIO en la carpeta "/ sys / class / gpio /" (que debería estar), e incluso tal script no condujo a la exportación de ninguno líneas
$ for i in {0..255}; do echo $i > /sys/class/gpio/export; done
Si observa el código de arranque básico o la documentación de este puente sur, puede ver que el controlador GPIO no es un dispositivo PCI separado. Forma parte de otro dispositivo PCI: LPC Interface Bridge. Usando los registros de espacio de configuración PCI de este dispositivo, debe habilitar el controlador GPIO y asignarle BASE_ADDRESS en el espacio de E / S. Esto abrirá una ventana en el espacio de E / S de 1KV. Al escribir / leer bytes en esta ventana, puede controlar las líneas GPIO.
Lo que podemos ver en el código 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 observamos los registros de dispositivos LPC en Linux a través de "lspci -xxx", veremos que los datos grabados por nosotros están en estos registros. Entonces todo parece estar configurado como debería.
Continuando mirando el código del controlador, noté que el controlador de Linux se comunica con el dispositivo a través del campo .acpi_match_table. Dado que nuestro dispositivo no se puede enumerar (no está ubicado ni en el PCI ni en el bus USB), se requiere un controlador de plataforma para él, y la conexión de este controlador con el dispositivo es a través de tablas ACPI. El caso habitual para x86, en el caso de ARM, registraríamos nuestro dispositivo en DeviceTree, o usaríamos los viejos códigos en el núcleo.
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), }, };
Funciona así: si el núcleo, al analizar la tabla ACPI, ve un dispositivo con el identificador _HID "INT33C7", intentará encontrar el controlador de la plataforma con identificadores coincidentes en los campos de la estructura ".driver-> acpi_match_table".
Cuando se encuentra una coincidencia, Linux ejecutará la función del controlador .probe.
Resultó que el código ACPI para este dispositivo se presentó en coreboot, solo lo comenté. Comentó debido al hecho de que para este dispositivo Windows no pudo encontrar el controlador y mostró "Dispositivo desconocido" en el administrador de dispositivos. Más sobre esto a continuación.
Entonces, estamos interesados en la información del archivo
src \ southbridge \ intel \ lynxpoint \ acpi \ serialio.asl (el código está un poco simplificado):
Scope (\_SB) { Device (PCI0) { ... Device (GPIO) {
Para comprender este código en detalle, debe familiarizarse con la sintaxis ASL en
la especificación ACPI .
Pero en resumen, este código crea un dispositivo con el identificador "INT33C7" que tiene 2 recursos:
I/O memory: 1400-17ff; IRQ: 14;
Dentro de su función .probe Linux, el controlador recibe los recursos del dispositivo anteriores de la siguiente manera:
io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
En base a estos datos, el código del controlador completará la estructura gpio_chip y registrará el controlador gpio en el sistema, lo que lo hará accesible a través de la interfaz sysfs.
Después de devolver el código ASL del dispositivo y volver a compilar la imagen del BIOS, el sistema logró acceder al GPIO a través de sysfs.
Para comenzar, la carpeta "gpiochip162" apareció en / sys / class / gpio. Esta carpeta contiene el archivo "base" y "ngpio". El archivo base es responsable del número del primer GPIO de este controlador, ngpio por su número.
$ cat /sys/class/gpio/gpiochip162/base 162 $ cat /sys/class/gpio/gpiochip162/ngpio 94
Por lo tanto, todo se exportó como debería. Ejecutamos el script:
$ for i in {162..255}; do echo $i > /sys/class/gpio/export; done
Después de eso, las subcarpetas gpioN aparecerán en la carpeta / sys / class / gpio /, dentro de la cual habrá archivos para controlar el estado de la línea.
Un par de comentarios:
- La carpeta / sys / class / gpio162 / es responsable de administrar GPIO0, la carpeta / sys / class / gpio163 / es responsable de GPIO1 Este cambio se produjo debido al hecho de que el controlador durante la inicialización de la estructura de control "struct gpio_chip" asignó "gc-> base = -1;". Es decir, dejé el núcleo para elegir los números yo mismo. Esto generalmente no es crítico, pero vale la pena recordarlo.
- El acceso se otorga solo a las líneas GPIO que están configuradas como GPIO, y no como cualquier característica nativa de Southbridge. Para tales líneas, el controlador muestra información en dmesg: "gpio% d reservado para ACPI". En el caso de coreboot, el GPIO está configurado en el archivo "gpio.h" en la carpeta con la placa base.
- El dispositivo y el controlador también se pueden asignar utilizando el método _CID (ID compatible), y la documentación de nuestro tema en el núcleo se presenta en el documento "enumeración de dispositivos basada en ACPI"
Vale la pena señalar que el dispositivo INT33C7 no tiene 2 placas base propietarias en el mismo conjunto de chips en las tablas ACPI (de IBASE y DFI). Es cierto que lo más probable es que no se generen líneas GPIO (no miré la documentación en ese momento en detalle).
Identificador "INT33C7"
Después de aumentar la funcionalidad de sysfs, tuve una pregunta, ¿de dónde vino el número de identificación "INT33C7"?
Después de mirar la documentación para el método _HID, quedó claro que vale la pena mirar
http://www.uefi.org/PNP_ACPI_Registry_HID (ID de hardware)_HID (ID de hardware)Este objeto se utiliza para proporcionar a OSPM la ID PNP o ID ACPI del dispositivo *
Al describir una plataforma, el uso de cualquier objeto _HID es opcional. Sin embargo, un objeto _HID debe ser
se usa para describir cualquier dispositivo que OSPM enumerará. OSPM solo enumera un dispositivo
cuando ningún enumerador de bus puede detectar la ID del dispositivo. Por ejemplo, los dispositivos en un bus ISA son
enumerado por OSPM. Use el objeto _ADR para describir dispositivos enumerados por enumeradores de bus
que no sea OSPM.
Argumentos:Ninguno
Valor de retorno:Un entero o cadena que contiene el HID
Un objeto _HID se evalúa como un ID de tipo EISA comprimido numérico de 32 bits o una cadena. Si un
cadena, el formato debe ser una identificación alfanumérica PNP o ACPI sin asterisco u otro
personajes
Un ID de PNP válido debe tener la forma "AAA ####" donde A es una letra mayúscula y # es un hexadecimal
dígito Un ID de ACPI válido debe tener la forma "NNNN ####" donde N es una letra mayúscula o un
dígito ('0' - '9') y # es un dígito hexadecimal. Esta especificación reserva la cadena "ACPI" para uso exclusivo
con la lista de dispositivos definidos. Además, reserva todas las cadenas que representan 4 dígitos HEX para
uso exclusivo con ID de proveedor asignados por PCI.
* -PNP ID y ACPI ID Registry están en
http://www.uefi.org/PNP_ACPI_Registry Hay 3 puntos en este enlace:
- aquí se indican todos los tipos de identificadores de 3 letras (ID de PNP)
- Las ID de PNP que comienzan con "PNP" reservadas por Microsoft se indican aquí.
- aquí se indican todos los tipos de identificadores de 4 letras (ID ACPI)
No está muy claro por qué, pero en la lista de ID de PNP puede encontrar que los identificadores "INT" están reservados en INTERPHASE CORPORATION:
INTERPHASE CORPORATION INT 11/29/1996
Aparentemente, no se publica una lista única de identificadores de dispositivo completos (parte de letra + digital). Pero con la ayuda de Google fue posible encontrar listas de dispositivos y sus _HID, por ejemplo,
aquí o
aquí .
Indican:
INT33C7=Intel Serial I/O GPIO Host Controller
Y a juzgar por el resto de las líneas de esta lista, todos los dispositivos INTxxxx son dispositivos Intel (ahora parece bastante obvio, pero la conexión con INTERPHASE CORPORATION todavía no está clara; tampoco está muy claro por qué la numeración comienza con números tan grandes, pero es visible en Discreción de Intel).
Controlador de comunicación y dispositivo en Windows
Habiendo satisfecho mi curiosidad, decidí descargar Windows en mi tablero. Como se esperaba, el sistema no pudo encontrar un controlador para el dispositivo. No hubo ayuda de los controladores para las placas IBASE y DFI, lo cual es comprensible, porque en el BIOS de estas placas este dispositivo no está indicado.
Logré encontrar un controlador
en el sitio web de MicrosoftSin embargo, allí este controlador se presenta solo para Windows 8.1 y superior. Todavía estoy trabajando con Windows 7.
Sin embargo, intenté descargar uno de los controladores y especificar su carpeta al buscar un controlador para mi dispositivo desconocido.
Sin embargo, el despachador no pudo asignar el controlador al dispositivo. Aunque el archivo inf contenía claramente información sobre el dispositivo 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
En el proceso de analizar el archivo INF, resultó que la sección [Fabricante] indicaba claramente que no estaba destinado a mi sistema:
Lo que significa Intel.NTamd64.6.3 se puede entender a
partir de la descripción :
nt[Architecture][.[OSMajorVersion][.[OSMinorVersion] OSMajorVersion=6 => Windows 7/Windows 8.1/Windows Server 2012 R2/... OSMinorVersion=3 => Windows 8.1/Windows Server 2012 R2
Tratar de impulsar el controlador de Windows 7 reemplazando Intel.NTamd64.6.3 con Intel.NTamd64.6.1, por decirlo suavemente, falló, ya que me dio una pantalla azul de la muerte y un sistema operativo no arrancable, por lo que tuve que hacer una recuperación.
El controlador para Win7 se encontró solo en un sitio web incomprensible en Internet, y luego el dispositivo en el administrador de dispositivos se muestra con un signo de exclamación.
Al darme cuenta de su impotencia, decidí probar la funcionalidad en Windows 10. Hubo una agradable sorpresa.
Intel Chipset Device Software (INF Update Utility) instaló el controlador para mi controlador sin ningún problema.

Como puede ver, este dispositivo tiene los recursos indicados por nosotros.

En teoría, después de instalar el controlador con el controlador GPIO, lo más probable es que sea posible trabajar a través de las funciones IOCTL (
como en este documento) .
Sin embargo, no hubo una tarea de programación GPIO de Windows, por lo que se pospuso la búsqueda de un documento similar para mi conjunto de chips.
Conclusión
Este artículo examinó la conexión entre el controlador y el dispositivo utilizando el método _HID ACPI. Dicha comunicación puede ser necesaria en un sistema x86 para dispositivos que no se pueden enumerar.
- En el caso de Linux, la comunicación con el controlador se realiza a través de .acpi_match_table
- En el caso de Windows, la comunicación con el controlador es a través de un archivo INF