Aktivieren des Benutzermoduszugriffs auf GPIO, I2C und SPI

Unter Windows 10 und höher haben APIs im Benutzermodus direkten Zugriff auf General Purpose Input/Output (GPIO), Inter-Integrated Circuit (I2C), Serial Peripheral Interface (SPI) und Universal Asynchronous Receiver/Transmitter (UART). Entwicklungsboards wie Raspberry Pi 2 machen eine Teilmenge dieser Verbindungen verfügbar, mit denen Sie ein Basisberechnungsmodul mit benutzerdefinierter Schaltung erweitern können, um eine bestimmte Anwendung zu adressieren. Diese Feldbusse werden in der Regel mit anderen wichtigen integrierten Funktionen gemeinsam genutzt, wobei nur eine Teilmenge von GPIO-Kontakten und -Bussen auf Kontaktleisten verfügbar gemacht wird. Um die Systemstabilität zu erhalten, müssen Sie angeben, welche Pins und Busse für die Änderung durch Anwendungen im Benutzermodus sicher sind.

In diesem Dokument wird beschrieben, wie Sie diese Konfiguration in Advanced Configuration and Power Interface (ACPI) angeben und Tools zum Überprüfen der korrekten Konfiguration bereitstellen.

Important

Die Zielgruppe für dieses Dokument ist Unified Extensible Firmware Interface (UEFI) und ACPI-Entwickler. Einige Kenntnisse mit ACPI, ACPI Source Language (ASL)-Erstellung und SpbCx/GpioClx werden angenommen.

Der Benutzermoduszugriff auf Busse auf niedriger Ebene unter Windows erfolgt über die vorhandenen Frameworks GpioClx und SpbCx. Ein neuer Treiber namens RhProxy, der auf Windows IoT Core und Windows Enterprise verfügbar ist, macht GpioClx und SpbCx Ressourcen für den Benutzermodus verfügbar. Um die APIs zu aktivieren, muss ein Geräteknoten für rhproxy in Ihren ACPI-Tabellen mit den einzelnen GPIO- und SPB-Ressourcen deklariert werden, die für den Benutzermodus verfügbar gemacht werden sollen. Dieses Dokument durchläuft die Erstellung und Überprüfung der ASL.

ASL nach Beispiel

Sehen wir uns die rhproxy-Geräteknotendeklaration auf Raspberry Pi 2 an. Erstellen Sie zunächst die ACPI-Gerätedeklaration im Bereich \_SB.

Device(RHPX)
{
    Name(_HID, "MSFT8000")
    Name(_CID, "MSFT8000")
    Name(_UID, 1)
}
  • _HID – Hardware-ID. Legen Sie diese auf eine herstellerspezifische Hardware-ID fest.
  • _CID – Kompatible ID. Muss "MSFT8000" sein.
  • _UID – Eindeutige ID. Auf 1 festgelegt.

Als Nächstes deklarieren wir die einzelnen GPIO- und SPB-Ressourcen, die für den Benutzermodus verfügbar gemacht werden sollen. Die Reihenfolge, in der Ressourcen deklariert werden, ist wichtig, da Ressourcenindizes zum Zuordnen von Eigenschaften zu Ressourcen verwendet werden. Wenn mehrere I2C- oder SPI-Busse offengelegt sind, wird der zuerst deklarierte Bus als „Standardbus“ für diesen Bustyp betrachtet und ist die Instanz, die von den GetDefaultAsync()-Methoden von Windows.Devices.I2c.I2cController und Windows.Devices.Spi.SpiController zurückgegeben wird.

SPI

Raspberry Pi verfügt über zwei offengelegte SPI-Busse. SPI0 verfügt über zwei Hardwarechip-Auswahllinien und SPI1 verfügt über eine Hardwarechipauswahllinie. Für jede Chipauswahllinie für jeden Bus ist eine SPISerialBus()-Ressourcendeklaration erforderlich. Die folgenden beiden SPISerialBus-Ressourcendeklarationen sind für die beiden Chip-Select-Leitungen von SPI0. Das DeviceSelection-Feld enthält einen eindeutigen Wert, den der Treiber als Hardwarechip-Auswahlzeilenbezeichner interpretiert. Der genaue Wert, den Sie im Feld DeviceSelection einfügen, hängt davon ab, wie Der Treiber dieses Feld der ACPI-Verbindungsbeschreibung interpretiert.

Note

Dieser Artikel enthält Verweise auf ältere Terminologie in Hardwareschnittstellenspezifikationen, die Microsoft nicht mehr in neuen Produkten und Dokumentationen verwendet werden. Sobald der Begriff aus der Software entfernt wurde, wird er auch aus diesem Artikel entfernt.

// Index 0
SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                           // MOSI - GPIO 10 - Pin 19
                           // MISO - GPIO 9  - Pin 21
                           // CE0  - GPIO 8  - Pin 24
    0,                     // Device selection (CE0)
    PolarityLow,           // Device selection polarity
    FourWireMode,          // wiremode
    0,                     // databit len: placeholder
    ControllerInitiated,   // target mode
    0,                     // connection speed: placeholder
    ClockPolarityLow,      // clock polarity: placeholder
    ClockPhaseFirst,       // clock phase: placeholder
    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
    0,                     // ResourceSourceIndex
                           // Resource usage
    )                      // Vendor Data

// Index 1
SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                           // MOSI - GPIO 10 - Pin 19
                           // MISO - GPIO 9  - Pin 21
                           // CE1  - GPIO 7  - Pin 26
    1,                     // Device selection (CE1)
    PolarityLow,           // Device selection polarity
    FourWireMode,          // wiremode
    0,                     // databit len: placeholder
    ControllerInitiated,   // target mode
    0,                     // connection speed: placeholder
    ClockPolarityLow,      // clock polarity: placeholder
    ClockPhaseFirst,       // clock phase: placeholder
    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
    0,                     // ResourceSourceIndex
                           // Resource usage
    )                      // Vendor Data

Wie weiß Software, dass diese beiden Ressourcen mit demselben Bus verknüpft werden sollen? Die Zuordnung zwischen dem Anzeigenamen des Busses und dem Ressourcenindex wird in den gerätespezifischen Daten (Device Specific Data, DSD) angegeben:

Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},

Dadurch wird ein Bus namens „SPI0“ mit zwei Chip-Select-Leitungen erstellt – Ressourcenindizes 0 und 1. Zum Deklarieren der Funktionen des SPI-Bus sind mehrere weitere Eigenschaften erforderlich.

Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },

Die MinClockInHz - und MaxClockInHz-Eigenschaften geben die minimalen und maximalen Taktgeschwindigkeiten an, die vom Controller unterstützt werden. Die API verhindert, dass Benutzer Werte außerhalb dieses Bereichs angeben. Die Taktgeschwindigkeit wird an Ihren SPB-Treiber im _SPE Feld der Verbindungsbeschreibung übergeben (ACPI-Abschnitt 6.4.3.8.2.2).

Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},

Die SupportedDataBitLengths-Eigenschaft listet die vom Controller unterstützten Datenbitlängen auf. Mehrere Werte können in einer durch Trennzeichen getrennten Liste angegeben werden. Die API verhindert, dass Benutzer Werte außerhalb dieser Liste angeben. Die Datenbitlänge wird an Ihren SPB-Treiber im feld _LEN des Verbindungsdeskriptors (ACPI Abschnitt 6.4.3.8.2.2) übergeben.

Sie können sich diese Ressourcendeklarationen als "Vorlagen" vorstellen. Einige der Felder werden beim Systemstart festgelegt, während andere zur Laufzeit dynamisch festgelegt werden. Die folgenden Felder des SPISerialBus-Deskriptors sind festgelegt:

  • Geräteauswahl
  • DeviceSelectionPolarity
  • WireMode
  • SlaveMode
  • ResourceSource

Die folgenden Felder sind Platzhalter für Werte, die vom Benutzer zur Laufzeit angegeben werden:

  • DataBitLength
  • Verbindungsgeschwindigkeit
  • Taktpolarität
  • ClockPhase

Da SPI1 nur eine einzelne Chipauswahllinie enthält, wird eine einzelne SPISerialBus() Ressource deklariert:

// Index 2
SPISerialBus(              // SCKL - GPIO 21 - Pin 40
                           // MOSI - GPIO 20 - Pin 38
                           // MISO - GPIO 19 - Pin 35
                           // CE1  - GPIO 17 - Pin 11
    1,                     // Device selection (CE1)
    PolarityLow,           // Device selection polarity
    FourWireMode,          // wiremode
    0,                     // databit len: placeholder
    ControllerInitiated,   // target mode
    0,                     // connection speed: placeholder
    ClockPolarityLow,      // clock polarity: placeholder
    ClockPhaseFirst,       // clock phase: placeholder
    "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
    0,                     // ResourceSourceIndex
                           // Resource usage
    )                      // Vendor Data

Die Deklaration des zugehörigen Anzeigenamens (erforderlich) wird in den gerätespezifischen Daten (DSD) angegeben und bezieht sich auf den Index dieser Ressourcendeklaration.

Package(2) { "bus-SPI-SPI1", Package() { 2 }},

Dadurch wird ein Bus mit dem Namen "SPI1" erstellt und dem Ressourcenindex 2 zugeordnet.

SPI-Treiberanforderungen

  • Muss SpbCx verwenden oder mit SpbCx kompatibel sein
  • Muss die MITT SPI Tests bestanden haben
  • Muss 4MHz Taktfrequenz unterstützen
  • Muss eine 8-Bit-Datenlänge unterstützen
  • Muss alle SPI-Modi unterstützen: 0, 1, 2, 3

I2C

Als Nächstes deklarieren wir die I2C-Ressourcen. Raspberry Pi macht einen einzelnen I2C-Bus auf Pins 3 und 5 verfügbar.

// Index 3
I2CSerialBus(              // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
    0xFFFF,                // SlaveAddress: placeholder
    ,                      // SlaveMode: default to ControllerInitiated
    0,                     // ConnectionSpeed: placeholder
    ,                      // Addressing Mode: placeholder
    "\\_SB.I2C1",          // ResourceSource: I2C bus controller name
    ,
    ,
    )                      // VendorData

Die Deklaration des zugehörigen Anzeigenamens (erforderlich), wird in den gerätespezifischen Daten (DSD) angegeben:

Package(2) { "bus-I2C-I2C1", Package() { 3 }},

Dadurch wird ein I2C-Bus mit dem aussagekräftigen Namen „I2C1“ deklariert, der auf Ressourcenindex 3 verweist, also auf den Index der I2CSerialBus()-Ressource, die wir oben deklariert haben.

Die folgenden Felder des I2CSerialBus()-Deskriptors sind behoben:

  • SlaveMode
  • ResourceSource

Die folgenden Felder sind Platzhalter für Werte, die vom Benutzer zur Laufzeit angegeben werden.

  • SlaveAddress
  • Verbindungsgeschwindigkeit
  • AddressingMode

I2C-Treiberanforderungen

  • Muss SpbCx verwenden oder spbCx-kompatibel sein
  • Muss die MITT I2C-Tests bestanden haben
  • Muss die 7-Bit-Adressierung unterstützen
  • Muss 100kHz Taktfrequenz unterstützen
  • Muss 400kHz Taktfrequenz unterstützen

GPIO

Als Nächstes deklarieren wir alle GPIO-Pins, die für den Benutzermodus verfügbar gemacht werden. Wir bieten die folgenden Anleitungen bei der Entscheidung, welche Pins verfügbar gemacht werden sollen:

  • Deklarieren Sie alle Kontakte auf verfügbar gemachten Kontaktleisten.
  • Deklarieren Sie Pins, die mit nützlichen Onboardingfunktionen wie Schaltflächen und LEDs verbunden sind.
  • Deklarieren Sie keine Pins, die für Systemfunktionen reserviert sind oder mit nichts verbunden sind.

Der folgende Block von ASL deklariert zwei Pins – GPIO4 und GPIO5. Die anderen Pins werden der Kürze halber hier nicht gezeigt. Anhang C enthält ein PowerShell-Beispielskript, das zum Generieren der GPIO-Ressourcen verwendet werden kann.

// Index 4 – GPIO 4
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 4 }

// Index 6 – GPIO 5
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 5 }

Die folgenden Anforderungen müssen beim Deklarieren von GPIO-Pins beachtet werden:

  • Nur speicherabgebildete GPIO-Controller werden unterstützt. GPIO-Controller, die über I2C/SPI angeschlossen sind, werden nicht unterstützt. Der Controllertreiber ist ein zugeordneter Speichercontroller, wenn er das MemoryMappedController-Flag in der CLIENT_CONTROLLER_BASIC_INFORMATION Struktur als Reaktion auf den CLIENT_QueryControllerBasicInformation Rückruf festlegt.
  • Jeder Pin erfordert sowohl eine GpioIO- als auch eine GpioInt-Ressource. Die GpioInt-Ressource muss sofort der GpioIO-Ressource folgen und muss auf dieselbe Pinnummer verweisen.
  • GPIO-Ressourcen müssen in aufsteigender Reihenfolge der Pinnummer angeordnet sein.
  • Jede GpioIO- und GpioInt-Ressource muss genau eine Pinnummer in der Pinliste enthalten.
  • Das ShareType-Feld muss bei beiden Deskriptoren auf „Shared“ gesetzt sein.
  • Das EdgeLevel-Feld des GpioInt-Deskriptors muss Edge sein.
  • Das ActiveLevel-Feld der GpioInt-Beschreibung muss ActiveBoth sein.
  • Das PinConfig-Feld
    • Muss in den GpioIO- und GpioInt-Deskriptoren identisch sein
    • Muss einer von PullUp, PullDown oder PullNone sein. Es kann nicht PullDefault sein.
    • Die Pull-Konfiguration muss mit dem Einschaltzustand des Pins übereinstimmen. Das Versetzen des Pins aus dem eingeschalteten Zustand in den angegebenen Pull-Modus darf den Zustand des Pins nicht ändern. Wenn das Datenblatt beispielsweise einen Pull-Up-Widerstand für den Kontakt festlegt, geben Sie „PinConfig“ als „PullUp“ an.

Der Firmware-, UEFI- und Treiberinitialisierungscode sollte den Einschaltzustand eines Kontakts während des Starts nicht ändern. Nur der Benutzer weiß, was an einen Pin angefügt ist und welche Zustandsübergänge daher sicher sind. Der Einschaltzustand jeder Pin muss dokumentiert sein, damit Benutzer Hardware entwerfen können, die ordnungsgemäß mit einem Pin interagieren kann. Ein Kontakt darf seinen Zustand während des Starts nicht unerwartet ändern.

Unterstützte Laufwerkmodi

Wenn Ihr GPIO-Controller integrierte Pull-Up- und Pull-Down-Widerstände zusätzlich zu einem hochohmigen Eingang und einem CMOS-Ausgang unterstützt, müssen Sie dies mit der optionalen SupportedDriveModes-Eigenschaft angeben.

Package (2) { “GPIO-SupportedDriveModes”, 0xf },

Die SupportedDriveModes-Eigenschaft gibt an, welche Laufwerkmodi vom GPIO-Controller unterstützt werden. Im obigen Beispiel werden alle folgenden Laufwerkmodi unterstützt. Die Eigenschaft ist eine Bitmaske der folgenden Werte:

Flag-Wert Fahrmodus Description
0x1 Hohe Eingangsimpedanz Der Pin unterstützt die Eingabe mit hoher Impedanz, die dem Wert "PullNone" in ACPI entspricht.
0x2 InputPullUp Der Pin unterstützt einen integrierten Pull-Up-Widerstand, der dem Wert "PullUp" in ACPI entspricht.
0x4 InputPullDown Der Pin unterstützt einen integrierten Pull-down-Widerstand, der dem Wert „PullDown“ in ACPI entspricht.
0x8 OutputCmos Der Kontakt unterstützt das Generieren von starken hohen und niedrigen Pegeln (im Gegensatz zu einem Open-Drain-Ausgang).

InputHighImpedance und OutputCmos werden von fast allen GPIO-Controllern unterstützt. Wenn die SupportedDriveModes-Eigenschaft nicht angegeben ist, ist dies der Standardwert.

Wenn ein GPIO-Signal vor dem Erreichen einer extern zugänglichen Stiftleiste einen Pegelwandler durchläuft, geben Sie die vom SoC unterstützten Ansteuerungsmodi an, auch wenn der Ansteuerungsmodus an der extern zugänglichen Stiftleiste nicht erkennbar wäre. Wenn ein Kontakt beispielsweise über einen bidirektionalen Pegelwandler verbunden wird, durch den ein Kontakt als Open-Drain mit Pull-Up-Widerstand erscheint, wird niemals ein hochohmiger Zustand auf der verfügbaren Kontaktleiste auftreten, auch wenn der Kontakt als hochohmiger Eingang konfiguriert ist. Sie sollten dennoch deklarieren, dass der Pin eine Eingabe mit hoher Impedanz unterstützt.

Pinnummerierung

Windows unterstützt zwei Pinnummerierungsschemas:

  • Sequenzielle Pinnummerierung – Benutzer sehen Zahlen wie 0, 1, 2... bis zur Anzahl der verfügbar gemachten Pins. 0 ist die erste gpioIo-Ressource, die in ASL deklariert ist, 1 ist die zweite gpioIo-Ressource, die in ASL deklariert ist usw.
  • Native Pinnummerierung – Benutzer sehen die in GpioIo-Deskriptoren angegebenen Pinnummern, z. B. 4, 5, 12, 13, ...
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },

Die eigenschaft UseDescriptorPinNumbers weist Windows an, die systemeigene Pinnummerierung anstelle der sequenziellen Pinnummerierung zu verwenden. Wenn die UseDescriptorPinNumbers-Eigenschaft nicht angegeben ist oder ihr Wert 0 ist, verwendet Windows standardmäßig die sequenzielle Pinnummerierung.

Wenn systemeigene Pinnummerierung verwendet wird, müssen Sie auch die PinCount-Eigenschaft angeben.

Package (2) { “GPIO-PinCount”, 54 },

Die PinCount-Eigenschaft sollte mit dem Wert übereinstimmen, der über die TotalPins-Eigenschaft im CLIENT_QueryControllerBasicInformation Rückruf des GpioClx Treibers zurückgegeben wird.

Wählen Sie das Nummerierungsschema aus, das mit vorhandenen veröffentlichten Dokumentationen für Ihr Board am besten kompatibel ist. Beispielsweise verwendet Raspberry Pi die native Kontaktnummerierung, da in vielen vorhandenen Kontaktbelegungsplänen die BCM2835-Kontaktnummern verwendet werden. MinnowBoardMax verwendet sequenzielle Pinnummerierung, da nur wenige Pinoutdiagramme vorhanden sind, und die sequenzielle Pinnummerierung vereinfacht die Entwicklerumgebung, da nur 10 Pins aus mehr als 200 Pins verfügbar gemacht werden. Die Entscheidung, sequenzielle oder systemeigene Pinnummerierung zu verwenden, sollte darauf abzielen, Die Verwirrung der Entwickler zu verringern.

GPIO-Treiberanforderungen

  • Muss GpioClx verwenden
  • Muss auf dem SOC im Speicher abgebildet sein
  • Muss die emulierte ActiveBoth-Unterbrechungsbehandlung verwenden

UART

Wenn Ihr UART-Treiber SerCx verwendet oder SerCx2, können Sie rhproxy verwenden, um den Treiber für den Benutzermodus verfügbar zu machen. UART-Treiber, die eine Geräteschnittstelle vom Typ GUID_DEVINTERFACE_COMPORT erstellen, müssen rhproxy nicht verwenden. Der Eingangstreiber Serial.sys ist einer dieser Fälle.

Um eine UART im Stil von SerCx für den Benutzermodus verfügbar zu machen, deklarieren Sie eine UARTSerialBus-Ressource wie folgt.

// Index 2
UARTSerialBus(           // Pin 17, 19 of JP1, for SIO_UART2
    115200,                // InitialBaudRate: in bits ber second
    ,                      // BitsPerByte: default to 8 bits
    ,                      // StopBits: Defaults to one bit
    0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
    ,                      // IsBigEndian: default to LittleEndian
    ,                      // Parity: Defaults to no parity
    ,                      // FlowControl: Defaults to no flow control
    32,                    // ReceiveBufferSize
    32,                    // TransmitBufferSize
    "\\_SB.URT2",          // ResourceSource: UART bus controller name
    ,
    ,
    ,
    )

Nur das ResourceSource-Feld ist festgelegt, während alle anderen Felder Platzhalter für Werte sind, die zur Laufzeit vom Benutzer angegeben werden.

Die Deklaration des zugehörigen Anzeigenamens lautet wie folgt:

Package(2) { "bus-UART-UART2", Package() { 2 }},

Dies weist dem Controller den Anzeigenamen „UART2“ zu. Dabei handelt es sich um den Bezeichner, den Benutzer*innen verwenden, um im Benutzermodus auf den Bus zuzugreifen.

Kontakt-Multiplexing zur Laufzeit

Pin-Muxing ist die Möglichkeit, denselben physischen Pin für verschiedene Funktionen zu verwenden. Mehrere verschiedene On-Chip-Peripheriegeräte, z. B. ein I2C-Controller, SPI-Controller und GPIO-Controller, können an den gleichen physischen Pin auf einem SOC weitergeleitet werden. Der Mux-Block steuert, welche Funktion jederzeit auf dem Pin aktiv ist. Die Firmware ist traditionell für die Einrichtung von Funktionszuweisungen beim Start verantwortlich, und diese Zuordnung bleibt über die Startsitzung statisch. Das Kontakt-Multiplexing zur Laufzeit bietet die Möglichkeit, Funktionszuweisungen für Kontakte zur Laufzeit neu zu konfigurieren. Wenn Benutzer die Funktion eines Pins zur Laufzeit auswählen können, beschleunigt die Entwicklung, indem Benutzer schnell die Pins eines Boards neu konfigurieren können, und die Hardware ermöglicht, eine breitere Palette von Anwendungen zu unterstützen, als eine statische Konfiguration.

Benutzer nutzen Muxing-Unterstützung für GPIO, I2C, SPI und UART, ohne zusätzlichen Code zu schreiben. Wenn ein Benutzer eine GPIO oder einen Bus mit OpenPin() oder FromIdAsync()öffnet, werden die zugrunde liegenden physischen Pins automatisch an die angeforderte Funktion muxiert. Wenn die Pins bereits von einer anderen Funktion verwendet werden, schlägt der Aufruf von OpenPin() oder FromIdAsync() fehl. Wenn der Benutzer das Gerät schließt, indem das GpioPin-, I2cDevice-, SpiDevice- oder SerialDevice-Objekt entfernt wird, werden die Pins freigegeben, sodass sie später für eine andere Funktion geöffnet werden können.

Windows enthält integrierte Unterstützung für Pin-Muxing in der GpioClx, SpbCx und SerCx Frameworks. Diese Frameworks arbeiten zusammen, um automatisch einen Pin zur richtigen Funktion zu wechseln, wenn auf einen GPIO-Pin oder -Bus zugegriffen wird. Der Zugriff auf die Pins wird koordiniert, um Konflikte bei mehreren Clients zu verhindern. Zusätzlich zu dieser integrierten Unterstützung sind die Schnittstellen und Protokolle für Pin-Muxing allgemeiner Zweck und können erweitert werden, um zusätzliche Geräte und Szenarien zu unterstützen.

In diesem Dokument werden zunächst die zugrunde liegenden Schnittstellen und Protokolle beschrieben, die an Pin-Muxing beteiligt sind, und anschließend wird beschrieben, wie Sie Unterstützung für Pin-Muxing zu GpioClx-, SpbCx- und SerCx-Controllertreibern hinzufügen.

Kontakt-Multiplexing-Architektur

In diesem Abschnitt werden die zugrunde liegenden Schnittstellen und Protokolle beschrieben, die an Pin-Muxing beteiligt sind. Kenntnisse der zugrunde liegenden Protokolle sind nicht unbedingt erforderlich, um Pin-Muxing mit GpioClx/SpbCx/SerCx-Treibern zu unterstützen. Einzelheiten dazu, wie die Unterstützung für Pin-Muxing mit GpioCls-/SpbCx-/SerCx-Treibern implementiert wird, finden Sie unter Implementieren der Unterstützung für Pin-Muxing in GpioClx-Clienttreibern und Verwenden der Muxing-Unterstützung in SpbCx- und SerCx-Controllertreibern.

Pin-Multiplexing erfolgt durch das Zusammenspiel mehrerer Komponenten.

  • Pin-Muxing-Server – dies sind Treiber, die den Pin-Muxing-Kontrollblock steuern. Pin-Muxing-Server empfangen Pin-Muxing-Anforderungen von Clients über Anforderungen zum Reservieren von Muxing-Ressourcen (über IRP_MJ_CREATE) und Anforderungen zum Wechseln der Funktion eines Pins (über *IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS-Anforderungen). Der Pin-Muxing-Server ist in der Regel der GPIO-Treiber, da der Muxing-Block manchmal Teil des GPIO-Blocks ist. Selbst wenn der Muxing-Block ein separates Peripheriegerät ist, ist der GPIO-Treiber ein logischer Ort, um Muxing-Funktionen zu platzieren.
  • Pin-Multiplexing-Clients – dies sind Treiber, die Pin-Multiplexing nutzen. Pin-Muxing-Clients erhalten Pin-Muxing-Ressourcen von ACPI-Firmware. Kontakt-Multiplexing-Ressourcen sind eine Art von Verbindungsressourcen und werden vom Ressourcenhub verwaltet. Kontakt-Multiplexing-Clients reservieren Kontakt-Multiplexing-Ressourcen, indem sie ein Handle für die Ressource öffnen. Um eine Hardwareänderung vorzunehmen, müssen Clients die Konfiguration festschreiben, indem sie eine IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS-Anforderung senden. Clients geben Kontakt-Multiplexing-Ressourcen frei, indem sie das Handle schließen, wodurch die Multiplexing-Konfiguration auf ihren Standardzustand zurückgesetzt wird.
  • ACPI-Firmware – gibt muxing-Konfiguration mit MsftFunctionConfig() Ressourcen an. MsftFunctionConfig-Ressourcen geben an, welche Pins in welcher Mux-Konfiguration von einem Client benötigt werden. MsftFunctionConfig-Ressourcen enthalten Funktionsnummer, Pullkonfiguration und Liste der Pinnummern. MsftFunctionConfig-Ressourcen werden an Pin-Muxing-Clients als Hardwareressourcen bereitgestellt, die von Treibern in ihrem PrepareHardware-Rückruf ähnlich wie GPIO- und SPB-Verbindungsressourcen empfangen werden. Clients empfangen eine Ressourcenhub-ID, die zum Öffnen eines Handles für die Ressource verwendet werden kann.

Sie müssen den Befehlszeilenschalter /MsftInternal an asl.exe übergeben, um ASL-Dateien zu kompilieren, die MsftFunctionConfig()-Deskriptoren enthalten, da diese Deskriptoren derzeit noch vom ACPI-Arbeitsausschuss geprüft werden. Beispiel: asl.exe /MsftInternal dsdt.asl

Die Sequenz der Vorgänge, die an pin-Muxing beteiligt sind, ist unten dargestellt.

Pin-Muxing-Interaktion zwischen Client und Server

  1. Der Client empfängt MsftFunctionConfig-Ressourcen von der ACPI-Firmware in seinem EvtDevicePrepareHardware()- Rückruf.
  2. Der Client verwendet die Hilfsfunktion RESOURCE_HUB_CREATE_PATH_FROM_ID() des Ressourcenhubs, um einen Pfad aus der Ressourcen-ID zu erstellen, und öffnet dann ein Handle zum Pfad (mithilfe von ZwCreateFile(), IoGetDeviceObjectPointer(), oder WdfIoTargetOpen()).
  3. Der Server extrahiert die Ressourcenhub-ID aus dem Dateipfad mithilfe von Ressourcenhub-Hilfsfunktionen RESOURCE_HUB_ID_FROM_FILE_NAME()und fragt dann den Ressourcenhub ab, um den Ressourcendeskriptor abzurufen.
  4. Der Server führt die Freigabevermittlung für jeden Kontakt im Deskriptor aus und schließt die IRP_MJ_CREATE-Anforderung ab.
  5. Der Client gibt eine IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS Anforderung für das empfangene Handle aus.
  6. Als Reaktion auf IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS führt der Server den Hardware-Muxing-Vorgang durch, indem die angegebene Funktion auf jedem Pin aktiv wird.
  7. Der Client fährt mit Vorgängen fort, die von der angeforderten Pin-Muxing-Konfiguration abhängen.
  8. Wenn der Client keine gemuxten Kontakte mehr benötigt, schließt er das Handle.
  9. Als Reaktion auf das Schließen des Handles setzt der Server die Pins in ihren ursprünglichen Zustand zurück.

Protokollbeschreibung für Pin-Muxing-Clients

In diesem Abschnitt wird beschrieben, wie ein Client Pin-Muxing-Funktionen verwendet. Dies gilt nicht für SerCx- und SpbCx-Controller-Treiber, da die Frameworks dieses Protokoll stellvertretend für die Controller-Treiber implementieren.

Analysieren von Ressourcen

Ein WDF-Treiber empfängt MsftFunctionConfig() Ressourcen in seiner EvtDevicePrepareHardware()- Routine. MsftFunctionConfig-Ressourcen können durch die folgenden Felder identifiziert werden:

CM_PARTIAL_RESOURCE_DESCRIPTOR::Type = CmResourceTypeConnection
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Class = CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Type = CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG

Eine EvtDevicePrepareHardware() Routine kann MsftFunctionConfig-Ressourcen wie folgt extrahieren:

EVT_WDF_DEVICE_PREPARE_HARDWARE evtDevicePrepareHardware;

_Use_decl_annotations_
NTSTATUS
evtDevicePrepareHardware (
    WDFDEVICE WdfDevice,
    WDFCMRESLIST ResourcesTranslated
    )
{
    PAGED_CODE();

    LARGE_INTEGER connectionId;
    ULONG functionConfigCount = 0;

    const ULONG resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
    for (ULONG index = 0; index < resourceCount; ++index) {
        const CM_PARTIAL_RESOURCE_DESCRIPTOR* resDescPtr =
            WdfCmResourceListGetDescriptor(ResourcesTranslated, index);

        switch (resDescPtr->Type) {
        case CmResourceTypeConnection:
            switch (resDescPtr->u.Connection.Class) {
            case CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG:
                switch (resDescPtr->u.Connection.Type) {
                case CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG:
                    switch (functionConfigCount) {
                    case 0:
                        // save the connection ID
                        connectionId.LowPart = resDescPtr->u.Connection.IdLowPart;
                        connectionId.HighPart = resDescPtr->u.Connection.IdHighPart;
                        break;
                    } // switch (functionConfigCount)
                    ++functionConfigCount;
                    break; // CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG

                } // switch (resDescPtr->u.Connection.Type)
                break; // CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
            } // switch (resDescPtr->u.Connection.Class)
            break;
        } // switch
    } // for (resource list)

    if (functionConfigCount < 1) {
        return STATUS_INVALID_DEVICE_CONFIGURATION;
    }
    // TODO: save connectionId in the device context for later use

    return STATUS_SUCCESS;
}

Reservierung und Zuweisung von Ressourcen

Wenn ein Client Kontakte muxen möchte, reserviert er die MsftFunctionConfig-Ressource und führt ein Commit für sie aus. Das folgende Beispiel zeigt, wie ein Client MsftFunctionConfig-Ressourcen reservieren und übernehmen kann.

_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS AcquireFunctionConfigResource (
    WDFDEVICE WdfDevice,
    LARGE_INTEGER ConnectionId,
    _Out_ WDFIOTARGET* ResourceHandlePtr
    )
{
    PAGED_CODE();

    //
    // Form the resource path from the connection ID
    //
    DECLARE_UNICODE_STRING_SIZE(resourcePath, RESOURCE_HUB_PATH_CHARS);
    NTSTATUS status = RESOURCE_HUB_CREATE_PATH_FROM_ID(
            &resourcePath,
            ConnectionId.LowPart,
            ConnectionId.HighPart);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Create a WDFIOTARGET
    //
    WDFIOTARGET resourceHandle;
    status = WdfIoTargetCreate(WdfDevice, WDF_NO_ATTRIBUTES, &resourceHandle);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Reserve the resource by opening a WDFIOTARGET to the resource
    //
    WDF_IO_TARGET_OPEN_PARAMS openParams;
    WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(
        &openParams,
        &resourcePath,
        FILE_GENERIC_READ | FILE_GENERIC_WRITE);

    status = WdfIoTargetOpen(resourceHandle, &openParams);
    if (!NT_SUCCESS(status)) {
        return status;
    }
    //
    // Commit the resource
    //
    status = WdfIoTargetSendIoctlSynchronously(
            resourceHandle,
            WDF_NO_HANDLE,      // WdfRequest
            IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS,
            nullptr,            // InputBuffer
            nullptr,            // OutputBuffer
            nullptr,            // RequestOptions
            nullptr);           // BytesReturned

    if (!NT_SUCCESS(status)) {
        WdfIoTargetClose(resourceHandle);
        return status;
    }

    //
    // Pins were successfully muxed, return the handle to the caller
    //
    *ResourceHandlePtr = resourceHandle;
    return STATUS_SUCCESS;
}

Der Treiber sollte das WDFIOTARGET in einem seiner Kontextbereiche speichern, damit er später geschlossen werden kann. Wenn der Treiber bereit ist, die Muxing-Konfiguration freizugeben, sollte er das Handle der Ressource schließen, indem er WdfObjectDelete() aufruft, oder WdfIoTargetClose(), falls das WDFIOTARGET wiederverwendet werden soll.

    WdfObjectDelete(resourceHandle);

Wenn der Client sein Ressourcenhandle schließt, werden die Kontakte wieder auf ihren Anfangszustand gemuxt und können dann von einem anderen Client abgerufen werden.

Protokollbeschreibung für Pin-Muxing-Server

In diesem Abschnitt wird beschrieben, wie ein Pin-Muxing-Server seine Funktionalität für Clients verfügbar macht. Dies gilt nicht für GpioClx Miniporttreiber, da das Framework dieses Protokoll im Auftrag von Clienttreibern implementiert. Ausführliche Informationen zur Unterstützung von Pin-Muxing in GpioClxClienttreibern finden Sie unter Implementieren der Muxing-Unterstützung in GpioClx-Clienttreibern.

Verarbeiten von IRP_MJ_CREATE-Anforderungen

Clients öffnen ein Handle für eine Ressource, wenn sie eine Kontakt-Multiplexing-Ressource reservieren wollen. Ein Kontakt-Multiplexing-Server empfängt IRP_MJ_CREATE-Anforderungen über einen REPARSE-Vorgang vom Ressourcenhub. Die nachfolgende Pfadkomponente der IRP_MJ_CREATE-Anforderung enthält die Ressourcenhub-ID, bei der es sich um eine 64-Bit-Ganzzahl im Hexadezimalformat handelt. Der Server sollte die Ressourcenhub-ID aus dem Dateinamen mithilfe RESOURCE_HUB_ID_FROM_FILE_NAME() von reshub.h extrahieren und IOCTL_RH_QUERY_CONNECTION_PROPERTIES an den Ressourcenhub senden, um den MsftFunctionConfig() Deskriptor abzurufen.

Der Server sollte den Deskriptor überprüfen und den Freigabemodus und die Pinliste aus dem Deskriptor extrahieren. Anschließend sollte er die Freigabevermittlung für die Kontakte ausführen, und sofern diese erfolgreich ist, die Kontakte als reserviert markieren, bevor er die Anforderung abschließt.

Die Freigabevermittlung ist insgesamt erfolgreich, wenn sie für jeden Kontakt in der Kontaktliste erfolgreich ausgeführt wird. Jeder Pin sollte wie folgt arbitriert werden:

  • Wenn der Kontakt noch nicht reserviert ist, ist die Freigabevermittlung erfolgreich.
  • Wenn der Kontakt bereits als „exklusiv“ reserviert ist, schlägt die Freigabevermittlung fehl.
  • Wenn der Pin bereits zur gemeinsamen Nutzung reserviert ist,
    • und die eingehende Anforderung freigegeben (Shared) ist, ist die Freigabevermittlung erfolgreich.
    • Wenn die eingehende Anforderung exklusiv ist, schlägt die Arbitrierung der gemeinsamen Nutzung fehl.

Wenn die Freigabevermittlung fehlschlägt, sollte die Anforderung mit STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE abgeschlossen werden. Wenn die Freigabevermittlung erfolgreich ist, sollte die Anforderung mit STATUS_SUCCESS abgeschlossen werden.

Beachten Sie, dass der Freigabemodus der eingehenden Anforderung vom MsftFunctionConfig-Deskriptor und nicht von IrpSp-Parameters.Create.ShareAccess> übernommen werden soll.

Verarbeiten von IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS-Anforderungen

Nachdem der Client eine MsftFunctionConfig-Ressource erfolgreich reserviert hat, indem er ein Handle öffnet, kann er IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS senden, um den Server anzufordern, den tatsächlichen Hardware-Muxing-Vorgang auszuführen. Wenn der Server IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS empfängt, sollte er für jeden Kontakt in der Kontaktliste die folgenden Schritte ausführen:

  • Legen Sie den im Element PinConfiguration der Struktur PNP_FUNCTION_CONFIG_DESCRIPTOR angegebenen Pullmodus in der Hardware fest.
  • Muxen des Kontakts auf die Funktion, die durch das FunctionNumber-Element der PNP_FUNCTION_CONFIG_DESCRIPTOR-Struktur angegeben ist

Der Server sollte dann die Anforderung mit STATUS_SUCCESS abschließen.

Die Bedeutung von FunctionNumber wird vom Server definiert, und es wird verstanden, dass der MsftFunctionConfig-Deskriptor mit Kenntnissen darüber erstellt wurde, wie der Server dieses Feld interpretiert.

Denken Sie daran, dass der Server beim Schließen des Handles die Pins auf die Konfiguration zurücksetzen muss, in der sie sich befanden, als IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS empfangen wurde. Daher muss der Server möglicherweise den Zustand der Pins speichern, bevor sie geändert werden.

Verarbeiten von IRP_MJ_CLOSE-Anforderungen

Wenn ein Client eine Multiplexing-Ressource nicht mehr benötigt, schließt er sein Handle. Wenn ein Server eine IRP_MJ_CLOSE Anforderung empfängt, sollte er die Pins in den Zustand zurücksetzen, in dem sie sich befanden, als IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS empfangen wurde. Wenn der Client nie eine IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS gesendet hat, ist keine Aktion erforderlich. Der Server sollte die Kontakte dann in Bezug auf die Freigabevermittlung als „verfügbar“ markieren und die Anforderung mit STATUS_SUCCESS abschließen. Achten Sie darauf, die Behandlung von IRP_MJ_CLOSE ordnungsgemäß mit der von IRP_MJ_CREATE zu synchronisieren.

Richtlinien für die Erstellung von ACPI-Tabellen

In diesem Abschnitt wird beschrieben, wie Muxing-Ressourcen für Clienttreiber bereitgestellt werden. Beachten Sie, dass Sie Microsoft ASL-Compilerbuild 14327 oder höher benötigen, um Tabellen zu kompilieren, die MsftFunctionConfig()-Ressourcen enthalten. MsftFunctionConfig()Ressourcen werden den Pin-Muxing-Clients als Hardware-Ressourcen bereitgestellt. MsftFunctionConfig() Ressourcen sollten Treibern zur Verfügung gestellt werden, die Änderungen am Pin-Muxing erfordern, in der Regel also SPB- und serielle Controllertreiber, nicht jedoch SPB- und serielle Peripherietreiber, da der Controllertreiber die Muxing-Konfiguration übernimmt. Das MsftFunctionConfig() ACPI-Makro ist wie folgt definiert:

  MsftFunctionConfig(Shared/Exclusive
                PinPullConfig,
                FunctionNumber,
                ResourceSource,
                ResourceSourceIndex,
                ResourceConsumer/ResourceProducer,
                VendorData) { Pin List }

  • Shared/Exclusive: Beim Wert „Exclusive“, kann der Kontakt jeweils von einem einzelnen Client abgerufen werden. Wenn sie freigegeben ist, können mehrere freigegebene Clients die Ressource erwerben. Stellen Sie dies immer auf exklusiv ein, da der Zugriff mehrerer unkoordinierter Clients auf eine änderbare Ressource zu Datenrennen und damit zu unvorhersehbaren Ergebnissen führen kann.
  • PinPullConfig – einer von
    • PullDefault – die vom SoC definierte Standard-Pull-Konfiguration beim Einschalten verwenden
    • PullUp – Pull-Up-Widerstand aktivieren
    • PullDown – Pulldown-Widerstand aktivieren
    • PullNone – alle Pullwiderstände deaktivieren
  • FunctionNumber – die Funktionsnummer, die in den Mux zu programmieren ist.
  • ResourceSource: Der ACPI-Namespacepfad des Kontakt-Multiplexing-Servers.
  • ResourceSourceIndex – Legen Sie diesen Wert auf 0 fest.
  • ResourceConsumer/ResourceProducer – auf ResourceConsumer festlegen
  • VendorData – optionale Binärdaten, deren Bedeutung vom Pin-Muxing-Server definiert wird. Dies sollte in der Regel leer bleiben.
  • Pinliste – eine durch Trennzeichen getrennte Liste von Pinnummern, auf die die Konfiguration angewendet wird. Wenn der Pin-Muxing-Server ein GpioClx-Treiber ist, sind dies GPIO-Pinnummern und haben dieselbe Bedeutung wie Pinnummern in einem GpioIo-Deskriptor.

Das folgende Beispiel zeigt, wie eine MsftFunctionConfig()-Ressource an einen I2C-Controllertreiber bereitgestellt werden kann.

Device(I2C1)
{
    Name(_HID, "BCM2841")
    Name(_CID, "BCMI2C")
    Name(_UID, 0x1)
    Method(_STA)
    {
        Return(0xf)
    }
    Method(_CRS, 0x0, NotSerialized)
    {
        Name(RBUF, ResourceTemplate()
        {
            Memory32Fixed(ReadWrite, 0x3F804000, 0x20)
            Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { 0x55 }
            MsftFunctionConfig(Exclusive, PullUp, 4, "\\_SB.GPI0", 0, ResourceConsumer, ) { 2, 3 }
        })
        Return(RBUF)
    }
}

Zusätzlich zu den Speicher- und Interruptressourcen, die ein Controllertreiber typischerweise benötigt, wird auch eine MsftFunctionConfig()-Ressource angegeben. Diese Ressource ermöglicht es dem I2C-Controllertreiber, die Kontakte 2 und 3, die vom Geräteknoten unter „\_SB.GPIO0“ verwaltet werden, auf die Funktion 4 mit aktiviertem Pull-Up-Widerstand zu schalten.

Unterstützung für Muxing in GpioClx-Clienttreibern

GpioClx verfügt über integrierte Unterstützung für Pin-Muxing. GpioClx-Miniporttreiber (auch als "GpioClx-Clienttreiber" bezeichnet) steuern die GPIO-Controllerhardware. Ab Windows 10 Build 14327 können GpioClx-Miniporttreiber Unterstützung für Pin-Muxing hinzufügen, indem zwei neue DDIs implementiert werden:

  • CLIENT_ConnectFunctionConfigPins – wird von GpioClx aufgerufen, um den Miniporttreiber anzuweisen, die angegebene Muxingkonfiguration anzuwenden.
  • CLIENT_DisconnectFunctionConfigPins: Wird von GpioClx aufgerufen, um den Miniporttreiber anzuweisen, die Multiplexing-Konfiguration zurückzusetzen.

Eine Beschreibung dieser Routinen finden Sie unter GpioClx-Ereignisrückruffunktionen .

Zusätzlich zu diesen beiden neuen DDIs sollten vorhandene DDIs auf Pin-Muxing-Kompatibilität überwacht werden:

  • CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt – CLIENT_ConnectIoPins wird von GpioClx aufgerufen, um den Miniporttreiber zu befehlen, um eine festgelegte Pins für die GPIO-Eingabe oder -Ausgabe zu konfigurieren. GPIO und MsftFunctionConfig schließen sich gegenseitig aus, d. h. ein Kontakt wird niemals gleichzeitig für GPIO und MsftFunctionConfig verbunden. Da die Standardfunktion eines Kontakts nicht GPIO sein muss, wird ein Kontakt möglicherweise nicht auf GPIO gemuxt, wenn ConnectIoPins aufgerufen wird. ConnectIoPins ist erforderlich, um alle erforderlichen Vorgänge auszuführen, um den Pin für GPIO IO vorzubereiten, einschließlich Muxing-Vorgängen. CLIENT_ConnectInterrupt sollten sich ähnlich verhalten, da Unterbrechungen als Sonderfall von GPIO-Eingaben betrachtet werden können.
  • CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt – Diese Routine sollte Pins an den Zustand zurückgeben, in dem sie sich befanden, als CLIENT_ConnectIoPins/CLIENT_ConnectInterrupt aufgerufen wurde, es sei denn, das PreserveConfiguration-Flag ist angegeben. Zusätzlich zum Wiederherstellen der Richtung von Pins in ihren Standardzustand sollte der Miniport auch den Muxingzustand der einzelnen Pins in den Zustand zurücksetzen, in dem es sich befand, als die _Connect Routine aufgerufen wurde.

Angenommen, die Standard-Muxing-Konfiguration eines Pins ist UART, und der Pin kann auch als GPIO verwendet werden. Wenn CLIENT_ConnectIoPins aufgerufen wird, um den Pin für GPIO zu verbinden, sollte er den Pin mit GPIO muxen, und in CLIENT_DisconnectIoPins sollte er den Pin zurück an UART muxen. Im Allgemeinen sollten die Disconnect-Routinen Vorgänge rückgängig machen, die von den Connect-Routinen durchgeführt werden.

Unterstützung für Multiplexing in SpbCx- und SerCx-Controllertreibern

Seit Windows 10 Build 14327 enthalten die Frameworks SpbCx und SerCx integrierte Unterstützung für Pin-Muxing, sodass SpbCx- und SerCx-Controllertreiber als Pin-Muxing-Clients fungieren können, ohne dass Codeänderungen an den Controllertreibern selbst erforderlich sind. Durch die Erweiterung löst jeder SpbCx/SerCx-Peripherietreiber, der eine Verbindung mit einem muxing-fähigen SpbCx/SerCx-Controllertreiber herstellt, Pin-Muxing-Aktivität aus.

Das folgende Diagramm zeigt die Abhängigkeiten zwischen den einzelnen Komponenten. Wie Sie sehen können, führt Pin-Muxing eine Abhängigkeit von SerCx- und SpbCx-Controllertreibern zum GPIO-Treiber ein, der in der Regel für Muxing verantwortlich ist.

Abhängigkeit des Pin-Muxing

Bei der Geräteinitialisierung werten die Frameworks SpbCx und SerCx alle MsftFunctionConfig()-Ressourcen aus, die dem Gerät als Hardwareressourcen bereitgestellt werden. SpbCx-/SerCx-Controllertreiber rufen dann bei Bedarf die Kontakt-Multiplexing-Ressourcen ab und geben sie frei.

SpbCx wendet die Pin-Muxing-Konfiguration in seinem IRP_MJ_CREATE-Handler direkt vor dem Aufruf des EvtSpbTargetConnect() -Rückrufs des Clienttreibers an. Wenn die Muxing-Konfiguration nicht angewendet werden konnte, wird der Rückruf des Controllertreibers EvtSpbTargetConnect() nicht aufgerufen. Daher kann ein SPB-Controllertreiber davon ausgehen, dass Kontakte beim Aufruf von EvtSpbTargetConnect() auf die SPB-Funktion gemuxt werden.

SpbCx setzt die Pin-Muxing-Konfiguration in seinem IRP_MJ_CLOSE-Handler zurück, unmittelbar nach dem Aufruf des EvtSpbTargetDisconnect()-Callbacks des Controller-Treibers. Dies führt dazu, dass Kontakte jedes Mal auf die SPB-Funktion gemuxt werden, wenn ein Peripherietreiber ein Handle für den SPB-Controllertreiber öffnet, und diese Zuweisung per Multiplexing aufgehoben wird, wenn der Peripherietreiber das Handle schließt.

SerCx verhält sich ähnlich. SerCx bezieht alle MsftFunctionConfig() Ressourcen in seinem IRP_MJ_CREATE-Handler unmittelbar vor dem Aufruf des EvtSerCx2FileOpen()-Callbacks des Controller-Treibers und gibt alle Ressourcen in seinem IRP_MJ_CLOSE-Handler unmittelbar nach dem Aufruf des EvtSerCx2FileClose-Callbacks des Controller-Treibers wieder frei.

Die Auswirkung des dynamischen Kontakt-Multiplexings für SerCx- und SpbCx-Controllertreiber besteht darin, dass sie in der Lage sein müssen, Kontakte zu tolerieren, deren Zuweisung zur SPB-/UART-Funktion per Multiplexing zu bestimmten Zeiten aufgehoben wird. Controllertreiber müssen davon ausgehen, dass Pins nicht multiplexiert werden, bis EvtSpbTargetConnect() oder EvtSerCx2FileOpen() aufgerufen wird. Kontakte werden während der folgenden Rückrufe nicht zwingenderweise auf die SPB-/UART-Funktion gemuxt. Es folgt keine vollständige Liste, sondern stellt die am häufigsten verwendeten PNP-Routinen dar, die von Controllertreibern implementiert werden.

  • DriverEntry
  • EvtDriverDeviceAdd
  • EvtDevicePrepareHardware/EvtDeviceReleaseHardware
  • EvtDeviceD0Entry/EvtDeviceD0Exit

Verifizierung

Wenn Sie rhproxy testen möchten, ist es hilfreich, das folgende Schritt-für-Schritt-Verfahren zu verwenden.

  1. Vergewissern Sie sich, dass jeder SpbCx, GpioClx und SerCx Controllertreiber ordnungsgemäß geladen wird und ordnungsgemäß funktioniert.
  2. Stellen Sie sicher, dass rhproxy auf dem System vorhanden ist. Einige Editionen und Builds von Windows verfügen nicht über sie.
  3. Kompilieren und laden Sie Ihren rhproxy-Knoten mit ACPITABL.dat
  4. Überprüfen, ob der rhproxy Geräteknoten vorhanden ist
  5. Überprüfen, ob rhproxy geladen und gestartet wird
  6. Überprüfen, ob die erwarteten Geräte für den Benutzermodus verfügbar gemacht werden
  7. Stellen Sie sicher, dass Sie über die Befehlszeile mit jedem Gerät interagieren können.
  8. Überprüfen, ob Sie mit jedem Gerät über eine UWP-App interagieren können
  9. Ausführen von HLK-Tests

Überprüfen von Controllertreibern

Da rhproxy andere Geräte im System für den Benutzermodus verfügbar macht, funktioniert es nur, wenn diese Geräte bereits funktionieren. Der erste Schritt besteht darin, zu überprüfen, ob diese Geräte – die I2C-, SPI- und GPIO-Controller, die Sie verfügbar machen möchten – bereits funktionieren.

Führen Sie an der Eingabeaufforderung den folgenden Befehl aus:

devcon status *

Sehen Sie sich die Ausgabe an und vergewissern Sie sich, dass alle relevanten Geräte gestartet sind. Wenn ein Gerät einen Problemcode aufweist, müssen Sie ermitteln, warum dieses Gerät nicht geladen wird. Alle Geräte sollten während des anfänglichen Plattform-Bringups aktiviert worden sein. Die Problembehandlung von SpbCx-, GpioClx- oder SerCx-Controller-Treibern geht über den Rahmen dieses Dokuments hinaus.

Überprüfen, ob rhproxy im System vorhanden ist

Überprüfen Sie, ob der rhproxy Dienst im System vorhanden ist.

reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy

Wenn der Registrierungsschlüssel nicht vorhanden ist, ist rhproxy auf Ihrem System nicht vorhanden. Rhproxy ist auf allen Builds von IoT Core und Windows Enterprise Build 15063 und höher vorhanden.

Kompilieren und Laden von ASL mit ACPITABL.dat

Nachdem Sie nun einen rhproxy ASL-Knoten erstellt haben, ist es an der Zeit, ihn zu kompilieren und zu laden. Sie können den rhproxy-Knoten in eine eigenständige AML-Datei kompilieren, die an die ACPI-Systemtabellen angefügt werden kann. Alternativ können Sie den rhproxy-Knoten direkt in die ACPI-Tabellen Ihrer Plattform einfügen, wenn Sie Zugriff auf die ACPI-Quellen Ihres Systems haben. Während der anfänglichen Inbetriebnahme kann es jedoch einfacher sein, ACPITABL.dat zu verwenden.

  1. Erstellen Sie eine Datei namens "yourboard.asl", und fügen Sie den RHPX-Geräteknoten in einen DefinitionBlock ein:

    DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
    {
        Scope (\_SB)
        {
            Device(RHPX)
            {
            ...
            }
        }
    }
    
  2. Laden Sie WDK herunter und finden Sie asl.exe unter C:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify

  3. Führen Sie den folgenden Befehl aus, um ACPITABL.dat zu generieren:

    asl.exe yourboard.asl
    
  4. Kopieren Sie die resultierende ACPITABL.dat Datei in "c:\windows\system32" auf Ihrem System unter Test.

  5. Aktivieren Sie „testsigning“ auf Ihrem Testsystem:

    bcdedit /set testsigning on
    
  6. Starten Sie das System unter Test neu. Das System fügt die in ACPITABL.dat definierten ACPI-Tabellen an die Systemfirmwaretabellen an.

Überprüfen, ob der rhproxy-Geräteknoten vorhanden ist

Führen Sie den folgenden Befehl aus, um den rhproxy-Geräteknoten aufzulisten.

devcon status *msft8000

Die Ausgabe von devcon sollte angeben, dass das Gerät vorhanden ist. Wenn der Geräteknoten nicht vorhanden ist, wurden die ACPI-Tabellen dem System nicht erfolgreich hinzugefügt.

Überprüfen, ob rhproxy geladen und gestartet wird

Überprüfen Sie den Status von rhproxy:

devcon status *msft8000

Wenn die Ausgabe angibt, dass rhproxy gestartet wird, wurde rhproxy geladen und erfolgreich gestartet. Wenn ein Problemcode angezeigt wird, müssen Sie untersuchen. Einige häufige Problemcodes sind:

  • Problem 51 - CM_PROB_WAITING_ON_DEPENDENCY Das System startet rhproxy nicht, da eine seiner Abhängigkeiten nicht geladen werden konnte. Dies bedeutet, dass entweder die an rhproxy übergebenen Ressourcen auf ungültige ACPI-Knoten verweisen oder die Zielgeräte nicht starten. Überprüfen Sie zunächst, ob alle Geräte erfolgreich ausgeführt werden (siehe "Überprüfen von Controllertreibern" oben). Überprüfen Sie dann Ihre ASL noch einmal und stellen Sie sicher, dass alle Ressourcenpfade (zum Beispiel \_SB.I2C1) korrekt sind und auf gültige Knoten in Ihrer DSDT verweisen.
  • Problem 10 - CM_PROB_FAILED_START Rhproxy konnte nicht gestartet werden, höchstwahrscheinlich aufgrund eines Ressourcenanalyseproblems. Gehen Sie Ihre ASL durch, prüfen Sie die Ressourcenindizes in der DSD noch einmal, und vergewissern Sie sich, dass GPIO-Ressourcen in aufsteigender Reihenfolge der Pinnummern angegeben sind.

Überprüfen, ob die erwarteten Geräte für den Benutzermodus verfügbar gemacht werden

Nachdem rhproxy ausgeführt wird, sollte er Geräteschnittstellen erstellt haben, auf die über den Benutzermodus zugegriffen werden kann. Wir verwenden mehrere Befehlszeilentools zum Aufzählen von Geräten und sehen, dass sie vorhanden sind.

Klonen Sie das https://github.com/ms-iot/samples Repository und erstellen Sie die Beispiele GpioTestTool, I2cTestTool, SpiTestTool und Mincomm. Kopieren Sie die Tools auf Ihr zu testendes Gerät, und verwenden Sie die folgenden Befehle, um Geräte aufzulisten.

I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list

Sie sollten Ihre Geräte und ihre benutzerfreundlichen Namen in der Liste sehen. Falls die richtigen Geräte und Anzeigenamen nicht angezeigt werden, überprüfen Sie Ihre ASL-Datei.

Überprüfen der einzelnen Geräte in der Befehlszeile

Der nächste Schritt besteht darin, die Befehlszeilentools zum Öffnen und Interagieren mit den Geräten zu verwenden.

I2CTestTool-Beispiel:

I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3

SpiTestTool-Beispiel:

SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3

Beispiel für GpioTestTool:

GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off

MinComm (serial) (Beispiel). Verbinden Sie Rx mit Tx, bevor Sie Folgendes ausführen:

MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)

Jedes Gerät in einer UWP-App überprüfen

Verwenden Sie die folgenden Beispiele, um zu überprüfen, ob Geräte von UWP funktionieren.

Führen Sie die HLK-Tests aus

Laden Sie die Hardware-Lab-Kit (HLK) herunter. Die folgenden Tests sind verfügbar:

Wenn Sie den rhproxy-Geräteknoten im HLK-Manager auswählen, werden die entsprechenden Tests automatisch ausgewählt.

Wählen Sie im HLK-Manager "Ressourcenhub-Proxygerät" aus:

Screenshot des Windows Hardware Lab Kit, der die Registerkarte „Auswahl“ mit der ausgewählten Option „Resource Hub-Proxy-Gerät“ zeigt.

Klicken Sie dann auf die Registerkarte "Tests", und wählen Sie "I2C WinRT", "Gpio WinRT" und "Spi WinRT"-Tests aus.

Screenshot vom Windows Hardware Lab Kit, der die Registerkarte „Tests“ mit ausgewählter Option „G P I O Win R T Functional and Stress Tests“ zeigt.

Klicken Sie auf "Ausgewählt ausführen". Weitere Dokumentation zu jedem Test ist verfügbar, indem Sie mit der rechten Maustaste auf den Test klicken und auf "Testbeschreibung" klicken.

Ressourcen

Anhang

Anhang A - Raspberry Pi ASL-Auflistung

Siehe auch Raspberry Pi 2 & 3 – Pin-Zuordnung

DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{

    Scope (\_SB)
    {
        //
        // RHProxy Device Node to enable WinRT API
        //
        Device(RHPX)
        {
            Name(_HID, "MSFT8000")
            Name(_CID, "MSFT8000")
            Name(_UID, 1)

            Name(_CRS, ResourceTemplate()
            {
                // Index 0
                SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                                           // MOSI - GPIO 10 - Pin 19
                                           // MISO - GPIO 9  - Pin 21
                                           // CE0  - GPIO 8  - Pin 24
                    0,                     // Device selection (CE0)
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    0,                     // databit len: placeholder
                    ControllerInitiated,   // target mode
                    0,                     // connection speed: placeholder
                    ClockPolarityLow,      // clock polarity: placeholder
                    ClockPhaseFirst,       // clock phase: placeholder
                    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                                           // Resource usage
                    )                      // Vendor Data

                // Index 1
                SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                                           // MOSI - GPIO 10 - Pin 19
                                           // MISO - GPIO 9  - Pin 21
                                           // CE1  - GPIO 7  - Pin 26
                    1,                     // Device selection (CE1)
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    0,                     // databit len: placeholder
                    ControllerInitiated,   // target mode
                    0,                     // connection speed: placeholder
                    ClockPolarityLow,      // clock polarity: placeholder
                    ClockPhaseFirst,       // clock phase: placeholder
                    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                                           // Resource usage
                    )                      // Vendor Data

                // Index 2
                SPISerialBus(              // SCKL - GPIO 21 - Pin 40
                                           // MOSI - GPIO 20 - Pin 38
                                           // MISO - GPIO 19 - Pin 35
                                           // CE1  - GPIO 17 - Pin 11
                    1,                     // Device selection (CE1)
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    0,                     // databit len: placeholder
                    ControllerInitiated,   // target mode
                    0,                     // connection speed: placeholder
                    ClockPolarityLow,      // clock polarity: placeholder
                    ClockPhaseFirst,       // clock phase: placeholder
                    "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                                           // Resource usage
                    )                      // Vendor Data
                // Index 3
                I2CSerialBus(              // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
                    0xFFFF,                // SlaveAddress: placeholder
                    ,                      // SlaveMode: default to ControllerInitiated
                    0,                     // ConnectionSpeed: placeholder
                    ,                      // Addressing Mode: placeholder
                    "\\_SB.I2C1",          // ResourceSource: I2C bus controller name
                    ,
                    ,
                    )                      // VendorData

                // Index 4 - GPIO 4 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 4 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 4 }
                // Index 6 - GPIO 5 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 5 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 5 }
                // Index 8 - GPIO 6 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 6 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 6 }
                // Index 10 - GPIO 12 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 12 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 12 }
                // Index 12 - GPIO 13 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 13 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 13 }
                // Index 14 - GPIO 16 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 16 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 16 }
                // Index 16 - GPIO 18 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 18 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 18 }
                // Index 18 - GPIO 22 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 22 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 22 }
                // Index 20 - GPIO 23 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 23 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 23 }
                // Index 22 - GPIO 24 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 24 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 24 }
                // Index 24 - GPIO 25 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 25 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 25 }
                // Index 26 - GPIO 26 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 26 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 26 }
                // Index 28 - GPIO 27 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 27 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 27 }
                // Index 30 - GPIO 35 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 35 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 35 }
                // Index 32 - GPIO 47 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 47 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 47 }
            })

            Name(_DSD, Package()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package()
                {
                    // Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
                    // SPI 0
                    Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},                       // Index 0 & 1
                    Package(2) { "SPI0-MinClockInHz", 7629 },                               // 7629 Hz
                    Package(2) { "SPI0-MaxClockInHz", 125000000 },                          // 125 MHz
                    Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},          // Data Bit Length
                    // SPI 1
                    Package(2) { "bus-SPI-SPI1", Package() { 2 }},                          // Index 2
                    Package(2) { "SPI1-MinClockInHz", 30518 },                              // 30518 Hz
                    Package(2) { "SPI1-MaxClockInHz", 125000000 },                          // 125 MHz
                    Package(2) { "SPI1-SupportedDataBitLengths", Package() { 8 }},          // Data Bit Length
                    // I2C1
                    Package(2) { "bus-I2C-I2C1", Package() { 3 }},
                    // GPIO Pin Count and supported drive modes
                    Package (2) { "GPIO-PinCount", 54 },
                    Package (2) { "GPIO-UseDescriptorPinNumbers", 1 },
                    Package (2) { "GPIO-SupportedDriveModes", 0xf },                        // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos
                }
            })
        }
    }
}

Anhang B: MinnowBoardMax-ASL-Eintrag

Siehe auch MinnowBoard Max Pin Mappings

DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
    Scope (\_SB)
    {
        Device(RHPX)
        {
            Name(_HID, "MSFT8000")
            Name(_CID, "MSFT8000")
            Name(_UID, 1)

            Name(_CRS, ResourceTemplate()
            {
                // Index 0
                SPISerialBus(            // Pin 5, 7, 9 , 11 of JP1 for SIO_SPI
                    1,                     // Device selection
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    8,                     // databit len
                    ControllerInitiated,   // target mode
                    8000000,               // Connection speed
                    ClockPolarityLow,      // Clock polarity
                    ClockPhaseSecond,      // clock phase
                    "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                    ResourceConsumer,      // Resource usage
                    JSPI,                  // DescriptorName: creates name for offset of resource descriptor
                    )                      // Vendor Data

                // Index 1
                I2CSerialBus(            // Pin 13, 15 of JP1, for SIO_I2C5 (signal)
                    0xFF,                  // SlaveAddress: bus address
                    ,                      // SlaveMode: default to ControllerInitiated
                    400000,                // ConnectionSpeed: in Hz
                    ,                      // Addressing Mode: default to 7 bit
                    "\\_SB.I2C6",          // ResourceSource: I2C bus controller name (For MinnowBoard Max, hardware I2C5(0-based) is reported as ACPI I2C6(1-based))
                    ,
                    ,
                    JI2C,                  // Descriptor Name: creates name for offset of resource descriptor
                    )                      // VendorData

                // Index 2
                UARTSerialBus(           // Pin 17, 19 of JP1, for SIO_UART2
                    115200,                // InitialBaudRate: in bits ber second
                    ,                      // BitsPerByte: default to 8 bits
                    ,                      // StopBits: Defaults to one bit
                    0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
                    ,                      // IsBigEndian: default to LittleEndian
                    ,                      // Parity: Defaults to no parity
                    ,                      // FlowControl: Defaults to no flow control
                    32,                    // ReceiveBufferSize
                    32,                    // TransmitBufferSize
                    "\\_SB.URT2",          // ResourceSource: UART bus controller name
                    ,
                    ,
                    UAR2,                  // DescriptorName: creates name for offset of resource descriptor
                    )

                // Index 3
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {0}  // Pin 21 of JP1 (GPIO_S5[00])
                // Index 4
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {0}

                // Index 5
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {1}  // Pin 23 of JP1 (GPIO_S5[01])
                // Index 6
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {1}

                // Index 7
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {2}  // Pin 25 of JP1 (GPIO_S5[02])
                // Index 8
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {2}

                // Index 9
                UARTSerialBus(           // Pin 6, 8, 10, 12 of JP1, for SIO_UART1
                    115200,                // InitialBaudRate: in bits ber second
                    ,                      // BitsPerByte: default to 8 bits
                    ,                      // StopBits: Defaults to one bit
                    0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
                    ,                      // IsBigEndian: default to LittleEndian
                    ,                      // Parity: Defaults to no parity
                    FlowControlHardware,   // FlowControl: Defaults to no flow control
                    32,                    // ReceiveBufferSize
                    32,                    // TransmitBufferSize
                    "\\_SB.URT1",          // ResourceSource: UART bus controller name
                    ,
                    ,
                    UAR1,              // DescriptorName: creates name for offset of resource descriptor
                    )

                // Index 10
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {62}  // Pin 14 of JP1 (GPIO_SC[62])
                // Index 11
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {62}

                // Index 12
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {63}  // Pin 16 of JP1 (GPIO_SC[63])
                // Index 13
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {63}

                // Index 14
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {65}  // Pin 18 of JP1 (GPIO_SC[65])
                // Index 15
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {65}

                // Index 16
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {64}  // Pin 20 of JP1 (GPIO_SC[64])
                // Index 17
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {64}

                // Index 18
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {94}  // Pin 22 of JP1 (GPIO_SC[94])
                // Index 19
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {94}

                // Index 20
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {95}  // Pin 24 of JP1 (GPIO_SC[95])
                // Index 21
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {95}

                // Index 22
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {54}  // Pin 26 of JP1 (GPIO_SC[54])
                // Index 23
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {54}
            })

            Name(_DSD, Package()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package()
                {
                    // SPI Mapping
                    Package(2) { "bus-SPI-SPI0", Package() { 0 }},

                    Package(2) { "SPI0-MinClockInHz", 100000 },
                    Package(2) { "SPI0-MaxClockInHz", 15000000 },
                    // SupportedDataBitLengths takes a list of support data bit length
                    // Example : Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8, 7, 16 }},
                    Package(2) { "SPI0-SupportedDataBitLengths", Package() { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }},
                     // I2C Mapping
                    Package(2) { "bus-I2C-I2C5", Package() { 1 }},
                    // UART Mapping
                    Package(2) { "bus-UART-UART2", Package() { 2 }},
                    Package(2) { "bus-UART-UART1", Package() { 9 }},
                }
            })
        }
    }
}

Anhang C – PowerShell-Beispielskript zum Generieren von GPIO-Ressourcen

Das folgende Skript kann verwendet werden, um die GPIO-Ressourcendeklarationen für Raspberry Pi zu generieren:

$pins = @(
    @{PinNumber=4;PullConfig='PullUp'},
    @{PinNumber=5;PullConfig='PullUp'},
    @{PinNumber=6;PullConfig='PullUp'},
    @{PinNumber=12;PullConfig='PullDown'},
    @{PinNumber=13;PullConfig='PullDown'},
    @{PinNumber=16;PullConfig='PullDown'},
    @{PinNumber=18;PullConfig='PullDown'},
    @{PinNumber=22;PullConfig='PullDown'},
    @{PinNumber=23;PullConfig='PullDown'},
    @{PinNumber=24;PullConfig='PullDown'},
    @{PinNumber=25;PullConfig='PullDown'},
    @{PinNumber=26;PullConfig='PullDown'},
    @{PinNumber=27;PullConfig='PullDown'},
    @{PinNumber=35;PullConfig='PullUp'},
    @{PinNumber=47;PullConfig='PullUp'})

# generate the resources
$FIRST_RESOURCE_INDEX = 4
$resourceIndex = $FIRST_RESOURCE_INDEX
$pins | % {
    $a = @"
// Index $resourceIndex - GPIO $($_.PinNumber) - $($_.Name)
GpioIO(Shared, $($_.PullConfig), , , , "\\_SB.GPI0", , , , ) { $($_.PinNumber) }
GpioInt(Edge, ActiveBoth, Shared, $($_.PullConfig), 0, "\\_SB.GPI0",) { $($_.PinNumber) }
"@
    Write-Host $a
    $resourceIndex += 2;
}