replace ad hoc driver loading with a proper driver manager, new DDK, new PnP manager with device matching, asynchronous startup, resource ownership and removal, add shared PCI capability helpers, replace typed, rigid services with a proper service manager, implement proper system shutdown and restart, shutting down unloads drivers and shuts down services, add simple power button, remove heavyweight boot self-tests and SMP stress runs, add monotonic timestamps to kernel debug output, fruitless USB and PS/2 fixes, make test builds opt in.

This commit is contained in:
maksw committed 2026-10-26 10:08:03 +01:00
1 parent c0ad63c27f
commit d36f19509c
160 files changed
+6563 -7366

No files matched your search

+10 -16
View File
@@ -1,10 +1,10 @@
#include <ntlite/ddk/module.h>
// Intel High Definition Audio PCI attachment and controller lifetime management.
#include "hda.h"
#include <string.h>
const NTL_DDK* gHdaDdk;
static DRIVER_OBJECT gHdaDriver;
static HDA_CONTROLLER* gHdaControllers[HDA_MAX_CONTROLLERS];
static uint32_t gHdaControllerCount;
@@ -157,7 +157,7 @@ static KSTATUS HdaConfigureInterrupt(HDA_CONTROLLER* controller) {
return NTLSTATUS_SUCCESS;
}
gHdaDdk->Debug->Print(
DbgPrint(
"HDA: MSI setup failed status=0x%x; attempting explicit INTx fallback\n",
status);
controller->UsingMsi = false;
@@ -182,7 +182,7 @@ static KSTATUS HdaWaitForControllerInterruptWorkIdle(HDA_CONTROLLER* controller)
if (controller->IsrActive == 0 &&
controller->Dpc.Inserted == 0 && controller->DpcActive == 0)
return NTLSTATUS_SUCCESS;
gHdaDdk->Timer->Stall(10);
KeStallExecution(10);
}
return NTLSTATUS_TIMEOUT;
}
@@ -268,7 +268,7 @@ static KSTATUS HdaStartDevice(HDA_CONTROLLER* controller) {
return status;
}
if (!KSUCCESS(status)) {
gHdaDdk->Debug->Print(
DbgPrint(
"HDA: no analog endpoint registered status=0x%x\n",
status);
}
@@ -379,14 +379,9 @@ static KSTATUS HdaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDevice
}
// Registers the Intel HDA transport driver with the I/O manager.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Debug || !ddk->Debug->Print || !ddk->Dma || !ddk->Timer ||
!ddk->Timer->QueryTicks || !ddk->Timer->Stall || !ddk->Audio ||
!ddk->Scheduler || !ddk->Scheduler->DelayThread)
return NTLSTATUS_INVALID_PARAMETER;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
gHdaDdk = ddk;
gHdaControllerCount = 0;
memset(gHdaControllers, 0, sizeof(gHdaControllers));
@@ -395,9 +390,8 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
gHdaDriver.IdTable = &gHdaIdTable;
gHdaDriver.DriverAddDevice = HdaAddDevice;
gHdaDriver.MajorFunction[IRP_MJ_PNP] = HdaDispatchPnp;
KSTATUS status = IoRegisterDriverObject(&gHdaDriver);
if (!KSUCCESS(status))
gHdaDdk->Debug->Print("HDA: IoRegisterDriverObject failed status=0x%x\n", status);
return status;
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gHdaDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
-2
View File
@@ -300,8 +300,6 @@ struct HDA_CONTROLLER {
uint64_t ControllerInterruptCount;
};
extern const NTL_DDK* gHdaDdk;
// Returns one byte from the controller register aperture.
uint8_t HdaRead8(const HDA_CONTROLLER* controller, uint32_t offset);
+12 -12
View File
@@ -281,7 +281,7 @@ static KSTATUS HdaCodecPowerD0(HDA_CODEC_STATE* state,
if ((powerState & HDA_POWER_ACTUAL_MASK) ==
(HDA_POWER_STATE_D0 << HDA_POWER_ACTUAL_SHIFT))
return NTLSTATUS_SUCCESS;
gHdaDdk->Timer->Stall(10);
KeStallExecution(10);
}
return NTLSTATUS_TIMEOUT;
}
@@ -583,7 +583,7 @@ static KSTATUS HdaCodecEnumerateAll(HDA_CODEC_STATE* state) {
continue;
}
lastStatus = status;
gHdaDdk->Debug->Print(
DbgPrint(
"HDA: codec %u topology discovery failed status=0x%x\n",
codecAddress,
status);
@@ -1176,7 +1176,7 @@ static void HdaCodecRefreshEndpointsLocked(HDA_CODEC_STATE* state) {
if (endpoint->Available != available) {
endpoint->Available = available;
if (endpoint->KernelEndpoint)
gHdaDdk->Audio->SetEndpointAvailable(endpoint->KernelEndpoint,
IoAudioSetEndpointAvailable(endpoint->KernelEndpoint,
available ? 1u : 0u);
}
if (!endpoint->Running || endpoint->Starting ||
@@ -1210,13 +1210,13 @@ static void HdaCodecRefreshEndpointsLocked(HDA_CODEC_STATE* state) {
uintptr_t flags = KeAcquireSpinlock(&state->CallbackLock);
endpoint->Running = false;
KeReleaseSpinlock(&state->CallbackLock, flags);
gHdaDdk->Debug->Print(
DbgPrint(
"HDA: jack reroute failed kind=%u route=%u status=0x%x\n",
endpoint->Kind,
selectedRoute,
status);
if (endpoint->KernelEndpoint) {
gHdaDdk->Audio->ReportEndpointFailure(endpoint->KernelEndpoint,
IoAudioReportEndpointFailure(endpoint->KernelEndpoint,
status,
0);
}
@@ -1306,7 +1306,7 @@ static void HdaCodecWorkThread(uintptr_t argument) {
static void HdaCodecPollThread(uintptr_t argument) {
HDA_CODEC_STATE* state = (HDA_CODEC_STATE*)argument;
while (state->PollRunning) {
(void)gHdaDdk->Scheduler->DelayThread(HDA_JACK_POLL_INTERVAL_MS);
(void)KeDelayThread(HDA_JACK_POLL_INTERVAL_MS);
if (!state->PollRunning)
break;
uintptr_t flags = KeAcquireSpinlock(&state->CallbackLock);
@@ -1355,7 +1355,7 @@ static void HdaCodecPeriodComplete(void* context,
endpoint = state->ActiveEndpoint->KernelEndpoint;
KeReleaseSpinlock(&state->CallbackLock, flags);
if (endpoint) {
gHdaDdk->Audio->NotifyPeriod(endpoint,
IoAudioNotifyPeriod(endpoint,
completedPeriodIndex,
presentedFrames,
finePositionFrames,
@@ -1453,7 +1453,7 @@ static void HdaCodecTransportFailure(void* context, KSTATUS failureStatus) {
KeReleaseSpinlock(&state->CallbackLock, flags);
for (uint8_t index = 0; index < state->EndpointCount; index++) {
if (state->Endpoints[index].KernelEndpoint) {
gHdaDdk->Audio->ReportEndpointFailure(
IoAudioReportEndpointFailure(
state->Endpoints[index].KernelEndpoint,
failureStatus,
0);
@@ -1747,7 +1747,7 @@ static KSTATUS HdaCodecRegisterEndpoints(HDA_CODEC_STATE* state) {
}
}
status = gHdaDdk->Audio->RegisterEndpoint(&registration,
status = IoAudioRegisterEndpoint(&registration,
&endpoint->KernelEndpoint);
if (!KSUCCESS(status))
return status;
@@ -1779,7 +1779,7 @@ static void HdaCodecStopWorkers(HDA_CODEC_STATE* state) {
// Discovers codec topology and registers usable analog render endpoints.
KSTATUS HdaCodecInitialize(HDA_CONTROLLER* controller) {
if (!controller || !gHdaDdk || !gHdaDdk->Audio || !gHdaDdk->Scheduler)
if (!controller)
return NTLSTATUS_INVALID_PARAMETER;
HDA_CODEC_STATE* state = (HDA_CODEC_STATE*)MmAllocatePoolTag(
sizeof(HDA_CODEC_STATE),
@@ -1801,7 +1801,7 @@ KSTATUS HdaCodecInitialize(HDA_CONTROLLER* controller) {
goto failed;
status = HdaCodecBuildRoutes(state);
if (!KSUCCESS(status)) {
gHdaDdk->Debug->Print(
DbgPrint(
"HDA: no usable 48000 Hz, stereo, 16-bit analog converter-to-pin route\n");
goto failed;
}
@@ -1873,7 +1873,7 @@ void HdaCodecStop(HDA_CONTROLLER* controller, IO_AUDIO_REMOVAL_MODE mode) {
HDA_LOGICAL_ENDPOINT* endpoint = &state->Endpoints[index - 1u];
if (!endpoint->KernelEndpoint)
continue;
gHdaDdk->Audio->UnregisterEndpoint(endpoint->KernelEndpoint, mode);
IoAudioUnregisterEndpoint(endpoint->KernelEndpoint, mode);
endpoint->KernelEndpoint = (IO_AUDIO_ENDPOINT*)0;
}
+28 -31
View File
@@ -16,15 +16,12 @@ static __forceinline void HdaMemoryBarrier(void) {
// Returns the controller's monotonic microsecond counter.
static uint64_t HdaQueryTicks(void) {
if (!gHdaDdk || !gHdaDdk->Timer || !gHdaDdk->Timer->QueryTicks)
return 0;
return gHdaDdk->Timer->QueryTicks();
return KeQueryTicks();
}
// Delays for a bounded controller settling interval.
static void HdaStall(uint32_t microseconds) {
if (gHdaDdk && gHdaDdk->Timer && gHdaDdk->Timer->Stall)
gHdaDdk->Timer->Stall(microseconds);
KeStallExecution(microseconds);
}
// Returns one byte from the controller register aperture.
@@ -170,7 +167,7 @@ static uint8_t HdaRingSizeSelector(uint16_t count) {
// Releases all DMA and synchronization resources owned by one controller.
void HdaReleaseDma(HDA_CONTROLLER* controller) {
if (!controller || !gHdaDdk || !gHdaDdk->Dma)
if (!controller)
return;
if (controller->StreamMutex) {
@@ -190,12 +187,12 @@ void HdaReleaseDma(HDA_CONTROLLER* controller) {
controller->RecoveryFinished = (EVENT*)0;
}
gHdaDdk->Dma->FreeCommonBuffer(controller->Output.BdlDma);
IoDmaFreeCommonBuffer(controller->Output.BdlDma);
for (uint32_t ringIndex = 0; ringIndex < HDA_MAX_LOGICAL_ENDPOINTS; ringIndex++)
gHdaDdk->Dma->FreeCommonBuffer(controller->Output.Rings[ringIndex].Dma);
gHdaDdk->Dma->FreeCommonBuffer(controller->PositionDma);
gHdaDdk->Dma->FreeCommonBuffer(controller->RirbDma);
gHdaDdk->Dma->FreeCommonBuffer(controller->CorbDma);
IoDmaFreeCommonBuffer(controller->Output.Rings[ringIndex].Dma);
IoDmaFreeCommonBuffer(controller->PositionDma);
IoDmaFreeCommonBuffer(controller->RirbDma);
IoDmaFreeCommonBuffer(controller->CorbDma);
controller->Output.BdlDma = (IO_DMA_BUFFER*)0;
for (uint32_t ringIndex = 0; ringIndex < HDA_MAX_LOGICAL_ENDPOINTS; ringIndex++) {
controller->Output.Rings[ringIndex].Dma = (IO_DMA_BUFFER*)0;
@@ -211,14 +208,14 @@ void HdaReleaseDma(HDA_CONTROLLER* controller) {
controller->Corb = (uint32_t*)0;
if (controller->DmaAdapter) {
gHdaDdk->Dma->PutAdapter(controller->DmaAdapter);
IoDmaPutAdapter(controller->DmaAdapter);
controller->DmaAdapter = (IO_DMA_ADAPTER*)0;
}
}
// Allocates the transport and output DMA resources for one controller.
KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
if (!controller || !controller->Fdo || !gHdaDdk || !gHdaDdk->Dma)
if (!controller || !controller->Fdo)
return NTLSTATUS_INVALID_PARAMETER;
IO_DMA_REQUIREMENTS requirements;
@@ -229,7 +226,7 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
requirements.Alignment = 128u;
requirements.MaximumSegments = 1u;
KSTATUS status = gHdaDdk->Dma->GetAdapter(controller->Fdo,
KSTATUS status = IoDmaGetAdapter(controller->Fdo,
&requirements,
&controller->DmaAdapter);
if (!KSUCCESS(status))
@@ -248,7 +245,7 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
return status;
}
status = gHdaDdk->Dma->AllocateCommonBuffer(controller->DmaAdapter,
status = IoDmaAllocateCommonBuffer(controller->DmaAdapter,
(size_t)controller->CorbEntryCount * sizeof(uint32_t),
128u,
&controller->CorbDma);
@@ -256,7 +253,7 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
HdaReleaseDma(controller);
return status;
}
status = gHdaDdk->Dma->AllocateCommonBuffer(controller->DmaAdapter,
status = IoDmaAllocateCommonBuffer(controller->DmaAdapter,
(size_t)controller->RirbEntryCount * sizeof(HDA_RIRB_ENTRY),
128u,
&controller->RirbDma);
@@ -266,7 +263,7 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
}
// The position buffer is optional because LPIB is the supported fallback.
status = gHdaDdk->Dma->AllocateCommonBuffer(controller->DmaAdapter,
status = IoDmaAllocateCommonBuffer(controller->DmaAdapter,
(size_t)controller->TotalStreamCount * sizeof(uint64_t),
128u,
&controller->PositionDma);
@@ -274,7 +271,7 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
controller->PositionDma = (IO_DMA_BUFFER*)0;
for (uint32_t ringIndex = 0; ringIndex < HDA_MAX_LOGICAL_ENDPOINTS; ringIndex++) {
status = gHdaDdk->Dma->AllocateCommonBuffer(
status = IoDmaAllocateCommonBuffer(
controller->DmaAdapter,
HDA_OUTPUT_BUFFER_BYTES,
128u,
@@ -284,7 +281,7 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
return status;
}
}
status = gHdaDdk->Dma->AllocateCommonBuffer(controller->DmaAdapter,
status = IoDmaAllocateCommonBuffer(controller->DmaAdapter,
HDA_OUTPUT_PERIOD_COUNT * sizeof(HDA_BDL_ENTRY),
128u,
&controller->Output.BdlDma);
@@ -293,27 +290,27 @@ KSTATUS HdaAllocateDma(HDA_CONTROLLER* controller) {
return status;
}
controller->Corb = (uint32_t*)gHdaDdk->Dma->GetCommonBufferAddress(controller->CorbDma);
controller->Rirb = (HDA_RIRB_ENTRY*)gHdaDdk->Dma->GetCommonBufferAddress(controller->RirbDma);
controller->CorbDeviceAddress = gHdaDdk->Dma->GetCommonBufferDeviceAddress(controller->CorbDma);
controller->RirbDeviceAddress = gHdaDdk->Dma->GetCommonBufferDeviceAddress(controller->RirbDma);
controller->Corb = (uint32_t*)IoDmaGetCommonBufferAddress(controller->CorbDma);
controller->Rirb = (HDA_RIRB_ENTRY*)IoDmaGetCommonBufferAddress(controller->RirbDma);
controller->CorbDeviceAddress = IoDmaGetCommonBufferDeviceAddress(controller->CorbDma);
controller->RirbDeviceAddress = IoDmaGetCommonBufferDeviceAddress(controller->RirbDma);
if (controller->PositionDma) {
controller->PositionBuffer = (volatile uint64_t*)
gHdaDdk->Dma->GetCommonBufferAddress(controller->PositionDma);
IoDmaGetCommonBufferAddress(controller->PositionDma);
controller->PositionDeviceAddress =
gHdaDdk->Dma->GetCommonBufferDeviceAddress(controller->PositionDma);
IoDmaGetCommonBufferDeviceAddress(controller->PositionDma);
}
for (uint32_t ringIndex = 0; ringIndex < HDA_MAX_LOGICAL_ENDPOINTS; ringIndex++) {
controller->Output.Rings[ringIndex].Buffer = (uint8_t*)
gHdaDdk->Dma->GetCommonBufferAddress(controller->Output.Rings[ringIndex].Dma);
IoDmaGetCommonBufferAddress(controller->Output.Rings[ringIndex].Dma);
controller->Output.Rings[ringIndex].DeviceAddress =
gHdaDdk->Dma->GetCommonBufferDeviceAddress(
IoDmaGetCommonBufferDeviceAddress(
controller->Output.Rings[ringIndex].Dma);
}
controller->Output.Bdl = (HDA_BDL_ENTRY*)
gHdaDdk->Dma->GetCommonBufferAddress(controller->Output.BdlDma);
IoDmaGetCommonBufferAddress(controller->Output.BdlDma);
controller->Output.BdlDeviceAddress =
gHdaDdk->Dma->GetCommonBufferDeviceAddress(controller->Output.BdlDma);
IoDmaGetCommonBufferDeviceAddress(controller->Output.BdlDma);
memset(controller->Corb, 0, (size_t)controller->CorbEntryCount * sizeof(uint32_t));
memset(controller->Rirb, 0, (size_t)controller->RirbEntryCount * sizeof(HDA_RIRB_ENTRY));
@@ -502,7 +499,7 @@ static KSTATUS HdaResetCorbReadPointer(HDA_CONTROLLER* controller) {
static KSTATUS HdaReportInitializationFailure(HDA_CONTROLLER* controller,
const char* stage,
KSTATUS status) {
gHdaDdk->Debug->Print(
DbgPrint(
"HDA: init stage=%s failed status=0x%x GCTL=0x%08x STATESTS=0x%04x "
"CORB=%02x/%02x/%04x/%04x RIRB=%02x/%02x/%04x SDCTL=0x%06x\n",
stage,
@@ -1381,7 +1378,7 @@ static void HdaRecoveryWorker(uintptr_t argument) {
if (!KSUCCESS(status) && status != NTLSTATUS_DEVICE_REMOVED) {
if (callbacks.TransportFailure)
callbacks.TransportFailure(callbackContext, status);
gHdaDdk->Debug->Print("HDA: recovery failed status=0x%x\n", status);
DbgPrint("HDA: recovery failed status=0x%x\n", status);
}
if (queueDpc)
(void)KeInsertQueueDpc(&controller->Dpc, (void*)0, (void*)0);
+36 -36
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
// PCI bus driver. This file owns PCI enumeration, PDO creation, BAR decoding, and explicit MMIO mappings for function drivers.
#include "pci.h"
@@ -9,11 +10,11 @@
#include <common/printf.h>
#include <ntlite/ddk/ddk.h>
#include <ntlite/ddk/pci_caps.h>
#include <ntlite/ddi/io_driver.h>
int _fltused; // MSVC floating-point helper anchor required by printf.obj
static const NTL_DDK* gDdk;
static DRIVER_OBJECT gPciDriver;
static uint32_t gPciDeviceCount;
@@ -65,14 +66,14 @@ static bool PciIsPdo(DEVICE_OBJECT* pdo, PCI_PDO_EXTENSION** outExt) {
// Implements the raw Read32 operation.
static uint32_t PciRawRead32(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset) {
if (!gDdk || !gDdk->Platform || !gDdk->Platform->PciRead32 || offset > 0xFCu) return 0xFFFFFFFFu;
return gDdk->Platform->PciRead32(0, bus, dev, fn, offset & 0xFCu);
if (offset > 0xFCu) return 0xFFFFFFFFu;
return KePciReadConfig32(0, bus, dev, fn, offset & 0xFCu);
}
// Implements the raw Write32 operation.
static void PciRawWrite32(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t offset, uint32_t value) {
if (!gDdk || !gDdk->Platform || !gDdk->Platform->PciWrite32 || offset > 0xFCu) return;
gDdk->Platform->PciWrite32(0, bus, dev, fn, offset & 0xFCu, value);
if (offset > 0xFCu) return;
KePciWriteConfig32(0, bus, dev, fn, offset & 0xFCu, value);
}
// Implements the raw Read8 operation.
@@ -386,7 +387,7 @@ static KSTATUS PciCreatePdo(uint8_t bus, uint8_t dev, uint8_t fn) {
}
gPciDeviceCount++;
gDdk->Debug->Print("pci: %v ven=%04x dev=%04x class=%02x%02x%02x irq=%u\n",
DbgPrint("pci: %v ven=%04x dev=%04x class=%02x%02x%02x irq=%u\n",
pdo->Name,
info.VendorId,
info.DeviceId,
@@ -411,7 +412,7 @@ static void PciEnumerateBus(void) {
for (uint8_t fn = 0; fn < fnLimit; fn++) {
KSTATUS st = PciCreatePdo((uint8_t)bus, (uint8_t)dev, fn);
if (!KSUCCESS(st) && st != NTLSTATUS_NOT_FOUND) {
gDdk->Debug->Print("pci: failed to create PDO for %02x:%02x.%u st=0x%x\n",
DbgPrint("pci: failed to create PDO for %02x:%02x.%u st=0x%x\n",
bus, dev, fn, st);
}
}
@@ -536,7 +537,7 @@ __declspec(dllexport) KSTATUS PciMapBar(DEVICE_OBJECT* pdo, uint8_t index, uint6
return st;
for (uint64_t off = 0; off < mapLength; off += NTL_DDK_PAGE_SIZE) {
st = gDdk->Memory->MapPage(virtBase + (uintptr_t)off, physBase + off, flags, NtlDdkMapFailIfPresent);
st = MmDdkMapPage(virtBase + (uintptr_t)off, physBase + off, flags, NtlDdkMapFailIfPresent);
if (!KSUCCESS(st))
return st;
}
@@ -578,25 +579,26 @@ __declspec(dllexport) KSTATUS PciGetInterrupt(DEVICE_OBJECT* pdo, uint8_t* outIr
return NTLSTATUS_SUCCESS;
}
// Returns capability.
// Reads configuration through the PCI provider bound to this PDO.
static uint32_t PciCapabilityRead32(void* context, uint16_t offset) {
const PCI_PDO_EXTENSION* ext = (const PCI_PDO_EXTENSION*)context;
return PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
offset);
}
// Finds one PCI capability using the shared DDK parser.
static uint8_t PciFindCapability(PCI_PDO_EXTENSION* ext, uint8_t capId) {
if (!ext || !ext->CapabilityOffset)
return 0;
uint8_t cap = ext->CapabilityOffset & 0xFCu;
for (uint32_t guard = 0; cap && guard < 48u; guard++) {
uint32_t hdr = PciRawRead32(ext->Info.Address.Bus,
ext->Info.Address.Device,
ext->Info.Address.Function,
cap);
uint8_t id = (uint8_t)(hdr & 0xFFu);
uint8_t next = (uint8_t)((hdr >> 8) & 0xFCu);
if (id == capId)
return cap;
cap = next;
}
return 0;
const NTL_PCI_CONFIG_READER reader = { ext, PciCapabilityRead32 };
uint8_t offset = 0;
if (!KSUCCESS(NtlPciFindCapability(&reader, ext->CapabilityOffset & 0xFCu,
capId, &offset)))
return 0;
return offset;
}
// Enables msi.
@@ -619,7 +621,7 @@ __declspec(dllexport) KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo, uint8_t irqSlot)
bool is64 = (control & PCI_MSI_CTRL_64BIT) != 0;
bool pvm = (control & PCI_MSI_CTRL_PVM) != 0;
NTL_DDK_MSI_MESSAGE message;
KSTATUS messageStatus = gDdk->Interrupt->ComposeMsiMessage(irqSlot, &message);
KSTATUS messageStatus = KeIrqComposeMsiMessage(irqSlot, &message);
if (!KSUCCESS(messageStatus))
return messageStatus;
@@ -643,7 +645,7 @@ __declspec(dllexport) KSTATUS PciEnableMsi(DEVICE_OBJECT* pdo, uint8_t irqSlot)
cmd |= PCI_COMMAND_INTX_DISABLE;
PciRawWrite16(bus, dev, fn, PCI_REG_COMMAND_STATUS, cmd);
gDdk->Debug->Print("pci: MSI enabled %02x:%02x.%u cap=0x%02x vector=0x%02x irqslot=%u %s\n",
DbgPrint("pci: MSI enabled %02x:%02x.%u cap=0x%02x vector=0x%02x irqslot=%u %s\n",
bus, dev, fn, cap, (unsigned)(message.Data & 0xFFu), irqSlot, is64 ? "64-bit" : "32-bit");
return NTLSTATUS_SUCCESS;
}
@@ -658,7 +660,7 @@ __declspec(dllexport) KSTATUS PciEnableMsiAuto(DEVICE_OBJECT* pdo, uint8_t* outI
return NTLSTATUS_NOT_SUPPORTED;
uint8_t irq = 0xFFu;
KSTATUS st = gDdk->Interrupt->AllocateMsiVector(&irq);
KSTATUS st = KeIrqAllocateMsiVector(&irq);
if (!KSUCCESS(st))
return st;
@@ -670,21 +672,19 @@ __declspec(dllexport) KSTATUS PciEnableMsiAuto(DEVICE_OBJECT* pdo, uint8_t* outI
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Debug || !ddk->Interrupt || !ddk->Memory || !ddk->Platform) return NTLSTATUS_INVALID_PARAMETER;
gDdk = ddk;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
gPciDeviceCount = 0;
IoInitializeDriverObject(&gPciDriver, SYS_SV_LITERAL("pci"));
gPciDriver.MajorFunction[IRP_MJ_PNP] = PciDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gPciDriver);
if (!KSUCCESS(st)) return st;
gDdk->Debug->Print("pci: DriverEntry ABI=%u\n", PciDriverAbiVersion());
DbgPrint("pci: module ABI=%u\n", PciDriverAbiVersion());
PciEnumerateBus();
gDdk->Debug->Print("pci: enumeration complete, devices=%u\n", gPciDeviceCount);
DbgPrint("pci: enumeration complete, devices=%u\n", gPciDeviceCount);
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gPciDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
+14 -8
View File
@@ -1,9 +1,9 @@
#include <ntlite/ddk/module.h>
// USB driver package entry point. This file registers the USB bus, class, hub, HID, storage, and xHCI drivers.
#include "usb.h"
DRIVER_OBJECT gXhciDriver;
const NTL_DDK* gUsbDdk;
static const IO_DEVICE_ID gXhciIds[] = {
{ IoBusPci, { "PCI\\CC_0C0330", sizeof("PCI\\CC_0C0330") - 1 } },
@@ -31,15 +31,12 @@ static KSTATUS UsbInitializeXhciDriver(void) {
gXhciDriver.IdTable = &gXhciIdTable;
gXhciDriver.DriverAddDevice = XhciAddDevice;
gXhciDriver.MajorFunction[IRP_MJ_PNP] = XhciDispatchPnp;
return IoRegisterDriverObject(&gXhciDriver);
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Dma || !ddk->Timer) return NTLSTATUS_INVALID_PARAMETER;
DbgPrint("usb: driver loading\n");
gUsbDdk = ddk;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("usb: driver loading phase2-xecp-20261023\n");
KSTATUS st = UsbInitializeBusModel();
if (!KSUCCESS(st)) {
@@ -80,3 +77,12 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("usb: driver initialized\n");
return NTLSTATUS_SUCCESS;
}
extern DRIVER_OBJECT gUsbBusDriver;
extern DRIVER_OBJECT gUsbCompositeDriver;
extern DRIVER_OBJECT gUsbHidDriver;
extern DRIVER_OBJECT gUsbStorageDriver;
extern DRIVER_OBJECT gUsbHubDriver;
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gXhciDriver, &gUsbBusDriver, &gUsbCompositeDriver, &gUsbHidDriver, &gUsbStorageDriver, &gUsbHubDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
+14 -7
View File
@@ -112,6 +112,7 @@ static __inline void UsbTrace(const char* fmt, ...) { (void)fmt; }
#define XHCI_TRB_TYPE_DISABLE_SLOT 10u
#define XHCI_TRB_TYPE_ADDRESS_DEVICE 11u
#define XHCI_TRB_TYPE_CONFIGURE_ENDPOINT 12u
#define XHCI_TRB_TYPE_STOP_ENDPOINT 15u
#define XHCI_CC_SUCCESS 1u
#define XHCI_CC_SHORT_PACKET 13u
@@ -129,6 +130,9 @@ static __inline void UsbTrace(const char* fmt, ...) { (void)fmt; }
#define XHCI_CONTEXT_ENTRIES(n) ((uint32_t)(n) << 27)
#define XHCI_SLOT_SPEED(s) ((uint32_t)(s) << 20)
#define XHCI_SLOT_HUB (1u << 26)
#define XHCI_SLOT_PORT_COUNT(n) ((uint32_t)(n) << 24)
#define XHCI_SLOT_TT_THINK(n) (((uint32_t)(n) & 3u) << 16)
#define XHCI_SLOT_ROOT_PORT(p) ((uint32_t)(p) << 16)
#define XHCI_EP_TYPE_CONTROL (4u << 3)
#define XHCI_EP_TYPE_BULK_OUT (2u << 3)
@@ -409,6 +413,8 @@ struct USB_HCD {
DEVICE_OBJECT* ControllerDevice;
DEVICE_OBJECT* RootHubPdo;
void* RootHubContext;
SPINLOCK RootHubLock;
bool RootScanRequested;
uint8_t ControllerIndex;
uint8_t MaxRootPorts;
};
@@ -674,6 +680,8 @@ typedef struct XHCI_DEVICE {
uint8_t DeviceProtocol;
uint8_t ConfigurationValue;
bool Configured;
uint8_t HubPortCount;
uint16_t HubCharacteristics;
USB_DEVICE* UsbDevice;
DEVICE_OBJECT* UsbPdo;
DEVICE_OBJECT* ParentDeviceObject;
@@ -786,7 +794,6 @@ typedef struct XHCI_WAIT_TARGET {
typedef struct XHCI_CONTROLLER {
uint32_t Magic;
const NTL_DDK* Ddk;
DEVICE_OBJECT* Fdo;
DEVICE_OBJECT* Pdo;
DEVICE_OBJECT* LowerDevice;
@@ -854,6 +861,7 @@ typedef struct XHCI_CONTROLLER {
volatile bool InterruptsEnabled;
volatile uint32_t InterruptCount;
volatile uint32_t EventDpcCount;
volatile uint32_t EventDpcBudgetHits;
SPINLOCK EventLock;
SPINLOCK WaitLock;
SPINLOCK CommandLock;
@@ -871,7 +879,6 @@ extern DRIVER_OBJECT gUsbCompositeDriver;
extern DRIVER_OBJECT gUsbHidDriver;
extern DRIVER_OBJECT gUsbHubDriver;
extern DRIVER_OBJECT gXhciDriver;
extern const NTL_DDK* gUsbDdk;
KSTATUS UsbInitializeBusModel(void);
KSTATUS UsbInitializeCompositeDriver(void);
@@ -919,9 +926,9 @@ uint32_t XhciRead32(volatile uint8_t* base, uint32_t reg);
void XhciWrite32(volatile uint8_t* base, uint32_t reg, uint32_t value);
uint64_t XhciRead64(volatile uint8_t* base, uint32_t reg);
void XhciWrite64(volatile uint8_t* base, uint32_t reg, uint64_t value);
void UsbDelayUs(const NTL_DDK* ddk, uint32_t us);
bool UsbWaitSet32(const NTL_DDK* ddk, volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs);
bool UsbWaitClear32(const NTL_DDK* ddk, volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs);
void UsbDelayUs(uint32_t us);
bool UsbWaitSet32( volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs);
bool UsbWaitClear32( volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs);
void* UsbDmaAllocPages(XHCI_CONTROLLER* xhci,
size_t pages,
uint64_t* outDeviceAddress,
@@ -948,7 +955,6 @@ void XhciLogPortStatus(XHCI_CONTROLLER* xhci);
void XhciPowerRootPorts(XHCI_CONTROLLER* xhci);
void XhciAckInterrupter0(XHCI_CONTROLLER* xhci);
void XhciUpdateErdp(XHCI_CONTROLLER* xhci);
bool XhciDrainEventRing(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target);
bool XhciDrainEventRingLocked(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target);
bool XhciWaitTargetComplete(const XHCI_WAIT_TARGET* target);
void XhciRegisterWaitTarget(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target);
@@ -993,7 +999,6 @@ void XhciProcessBootKeyboardReport(XHCI_DEVICE* dev, const uint8_t* report, uint
void XhciProcessBootMouseReport(XHCI_DEVICE* dev, const uint8_t* report, uint16_t len);
KSTATUS XhciArmHidInterruptIn(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev);
void XhciArmAllHid(XHCI_CONTROLLER* xhci);
void XhciHandleAsyncTransferEvent(XHCI_CONTROLLER* xhci, uint64_t trbDeviceAddress, uint32_t completionCode, uint8_t slotId, uint8_t endpointId, uint32_t residue);
KSTATUS XhciStartHidInterrupts(XHCI_CONTROLLER* xhci);
KSTATUS XhciSetHidBootProtocol(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev);
KSTATUS XhciAllocateHidMemory(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev);
@@ -1002,6 +1007,8 @@ KSTATUS UsbHidAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObje
KSTATUS UsbHidDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
void XhciInitialiseTransferRing(XHCI_TRB* ring, uint64_t ringDeviceAddress, uint32_t trbCount, uint8_t cycle);
KSTATUS XhciConfigurePipeEndpoint(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, USB_PIPE* pipe);
KSTATUS XhciConfigureHubContext(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, uint8_t portCount, uint16_t characteristics);
void XhciBuildConfigureSlotContext(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, uint32_t* slot, uint8_t endpointId);
KSTATUS XhciBulkTransfer(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, uint8_t endpointId, XHCI_TRB* ring, uint64_t ringDeviceAddress, uint32_t* enqueue, uint8_t* cycle, uint64_t bufferDeviceAddress, uint32_t length, uint32_t* outActual);
KSTATUS UsbStorageBulkIn(USB_STORAGE_EXTENSION* storage, uint64_t deviceAddress, uint32_t length, uint32_t* outActual);
KSTATUS UsbStorageBulkOut(USB_STORAGE_EXTENSION* storage, uint64_t deviceAddress, uint32_t length, uint32_t* outActual);
+3 -5
View File
@@ -69,8 +69,8 @@ void* UsbAllocateDmaBuffer(USB_DEVICE* dev,
// Frees a DMA buffer allocated for a USB class driver.
void UsbFreeDmaBuffer(IO_DMA_BUFFER* buffer) {
if (buffer && gUsbDdk && gUsbDdk->Dma)
gUsbDdk->Dma->FreeCommonBuffer(buffer);
if (buffer)
IoDmaFreeCommonBuffer(buffer);
}
// Creates device.
@@ -275,9 +275,6 @@ KSTATUS UsbInitializeBusModel(void) {
gUsbBusDriver.MajorFunction[IRP_MJ_PNP] = UsbDispatchPdoPnp;
gUsbBusDriver.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UsbDispatchInternalDeviceControl;
KSTATUS st = IoRegisterDriverObject(&gUsbBusDriver);
if (!KSUCCESS(st)) return st;
gUsbBusModelReady = true;
return NTLSTATUS_SUCCESS;
}
@@ -290,6 +287,7 @@ void UsbInitializeHcd(USB_HCD* hcd,
if (!hcd) return;
memset(hcd, 0, sizeof(*hcd));
hcd->Operations = ops;
hcd->RootHubLock = (SPINLOCK)SPINLOCK_INIT;
hcd->ControllerContext = controllerContext;
hcd->DriverObject = &gUsbBusDriver;
hcd->ControllerIndex = controllerIndex ? controllerIndex : ++gUsbNextControllerIndex;
+1 -1
View File
@@ -152,5 +152,5 @@ KSTATUS UsbInitializeCompositeDriver(void) {
gUsbCompositeDriver.DriverAddDevice = UsbCompositeAddDevice;
gUsbCompositeDriver.MajorFunction[IRP_MJ_PNP] = UsbCompositeDispatchPnp;
gUsbCompositeDriver.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UsbDispatchInternalDeviceControl;
return IoRegisterDriverObject(&gUsbCompositeDriver);
return NTLSTATUS_SUCCESS;
}
+23
View File
@@ -11,6 +11,8 @@ KSTATUS XhciSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
setup.wIndex = 0;
setup.wLength = 0;
DbgPrint("usb-stage: slot=%u SET_CONFIGURATION begin value=%u\n",
dev->SlotId, configurationValue);
KSTATUS st = XhciControlNoData(xhci, dev, &setup);
if (!KSUCCESS(st)) {
DbgPrint("usb: SET_CONFIGURATION slot=%u value=%u failed st=0x%x\n",
@@ -20,6 +22,8 @@ KSTATUS XhciSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
dev->ConfigurationValue = configurationValue;
dev->Configured = true;
DbgPrint("usb-stage: slot=%u SET_CONFIGURATION done value=%u\n",
dev->SlotId, configurationValue);
UsbTrace("usb: SET_CONFIGURATION slot=%u value=%u complete\n",
dev->SlotId, configurationValue);
return NTLSTATUS_SUCCESS;
@@ -220,6 +224,7 @@ KSTATUS XhciDiscoverAndSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
USB_CONFIGURATION_DESCRIPTOR config;
memset(&config, 0, sizeof(config));
uint16_t totalLength = 0;
DbgPrint("usb-stage: slot=%u GET_CONFIGURATION begin\n", dev->SlotId);
KSTATUS st = XhciGetConfigurationDescriptor(xhci, dev, 0, &config, &totalLength);
if (!KSUCCESS(st)) {
DbgPrint("usb: slot=%u configuration descriptor read failed st=0x%x\n",
@@ -227,6 +232,8 @@ KSTATUS XhciDiscoverAndSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
return st;
}
DbgPrint("usb-stage: slot=%u GET_CONFIGURATION done total=%u value=%u\n",
dev->SlotId, totalLength, config.bConfigurationValue);
XhciLogConfigurationTree(xhci, dev, &config, totalLength);
if (config.bConfigurationValue == 0) {
@@ -239,6 +246,7 @@ KSTATUS XhciDiscoverAndSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
if (!KSUCCESS(st)) return st;
if (!dev->UsbPdo) {
DbgPrint("usb-stage: slot=%u PDO creation begin\n", dev->SlotId);
st = UsbCreateDevicePdo(&xhci->Hcd, dev,
dev->ParentDeviceObject ? dev->ParentDeviceObject :
(xhci->Hcd.RootHubPdo ? xhci->Hcd.RootHubPdo : xhci->Hcd.ControllerDevice));
@@ -246,6 +254,7 @@ KSTATUS XhciDiscoverAndSetConfiguration(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
DbgPrint("usb: create device PDO slot=%u failed st=0x%x\n", dev->SlotId, st);
return st;
}
DbgPrint("usb-stage: slot=%u PDO creation done\n", dev->SlotId);
}
return NTLSTATUS_SUCCESS;
@@ -286,8 +295,14 @@ static KSTATUS XhciEnumeratePathEx(XHCI_CONTROLLER* xhci,
if (!xhci || !path || path->RootPort == 0)
return NTLSTATUS_INVALID_PARAMETER;
DbgPrint("usb-stage: hcd=%02x:%02x.%u root=%u hub-slot=%u hub-port=%u enable-slot begin\n",
xhci->Bus, xhci->Dev, xhci->Fn, path->RootPort,
path->BehindHub ? path->ParentHubSlot : 0,
path->BehindHub ? path->ParentHubPort : 0);
uint8_t slotId = 0;
KSTATUS st = XhciEnableSlot(xhci, &slotId);
DbgPrint("usb-stage: hcd=%02x:%02x.%u enable-slot done st=0x%x slot=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, st, slotId);
if (!KSUCCESS(st)) return st;
XHCI_DEVICE* dev = &xhci->Devices[slotId];
@@ -307,7 +322,11 @@ static KSTATUS XhciEnumeratePathEx(XHCI_CONTROLLER* xhci,
XhciBuildDefaultControlContext(xhci, dev);
DbgPrint("usb-stage: hcd=%02x:%02x.%u slot=%u address-device begin speed=%u route=%05x\n",
xhci->Bus, xhci->Dev, xhci->Fn, slotId, speed, path->RouteString);
st = XhciAddressDevice(xhci, dev);
DbgPrint("usb-stage: hcd=%02x:%02x.%u slot=%u address-device done st=0x%x\n",
xhci->Bus, xhci->Dev, xhci->Fn, slotId, st);
if (!KSUCCESS(st)) {
XhciRollbackEnumeratedSlot(xhci, slotId);
return st;
@@ -316,7 +335,11 @@ static KSTATUS XhciEnumeratePathEx(XHCI_CONTROLLER* xhci,
USB_DEVICE_DESCRIPTOR desc;
memset(&desc, 0, sizeof(desc));
DbgPrint("usb-stage: hcd=%02x:%02x.%u slot=%u get-device-descriptor begin\n",
xhci->Bus, xhci->Dev, xhci->Fn, slotId);
st = XhciGetDeviceDescriptorTimeout(xhci, dev, &desc, USB_XHCI_ENUM_CONTROL_TIMEOUT_US);
DbgPrint("usb-stage: hcd=%02x:%02x.%u slot=%u get-device-descriptor done st=0x%x\n",
xhci->Bus, xhci->Dev, xhci->Fn, slotId, st);
if (!KSUCCESS(st)) {
DbgPrint("usb: port %u slot %u descriptor read failed st=0x%x\n",
logicalPort, slotId, st);
+63 -28
View File
@@ -213,9 +213,9 @@ KSTATUS XhciAllocateHidMemory(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
dev->HidRing = (XHCI_TRB*)UsbDmaAllocPages(xhci, 1, &dev->HidRingDeviceAddress, &dev->HidRingDma);
dev->HidBuffer = (uint8_t*)UsbDmaAllocPages(xhci, 1, &dev->HidBufferDeviceAddress, &dev->HidBufferDma);
if (!dev->HidRing || !dev->HidBuffer) {
if (gUsbDdk && gUsbDdk->Dma) {
gUsbDdk->Dma->FreeCommonBuffer(dev->HidBufferDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->HidRingDma);
{
IoDmaFreeCommonBuffer(dev->HidBufferDma);
IoDmaFreeCommonBuffer(dev->HidRingDma);
}
dev->HidBufferDma = (IO_DMA_BUFFER*)0;
dev->HidRingDma = (IO_DMA_BUFFER*)0;
@@ -261,10 +261,7 @@ KSTATUS XhciConfigureHidEndpoint(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
icc[0] = 0;
icc[1] = (1u << 0) | (1u << dci);
slot[0] = XHCI_CONTEXT_ENTRIES(dci) | XHCI_SLOT_SPEED(dev->Speed);
slot[1] = XHCI_SLOT_ROOT_PORT(dev->Port);
slot[2] = 0;
slot[3] = 0;
XhciBuildConfigureSlotContext(xhci, dev, slot, dci);
uint16_t maxPacket = dev->HidMaxPacket & 0x07FFu;
if (maxPacket == 0) maxPacket = dev->HidKeyboard ? 8u : 4u;
@@ -442,8 +439,10 @@ static void UsbHidInterruptComplete(USB_URB* urb, void* context) {
return;
ext->InterruptPending = false;
if (ext->SurpriseRemoved || ext->Removed || !ext->Started)
if (ext->SurpriseRemoved || ext->Removed || !ext->Started) {
IoReleaseRemoveLock(&ext->RemoveLock, (IRP*)0);
return;
}
if (KSUCCESS(urb->Status)) {
uint16_t length = (uint16_t)urb->ActualLength;
@@ -468,6 +467,7 @@ static void UsbHidInterruptComplete(USB_URB* urb, void* context) {
if (!ext->SurpriseRemoved && !ext->Removed)
(void)UsbHidArmInterrupt(ext);
IoReleaseRemoveLock(&ext->RemoveLock, (IRP*)0);
}
// Implements the hid Send Boot Protocol operation.
@@ -523,6 +523,11 @@ static KSTATUS UsbHidArmInterrupt(USB_HID_EXTENSION* ext) {
if (ext->InterruptPending)
return NTLSTATUS_SUCCESS;
// One in-flight callback owns a remove reference through dispatch or cancel.
KSTATUS refStatus = IoAcquireRemoveLock(&ext->RemoveLock, (IRP*)0);
if (!KSUCCESS(refStatus))
return refStatus;
ext->InterruptPending = true;
memset(ext->ReportBuffer, 0, ext->ReportLength);
memset(&ext->InterruptUrb, 0, sizeof(ext->InterruptUrb));
ext->InterruptUrb.Function = UrbFunctionInterruptTransfer;
@@ -536,12 +541,13 @@ static KSTATUS UsbHidArmInterrupt(USB_HID_EXTENSION* ext) {
ext->InterruptUrb.CompleteContext = ext;
KSTATUS st = UsbSubmitUrbAsync(ext->LowerDevice, &ext->InterruptUrb);
if (st != NTLSTATUS_PENDING && !KSUCCESS(st))
return st;
if (ext->InterruptUrb.Status != NTLSTATUS_PENDING && ext->InterruptUrb.Status != NTLSTATUS_SUCCESS)
return ext->InterruptUrb.Status;
ext->InterruptPending = true;
// The USB PDO returns PENDING even when the HCD rejected the URB and
// completed its IRP synchronously. Inspect the URB's actual status.
if (st != NTLSTATUS_PENDING || ext->InterruptUrb.Status != NTLSTATUS_PENDING) {
ext->InterruptPending = false;
IoReleaseRemoveLock(&ext->RemoveLock, (IRP*)0);
return st == NTLSTATUS_PENDING ? ext->InterruptUrb.Status : st;
}
return NTLSTATUS_SUCCESS;
}
@@ -616,8 +622,6 @@ static KSTATUS UsbHidStartDevice(DEVICE_OBJECT* device, USB_HID_EXTENSION* ext)
ext->LastModifiers = 0;
ext->LastButtons = 0;
KeInputRegisterDevice(ext->Keyboard ? "usb-hid-keyboard" : (ext->AbsoluteMouse ? "usb-hid-tablet" : "usb-hid-mouse"), 0, &ext->InputDeviceId);
ext->Started = true;
device->PnpState = DevicePnpStarted;
if (ext->InterfacePdo)
@@ -627,9 +631,21 @@ static KSTATUS UsbHidStartDevice(DEVICE_OBJECT* device, USB_HID_EXTENSION* ext)
(XHCI_CONTROLLER*)ext->Device->Hcd->ControllerContext : (XHCI_CONTROLLER*)0;
st = UsbHidArmInterrupt(ext);
if (!KSUCCESS(st))
if (!KSUCCESS(st)) {
ext->Started = false;
device->PnpState = DevicePnpStopped;
if (ext->InterfacePdo)
ext->InterfacePdo->PnpState = DevicePnpStopped;
if (ext->InterruptPipe) {
ext->InterruptPipe->Open = false;
UsbDereferencePipe(ext->InterruptPipe);
ext->InterruptPipe = (USB_PIPE*)0;
}
UsbHidReleaseDma(ext);
return st;
}
KeInputRegisterDevice(ext->Keyboard ? "usb-hid-keyboard" : (ext->AbsoluteMouse ? "usb-hid-tablet" : "usb-hid-mouse"), 0, &ext->InputDeviceId);
if (xhci)
xhci->HidDeviceCount++;
@@ -679,8 +695,13 @@ KSTATUS UsbHidDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (ext) {
ext->SurpriseRemoved = true;
ext->Started = false;
if (ext->InterruptPending)
(void)UsbCancelUrb(&ext->InterruptUrb);
if (ext->InterruptPending) {
st = UsbCancelUrb(&ext->InterruptUrb);
if (!KSUCCESS(st)) {
IoCompleteRequest(irp, st, 0);
return NTLSTATUS_PENDING;
}
}
}
return IoForwardIrpToLower(device, irp);
@@ -689,13 +710,15 @@ KSTATUS UsbHidDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
if (ext) {
ext->Removed = true;
ext->Started = false;
if (ext->InterruptPending)
(void)UsbCancelUrb(&ext->InterruptUrb);
if (ext->InterruptPipe) {
ext->InterruptPipe->Open = false;
UsbDereferencePipe(ext->InterruptPipe);
ext->InterruptPipe = (USB_PIPE*)0;
if (ext->InterruptPending) {
st = UsbCancelUrb(&ext->InterruptUrb);
if (!KSUCCESS(st)) {
IoCompleteRequest(irp, st, 0);
return NTLSTATUS_PENDING;
}
}
if (ext->InterruptPipe)
ext->InterruptPipe->Open = false;
if (ext->Device && ext->Device->Hcd) {
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)ext->Device->Hcd->ControllerContext;
if (xhci && xhci->HidDeviceCount)
@@ -706,6 +729,10 @@ KSTATUS UsbHidDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
IoDestroyRemoveLock(&ext->RemoveLock);
ext->RemoveLockReady = false;
}
if (ext->InterruptPipe) {
UsbDereferencePipe(ext->InterruptPipe);
ext->InterruptPipe = (USB_PIPE*)0;
}
UsbHidReleaseDma(ext);
}
@@ -751,8 +778,16 @@ KSTATUS UsbHidAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObje
bool bootMouse = pdoExt->InterfaceDescriptor.bInterfaceSubClass == USB_HID_SUBCLASS_BOOT &&
pdoExt->InterfaceDescriptor.bInterfaceProtocol == USB_HID_PROTOCOL_MOUSE;
bool qemuTablet = UsbHidIsQemuAbsoluteTabletPdo(pdoExt, ep);
if (!bootKeyboard && !bootMouse && !qemuTablet)
return NTLSTATUS_INVALID_PARAMETER;
if (!bootKeyboard && !bootMouse && !qemuTablet) {
// A nonboot HID interface requires its report descriptor to be parsed.
// Avoid treating opaque reports as boot mouse packets.
DbgPrint("usb: HID slot=%u if=%u subclass=%u protocol=%u requires report parser\n",
pdoExt->Device->SlotId,
pdoExt->InterfaceDescriptor.bInterfaceNumber,
pdoExt->InterfaceDescriptor.bInterfaceSubClass,
pdoExt->InterfaceDescriptor.bInterfaceProtocol);
return NTLSTATUS_NOT_SUPPORTED;
}
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreateDevice(driver, sizeof(USB_HID_EXTENSION), &fdo);
@@ -799,5 +834,5 @@ KSTATUS UsbInitializeHidDriver(void) {
gUsbHidDriver.IdTable = &gUsbHidIdTable;
gUsbHidDriver.DriverAddDevice = UsbHidAddDevice;
gUsbHidDriver.MajorFunction[IRP_MJ_PNP] = UsbHidDispatchPnp;
return IoRegisterDriverObject(&gUsbHidDriver);
return NTLSTATUS_SUCCESS;
}
+156 -42
View File
@@ -99,7 +99,7 @@ static KSTATUS UsbHubEnumerateRootPortWithRetries(USB_HUB_EXTENSION* hub,
DbgPrint("usb-hub: root port %u enumeration attempt %u failed st=0x%x; retrying\n",
port, attempt, last);
UsbDelayUs(xhci->Ddk, 50000);
UsbDelayUs(50000);
}
if (UsbHubRootPortConnected(xhci, port)) {
@@ -126,7 +126,7 @@ static KSTATUS UsbHubEnumerateConnectedRootPort(USB_HUB_EXTENSION* hub,
hub->RootPortSlot[port] = USB_HUB_PORT_ENUMERATING;
hub->RootPortState[port] = UsbHubPortConnectedDebounce;
UsbDelayUs(xhci->Ddk, 30000u);
UsbDelayUs(30000u);
if (!UsbHubRootPortConnected(xhci, port)) {
UsbHubClearRootPortFailure(hub, port);
hub->RootPortSlot[port] = 0;
@@ -393,13 +393,21 @@ static KSTATUS UsbHubResetExternalPort(USB_HUB_EXTENSION* hub, uint8_t port, uin
USB_HUB_PORT_STATUS ps;
memset(&ps, 0, sizeof(ps));
bool resetComplete = false;
for (uint32_t i = 0; i < 500u; i++) {
UsbDelayUs(((XHCI_CONTROLLER*)hub->Hcd->ControllerContext)->Ddk, 1000u);
UsbDelayUs(1000u);
st = UsbHubGetPortStatus(hub, port, &ps);
if (!KSUCCESS(st))
return st;
if (ps.Change & USB_HUB_PORT_CHANGE_RESET)
if (ps.Change & USB_HUB_PORT_CHANGE_RESET) {
resetComplete = true;
break;
}
}
if (!resetComplete) {
DbgPrint("usb-hub: slot=%u port=%u reset timed out status=%04x change=%04x\n",
hub->Device ? hub->Device->SlotId : 0, port, ps.Status, ps.Change);
return NTLSTATUS_TIMEOUT;
}
(void)UsbHubClearPortFeature(hub, port, USB_HUB_PORT_FEAT_C_RESET);
@@ -464,7 +472,7 @@ static void UsbHubHandleExternalPortChange(USB_HUB_EXTENSION* hub, uint8_t port)
hub->ChildSlot[port] = USB_HUB_PORT_ENUMERATING;
hub->ChildPortState[port] = UsbHubPortConnectedDebounce;
UsbDelayUs(((XHCI_CONTROLLER*)hub->Hcd->ControllerContext)->Ddk, 30000u);
UsbDelayUs(30000u);
uint8_t speed = 0;
hub->ChildPortState[port] = UsbHubPortResetting;
@@ -478,8 +486,12 @@ static void UsbHubHandleExternalPortChange(USB_HUB_EXTENSION* hub, uint8_t port)
}
hub->ChildPortState[port] = UsbHubPortEnumerating;
DbgPrint("usb-stage: hub-slot=%u port=%u child enumeration begin speed=%u\n",
hub->Device ? hub->Device->SlotId : 0, port, speed);
uint8_t slot = 0;
st = XhciEnumerateHubPortEx((XHCI_CONTROLLER*)hub->Hcd->ControllerContext, hub, port, speed, &slot);
DbgPrint("usb-stage: hub-slot=%u port=%u child enumeration done st=0x%x slot=%u\n",
hub->Device ? hub->Device->SlotId : 0, port, st, slot);
if (KSUCCESS(st)) {
hub->ChildSlot[port] = slot;
hub->ChildPortState[port] = UsbHubPortChildPresent;
@@ -580,6 +592,12 @@ static bool UsbHubTakeInitialRootScan(USB_HUB_EXTENSION* hub) {
// Implements the hub Worker operation.
static void UsbHubWorker(void* arg) {
USB_HUB_EXTENSION* hub = (USB_HUB_EXTENSION*)arg;
if (hub && hub->Kind == UsbHubKindRoot && hub->Hcd) {
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)hub->Hcd->ControllerContext;
if (xhci)
DbgPrint("usb-stage: hcd=%02x:%02x.%u root worker entered ports=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, hub->PortCount);
}
while (hub && hub->WorkerRunning) {
KSTATUS st = KeWaitSemaphore(hub->WorkerSemaphore, KE_WAIT_INFINITE);
if (!KSUCCESS(st))
@@ -588,8 +606,11 @@ static void UsbHubWorker(void* arg) {
break;
if (hub->Kind == UsbHubKindRoot) {
if (UsbHubTakeInitialRootScan(hub))
(void)UsbHubDoRootPortScan(hub->Hcd);
if (UsbHubTakeInitialRootScan(hub)) {
KSTATUS scanStatus = UsbHubDoRootPortScan(hub->Hcd);
if (!KSUCCESS(scanStatus))
DbgPrint("usb-stage: root scan aborted st=0x%x\n", scanStatus);
}
uint8_t port = 0;
while (UsbHubPopPendingRootPort(hub, &port))
@@ -657,6 +678,12 @@ static KSTATUS UsbHubStartWorker(USB_HUB_EXTENSION* hub) {
UsbHubStopWorker(hub);
return status;
}
if (hub->Kind == UsbHubKindRoot && hub->Hcd) {
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)hub->Hcd->ControllerContext;
if (xhci)
DbgPrint("usb-stage: hcd=%02x:%02x.%u root worker created\n",
xhci->Bus, xhci->Dev, xhci->Fn);
}
return NTLSTATUS_SUCCESS;
}
@@ -675,6 +702,8 @@ static KSTATUS UsbHubDoRootPortScan(USB_HCD* hcd) {
if (!xhci || !xhci->Op)
return NTLSTATUS_INVALID_PARAMETER;
DbgPrint("usb-stage: hcd=%02x:%02x.%u root scan begin ports=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, hub->PortCount);
for (uint8_t port = 1; port <= hub->PortCount; port++) {
uint32_t portsc = XhciRead32(xhci->Op, XhciPortReg(port));
if (!(portsc & XHCI_PORTSC_CCS))
@@ -686,9 +715,13 @@ static KSTATUS UsbHubDoRootPortScan(USB_HCD* hcd) {
continue;
}
DbgPrint("usb-stage: hcd=%02x:%02x.%u root-port=%u begin portsc=%08x\n",
xhci->Bus, xhci->Dev, xhci->Fn, port, portsc);
attempted++;
uint8_t slot = 0;
KSTATUS st = UsbHubEnumerateConnectedRootPort(hub, xhci, port, &slot);
DbgPrint("usb-stage: hcd=%02x:%02x.%u root-port=%u done st=0x%x slot=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, port, st, slot);
if (KSUCCESS(st)) {
hub->RootPortSlot[port] = slot;
hub->RootPortState[port] = UsbHubPortChildPresent;
@@ -699,27 +732,45 @@ static KSTATUS UsbHubDoRootPortScan(USB_HCD* hcd) {
}
}
DbgPrint("usb-hub: root-port scan complete; attempted=%u configured=%u\n", attempted, configured);
DbgPrint("usb-hub: hcd=%02x:%02x.%u root-port scan complete; attempted=%u configured=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, attempted, configured);
uintptr_t flags = KeAcquireSpinlock(&hub->PendingLock);
hub->InitialScanComplete = true;
hub->InitialScanInProgress = false;
KeReleaseSpinlock(&hub->PendingLock, flags);
return NTLSTATUS_SUCCESS;
}
// Implements the hub Schedule Root Scan operation.
KSTATUS UsbHubScheduleRootScan(USB_HCD* hcd) {
if (!hcd || !hcd->RootHubContext)
return NTLSTATUS_INVALID_PARAMETER;
USB_HUB_EXTENSION* hub = (USB_HUB_EXTENSION*)hcd->RootHubContext;
if (hub->Kind != UsbHubKindRoot || !hub->Started)
return NTLSTATUS_OBJECT_DEAD;
static SEMAPHORE* UsbHubQueueInitialScan(USB_HUB_EXTENSION* hub) {
if (!hub || !hub->Started || !hub->WorkerSemaphore)
return (SEMAPHORE*)0;
uintptr_t flags = KeAcquireSpinlock(&hub->PendingLock);
if (!hub->InitialScanComplete && !hub->InitialScanInProgress)
bool pending = !hub->InitialScanComplete && !hub->InitialScanInProgress;
if (pending)
hub->InitialScanPending = true;
KeReleaseSpinlock(&hub->PendingLock, flags);
if (hub->WorkerSemaphore)
KeSignalSemaphore(hub->WorkerSemaphore);
if (!pending)
return (SEMAPHORE*)0;
ObReferenceObject(&hub->WorkerSemaphore->Header);
return hub->WorkerSemaphore;
}
KSTATUS UsbHubScheduleRootScan(USB_HCD* hcd) {
if (!hcd || !hcd->RootHubPdo)
return NTLSTATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&hcd->RootHubLock);
hcd->RootScanRequested = true;
SEMAPHORE* wake = UsbHubQueueInitialScan((USB_HUB_EXTENSION*)hcd->RootHubContext);
KeReleaseSpinlock(&hcd->RootHubLock, flags);
if (wake) {
KeSignalSemaphore(wake);
ObDereferenceObject(&wake->Header);
}
return NTLSTATUS_SUCCESS;
}
@@ -800,8 +851,10 @@ static void UsbHubExternalChangeComplete(USB_URB* urb, void* context) {
return;
hub->ChangeUrbPending = false;
if (!KSUCCESS(urb->Status) || hub->Removed || hub->SurpriseRemoved)
if (!KSUCCESS(urb->Status) || hub->Removed || hub->SurpriseRemoved) {
IoReleaseRemoveLock(&hub->RemoveLock, (IRP*)0);
return;
}
uint32_t actual = urb->ActualLength;
if (actual > USB_HUB_CHANGE_BITMAP_BYTES)
@@ -813,6 +866,7 @@ static void UsbHubExternalChangeComplete(USB_URB* urb, void* context) {
if (byteIndex < actual && (hub->ChangeBitmap[byteIndex] & (1u << bit)))
UsbHubQueueExternalPortChange(hub, port);
}
IoReleaseRemoveLock(&hub->RemoveLock, (IRP*)0);
}
// Implements the hub Arm External Interrupt operation.
@@ -820,6 +874,10 @@ static void UsbHubArmExternalInterrupt(USB_HUB_EXTENSION* hub) {
if (!hub || !hub->InterruptPipe || !hub->ChangeBitmap || hub->ChangeUrbPending)
return;
KSTATUS refStatus = IoAcquireRemoveLock(&hub->RemoveLock, (IRP*)0);
if (!KSUCCESS(refStatus))
return;
hub->ChangeUrbPending = true;
memset(hub->ChangeBitmap, 0, USB_HUB_CHANGE_BITMAP_BYTES);
memset(&hub->ChangeUrb, 0, sizeof(hub->ChangeUrb));
hub->ChangeUrb.Function = UrbFunctionInterruptTransfer;
@@ -835,11 +893,12 @@ static void UsbHubArmExternalInterrupt(USB_HUB_EXTENSION* hub) {
hub->ChangeUrb.CompleteContext = hub;
KSTATUS st = UsbSubmitUrbAsync(hub->LowerDevice, &hub->ChangeUrb);
if (st == NTLSTATUS_PENDING) {
hub->ChangeUrbPending = true;
} else if (!KSUCCESS(st)) {
if (st != NTLSTATUS_PENDING || hub->ChangeUrb.Status != NTLSTATUS_PENDING) {
hub->ChangeUrbPending = false;
IoReleaseRemoveLock(&hub->RemoveLock, (IRP*)0);
DbgPrint("usb-hub: slot=%u interrupt arm failed st=0x%x\n",
hub->Device ? hub->Device->SlotId : 0, st);
hub->Device ? hub->Device->SlotId : 0,
st == NTLSTATUS_PENDING ? hub->ChangeUrb.Status : st);
}
}
@@ -853,12 +912,30 @@ static KSTATUS UsbHubStartRootDevice(DEVICE_OBJECT* device, USB_HUB_EXTENSION* h
if (!KSUCCESS(st))
return st;
hub->Started = true;
device->PnpState = DevicePnpStarted;
if (hub->HubPdo)
hub->HubPdo->PnpState = DevicePnpStarted;
DbgPrint("usb-hub: root hub started ports=%u\n", hub->PortCount);
uintptr_t flags = KeAcquireSpinlock(&hub->Hcd->RootHubLock);
hub->Started = true;
SEMAPHORE* wake = hub->Hcd->RootScanRequested ? UsbHubQueueInitialScan(hub) : (SEMAPHORE*)0;
KeReleaseSpinlock(&hub->Hcd->RootHubLock, flags);
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)hub->Hcd->ControllerContext;
if (xhci)
DbgPrint("usb-hub: hcd=%02x:%02x.%u root hub started ports=%u scan=%s\n",
xhci->Bus, xhci->Dev, xhci->Fn, hub->PortCount,
wake ? "queued" : "not-queued");
// Publish the startup checkpoint before waking enumeration. A bad port or
// an interrupt storm can otherwise hide which hub started the work.
if (wake) {
KeSignalSemaphore(wake);
ObDereferenceObject(&wake->Header);
if (xhci)
DbgPrint("usb-stage: hcd=%02x:%02x.%u initial scan wake returned\n",
xhci->Bus, xhci->Dev, xhci->Fn);
}
return NTLSTATUS_SUCCESS;
}
@@ -888,10 +965,24 @@ static KSTATUS UsbHubStartExternalDevice(DEVICE_OBJECT* device, USB_HUB_EXTENSIO
}
hub->PowerOnToPowerGoodMs = desc.bPwrOn2PwrGood ? (uint8_t)(desc.bPwrOn2PwrGood * 2u) : 100u;
// xHCI needs the hub's Slot Context before routing low/full-speed child
// transfers through a high-speed transaction translator.
XHCI_CONTROLLER* xhci = hub->Hcd ? (XHCI_CONTROLLER*)hub->Hcd->ControllerContext : (XHCI_CONTROLLER*)0;
XHCI_DEVICE* xdev = xhci && hub->Device->SlotId <= XHCI_MAX_TRACKED_SLOTS
? &xhci->Devices[hub->Device->SlotId] : (XHCI_DEVICE*)0;
if (!xdev || !xdev->Allocated) {
UsbHubReleaseDma(hub);
return NTLSTATUS_DEVICE_ERROR;
}
st = XhciConfigureHubContext(xhci, xdev, hub->PortCount, desc.wHubCharacteristics);
if (!KSUCCESS(st)) {
UsbHubReleaseDma(hub);
return st;
}
for (uint8_t port = 1; port <= hub->PortCount; port++)
(void)UsbHubSetPortFeature(hub, port, USB_HUB_PORT_FEAT_POWER);
UsbDelayUs(((XHCI_CONTROLLER*)hub->Hcd->ControllerContext)->Ddk,
(uint32_t)hub->PowerOnToPowerGoodMs * 1000u);
UsbDelayUs((uint32_t)hub->PowerOnToPowerGoodMs * 1000u);
st = UsbHubStartWorker(hub);
if (!KSUCCESS(st)) {
@@ -971,12 +1062,22 @@ KSTATUS UsbHubDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
device->PnpState = DevicePnpSurpriseRemoved;
if (hub) {
hub->SurpriseRemoved = true;
if (hub->Kind == UsbHubKindRoot && hub->Hcd) {
uintptr_t flags = KeAcquireSpinlock(&hub->Hcd->RootHubLock);
if (hub->Hcd->RootHubContext == hub)
hub->Hcd->RootHubContext = (void*)0;
hub->Started = false;
KeReleaseSpinlock(&hub->Hcd->RootHubLock, flags);
}
hub->WorkerRunning = false;
if (hub->ChangeUrbPending)
(void)UsbCancelUrb(&hub->ChangeUrb);
if (hub->WorkerSemaphore)
KeSignalSemaphore(hub->WorkerSemaphore);
UsbHubStopWorker(hub);
if (hub->ChangeUrbPending) {
st = UsbCancelUrb(&hub->ChangeUrb);
if (!KSUCCESS(st)) {
IoCompleteRequest(irp, st, 0);
return NTLSTATUS_PENDING;
}
}
// Remove downstream PDOs owned by this hub FDO. The explicit
// slot arrays are still used as the hardware lookup table; the
@@ -1000,23 +1101,34 @@ KSTATUS UsbHubDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
device->PnpState = DevicePnpDeleted;
if (hub) {
hub->Removed = true;
hub->WorkerRunning = false;
if (hub->ChangeUrbPending)
(void)UsbCancelUrb(&hub->ChangeUrb);
(void)UsbRemoveDeviceObjectChildren(device, false);
if (hub->InterruptPipe) {
hub->InterruptPipe->Open = false;
UsbDereferencePipe(hub->InterruptPipe);
hub->InterruptPipe = (USB_PIPE*)0;
if (hub->Kind == UsbHubKindRoot && hub->Hcd) {
uintptr_t flags = KeAcquireSpinlock(&hub->Hcd->RootHubLock);
if (hub->Hcd->RootHubContext == hub)
hub->Hcd->RootHubContext = (void*)0;
hub->Started = false;
KeReleaseSpinlock(&hub->Hcd->RootHubLock, flags);
}
hub->WorkerRunning = false;
UsbHubStopWorker(hub);
if (hub->Kind == UsbHubKindRoot && hub->Hcd && hub->Hcd->RootHubContext == hub)
hub->Hcd->RootHubContext = (void*)0;
if (hub->ChangeUrbPending) {
st = UsbCancelUrb(&hub->ChangeUrb);
if (!KSUCCESS(st)) {
IoCompleteRequest(irp, st, 0);
return NTLSTATUS_PENDING;
}
}
(void)UsbRemoveDeviceObjectChildren(device, false);
if (hub->InterruptPipe)
hub->InterruptPipe->Open = false;
if (hub->RemoveLockReady) {
IoReleaseRemoveLockAndWait(&hub->RemoveLock, irp);
IoDestroyRemoveLock(&hub->RemoveLock);
hub->RemoveLockReady = false;
}
if (hub->InterruptPipe) {
UsbDereferencePipe(hub->InterruptPipe);
hub->InterruptPipe = (USB_PIPE*)0;
}
UsbHubReleaseDma(hub);
}
@@ -1118,7 +1230,9 @@ KSTATUS UsbHubAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObje
}
if (kind == UsbHubKindRoot) {
uintptr_t flags = KeAcquireSpinlock(&hub->Hcd->RootHubLock);
hub->Hcd->RootHubContext = hub;
KeReleaseSpinlock(&hub->Hcd->RootHubLock, flags);
DbgPrint("usb-hub: root hub FDO attached\n");
} else {
DbgPrint("usb-hub: external hub FDO attached slot=%u ep=%02x\n",
@@ -1135,5 +1249,5 @@ KSTATUS UsbInitializeHubDriver(void) {
gUsbHubDriver.IdTable = &gUsbHubIdTable;
gUsbHubDriver.DriverAddDevice = UsbHubAddDevice;
gUsbHubDriver.MajorFunction[IRP_MJ_PNP] = UsbHubDispatchPnp;
return IoRegisterDriverObject(&gUsbHubDriver);
return NTLSTATUS_SUCCESS;
}
+7 -7
View File
@@ -347,7 +347,7 @@ KSTATUS UsbStorageTestUnitReady(USB_STORAGE_EXTENSION* storage) {
if (KSUCCESS(st)) return NTLSTATUS_SUCCESS;
last = st;
UsbDelayUs(xhci->Ddk, 10000u);
UsbDelayUs(10000u);
}
return last;
@@ -468,7 +468,7 @@ void UsbStorageAcquireIo(USB_STORAGE_EXTENSION* storage) {
if (!storage) return;
XHCI_CONTROLLER* xhci = storage->Device ? (XHCI_CONTROLLER*)storage->Device->Hcd->ControllerContext : (XHCI_CONTROLLER*)0;
while (NtlAtomicCompareExchange32(&storage->IoBusy, 1, 0) != 0) {
if (xhci) UsbDelayUs(xhci->Ddk, 10);
if (xhci) UsbDelayUs(10);
}
}
@@ -584,10 +584,10 @@ KSTATUS XhciAllocateMassStorageMemory(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
dev->MassOutRing = (XHCI_TRB*)UsbDmaAllocPages(xhci, 1, &dev->MassOutRingDeviceAddress, &dev->MassOutRingDma);
dev->MassBuffer = (uint8_t*)UsbDmaAllocPages(xhci, USB_STORAGE_DMA_PAGES, &dev->MassBufferDeviceAddress, &dev->MassBufferDma);
if (!dev->MassInRing || !dev->MassOutRing || !dev->MassBuffer) {
if (gUsbDdk && gUsbDdk->Dma) {
gUsbDdk->Dma->FreeCommonBuffer(dev->MassBufferDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->MassOutRingDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->MassInRingDma);
{
IoDmaFreeCommonBuffer(dev->MassBufferDma);
IoDmaFreeCommonBuffer(dev->MassOutRingDma);
IoDmaFreeCommonBuffer(dev->MassInRingDma);
}
dev->MassBufferDma = (IO_DMA_BUFFER*)0;
dev->MassOutRingDma = (IO_DMA_BUFFER*)0;
@@ -1059,5 +1059,5 @@ KSTATUS UsbInitializeStorageDriver(void) {
gUsbStorageDriver.MajorFunction[IRP_MJ_WRITE] = UsbStorageDispatchReadWrite;
gUsbStorageDriver.MajorFunction[IRP_MJ_FLUSH_BUFFERS] = UsbStorageDispatchFlush;
gUsbStorageDriver.MajorFunction[IRP_MJ_PNP] = UsbStorageDispatchPnp;
return IoRegisterDriverObject(&gUsbStorageDriver);
return NTLSTATUS_SUCCESS;
}
+293 -104
View File
@@ -48,27 +48,22 @@ void XhciWrite64(volatile uint8_t* base, uint32_t reg, uint64_t value) {
}
// Implements the delay Us operation.
void UsbDelayUs(const NTL_DDK* ddk, uint32_t us) {
if (ddk && ddk->Timer && ddk->Timer->Stall) ddk->Timer->Stall(us);
else {
for (uint32_t i = 0; i < us * 32u; i++) _mm_pause();
}
void UsbDelayUs(uint32_t us) {
KeStallExecution(us);
}
bool UsbWaitSet32(const NTL_DDK* ddk, volatile uint8_t* base, uint32_t reg,
uint32_t mask, uint32_t timeoutUs) {
bool UsbWaitSet32(volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs) {
for (uint32_t i = 0; i < timeoutUs; i++) {
if ((XhciRead32(base, reg) & mask) == mask) return true;
UsbDelayUs(ddk, 1);
UsbDelayUs(1);
}
return false;
}
bool UsbWaitClear32(const NTL_DDK* ddk, volatile uint8_t* base, uint32_t reg,
uint32_t mask, uint32_t timeoutUs) {
bool UsbWaitClear32(volatile uint8_t* base, uint32_t reg, uint32_t mask, uint32_t timeoutUs) {
for (uint32_t i = 0; i < timeoutUs; i++) {
if ((XhciRead32(base, reg) & mask) == 0) return true;
UsbDelayUs(ddk, 1);
UsbDelayUs(1);
}
return false;
}
@@ -83,7 +78,7 @@ void* UsbDmaAllocPages(XHCI_CONTROLLER* xhci,
return (void*)0;
IO_DMA_BUFFER* buffer = (IO_DMA_BUFFER*)0;
KSTATUS status = xhci->Ddk->Dma->AllocateCommonBuffer(xhci->DmaAdapter,
KSTATUS status = IoDmaAllocateCommonBuffer(xhci->DmaAdapter,
pages * (size_t)PAGE_SIZE,
PAGE_SIZE,
&buffer);
@@ -93,14 +88,14 @@ void* UsbDmaAllocPages(XHCI_CONTROLLER* xhci,
return (void*)0;
}
*outDeviceAddress = xhci->Ddk->Dma->GetCommonBufferDeviceAddress(buffer);
*outDeviceAddress = IoDmaGetCommonBufferDeviceAddress(buffer);
*outBuffer = buffer;
return xhci->Ddk->Dma->GetCommonBufferAddress(buffer);
return IoDmaGetCommonBufferAddress(buffer);
}
// Releases all DMA allocations owned by one xHCI slot.
void XhciReleaseDeviceDma(XHCI_DEVICE* dev) {
if (!dev || !gUsbDdk || !gUsbDdk->Dma)
if (!dev)
return;
for (uint32_t endpoint = 1; endpoint < 32; endpoint++) {
@@ -110,15 +105,15 @@ void XhciReleaseDeviceDma(XHCI_DEVICE* dev) {
UsbDereferencePipe(pipe);
}
gUsbDdk->Dma->FreeCommonBuffer(dev->MassBufferDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->HidBufferDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->DescriptorDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->MassOutRingDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->MassInRingDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->HidRingDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->Ep0RingDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->DeviceContextDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->InputContextDma);
IoDmaFreeCommonBuffer(dev->MassBufferDma);
IoDmaFreeCommonBuffer(dev->HidBufferDma);
IoDmaFreeCommonBuffer(dev->DescriptorDma);
IoDmaFreeCommonBuffer(dev->MassOutRingDma);
IoDmaFreeCommonBuffer(dev->MassInRingDma);
IoDmaFreeCommonBuffer(dev->HidRingDma);
IoDmaFreeCommonBuffer(dev->Ep0RingDma);
IoDmaFreeCommonBuffer(dev->DeviceContextDma);
IoDmaFreeCommonBuffer(dev->InputContextDma);
dev->MassBufferDma = (IO_DMA_BUFFER*)0;
dev->HidBufferDma = (IO_DMA_BUFFER*)0;
@@ -143,22 +138,22 @@ void XhciReleaseDeviceDma(XHCI_DEVICE* dev) {
// Releases controller-wide xHCI DMA allocations.
static void XhciReleaseControllerDma(XHCI_CONTROLLER* xhci) {
if (!xhci || !xhci->Ddk || !xhci->Ddk->Dma)
if (!xhci)
return;
for (uint32_t slot = 1; slot <= XHCI_MAX_TRACKED_SLOTS; slot++)
XhciReleaseDeviceDma(&xhci->Devices[slot]);
for (uint16_t i = 0; i < XHCI_MAX_SCRATCHPADS; i++) {
xhci->Ddk->Dma->FreeCommonBuffer(xhci->ScratchpadDma[i]);
IoDmaFreeCommonBuffer(xhci->ScratchpadDma[i]);
xhci->ScratchpadDma[i] = (IO_DMA_BUFFER*)0;
xhci->ScratchpadDeviceAddress[i] = 0;
}
xhci->Ddk->Dma->FreeCommonBuffer(xhci->ScratchpadArrayDma);
xhci->Ddk->Dma->FreeCommonBuffer(xhci->ErstDma);
xhci->Ddk->Dma->FreeCommonBuffer(xhci->EventRingDma);
xhci->Ddk->Dma->FreeCommonBuffer(xhci->CommandRingDma);
xhci->Ddk->Dma->FreeCommonBuffer(xhci->DcbaaDma);
IoDmaFreeCommonBuffer(xhci->ScratchpadArrayDma);
IoDmaFreeCommonBuffer(xhci->ErstDma);
IoDmaFreeCommonBuffer(xhci->EventRingDma);
IoDmaFreeCommonBuffer(xhci->CommandRingDma);
IoDmaFreeCommonBuffer(xhci->DcbaaDma);
xhci->ScratchpadArrayDma = (IO_DMA_BUFFER*)0;
xhci->ErstDma = (IO_DMA_BUFFER*)0;
xhci->EventRingDma = (IO_DMA_BUFFER*)0;
@@ -170,7 +165,7 @@ static void XhciReleaseControllerDma(XHCI_CONTROLLER* xhci) {
xhci->CommandRing = (XHCI_TRB*)0;
xhci->Dcbaa = (uint64_t*)0;
xhci->Ddk->Dma->PutAdapter(xhci->DmaAdapter);
IoDmaPutAdapter(xhci->DmaAdapter);
xhci->DmaAdapter = (IO_DMA_ADAPTER*)0;
}
@@ -220,6 +215,76 @@ uint32_t* XhciInputEndpointContext(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
return (uint32_t*)(dev->InputContext + (uint32_t)(endpointId + 1u) * xhci->ContextBytes);
}
// Reconstructs the addressed device topology when configuring an endpoint or hub.
// Configure Endpoint must not discard route, TT, or hub attributes on the slot.
void XhciBuildConfigureSlotContext(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
uint32_t* slot, uint8_t endpointId) {
if (!xhci || !dev || !slot)
return;
memset(slot, 0, xhci->ContextBytes);
uint8_t lastContext = endpointId;
if (dev->DeviceContext) {
uint32_t previous = ((const uint32_t*)dev->DeviceContext)[0];
uint8_t previousLast = (uint8_t)((previous >> 27) & 31u);
if (previousLast > lastContext)
lastContext = previousLast;
}
uint8_t rootPort = dev->Path.RootPort ? dev->Path.RootPort : dev->Port;
slot[0] = XHCI_CONTEXT_ENTRIES(lastContext) | XHCI_SLOT_SPEED(dev->Speed) |
(dev->Path.RouteString & 0xfffffu);
slot[1] = XHCI_SLOT_ROOT_PORT(rootPort);
if (dev->Path.BehindHub && dev->Speed <= 2u && dev->Path.ParentHubSlot) {
slot[2] = (uint32_t)dev->Path.ParentHubSlot |
((uint32_t)dev->Path.ParentHubPort << 8);
}
if (dev->HubPortCount) {
slot[0] |= XHCI_SLOT_HUB;
slot[1] |= XHCI_SLOT_PORT_COUNT(dev->HubPortCount);
if (dev->Speed == 3u)
slot[2] |= XHCI_SLOT_TT_THINK(dev->HubCharacteristics >> 5);
}
}
// Publishes an external hub's topology to xHCI before its child ports are used.
KSTATUS XhciConfigureHubContext(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
uint8_t portCount, uint16_t characteristics) {
if (!xhci || !dev || !dev->Addressed || !dev->InputContext ||
!dev->DeviceContext || !portCount)
return NTLSTATUS_INVALID_PARAMETER;
uint8_t oldPortCount = dev->HubPortCount;
uint16_t oldCharacteristics = dev->HubCharacteristics;
dev->HubPortCount = portCount;
dev->HubCharacteristics = characteristics;
memset(dev->InputContext, 0, PAGE_SIZE);
uint32_t* icc = XhciInputControlContext(xhci, dev);
uint32_t* slot = XhciInputSlotContext(xhci, dev);
// Update only the slot context; existing endpoint contexts remain active.
icc[1] = 1u;
XhciBuildConfigureSlotContext(xhci, dev, slot, 1u);
XHCI_COMMAND_RESULT result;
memset(&result, 0, sizeof(result));
DbgPrint("usb-stage: hcd=%02x:%02x.%u hub-slot=%u configure-context begin ports=%u tt=%u speed=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, dev->SlotId,
portCount, (characteristics >> 5) & 3u, dev->Speed);
KSTATUS st = XhciSubmitCommand(xhci, dev->InputContextDeviceAddress, 0,
(XHCI_TRB_TYPE_CONFIGURE_ENDPOINT << XHCI_TRB_TYPE_SHIFT) |
((uint32_t)dev->SlotId << 24),
&result);
if (!KSUCCESS(st) || result.CompletionCode != XHCI_CC_SUCCESS) {
DbgPrint("usb-stage: hub-slot=%u configure-context failed st=0x%x cc=%u\n",
dev->SlotId, st, result.CompletionCode);
dev->HubPortCount = oldPortCount;
dev->HubCharacteristics = oldCharacteristics;
return KSUCCESS(st) ? NTLSTATUS_DEVICE_ERROR : st;
}
DbgPrint("usb-stage: hub-slot=%u configure-context done\n", dev->SlotId);
return NTLSTATUS_SUCCESS;
}
// Implements the ep Max Packet operation.
uint32_t XhciEpMaxPacket(uint8_t speed) {
switch (speed) {
@@ -254,6 +319,15 @@ const char* XhciPortSpeedName(uint32_t speed) {
}
}
// Advances an xHCI extended-capability offset using the relative DWORD link.
static uint32_t XhciNextExtendedCapabilityDword(uint32_t current, uint8_t next,
uint32_t mappedBytes) {
if (!next) return 0;
uint64_t following = (uint64_t)current + next;
if (following * 4u + sizeof(uint32_t) > mappedBytes) return 0;
return (uint32_t)following;
}
// Parses supported Protocols.
void XhciParseSupportedProtocols(XHCI_CONTROLLER* xhci) {
memset(xhci->PortProtocolMajor, 0, sizeof(xhci->PortProtocolMajor));
@@ -297,8 +371,18 @@ void XhciParseSupportedProtocols(XHCI_CONTROLLER* xhci) {
}
}
xecp = next;
xecp = XhciNextExtendedCapabilityDword(xecp, next, xhci->MmioBytes);
}
uint32_t usb2Ports = 0;
uint32_t usb3Ports = 0;
for (uint32_t port = 1; port <= xhci->MaxPorts; port++) {
if (xhci->PortProtocolMajor[port] == 2u) usb2Ports++;
else if (xhci->PortProtocolMajor[port] >= 3u) usb3Ports++;
}
DbgPrint("usb: xHCI hcd=%02x:%02x.%u protocol ports usb2=%u usb3=%u unknown=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, usb2Ports, usb3Ports,
(uint32_t)xhci->MaxPorts - usb2Ports - usb3Ports);
}
// Implements the port Protocol Major operation.
@@ -385,7 +469,7 @@ void XhciPowerRootPorts(XHCI_CONTROLLER* xhci) {
}
if (powered) {
UsbDelayUs(xhci->Ddk, 20000u);
UsbDelayUs(20000u);
DbgPrint("usb: xHCI powered %u previously-off root port(s)\n", powered);
}
}
@@ -465,12 +549,43 @@ static XHCI_WAIT_TARGET* XhciClaimTransferWaiter(XHCI_CONTROLLER* xhci,
return w;
}
// Implements the drain Event Ring operation.
bool XhciDrainEventRing(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target) {
(void)target;
bool processed = false;
// A completion leaves EventLock with its class-device rundown reference held.
// Client callbacks can rearm transfers or acquire unrelated PnP locks.
#define XHCI_COMPLETION_BATCH 16u
while (true) {
typedef struct XHCI_ASYNC_COMPLETION {
USB_URB* Urb;
IRP* Irp;
KSTATUS Status;
uint32_t ActualLength;
} XHCI_ASYNC_COMPLETION;
// Claims an asynchronous TD exactly once while the event lock is owned.
static bool XhciClaimAsyncCompletion(XHCI_CONTROLLER* xhci, uint64_t trbAddress,
uint32_t completionCode, uint8_t slotId,
uint8_t endpointId, uint32_t residue,
XHCI_ASYNC_COMPLETION* completion);
// Executes callbacks outside the event lock; class remove locks own their lifetime.
static void XhciDispatchAsyncCompletion(const XHCI_ASYNC_COMPLETION* completed) {
USB_URB* urb = completed->Urb;
if (urb->Complete)
urb->Complete(urb, urb->CompleteContext);
if (completed->Irp)
IoCompleteRequest(completed->Irp, completed->Status,
KSUCCESS(completed->Status) ? completed->ActualLength : 0);
}
// Drains a bounded batch while the event lock is held.
static bool XhciDrainEventRing(XHCI_CONTROLLER* xhci,
XHCI_ASYNC_COMPLETION* completions, uint32_t* completionCount,
uint32_t* changedPorts) {
bool processed = false;
*completionCount = 0;
for (uint32_t drained = 0; drained < XHCI_EVENT_TRBS; drained++) {
if (*completionCount == XHCI_COMPLETION_BATCH)
break;
XHCI_TRB* ev = &xhci->EventRing[xhci->EventDequeue];
uint32_t control = ev->Control;
uint8_t cycle = (uint8_t)(control & XHCI_TRB_CYCLE);
@@ -495,15 +610,15 @@ bool XhciDrainEventRing(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target) {
UsbTrace("usb: xHCI transfer event trb=0x%016llX cc=%u slot=%u ep=%u residue=%u\n",
(unsigned long long)param, cc, slotId, epId, residue);
}
XHCI_WAIT_TARGET* waiter = XhciClaimTransferWaiter(xhci, param, slotId, epId, cc, residue);
if (!waiter)
XhciHandleAsyncTransferEvent(xhci, param, cc, slotId, epId, residue);
if (!waiter && XhciClaimAsyncCompletion(xhci, param, cc, slotId, epId, residue,
&completions[*completionCount]))
(*completionCount)++;
} else if (type == XHCI_TRB_TYPE_PORT_SC) {
uint32_t portId = ev->ParameterLo >> 24;
UsbTrace("usb: xHCI port-status-change event port=%u cc=%u\n", portId, cc);
if (portId && portId <= xhci->MaxPorts)
UsbHubQueueRootPortChange(&xhci->Hcd, (uint8_t)portId);
if (portId && portId <= xhci->MaxPorts && portId <= USB_ROOT_HUB_MAX_PORTS)
changedPorts[portId / 32u] |= 1u << (portId & 31u);
} else {
DbgPrint("usb: xHCI event type=%u cc=%u p=0x%016llX status=%08x ctrl=%08x\n",
type, cc, (unsigned long long)param, ev->Status, ev->Control);
@@ -521,12 +636,27 @@ bool XhciDrainEventRing(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target) {
return processed;
}
// Implements the drain Event Ring Locked operation.
// Serializes event-ring ownership without calling into class drivers under the lock.
bool XhciDrainEventRingLocked(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target) {
(void)target;
if (!xhci) return false;
XHCI_ASYNC_COMPLETION completions[XHCI_COMPLETION_BATCH];
uint32_t changedPorts[8] = { 0 };
uint32_t count = 0;
uintptr_t flags = KeAcquireSpinlock(&xhci->EventLock);
bool processed = XhciDrainEventRing(xhci, target);
bool processed = XhciDrainEventRing(xhci, completions, &count, changedPorts);
KeReleaseSpinlock(&xhci->EventLock, flags);
// Hub wakeups can take scheduler locks; keep them outside EventLock too.
for (uint32_t word = 0; word < 8; word++) {
uint32_t bits = changedPorts[word];
for (uint32_t bit = 0; bit < 32; bit++) {
if (bits & (1u << bit))
UsbHubQueueRootPortChange(&xhci->Hcd, (uint8_t)(word * 32u + bit));
}
}
for (uint32_t i = 0; i < count; i++)
XhciDispatchAsyncCompletion(&completions[i]);
return processed;
}
@@ -591,7 +721,7 @@ KSTATUS XhciWaitForArmedTarget(XHCI_CONTROLLER* xhci, XHCI_WAIT_TARGET* target,
KeInsertQueueDpc(&xhci->EventDpc, (void*)0, (void*)0);
}
UsbDelayUs(xhci->Ddk, 1);
UsbDelayUs(1);
}
XhciUnregisterWaitTarget(xhci, target);
@@ -617,9 +747,17 @@ void XhciEventDpcRoutine(KDPC* dpc, void* context,
return;
xhci->EventDpcCount++;
while (XhciDrainEventRingLocked(xhci, NULL)) {
// Keep draining until the software dequeue catches up to the producer.
// Processing is bounded even if connected hubs continuously report changes.
// Updating ERDP clears EHB; remaining events cause the interrupter to
// assert again, allowing other DPCs and scheduled threads to make progress.
for (uint32_t pass = 0; pass < 4u; pass++) {
if (!XhciDrainEventRingLocked(xhci, NULL))
return;
}
uint32_t hits = ++xhci->EventDpcBudgetHits;
if ((hits & (hits - 1u)) == 0u)
DbgPrint("usb: xHCI hcd=%02x:%02x.%u event DPC budget reached count=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, hits);
}
#define XHCI_CONTROLLER_MAGIC 0x58484349u // XHCI
@@ -700,7 +838,7 @@ KSTATUS XhciBiosHandoff(XHCI_CONTROLLER* xhci) {
ok = true;
break;
}
UsbDelayUs(xhci->Ddk, 1);
UsbDelayUs(1);
}
if (!ok) {
DbgPrint("usb: xHCI BIOS handoff timed out; continuing anyway\n");
@@ -712,7 +850,7 @@ KSTATUS XhciBiosHandoff(XHCI_CONTROLLER* xhci) {
return NTLSTATUS_SUCCESS;
}
xecp = next;
xecp = XhciNextExtendedCapabilityDword(xecp, next, xhci->MmioBytes);
}
return NTLSTATUS_SUCCESS;
@@ -723,7 +861,7 @@ KSTATUS XhciStopAndReset(XHCI_CONTROLLER* xhci) {
uint32_t cmd = XhciRead32(xhci->Op, XHCI_OP_USBCMD);
if (cmd & XHCI_USBCMD_RS) {
XhciWrite32(xhci->Op, XHCI_OP_USBCMD, cmd & ~XHCI_USBCMD_RS);
if (!UsbWaitSet32(xhci->Ddk, xhci->Op, XHCI_OP_USBSTS,
if (!UsbWaitSet32(xhci->Op, XHCI_OP_USBSTS,
XHCI_USBSTS_HCH, 1000000u)) {
DbgPrint("usb: xHCI stop timeout usbsts=%08x\n",
XhciRead32(xhci->Op, XHCI_OP_USBSTS));
@@ -732,14 +870,14 @@ KSTATUS XhciStopAndReset(XHCI_CONTROLLER* xhci) {
}
XhciWrite32(xhci->Op, XHCI_OP_USBCMD, XHCI_USBCMD_HCRST);
if (!UsbWaitClear32(xhci->Ddk, xhci->Op, XHCI_OP_USBCMD,
if (!UsbWaitClear32(xhci->Op, XHCI_OP_USBCMD,
XHCI_USBCMD_HCRST, 1000000u)) {
DbgPrint("usb: xHCI reset timeout usbcmd=%08x\n",
XhciRead32(xhci->Op, XHCI_OP_USBCMD));
return NTLSTATUS_TIMEOUT;
}
if (!UsbWaitClear32(xhci->Ddk, xhci->Op, XHCI_OP_USBSTS,
if (!UsbWaitClear32(xhci->Op, XHCI_OP_USBSTS,
XHCI_USBSTS_CNR, 1000000u)) {
DbgPrint("usb: xHCI controller-not-ready timeout usbsts=%08x\n",
XhciRead32(xhci->Op, XHCI_OP_USBSTS));
@@ -769,8 +907,7 @@ static void XhciHaltForDmaRelease(XHCI_CONTROLLER* xhci) {
uint32_t command = XhciRead32(xhci->Op, XHCI_OP_USBCMD);
command &= ~(XHCI_USBCMD_RS | XHCI_USBCMD_INTE);
XhciWrite32(xhci->Op, XHCI_OP_USBCMD, command);
if (!UsbWaitSet32(xhci->Ddk,
xhci->Op,
if (!UsbWaitSet32(xhci->Op,
XHCI_OP_USBSTS,
XHCI_USBSTS_HCH,
1000000u))
@@ -1048,7 +1185,7 @@ KSTATUS XhciStart(XHCI_CONTROLLER* xhci) {
cmd |= XHCI_USBCMD_RS;
XhciWrite32(xhci->Op, XHCI_OP_USBCMD, cmd);
if (!UsbWaitClear32(xhci->Ddk, xhci->Op, XHCI_OP_USBSTS,
if (!UsbWaitClear32(xhci->Op, XHCI_OP_USBSTS,
XHCI_USBSTS_HCH, 1000000u)) {
DbgPrint("usb: xHCI start timeout usbsts=%08x\n",
XhciRead32(xhci->Op, XHCI_OP_USBSTS));
@@ -1099,6 +1236,8 @@ KSTATUS XhciResetPort(XHCI_CONTROLLER* xhci, uint8_t port, uint8_t* outSpeed) {
uint32_t speed = (portsc & XHCI_PORTSC_SPEED_MASK) >> XHCI_PORTSC_SPEED_SHIFT;
uint8_t protocol = XhciPortProtocolMajor(xhci, port, portsc);
DbgPrint("usb-stage: hcd=%02x:%02x.%u root-port=%u reset begin proto=%u speed=%u portsc=%08x\n",
xhci->Bus, xhci->Dev, xhci->Fn, port, protocol, speed, portsc);
XhciClearPortChanges(xhci, port);
portsc = XhciRead32(xhci->Op, off);
@@ -1120,7 +1259,7 @@ KSTATUS XhciResetPort(XHCI_CONTROLLER* xhci, uint8_t port, uint8_t* outSpeed) {
break;
}
XhciDrainEventRingLocked(xhci, NULL);
UsbDelayUs(xhci->Ddk, 1);
UsbDelayUs(1);
}
XhciClearPortChanges(xhci, port);
@@ -1133,6 +1272,8 @@ KSTATUS XhciResetPort(XHCI_CONTROLLER* xhci, uint8_t port, uint8_t* outSpeed) {
(portsc & XHCI_PORTSC_PED) ? 1u : 0u,
protocol, XhciPortSpeedName(speed), speed);
DbgPrint("usb-stage: hcd=%02x:%02x.%u root-port=%u superspeed ready=%u portsc=%08x\n",
xhci->Bus, xhci->Dev, xhci->Fn, port, enabled ? 1u : 0u, portsc);
if (!enabled || !(portsc & XHCI_PORTSC_CCS) || !(portsc & XHCI_PORTSC_PED))
return NTLSTATUS_DEVICE_ERROR;
return NTLSTATUS_SUCCESS;
@@ -1149,11 +1290,12 @@ KSTATUS XhciResetPort(XHCI_CONTROLLER* xhci, uint8_t port, uint8_t* outSpeed) {
break;
}
XhciDrainEventRingLocked(xhci, NULL);
UsbDelayUs(xhci->Ddk, 1);
UsbDelayUs(1);
}
if (!resetDone) {
DbgPrint("usb: xHCI port %u reset timeout portsc=%08x\n", port, portsc);
DbgPrint("usb: xHCI hcd=%02x:%02x.%u port %u reset timeout portsc=%08x\n",
xhci->Bus, xhci->Dev, xhci->Fn, port, portsc);
return NTLSTATUS_TIMEOUT;
}
@@ -1167,6 +1309,8 @@ KSTATUS XhciResetPort(XHCI_CONTROLLER* xhci, uint8_t port, uint8_t* outSpeed) {
(portsc & XHCI_PORTSC_PED) ? 1u : 0u,
protocol, XhciPortSpeedName(speed), speed);
DbgPrint("usb-stage: hcd=%02x:%02x.%u root-port=%u reset done portsc=%08x speed=%u\n",
xhci->Bus, xhci->Dev, xhci->Fn, port, portsc, speed);
if (!(portsc & XHCI_PORTSC_CCS) || !(portsc & XHCI_PORTSC_PED))
return NTLSTATUS_DEVICE_ERROR;
@@ -1674,10 +1818,7 @@ KSTATUS XhciConfigurePipeEndpoint(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, USB_P
icc[0] = 0;
icc[1] = (1u << 0) | (1u << dci);
slot[0] = XHCI_CONTEXT_ENTRIES(dci) | XHCI_SLOT_SPEED(dev->Speed);
slot[1] = XHCI_SLOT_ROOT_PORT(dev->Port);
slot[2] = 0;
slot[3] = 0;
XhciBuildConfigureSlotContext(xhci, dev, slot, dci);
uint16_t maxPacket = pipe->MaxPacketSize & 0x07FFu;
if (maxPacket == 0) maxPacket = 8u;
@@ -1692,7 +1833,7 @@ KSTATUS XhciConfigurePipeEndpoint(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, USB_P
} else if (pipe->Type == UsbPipeBulk) {
endpointType = XHCI_EP_TYPE_BULK_OUT;
} else {
xhci->Ddk->Dma->FreeCommonBuffer(ctx->RingDma);
IoDmaFreeCommonBuffer(ctx->RingDma);
MmFreePool(ctx);
return NTLSTATUS_NOT_SUPPORTED;
}
@@ -1715,7 +1856,7 @@ KSTATUS XhciConfigurePipeEndpoint(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev, USB_P
if (!KSUCCESS(st) || result.CompletionCode != XHCI_CC_SUCCESS) {
DbgPrint("usb: Configure pipe endpoint failed slot=%u ep=%u type=%u st=0x%x cc=%u\n",
dev->SlotId, dci, pipe->Type, st, result.CompletionCode);
xhci->Ddk->Dma->FreeCommonBuffer(ctx->RingDma);
IoDmaFreeCommonBuffer(ctx->RingDma);
MmFreePool(ctx);
return KSUCCESS(st) ? NTLSTATUS_DEVICE_ERROR : st;
}
@@ -1740,8 +1881,15 @@ static KSTATUS XhciHcdSubmitInterruptUrb(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev
XHCI_PIPE_CONTEXT* ctx = (XHCI_PIPE_CONTEXT*)urb->Pipe->HcdPipeContext;
if (!ctx || !ctx->Configured)
return NTLSTATUS_DEVICE_ERROR;
if (ctx->ActiveTransfer)
uintptr_t flags = KeAcquireSpinlock(&xhci->EventLock);
if (ctx->ActiveTransfer) {
KeReleaseSpinlock(&xhci->EventLock, flags);
return NTLSTATUS_QUEUE_FULL;
}
if (urb->Pipe->Halted) {
KeReleaseSpinlock(&xhci->EventLock, flags);
return NTLSTATUS_OBJECT_DEAD;
}
uint64_t trbDeviceAddress = 0;
st = XhciRingAppend(ctx->Ring,
@@ -1755,7 +1903,10 @@ static KSTATUS XhciHcdSubmitInterruptUrb(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev
XHCI_TRB_ISP |
XHCI_TRB_IOC,
&trbDeviceAddress);
if (!KSUCCESS(st)) return st;
if (!KSUCCESS(st)) {
KeReleaseSpinlock(&xhci->EventLock, flags);
return st;
}
ctx->ActiveTransfer = true;
ctx->ActiveTrbDeviceAddress = trbDeviceAddress;
@@ -1768,58 +1919,51 @@ static KSTATUS XhciHcdSubmitInterruptUrb(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev
XhciBarrier();
XhciWrite32(xhci->Doorbells, (uint32_t)dev->SlotId * 4u, ctx->EndpointId);
KeReleaseSpinlock(&xhci->EventLock, flags);
return NTLSTATUS_PENDING;
}
void XhciHandleAsyncTransferEvent(XHCI_CONTROLLER* xhci, uint64_t trbDeviceAddress,
uint32_t completionCode, uint8_t slotId,
uint8_t endpointId, uint32_t residue) {
if (!xhci || slotId == 0 || slotId > XHCI_MAX_TRACKED_SLOTS || endpointId >= 32)
return;
// Completes ownership of an interrupt URB before its callback is dispatched.
static bool XhciClaimAsyncCompletion(XHCI_CONTROLLER* xhci, uint64_t trbDeviceAddress,
uint32_t completionCode, uint8_t slotId,
uint8_t endpointId, uint32_t residue,
XHCI_ASYNC_COMPLETION* completed) {
if (!xhci || !completed || slotId == 0 || slotId > XHCI_MAX_TRACKED_SLOTS || endpointId >= 32)
return false;
XHCI_DEVICE* dev = &xhci->Devices[slotId];
USB_PIPE* pipe = dev->EndpointPipes[endpointId];
if (!pipe || !pipe->HcdPipeContext)
return;
return false;
XHCI_PIPE_CONTEXT* ctx = (XHCI_PIPE_CONTEXT*)pipe->HcdPipeContext;
if (!ctx->ActiveTransfer || ctx->ActiveTrbDeviceAddress != trbDeviceAddress)
return;
return false;
USB_URB* urb = ctx->ActiveUrb;
ctx->ActiveTransfer = false;
ctx->ActiveTrbDeviceAddress = 0;
ctx->ActiveUrb = (USB_URB*)0;
if (!urb)
return;
return false;
KSTATUS st = NTLSTATUS_SUCCESS;
if (urb->Cancelled) {
if (urb->Cancelled)
st = NTLSTATUS_CANCELLED;
} else if (completionCode != XHCI_CC_SUCCESS &&
completionCode != XHCI_CC_SHORT_PACKET) {
else if (completionCode != XHCI_CC_SUCCESS && completionCode != XHCI_CC_SHORT_PACKET)
st = NTLSTATUS_DEVICE_ERROR;
}
uint32_t actual = 0;
if (KSUCCESS(st)) {
actual = (residue <= urb->Length) ? (urb->Length - residue) : 0;
}
uint32_t actual = KSUCCESS(st) && residue <= urb->Length ? urb->Length - residue : 0;
urb->Pending = false;
urb->Status = st;
urb->ActualLength = actual;
urb->HcdCompletionCode = completionCode;
IRP* completeIrp = urb->Irp;
completed->Urb = urb;
completed->Irp = urb->Irp;
completed->Status = st;
completed->ActualLength = actual;
urb->Irp = (IRP*)0;
if (urb->Complete)
urb->Complete(urb, urb->CompleteContext);
if (completeIrp)
IoCompleteRequest(completeIrp, st, KSUCCESS(st) ? actual : 0);
return true;
}
// Implements the hcd Submit Bulk Urb operation.
@@ -1905,13 +2049,59 @@ static KSTATUS XhciHcdSubmitUrb(USB_HCD* hcd, USB_URB* urb) {
return st;
}
// Implements the hcd Cancel Urb operation.
static KSTATUS XhciHcdCancelUrb(USB_HCD* hcd, USB_URB* urb) {
(void)hcd;
if (!urb) return NTLSTATUS_INVALID_PARAMETER;
if (!hcd || !urb || !urb->Device || !urb->Pipe)
return NTLSTATUS_INVALID_PARAMETER;
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)hcd->ControllerContext;
XHCI_DEVICE* dev = (XHCI_DEVICE*)urb->Device->HcdDeviceContext;
if (!xhci || !dev || dev->SlotId == 0 || !urb->Pipe->HcdPipeContext)
return NTLSTATUS_INVALID_PARAMETER;
XHCI_PIPE_CONTEXT* ctx = (XHCI_PIPE_CONTEXT*)urb->Pipe->HcdPipeContext;
uintptr_t flags = KeAcquireSpinlock(&xhci->EventLock);
urb->Cancelled = true;
if (!urb->Pending)
urb->Status = NTLSTATUS_CANCELLED;
bool active = ctx->ActiveTransfer && ctx->ActiveUrb == urb;
KeReleaseSpinlock(&xhci->EventLock, flags);
if (!active)
return NTLSTATUS_SUCCESS;
XHCI_COMMAND_RESULT result;
memset(&result, 0, sizeof(result));
KSTATUS st = XhciSubmitCommand(xhci, 0, 0,
(XHCI_TRB_TYPE_STOP_ENDPOINT << XHCI_TRB_TYPE_SHIFT) |
((uint32_t)ctx->EndpointId << 16) |
((uint32_t)dev->SlotId << 24),
&result);
flags = KeAcquireSpinlock(&xhci->EventLock);
if (!ctx->ActiveTransfer || ctx->ActiveUrb != urb) {
KeReleaseSpinlock(&xhci->EventLock, flags);
return NTLSTATUS_SUCCESS;
}
if (!KSUCCESS(st) || result.CompletionCode != XHCI_CC_SUCCESS) {
KeReleaseSpinlock(&xhci->EventLock, flags);
DbgPrint("usb: xHCI STOP_ENDPOINT failed slot=%u ep=%u st=0x%x cc=%u\n",
dev->SlotId, ctx->EndpointId, st, result.CompletionCode);
return KSUCCESS(st) ? NTLSTATUS_DEVICE_ERROR : st;
}
ctx->ActiveTransfer = false;
ctx->ActiveTrbDeviceAddress = 0;
ctx->ActiveUrb = (USB_URB*)0;
urb->Pipe->Halted = true;
urb->Pending = false;
urb->Status = NTLSTATUS_CANCELLED;
urb->ActualLength = 0;
urb->HcdCompletionCode = result.CompletionCode;
IRP* completeIrp = urb->Irp;
urb->Irp = (IRP*)0;
KeReleaseSpinlock(&xhci->EventLock, flags);
if (urb->Complete)
urb->Complete(urb, urb->CompleteContext);
if (completeIrp)
IoCompleteRequest(completeIrp, NTLSTATUS_CANCELLED, 0);
return NTLSTATUS_SUCCESS;
}
@@ -1933,8 +2123,7 @@ static void XhciHcdDestroyPipe(USB_HCD* hcd, USB_PIPE* pipe) {
if (!pipe || !pipe->HcdPipeContext)
return;
XHCI_PIPE_CONTEXT* ctx = (XHCI_PIPE_CONTEXT*)pipe->HcdPipeContext;
if (gUsbDdk && gUsbDdk->Dma)
gUsbDdk->Dma->FreeCommonBuffer(ctx->RingDma);
IoDmaFreeCommonBuffer(ctx->RingDma);
ctx->RingDma = (IO_DMA_BUFFER*)0;
ctx->Ring = (XHCI_TRB*)0;
pipe->HcdPipeContext = (void*)0;
@@ -2109,7 +2298,7 @@ KSTATUS XhciStartController(XHCI_CONTROLLER* xhci) {
dmaRequirements.Boundary = 0x10000u;
dmaRequirements.MaximumSegmentLength = 0x10000u;
dmaRequirements.MaximumSegments = XHCI_PIPE_RING_TRBS - 1u;
st = xhci->Ddk->Dma->GetAdapter(xhci->Fdo,
st = IoDmaGetAdapter(xhci->Fdo,
&dmaRequirements,
&xhci->DmaAdapter);
if (!KSUCCESS(st)) {
@@ -2165,7 +2354,7 @@ KSTATUS XhciStartController(XHCI_CONTROLLER* xhci) {
if (!KSUCCESS(st))
DbgPrint("usb: root hub async scan scheduling failed st=0x%x\n", st);
else
DbgPrint("usb: root hub initial scan queued asynchronously\n");
DbgPrint("usb: root hub initial scan requested\n");
DbgPrint("usb: xHCI host controller initialised; HID boot input active=%u mass-storage will arrive through hotplug\n",
xhci->HidDeviceCount);
@@ -2247,7 +2436,7 @@ KSTATUS XhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)fdo->DeviceExtension;
memset(xhci, 0, sizeof(*xhci));
xhci->Magic = XHCI_CONTROLLER_MAGIC;
xhci->Ddk = gUsbDdk;
xhci->Fdo = fdo;
xhci->Pdo = physicalDeviceObject;
xhci->Irq = 0xFFu;
+14 -14
View File
@@ -1,10 +1,9 @@
#include <ntlite/ddk/module.h>
// VMware SVGA-II PCI display provider. This file owns adapter setup, FIFO command submission, framebuffer presentation, and cursor integration.
#include <stdbool.h>
#include "vmwaresvga.h"
const NTL_DDK* gVmwSvgaDdk;
static DRIVER_OBJECT gVmwSvgaDriver;
static const IO_DEVICE_ID gVmwSvgaIds[] = {
@@ -1500,8 +1499,10 @@ static KSTATUS VmwSvgaStartDevice(VMWSVGA_DEVICE* v) {
st = KeDisplaySetPrimary(&v->DisplayDevice);
KeDisplaySuspendConsole(false);
if (!KSUCCESS(st))
if (!KSUCCESS(st)) {
(void)KeDisplayUnregisterDevice(&v->DisplayDevice);
return st;
}
v->Started = true;
v->Fdo->PnpState = DevicePnpStarted;
@@ -1534,11 +1535,15 @@ KSTATUS VmwSvgaDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
return NTLSTATUS_SUCCESS;
case IRP_MN_SURPRISE_REMOVAL:
if (v->DisplayDevice.Ops)
(void)KeDisplayUnregisterDevice(&v->DisplayDevice);
v->SurpriseRemoved = true;
device->PnpState = DevicePnpSurpriseRemoved;
return NTLSTATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
if (v->DisplayDevice.Ops)
(void)KeDisplayUnregisterDevice(&v->DisplayDevice);
v->Removed = true;
device->PnpState = DevicePnpDeleted;
if (v->Backbuffer) {
@@ -1588,23 +1593,18 @@ KSTATUS VmwSvgaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObj
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk)
return NTLSTATUS_INVALID_PARAMETER;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("VMWSVGA: driver loading...\n");
gVmwSvgaDdk = ddk;
memset(&gVmwSvgaDriver, 0, sizeof(gVmwSvgaDriver));
IoInitializeDriverObject(&gVmwSvgaDriver, SYS_SV_LITERAL("vmwaresvga"));
gVmwSvgaDriver.IdTable = &gVmwSvgaIdTable;
gVmwSvgaDriver.DriverAddDevice = VmwSvgaAddDevice;
gVmwSvgaDriver.MajorFunction[IRP_MJ_PNP] = VmwSvgaDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gVmwSvgaDriver);
if (!KSUCCESS(st))
DbgPrint("VMWSVGA: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gVmwSvgaDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
@@ -210,7 +210,5 @@ typedef struct VMWSVGA_DEVICE {
DISPLAY_DEVICE DisplayDevice;
} VMWSVGA_DEVICE;
extern const NTL_DDK* gVmwSvgaDdk;
KSTATUS VmwSvgaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS VmwSvgaDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
+89 -16
View File
@@ -1,17 +1,90 @@
[boot]
pci.sys
hda.sys
ps2.sys
cereal.sys
ahci.sys
ata.sys
usb.sys
fat.sys
ntfs.sys
ext4.sys
; drivers.ini
[runtime]
lwip.sys
vmwaresvga.sys
rtl8139.sys
rtl816x.sys
[class.bus]
[class.storage]
requires=bus
[class.filesystem]
after=storage
[class.usb-host]
requires=bus
[class.network-adapter]
requires=bus
[class.network-stack]
after=network-adapter
[driver.pci]
image=pci.sys
start=boot
class=bus
critical=true
[driver.hda]
image=hda.sys
start=boot
requires=pci
[driver.ps2]
image=ps2.sys
start=boot
[driver.cereal]
image=cereal.sys
start=boot
[driver.ahci]
image=ahci.sys
start=boot
class=storage
[driver.ata]
image=ata.sys
start=boot
class=storage
[driver.usb]
image=usb.sys
start=boot
class=usb-host
[driver.fat]
image=fat.sys
start=boot
class=filesystem
after=usb
[driver.ntfs]
image=ntfs.sys
start=boot
class=filesystem
after=usb
[driver.ext4]
image=ext4.sys
start=boot
class=filesystem
after=usb
[driver.lwip]
image=lwip.sys
start=runtime
class=network-stack
[driver.vmwaresvga]
image=vmwaresvga.sys
start=runtime
requires=pci
[driver.rtl8139]
image=rtl8139.sys
start=runtime
class=network-adapter
[driver.rtl816x]
image=rtl816x.sys
start=runtime
class=network-adapter
+5 -5
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
/*
* NTLite ext2/ext3/ext4 read/write filesystem driver backed by lwext4.
*
@@ -1154,12 +1155,9 @@ static void Ext4PartitionChange(const IO_PARTITION_INFO* partition,
}
}
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("EXT4: Init\n");
if (!ddk)
return NTLSTATUS_INVALID_PARAMETER;
if (init)
init->Name = "ext4";
Ext4ListInit(&gExt4Mounts);
gExt4MountedCount = 0;
@@ -1177,3 +1175,5 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("EXT4: Init complete; mounted %u volume(s).\n", gExt4MountedCount);
return NTLSTATUS_SUCCESS;
}
NTL_DECLARE_MODULE(DriverInitialize);
+6 -4
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
// FAT mount discovery, BPB validation, and driver lifetime.
#include <stdbool.h>
@@ -275,11 +276,10 @@ static void FatPartitionChange(const IO_PARTITION_INFO* partition,
}
// Initializes FAT and subscribes to the authoritative kernel partition stream.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("FAT: Init\n");
if (!ddk)
return NTLSTATUS_INVALID_PARAMETER;
(void)init;
FatCacheInvalidate();
LIST_INIT(&gFatMounts);
@@ -297,3 +297,5 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("FAT: Init complete; mounted %u volume(s).\n", gMountedCount);
return NTLSTATUS_SUCCESS;
}
NTL_DECLARE_MODULE(DriverInitialize);
+6 -4
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
// Native read-only NTFS filesystem driver for NTLite.
// Portions are based on ntfs-efi by Mark Harmstone (2023), GPLv2-or-later.
// The port removes UEFI protocol/header dependencies and targets NTLite's IO_VOLUME_PROVIDER ABI.
@@ -1597,11 +1598,10 @@ static void NtfsPartitionChange(const IO_PARTITION_INFO* partition,
}
// Initializes NTFS and subscribes to the authoritative kernel partition stream.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("NTFS: Init\n");
if (!ddk)
return NTLSTATUS_INVALID_PARAMETER;
(void)init;
LIST_INIT(&gNtfsMounts);
gMountedCount = 0;
@@ -1618,3 +1618,5 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("NTFS: Init complete; mounted %u volume(s).\n", gMountedCount);
return NTLSTATUS_SUCCESS;
}
NTL_DECLARE_MODULE(DriverInitialize);
+5 -5
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
/* NTFS-3G filesystem provider for NTLite. */
#include "config.h"
@@ -1137,12 +1138,9 @@ static void Ntfs3gPartitionChange(const IO_PARTITION_INFO* partition,
}
}
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("NTFS3G: Init (libntfs-3g replacement driver)\n");
if (!ddk)
return NTLSTATUS_INVALID_PARAMETER;
if (init)
init->Name = "ntfs";
Ntfs3gListInit(&gNtfs3gMounts);
gNtfs3gMountedCount = 0;
Ntfs3gEnsureMutexes();
@@ -1152,3 +1150,5 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("NTFS3G: Init complete; mounted %u volume(s).\n", gNtfs3gMountedCount);
return NTLSTATUS_SUCCESS;
}
NTL_DECLARE_MODULE(DriverInitialize);
+37 -4
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
// PS/2 input driver package entry point. This file registers keyboard and mouse devices.
#include "ps2.h"
@@ -14,6 +15,14 @@ static volatile int gMousePacketIndex;
static PS2_MOUSE_PACKET gMouseDpcQueue[MOUSE_DPC_QUEUE_SIZE];
static volatile int gMouseDpcHead;
static volatile int gMouseDpcTail;
static volatile uint32_t gKeyboardIrqCount;
static volatile uint32_t gKeyboardByteCount;
static volatile uint32_t gKeyboardEventCount;
static volatile uint32_t gMouseIrqCount;
static volatile uint32_t gMouseByteCount;
static volatile uint32_t gMousePacketCount;
static volatile uint32_t gKeyboardForeignIrqCount;
static volatile uint32_t gMouseForeignIrqCount;
// Implements the ps2 Set1 To Key operation.
static INPUT_KEY Ps2Set1ToKey(uint8_t make, bool extended) {
@@ -137,6 +146,10 @@ static void Ps2KeyboardDpcRoutine(KDPC* dpc, void* context, void* systemArgument
INPUT_KEY_EVENT event = gKeyboardDpcQueue[gKeyboardDpcHead];
gKeyboardDpcHead = (gKeyboardDpcHead + 1) & (int)KEYBOARD_DPC_QUEUE_MASK;
KeInputSubmitKey(&event);
uint32_t n = ++gKeyboardEventCount;
if ((n & (n - 1u)) == 0u)
DbgPrint("ps2: keyboard progress irq=%u raw=%u events=%u foreign=%u\n",
gKeyboardIrqCount, gKeyboardByteCount, n, gKeyboardForeignIrqCount);
}
}
@@ -162,7 +175,15 @@ static void Ps2QueueKeyboardEvent(INPUT_KEY key, bool pressed) {
// Implements the ps2 Keyboard Isr operation.
static void Ps2KeyboardIsr(void) {
++gKeyboardIrqCount;
uint8_t status = __inbyte(PS2_STAT);
// The 8042 output buffer is shared; never consume AUX bytes as scancodes.
if (!(status & PS2_STAT_OUT_FULL) || (status & PS2_STAT_AUX_DATA)) {
++gKeyboardForeignIrqCount;
return;
}
uint8_t sc = __inbyte(PS2_DATA);
++gKeyboardByteCount;
if (sc == SC1_EXT_PREFIX) {
gKeyboardNextExtended = true;
return;
@@ -197,12 +218,23 @@ static void Ps2MouseDpcRoutine(KDPC* dpc, void* context, void* systemArgument1,
.buttons = packet.buttons,
};
KeInputSubmitMouse(&event);
uint32_t n = ++gMousePacketCount;
if ((n & (n - 1u)) == 0u)
DbgPrint("ps2: mouse progress irq=%u raw=%u packets=%u foreign=%u\n",
gMouseIrqCount, gMouseByteCount, n, gMouseForeignIrqCount);
}
}
// Implements the ps2 Mouse Isr operation.
static void Ps2MouseIsr(void) {
++gMouseIrqCount;
uint8_t status = __inbyte(PS2_STAT);
if (!(status & PS2_STAT_OUT_FULL) || !(status & PS2_STAT_AUX_DATA)) {
++gMouseForeignIrqCount;
return;
}
uint8_t data = __inbyte(PS2_DATA);
++gMouseByteCount;
if (gMousePacketIndex == 0 && !(data & 0x08u))
return;
@@ -281,10 +313,9 @@ static void Ps2MouseInitialize(void) {
DbgPrint("ps2: mouse enable did not ACK\n");
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)ddk;
(void)init;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
uint32_t keyboardId = 0, mouseId = 0;
KeInputRegisterDevice("ps2-keyboard", 0, &keyboardId);
@@ -308,3 +339,5 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("ps2: initialized keyboard=%u mouse=%u\n", keyboardId, mouseId);
return NTLSTATUS_SUCCESS;
}
NTL_DECLARE_MODULE(DriverInitialize);
+1
View File
@@ -19,6 +19,7 @@
#define PS2_STAT_OUT_FULL 0x01u
#define PS2_STAT_IN_FULL 0x02u
#define PS2_STAT_AUX_DATA 0x20u
#define PS2_IRQ_KEYBOARD 1u
#define PS2_IRQ_MOUSE 12u
+6 -5
View File
@@ -6,7 +6,7 @@
#include <intrin.h>
#include <ntlite/status.h>
#include <ntlite/ddk/ddk.h>
#include <ntlite/ddk/module.h>
#include <ntlite/ddi/input_device.h>
#include <ntlite/ddk/debug.h>
#include <ntlite/ddk/dpc.h>
@@ -339,10 +339,9 @@ static KSTATUS SerialConfigureCom1(void) {
return NTLSTATUS_DEVICE_ERROR;
}
// DriverEntry registers COM1 as an input source.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)ddk;
(void)init;
// Initializes the optional COM1 input source.
static KSTATUS SerialInitialize(NTL_MODULE* module) {
(void)module;
if (!SerialProbeCom1()) {
DbgPrint("serial: COM1 not present; input driver disabled\n");
@@ -374,3 +373,5 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("serial: initialized COM1 input device=%u irq=%u\n", deviceId, SERIAL_COM1_IRQ);
return NTLSTATUS_SUCCESS;
}
NTL_DECLARE_MODULE(SerialInitialize);
+3 -3
View File
@@ -20,6 +20,6 @@ Build notes:
Load order:
`drivers.ini` should load `lwip.sys` before NIC drivers so the provider is
ready when the NIC registers. The kernel also supports provider-after-device
registration, but provider-first keeps boot logs cleaner.
`drivers.ini` v2 uses `class.network-stack` with `after=network-adapter`.
NIC modules initialize first; lwIP attaches to already registered adapters.
The stack also initializes normally when no physical NIC is present.
+11 -20
View File
@@ -1,3 +1,4 @@
#include <ntlite/ddk/module.h>
// lwIP stack provider glue. This file bridges the kernel network-device model into lwIP.
#include <ntlite/atomic.h>
@@ -111,7 +112,6 @@ typedef struct LWIP_PROVIDER_SOCKET {
static LWIP_BINDING* gBindings[LWIP_MAX_NETIFS];
static volatile int gLwipInitialized = 0;
static const NTL_DDK* gLwipDdk;
static KSTATUS LwipProviderAttachDevice(NET_DEVICE* device);
static KSTATUS LwipProviderReceiveFrame(NET_DEVICE* device, const void* frame, size_t length);
@@ -770,21 +770,15 @@ static void LwipInitDone(void* arg) {
// Delays the current provider thread through the DDK scheduler table.
static KSTATUS LwipDelayThread(uint64_t milliseconds) {
if (!gLwipDdk || !gLwipDdk->Scheduler || !gLwipDdk->Scheduler->DelayThread)
return NTLSTATUS_INVALID_PARAMETER;
return gLwipDdk->Scheduler->DelayThread(milliseconds);
return KeDelayThread(milliseconds);
}
// Implements the stack Initialize operation.
static KSTATUS LwipStackInitialize(const NTL_DDK* ddk) {
static KSTATUS LwipStackInitialize(void) {
if (gLwipInitialized)
return NTLSTATUS_SUCCESS;
if (!ddk || !ddk->Timer || !ddk->Timer->QueryTicks ||
!ddk->Scheduler || !ddk->Scheduler->DelayThread)
return NTLSTATUS_INVALID_PARAMETER;
gLwipDdk = ddk;
LwipPortSetTimerQuery(ddk->Timer->QueryTicks);
LwipPortSetTimerQuery(KeQueryTicks);
SEMAPHORE* done = 0;
KSTATUS st = KeSemaphoreCreate(0, 1, &done);
@@ -1822,9 +1816,9 @@ static KSTATUS LwipDispatchInternalDeviceControl(DEVICE_OBJECT* device, IRP* irp
return LwipDispatchSocketRequest(request);
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("lwIP: driver loading...\n");
LWIP_NETIF_CONFIG defaultConfig;
@@ -1835,7 +1829,7 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
return st;
}
st = LwipStackInitialize(ddk);
st = LwipStackInitialize();
if (!KSUCCESS(st)) {
DbgPrint("lwIP: initialization failed: 0x%x\n", st);
return st;
@@ -1844,12 +1838,6 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
IoInitializeDriverObject(&gLwipDriver, SYS_SV_LITERAL("lwip-stack"));
gLwipDriver.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = LwipDispatchInternalDeviceControl;
st = IoRegisterDriverObject(&gLwipDriver);
if (!KSUCCESS(st)) {
DbgPrint("lwIP: driver object registration failed: 0x%x\n", st);
return st;
}
st = IoCreateDevice(&gLwipDriver, 0, &gLwipDevice);
if (!KSUCCESS(st)) {
DbgPrint("lwIP: stack device creation failed: 0x%x\n", st);
@@ -1867,3 +1855,6 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
DbgPrint("lwIP: driver initialized\n");
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gLwipDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
+20 -25
View File
@@ -1,8 +1,8 @@
#include <ntlite/ddk/module.h>
// Realtek RTL8139 network driver. This file owns PCI attachment, MMIO setup, RX/TX rings, and net-device registration.
#include "rtl8139.h"
const NTL_DDK* gRtl8139Ddk;
static DRIVER_OBJECT gRtl8139Driver;
static RTL8139_DEVICE* gRtl8139Devices[RTL8139_MAX_DEVICES];
static uint32_t gRtl8139DeviceCount;
@@ -69,8 +69,7 @@ static KSTATUS Rtl8139Reset(RTL8139_DEVICE* r) {
for (uint32_t i = 0; i < 1000; i++) {
if ((Rtl8139Read8(r, RTL8139_REG_CMD) & RTL8139_CMD_RST) == 0)
return NTLSTATUS_SUCCESS;
if (gRtl8139Ddk->Timer->Stall)
gRtl8139Ddk->Timer->Stall(1000);
KeStallExecution(1000);
}
return NTLSTATUS_TIMEOUT;
}
@@ -100,17 +99,17 @@ static void Rtl8139StopDma(RTL8139_DEVICE* r) {
// Releases the common buffers and adapter owned by one RTL8139 device.
static void Rtl8139ReleaseDma(RTL8139_DEVICE* r) {
if (!r || !gRtl8139Ddk || !gRtl8139Ddk->Dma)
if (!r)
return;
gRtl8139Ddk->Dma->FreeCommonBuffer(r->TxDma);
gRtl8139Ddk->Dma->FreeCommonBuffer(r->RxDma);
IoDmaFreeCommonBuffer(r->TxDma);
IoDmaFreeCommonBuffer(r->RxDma);
r->TxDma = (IO_DMA_BUFFER*)0;
r->RxDma = (IO_DMA_BUFFER*)0;
r->TxBuffers = (uint8_t*)0;
r->RxBuffer = (uint8_t*)0;
r->TxDeviceAddress = 0;
r->RxDeviceAddress = 0;
gRtl8139Ddk->Dma->PutAdapter(r->DmaAdapter);
IoDmaPutAdapter(r->DmaAdapter);
r->DmaAdapter = (IO_DMA_ADAPTER*)0;
}
@@ -123,13 +122,13 @@ static KSTATUS Rtl8139AllocateDma(RTL8139_DEVICE* r) {
requirements.MaximumSegmentLength = RTL8139_TX_BUF_SIZE;
requirements.MaximumSegments = 1;
KSTATUS status = gRtl8139Ddk->Dma->GetAdapter(r->Fdo,
KSTATUS status = IoDmaGetAdapter(r->Fdo,
&requirements,
&r->DmaAdapter);
if (!KSUCCESS(status))
return status;
status = gRtl8139Ddk->Dma->AllocateCommonBuffer(r->DmaAdapter,
status = IoDmaAllocateCommonBuffer(r->DmaAdapter,
RTL8139_RX_ALLOC_SIZE,
PAGE_SIZE,
&r->RxDma);
@@ -138,7 +137,7 @@ static KSTATUS Rtl8139AllocateDma(RTL8139_DEVICE* r) {
return status;
}
status = gRtl8139Ddk->Dma->AllocateCommonBuffer(r->DmaAdapter,
status = IoDmaAllocateCommonBuffer(r->DmaAdapter,
RTL8139_TX_SLOTS * RTL8139_TX_BUF_SIZE,
PAGE_SIZE,
&r->TxDma);
@@ -147,10 +146,10 @@ static KSTATUS Rtl8139AllocateDma(RTL8139_DEVICE* r) {
return status;
}
r->RxBuffer = (uint8_t*)gRtl8139Ddk->Dma->GetCommonBufferAddress(r->RxDma);
r->TxBuffers = (uint8_t*)gRtl8139Ddk->Dma->GetCommonBufferAddress(r->TxDma);
r->RxDeviceAddress = gRtl8139Ddk->Dma->GetCommonBufferDeviceAddress(r->RxDma);
r->TxDeviceAddress = gRtl8139Ddk->Dma->GetCommonBufferDeviceAddress(r->TxDma);
r->RxBuffer = (uint8_t*)IoDmaGetCommonBufferAddress(r->RxDma);
r->TxBuffers = (uint8_t*)IoDmaGetCommonBufferAddress(r->TxDma);
r->RxDeviceAddress = IoDmaGetCommonBufferDeviceAddress(r->RxDma);
r->TxDeviceAddress = IoDmaGetCommonBufferDeviceAddress(r->TxDma);
DbgPrint("RTL8139: rx=0x%016llX tx=0x%016llX\n",
(unsigned long long)r->RxDeviceAddress,
@@ -603,14 +602,11 @@ KSTATUS Rtl8139AddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObj
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Dma || !ddk->Timer)
return NTLSTATUS_INVALID_PARAMETER;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("RTL8139: driver loading...\n");
gRtl8139Ddk = ddk;
gRtl8139DeviceCount = 0;
memset(&gRtl8139Driver, 0, sizeof(gRtl8139Driver));
@@ -618,9 +614,8 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
gRtl8139Driver.IdTable = &gRtl8139IdTable;
gRtl8139Driver.DriverAddDevice = Rtl8139AddDevice;
gRtl8139Driver.MajorFunction[IRP_MJ_PNP] = Rtl8139DispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gRtl8139Driver);
if (!KSUCCESS(st))
DbgPrint("RTL8139: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gRtl8139Driver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
-2
View File
@@ -133,7 +133,5 @@ typedef struct RTL8139_DEVICE {
NET_DEVICE NetDevice;
} RTL8139_DEVICE;
extern const NTL_DDK* gRtl8139Ddk;
KSTATUS Rtl8139AddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS Rtl8139DispatchPnp(DEVICE_OBJECT* device, IRP* irp);
+28 -33
View File
@@ -1,8 +1,8 @@
#include <ntlite/ddk/module.h>
// Realtek RTL816x network driver. This file owns PCI attachment, descriptor rings, and net-device registration.
#include "rtl816x.h"
const NTL_DDK* gRtl816xDdk;
static DRIVER_OBJECT gRtl816xDriver;
static RTL816X_DEVICE* gRtl816xDevices[RTL816X_MAX_DEVICES];
static uint32_t gRtl816xDeviceCount;
@@ -70,8 +70,7 @@ static KSTATUS RtlReset(RTL816X_DEVICE* r) {
for (uint32_t i = 0; i < 1000; i++) {
if ((RtlRead8(r, RTL_REG_CHIP_CMD) & RTL_CMD_RESET) == 0)
return NTLSTATUS_SUCCESS;
if (gRtl816xDdk->Timer->Stall)
gRtl816xDdk->Timer->Stall(1000);
KeStallExecution(1000);
}
return NTLSTATUS_TIMEOUT;
}
@@ -101,12 +100,12 @@ static void RtlStopDma(RTL816X_DEVICE* r) {
// Releases the common buffers and adapter owned by one RTL816x device.
static void RtlReleaseDma(RTL816X_DEVICE* r) {
if (!r || !gRtl816xDdk || !gRtl816xDdk->Dma)
if (!r)
return;
gRtl816xDdk->Dma->FreeCommonBuffer(r->TxBuffersDma);
gRtl816xDdk->Dma->FreeCommonBuffer(r->RxBuffersDma);
gRtl816xDdk->Dma->FreeCommonBuffer(r->TxRingDma);
gRtl816xDdk->Dma->FreeCommonBuffer(r->RxRingDma);
IoDmaFreeCommonBuffer(r->TxBuffersDma);
IoDmaFreeCommonBuffer(r->RxBuffersDma);
IoDmaFreeCommonBuffer(r->TxRingDma);
IoDmaFreeCommonBuffer(r->RxRingDma);
r->TxBuffersDma = (IO_DMA_BUFFER*)0;
r->RxBuffersDma = (IO_DMA_BUFFER*)0;
r->TxRingDma = (IO_DMA_BUFFER*)0;
@@ -119,7 +118,7 @@ static void RtlReleaseDma(RTL816X_DEVICE* r) {
r->RxBuffersDeviceAddress = 0;
r->TxRingDeviceAddress = 0;
r->RxRingDeviceAddress = 0;
gRtl816xDdk->Dma->PutAdapter(r->DmaAdapter);
IoDmaPutAdapter(r->DmaAdapter);
r->DmaAdapter = (IO_DMA_ADAPTER*)0;
}
@@ -132,41 +131,41 @@ static KSTATUS RtlAllocateDma(RTL816X_DEVICE* r) {
requirements.MaximumSegmentLength = RTL_BUF_SIZE;
requirements.MaximumSegments = RTL_TX_COUNT;
KSTATUS status = gRtl816xDdk->Dma->GetAdapter(r->Fdo,
KSTATUS status = IoDmaGetAdapter(r->Fdo,
&requirements,
&r->DmaAdapter);
if (!KSUCCESS(status))
return status;
status = gRtl816xDdk->Dma->AllocateCommonBuffer(r->DmaAdapter,
status = IoDmaAllocateCommonBuffer(r->DmaAdapter,
PAGE_SIZE * RTL_RING_PAGES,
PAGE_SIZE,
&r->RxRingDma);
if (!KSUCCESS(status)) goto fail;
status = gRtl816xDdk->Dma->AllocateCommonBuffer(r->DmaAdapter,
status = IoDmaAllocateCommonBuffer(r->DmaAdapter,
PAGE_SIZE * RTL_RING_PAGES,
PAGE_SIZE,
&r->TxRingDma);
if (!KSUCCESS(status)) goto fail;
status = gRtl816xDdk->Dma->AllocateCommonBuffer(r->DmaAdapter,
status = IoDmaAllocateCommonBuffer(r->DmaAdapter,
PAGE_SIZE * RTL_RXBUF_PAGES,
PAGE_SIZE,
&r->RxBuffersDma);
if (!KSUCCESS(status)) goto fail;
status = gRtl816xDdk->Dma->AllocateCommonBuffer(r->DmaAdapter,
status = IoDmaAllocateCommonBuffer(r->DmaAdapter,
PAGE_SIZE * RTL_TXBUF_PAGES,
PAGE_SIZE,
&r->TxBuffersDma);
if (!KSUCCESS(status)) goto fail;
r->RxRing = (RTL_DESC*)gRtl816xDdk->Dma->GetCommonBufferAddress(r->RxRingDma);
r->TxRing = (RTL_DESC*)gRtl816xDdk->Dma->GetCommonBufferAddress(r->TxRingDma);
r->RxBuffers = (uint8_t*)gRtl816xDdk->Dma->GetCommonBufferAddress(r->RxBuffersDma);
r->TxBuffers = (uint8_t*)gRtl816xDdk->Dma->GetCommonBufferAddress(r->TxBuffersDma);
r->RxRingDeviceAddress = gRtl816xDdk->Dma->GetCommonBufferDeviceAddress(r->RxRingDma);
r->TxRingDeviceAddress = gRtl816xDdk->Dma->GetCommonBufferDeviceAddress(r->TxRingDma);
r->RxBuffersDeviceAddress = gRtl816xDdk->Dma->GetCommonBufferDeviceAddress(r->RxBuffersDma);
r->TxBuffersDeviceAddress = gRtl816xDdk->Dma->GetCommonBufferDeviceAddress(r->TxBuffersDma);
r->RxRing = (RTL_DESC*)IoDmaGetCommonBufferAddress(r->RxRingDma);
r->TxRing = (RTL_DESC*)IoDmaGetCommonBufferAddress(r->TxRingDma);
r->RxBuffers = (uint8_t*)IoDmaGetCommonBufferAddress(r->RxBuffersDma);
r->TxBuffers = (uint8_t*)IoDmaGetCommonBufferAddress(r->TxBuffersDma);
r->RxRingDeviceAddress = IoDmaGetCommonBufferDeviceAddress(r->RxRingDma);
r->TxRingDeviceAddress = IoDmaGetCommonBufferDeviceAddress(r->TxRingDma);
r->RxBuffersDeviceAddress = IoDmaGetCommonBufferDeviceAddress(r->RxBuffersDma);
r->TxBuffersDeviceAddress = IoDmaGetCommonBufferDeviceAddress(r->TxBuffersDma);
DbgPrint("RTL816X: rxRing=0x%016llX txRing=0x%016llX rxBuf=0x%016llX txBuf=0x%016llX\n",
(unsigned long long)r->RxRingDeviceAddress,
@@ -667,14 +666,11 @@ KSTATUS Rtl816xAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObj
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Dma || !ddk->Timer)
return NTLSTATUS_INVALID_PARAMETER;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("RTL816X: driver loading...\n");
gRtl816xDdk = ddk;
gRtl816xDeviceCount = 0;
memset(&gRtl816xDriver, 0, sizeof(gRtl816xDriver));
@@ -682,9 +678,8 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
gRtl816xDriver.IdTable = &gRtl816xIdTable;
gRtl816xDriver.DriverAddDevice = Rtl816xAddDevice;
gRtl816xDriver.MajorFunction[IRP_MJ_PNP] = Rtl816xDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gRtl816xDriver);
if (!KSUCCESS(st))
DbgPrint("RTL816X: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gRtl816xDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
-2
View File
@@ -151,7 +151,5 @@ typedef struct RTL816X_DEVICE {
NET_DEVICE NetDevice;
} RTL816X_DEVICE;
extern const NTL_DDK* gRtl816xDdk;
KSTATUS Rtl816xAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS Rtl816xDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
+20 -24
View File
@@ -1,8 +1,8 @@
#include <ntlite/ddk/module.h>
// AHCI storage driver. This file owns controller attachment, drive discovery, command submission, and worker-driven IRP completion.
#include "ahci.h"
const NTL_DDK* gAhciDdk;
DRIVER_OBJECT g_driver;
static AHCI_CONTROLLER* g_controllers[MAX_AHCI_CONTROLLERS];
@@ -102,13 +102,13 @@ static void AhciReleaseDriveRuntime(AHCI_DRIVE* drv) {
// Releases the DMA buffers owned by one AHCI drive.
static void AhciReleaseDriveDma(AHCI_DRIVE* drv) {
if (!drv || !gAhciDdk || !gAhciDdk->Dma)
if (!drv)
return;
if (drv->port && drv->controller &&
!drv->surpriseRemoved && !drv->controller->surpriseRemoved)
port_stop(drv->port);
gAhciDdk->Dma->FreeCommonBuffer(drv->bounceDma);
gAhciDdk->Dma->FreeCommonBuffer(drv->structDma);
IoDmaFreeCommonBuffer(drv->bounceDma);
IoDmaFreeCommonBuffer(drv->structDma);
drv->bounceDma = (IO_DMA_BUFFER*)0;
drv->structDma = (IO_DMA_BUFFER*)0;
drv->bounceDeviceAddress = 0;
@@ -122,16 +122,16 @@ static KSTATUS port_init_memory(AHCI_DRIVE* drv) {
if (!drv || !drv->controller || !drv->controller->dmaAdapter)
return NTLSTATUS_INVALID_PARAMETER;
KSTATUS status = gAhciDdk->Dma->AllocateCommonBuffer(drv->controller->dmaAdapter,
KSTATUS status = IoDmaAllocateCommonBuffer(drv->controller->dmaAdapter,
PORT_PAGES_STRUCT * PAGE_SIZE,
PAGE_SIZE,
&drv->structDma);
if (!KSUCCESS(status))
return status;
drv->structVirt = gAhciDdk->Dma->GetCommonBufferAddress(drv->structDma);
drv->structDeviceAddress = gAhciDdk->Dma->GetCommonBufferDeviceAddress(drv->structDma);
drv->structVirt = IoDmaGetCommonBufferAddress(drv->structDma);
drv->structDeviceAddress = IoDmaGetCommonBufferDeviceAddress(drv->structDma);
status = gAhciDdk->Dma->AllocateCommonBuffer(drv->controller->dmaAdapter,
status = IoDmaAllocateCommonBuffer(drv->controller->dmaAdapter,
BOUNCE_BYTES,
PAGE_SIZE,
&drv->bounceDma);
@@ -139,8 +139,8 @@ static KSTATUS port_init_memory(AHCI_DRIVE* drv) {
AhciReleaseDriveDma(drv);
return status;
}
drv->bounceVirt = gAhciDdk->Dma->GetCommonBufferAddress(drv->bounceDma);
drv->bounceDeviceAddress = gAhciDdk->Dma->GetCommonBufferDeviceAddress(drv->bounceDma);
drv->bounceVirt = IoDmaGetCommonBufferAddress(drv->bounceDma);
drv->bounceDeviceAddress = IoDmaGetCommonBufferDeviceAddress(drv->bounceDma);
HBA_PORT* port = drv->port;
port_stop(port);
@@ -701,7 +701,7 @@ static KSTATUS AhciDispatchControllerPnp(DEVICE_OBJECT* device, IRP* irp) {
}
}
AhciUnregisterController(ctl);
gAhciDdk->Dma->PutAdapter(ctl->dmaAdapter);
IoDmaPutAdapter(ctl->dmaAdapter);
ctl->dmaAdapter = (IO_DMA_ADAPTER*)0;
IoDetachDevice(device);
IoDeleteDevice(device);
@@ -940,7 +940,7 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
dmaRequirements.Alignment = 2;
dmaRequirements.MaximumSegmentLength = 1u << 22;
dmaRequirements.MaximumSegments = PORT_PRDT_COUNT;
st = gAhciDdk->Dma->GetAdapter(ctl->fdo, &dmaRequirements, &ctl->dmaAdapter);
st = IoDmaGetAdapter(ctl->fdo, &dmaRequirements, &ctl->dmaAdapter);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: DMA adapter creation failed (0x%x)\n", st);
return st;
@@ -949,7 +949,7 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
st = AhciRegisterController(ctl);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: controller registry full (0x%x)\n", st);
gAhciDdk->Dma->PutAdapter(ctl->dmaAdapter);
IoDmaPutAdapter(ctl->dmaAdapter);
ctl->dmaAdapter = (IO_DMA_ADAPTER*)0;
return st;
}
@@ -1159,14 +1159,11 @@ static KSTATUS AhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDevic
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Memory || !ddk->Memory->PhysToVirt || !ddk->Dma)
return NTLSTATUS_INVALID_PARAMETER;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("AHCI: driver loading...\n");
gAhciDdk = ddk;
g_controllerCount = 0;
g_nextDiskIndex = 0;
@@ -1178,9 +1175,8 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
g_driver.MajorFunction[IRP_MJ_WRITE] = AhciDispatchReadWrite;
g_driver.MajorFunction[IRP_MJ_FLUSH_BUFFERS] = AhciDispatchFlush;
g_driver.MajorFunction[IRP_MJ_PNP] = AhciDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&g_driver);
if (!KSUCCESS(st))
DbgPrint("AHCI: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &g_driver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
-1
View File
@@ -385,7 +385,6 @@ struct AHCI_CONTROLLER {
bool removed;
};
extern const NTL_DDK* gAhciDdk;
extern DRIVER_OBJECT g_driver;
KSTATUS ahci_map_mmio(uint64_t physBase, uint64_t length);
+2 -2
View File
@@ -10,9 +10,9 @@ KSTATUS ahci_map_mmio(uint64_t physBase, uint64_t length) {
uint64_t pageEnd = (physBase + length + PAGE_SIZE - 1u) & ~(uint64_t)(PAGE_SIZE - 1u);
int pageIndex = 0;
for (uint64_t phys = pageBase; phys < pageEnd; phys += PAGE_SIZE, pageIndex++) {
uintptr_t virt = (uintptr_t)gAhciDdk->Memory->PhysToVirt(phys);
uintptr_t virt = (uintptr_t)MmDdkPhysToVirt(phys);
uint64_t flags = PAGE_PRESENT | PAGE_WRITE | PAGE_CACHE_UC;
KSTATUS st = gAhciDdk->Memory->MapPage(virt,
KSTATUS st = MmDdkMapPage(virt,
phys,
flags,
NtlDdkMapReplaceExisting);
+12 -16
View File
@@ -1,8 +1,8 @@
#include <ntlite/ddk/module.h>
// ATA compatibility storage driver. This file owns legacy IDE probing and PIO disk access for older virtual hardware.
#include "ata.h"
const NTL_DDK* gAtaDdk;
static DRIVER_OBJECT gAtaDriver;
static ATA_CONTROLLER* gAtaControllers[ATA_MAX_CONTROLLERS];
static uint32_t gAtaControllerCount;
@@ -56,12 +56,12 @@ static void AtaDelay400ns(ATA_CHANNEL* ch) {
// Returns the monotonic DDK timer in microseconds.
static uint64_t AtaQueryTicks(void) {
return gAtaDdk->Timer->QueryTicks();
return KeQueryTicks();
}
// Delays briefly between ATA status samples without involving the scheduler.
static void AtaPollDelay(void) {
gAtaDdk->Timer->Stall(ATA_POLL_INTERVAL_US);
KeStallExecution(ATA_POLL_INTERVAL_US);
}
// Returns whether a status byte represents an unimplemented/floating legacy channel.
@@ -125,9 +125,9 @@ static KSTATUS AtaResetChannel(ATA_CHANNEL* ch) {
DbgPrint("ATA: channel %u reset begin status=0x%02x\n", ch->Index, before);
AtaDeviceControl(ch, ATA_DEVICE_CONTROL_NIEN | ATA_DEVICE_CONTROL_SRST);
gAtaDdk->Timer->Stall(ATA_RESET_ASSERT_US);
KeStallExecution(ATA_RESET_ASSERT_US);
AtaDeviceControl(ch, ATA_DEVICE_CONTROL_NIEN);
gAtaDdk->Timer->Stall(ATA_RESET_SETTLE_US);
KeStallExecution(ATA_RESET_SETTLE_US);
uint8_t finalStatus = AtaAltStatus(ch);
if (AtaStatusIsAbsent(finalStatus)) {
@@ -922,14 +922,11 @@ KSTATUS AtaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject)
return NTLSTATUS_SUCCESS;
}
// Implements the driver Entry operation.
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
(void)init;
if (!ddk || !ddk->Timer || !ddk->Timer->QueryTicks || !ddk->Timer->Stall)
return NTLSTATUS_INVALID_PARAMETER;
static KSTATUS DriverInitialize(NTL_MODULE* module) {
(void)module;
DbgPrint("ATA: driver loading...\n");
gAtaDdk = ddk;
gAtaControllerCount = 0;
memset(&gAtaDriver, 0, sizeof(gAtaDriver));
@@ -940,9 +937,8 @@ KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
gAtaDriver.MajorFunction[IRP_MJ_WRITE] = AtaDispatchReadWrite;
gAtaDriver.MajorFunction[IRP_MJ_FLUSH_BUFFERS] = AtaDispatchFlush;
gAtaDriver.MajorFunction[IRP_MJ_PNP] = AtaDispatchPnp;
KSTATUS st = IoRegisterDriverObject(&gAtaDriver);
if (!KSUCCESS(st))
DbgPrint("ATA: IoRegisterDriverObject failed: 0x%x\n", st);
return st;
return NTLSTATUS_SUCCESS;
}
static DRIVER_OBJECT* const gModuleIoDrivers[] = { &gAtaDriver };
NTL_DECLARE_IO_MODULE(DriverInitialize, gModuleIoDrivers);
-2
View File
@@ -133,8 +133,6 @@ typedef struct ATA_CONTROLLER {
uint8_t DeviceCount;
} ATA_CONTROLLER;
extern const NTL_DDK* gAtaDdk;
KSTATUS AtaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject);
KSTATUS AtaDispatchPnp(DEVICE_OBJECT* device, IRP* irp);
KSTATUS AtaDispatchReadWrite(DEVICE_OBJECT* device, IRP* irp);