Port-Konfiguration
In den vorherigen Kapiteln haben wir die ersten 9 Schritte der xHCI-Host-Controller-Initialisierung durchgeführt: Die PCIe Host Bridge wurde eingerichtet, die xHCI-Ringe (Command, Event, Transfer) wurden alloziert und der Controller wurde schließlich gestartet. Im letzten Kapitel haben wir den ersten Schritt des 10 Schrittes durchgeführt "Die Ports des Root Hubs initialisiert".
In diesem Kapitel widmen wir uns dem zweiten Teil des zehnten und entscheidenden Schritt: Die Ports des Root Hubs konfigurieren. Hier erwachen die physikalischen USB-Buchsen des Raspberry Pi 4 zum Leben.
Schauen wir uns den Code-Block in usb_Initialize() an:
// ========================================================================
// [10/10] Root Ports initialisieren und konfigurieren
// ========================================================================
USB_LOG(cyan, "\n[10/10] Root Ports initialisieren und konfigurieren...");
USB_LOG(white, " -> Warte 300ms, damit sich die Hardware stabilisieren kann...");
unsigned nMsDelay = 300;
Timer_SimpleMsDelay(nMsDelay);
// Alle Ports initialisieren
for (unsigned nPort = 0; nPort < s_xhciRootHub.m_nPorts; nPort++)
{
USB_LOG(white, " -> Initialisiere Port %u...", nPort + 1);
CXHCIRootPort_Initialize(&s_xhciRootHub.m_pRootPort[nPort]);
}
// Alle Ports konfigurieren
for (unsigned nPort = 0; nPort < s_xhciRootHub.m_nPorts; nPort++)
{
USB_LOG(white, " -> Konfiguriere Port %u...", nPort + 1);
CXHCIRootPort_Configure(&s_xhciRootHub.m_pRootPort[nPort]);
}
USB_LOG(great, "\n=== CXHCIDevice_Initialize() erfolgreich abgeschlossen ===\n");
Schritt 10 teilt sich logisch in zwei aufeinander aufbauende Phasen auf. Die erste Phase haben wir bereits besprochen:
- Initialize Phase (
CXHCIRootPort_Initialize): Physikalische Hardware-Erkennung, Reset und Adressierung über das xHCI-Protokoll. - Configure Phase (
CXHCIRootPort_Configure): Laden der Treiber, Auslesen der Konfigurationsdeskriptoren und Bereitstellung der Funktionen.
Die Konfigurations-Phase (CXHCIRootPort_Configure)
Nachdem alle Ports initialisiert und grundlegend adressiert wurden, wird in einer zweiten Schleife CXHCIRootPort_Configure() aufgerufen.
boolean CXHCIRootPort_Configure(CXHCIRootPort *pPort)
{
// 1. Prüfen, ob bei der Initialisierung ein Gerät erkannt wurde
if (pPort->m_pUSBDevice == 0)
{
return FALSE;
}
// 2. Device-Informationen (Vendor ID, Product ID) protokollieren
...
// 3. Konfiguration und Treiber-Bindung durchführen
for (unsigned nFunction = 0; nFunction < USBDEV_MAX_FUNCTIONS; nFunction++)
{
if (pPort->m_pUSBDevice->m_USBDevice.m_pFunction[nFunction] != 0)
{
pPort->m_pUSBDevice->m_USBDevice.m_pFunction[nFunction]->Configure(...);
}
}
// 4. Erneute Over-Current-Sicherheitsprüfung
...
}
Was passiert während der Konfiguration?
- Schnittstellen (Functions) aktivieren: Ein USB-Gerät stellt ein oder mehrere Interfaces (Funktionen) bereit. Im Fall des Raspberry Pi 4 ist z. B. am Root-Hub intern der USB-3.0/2.0-Hub-Chip (VIA VL805) angeschlossen.
- Treiber über die Device Factory binden: Die CUSBDeviceFactory erkennt anhand der Interface-Klasse (z. B. Class 9 für USB-Hubs) den benötigten Treiber:
- Bei einem Hub wird der Treiber CUSBStandardHub geladen.
- Dieser übernimmt daraufhin die Stromversorgung der nachgelagerten Ports (PORT_POWER) und startet die Enumeration für alle externen USB-A-Buchsen.
- Abschluss & Betriebsbereitschaft: Nach erfolgreicher Ausführung von
Configure()ist das USB-Subsystem vollständig betriebsbereit. Der xHCI-Controller nimmt Befehle entgegen, empfängt Interrupts über den Event-Ring und kann Daten mit den erkannten USB-Geräten austauschen.
Zusammenfassung aller 10 Schritte
Damit ist die vollständige Initialisierung der xHCI-Hardware abgeschlossen:
| Schritt | Beschreibung |
|---|---|
| [1] PCIe Host Bridge | Aktivieren des PCIe-Busses und Mapping der MMIO-Bereiche |
| [2] xHCI Device | PCIe-Konfiguration & Auslesen der Hardware-Capabilities (HCSPARAMS) |
| [3] Slot Manager | Allozieren des DCBAA ("Telefonbuch" der USB-Geräte) |
| [4] Event Manager | ERST & Event-Ring ("Briefkasten" für Rückmeldungen vom Controller) |
| [5] Command Manager | CRCR & Command-Ring ("Wunschliste" der CPU an den Controller) |
| [6] Scratchpad Buffer | Allozieren von temporärem Arbeitsspeicher im Coherent Memory |
| [7] Root Hub | Erstellen der logischen Strukturen für die physikalischen Ports |
| [8] IRQ Handler | Verbinden des Interrupt-Handlers mit dem System |
| [9] Controller Start | Setzen des RUN/STOP-Bits im USBCMD-Register |
| [10] Port Init & Config | Reset der Ports, Zuweisung von SlotIDs/USB-Adressen & Treiber-Bindung |
Den Sourcecode bekommst du hier: https://www.satyria.de/arm/sources/RPI4/C/USB4_PortsConfig.zip