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:
1 parent
c0ad63c27f
commit
d36f19509c
160 files changed
+6563
-7366
No files matched your search
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(®istration,
|
||||
status = IoAudioRegisterEndpoint(®istration,
|
||||
&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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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,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);
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user