isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
This commit is contained in:
1 parent
3dacbd32c8
commit
73abd6f90d
441 files changed
+187073
-6549
No files matched your search
+216
-39
@@ -54,29 +54,92 @@ static void AtaDelay400ns(ATA_CHANNEL* ch) {
|
||||
(void)AtaAltStatus(ch);
|
||||
}
|
||||
|
||||
// Waits for not Busy.
|
||||
static KSTATUS AtaWaitNotBusy(ATA_CHANNEL* ch) {
|
||||
for (uint32_t i = 0; i < ATA_POLL_LIMIT; i++) {
|
||||
if (!(AtaIn8(ch, ATA_REG_STATUS) & ATA_STATUS_BSY))
|
||||
return NTLSTATUS_SUCCESS;
|
||||
KeYield();
|
||||
}
|
||||
return NTLSTATUS_TIMEOUT;
|
||||
// Returns the monotonic DDK timer in microseconds.
|
||||
static uint64_t AtaQueryTicks(void) {
|
||||
return gAtaDdk->Timer->QueryTicks();
|
||||
}
|
||||
|
||||
// Waits for drq.
|
||||
static KSTATUS AtaWaitDrq(ATA_CHANNEL* ch) {
|
||||
for (uint32_t i = 0; i < ATA_POLL_LIMIT; i++) {
|
||||
uint8_t st = AtaIn8(ch, ATA_REG_STATUS);
|
||||
if (st & ATA_STATUS_ERR)
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
if (st & ATA_STATUS_DF)
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
if (!(st & ATA_STATUS_BSY) && (st & ATA_STATUS_DRQ))
|
||||
return NTLSTATUS_SUCCESS;
|
||||
KeYield();
|
||||
// Delays briefly between ATA status samples without involving the scheduler.
|
||||
static void AtaPollDelay(void) {
|
||||
gAtaDdk->Timer->Stall(ATA_POLL_INTERVAL_US);
|
||||
}
|
||||
|
||||
// Returns whether a status byte represents an unimplemented/floating legacy channel.
|
||||
static bool AtaStatusIsAbsent(uint8_t status) {
|
||||
return status == 0x00u || status == 0xFFu;
|
||||
}
|
||||
|
||||
// Waits until one microsecond deadline expires while polling alternate status.
|
||||
static KSTATUS AtaWaitStatus(ATA_CHANNEL* ch, uint64_t timeoutUs, bool requireDrq, bool checkErrors,
|
||||
uint8_t* finalStatusOut) {
|
||||
uint64_t start = AtaQueryTicks();
|
||||
uint64_t deadline = start > UINT64_MAX - timeoutUs ? UINT64_MAX : start + timeoutUs;
|
||||
uint64_t pollBudget = timeoutUs / ATA_POLL_INTERVAL_US + 2u;
|
||||
|
||||
for (;;) {
|
||||
uint8_t status = AtaAltStatus(ch);
|
||||
if (finalStatusOut) *finalStatusOut = status;
|
||||
if (AtaStatusIsAbsent(status)) return NTLSTATUS_NOT_FOUND;
|
||||
if (!(status & ATA_STATUS_BSY)) {
|
||||
if (checkErrors && (status & (ATA_STATUS_ERR | ATA_STATUS_DF)))
|
||||
return NTLSTATUS_DEVICE_ERROR;
|
||||
if (!requireDrq || (status & ATA_STATUS_DRQ))
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
if (AtaQueryTicks() >= deadline || pollBudget-- == 0u)
|
||||
return NTLSTATUS_TIMEOUT;
|
||||
AtaPollDelay();
|
||||
}
|
||||
return NTLSTATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
// Waits boundedly for BSY to clear using elapsed hardware time rather than scheduler iterations.
|
||||
static KSTATUS AtaWaitNotBusy(ATA_CHANNEL* ch) {
|
||||
return AtaWaitStatus(ch, ATA_POLL_TIMEOUT_US, false, true, (uint8_t*)0);
|
||||
}
|
||||
|
||||
// Waits boundedly for a data phase while rejecting absent and failed devices early.
|
||||
static KSTATUS AtaWaitDrq(ATA_CHANNEL* ch) {
|
||||
return AtaWaitStatus(ch, ATA_POLL_TIMEOUT_US, true, true, (uint8_t*)0);
|
||||
}
|
||||
|
||||
// Emits the task-file state needed to distinguish selection, signature, and command failures.
|
||||
static void AtaLogProbeState(const ATA_DEVICE* dev, const char* stage, KSTATUS result) {
|
||||
if (!dev || !dev->Channel) return;
|
||||
ATA_CHANNEL* ch = dev->Channel;
|
||||
DbgPrint("ATA: channel %u %s identify %s result=0x%x status=0x%02x error=0x%02x lba1=0x%02x lba2=0x%02x\n",
|
||||
ch->Index,
|
||||
dev->Drive ? "slave" : "master",
|
||||
stage ? stage : "stage",
|
||||
result,
|
||||
AtaAltStatus(ch),
|
||||
AtaIn8(ch, ATA_REG_ERROR),
|
||||
AtaIn8(ch, ATA_REG_LBA1),
|
||||
AtaIn8(ch, ATA_REG_LBA2));
|
||||
}
|
||||
|
||||
// Resets one legacy ATA channel before probing so firmware state cannot leak into IDENTIFY.
|
||||
static KSTATUS AtaResetChannel(ATA_CHANNEL* ch) {
|
||||
if (!ch) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
uint8_t before = AtaAltStatus(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);
|
||||
AtaDeviceControl(ch, ATA_DEVICE_CONTROL_NIEN);
|
||||
gAtaDdk->Timer->Stall(ATA_RESET_SETTLE_US);
|
||||
|
||||
uint8_t finalStatus = AtaAltStatus(ch);
|
||||
if (AtaStatusIsAbsent(finalStatus)) {
|
||||
DbgPrint("ATA: channel %u reset found no responding device status=0x%02x\n",
|
||||
ch->Index, finalStatus);
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
KSTATUS status = AtaWaitStatus(ch, ATA_RESET_TIMEOUT_US, false, false, &finalStatus);
|
||||
DbgPrint("ATA: channel %u reset complete result=0x%x status=0x%02x\n",
|
||||
ch->Index, status, finalStatus);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Implements the select Drive operation.
|
||||
@@ -86,7 +149,7 @@ static void AtaSelectDrive(ATA_DEVICE* dev) {
|
||||
AtaDelay400ns(ch);
|
||||
}
|
||||
|
||||
// Implements the identify operation.
|
||||
// Implements IDENTIFY with stage diagnostics and finite hardware deadlines.
|
||||
static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
|
||||
ATA_CHANNEL* ch = dev->Channel;
|
||||
uint16_t ident[256];
|
||||
@@ -95,8 +158,20 @@ static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
|
||||
KSTATUS st = KeWaitSemaphore(ch->Lock, KE_WAIT_INFINITE);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
DbgPrint("ATA: channel %u %s identify lock acquired\n",
|
||||
ch->Index, dev->Drive ? "slave" : "master");
|
||||
|
||||
AtaSelectDrive(dev);
|
||||
DbgPrint("ATA: channel %u %s identify selected status=0x%02x\n",
|
||||
ch->Index, dev->Drive ? "slave" : "master", AtaAltStatus(ch));
|
||||
|
||||
st = AtaWaitStatus(ch, ATA_POLL_TIMEOUT_US, false, false, (uint8_t*)0);
|
||||
if (!KSUCCESS(st)) {
|
||||
AtaLogProbeState(dev, "pre-command wait", st);
|
||||
KeSignalSemaphore(ch->Lock);
|
||||
return st;
|
||||
}
|
||||
|
||||
AtaOut8(ch, ATA_REG_SECTOR_COUNT, 0);
|
||||
AtaOut8(ch, ATA_REG_LBA0, 0);
|
||||
AtaOut8(ch, ATA_REG_LBA1, 0);
|
||||
@@ -104,25 +179,33 @@ static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
|
||||
AtaOut8(ch, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_DEVICE);
|
||||
AtaDelay400ns(ch);
|
||||
|
||||
uint8_t status = AtaIn8(ch, ATA_REG_STATUS);
|
||||
if (status == 0) {
|
||||
uint8_t status = AtaAltStatus(ch);
|
||||
DbgPrint("ATA: channel %u %s identify command issued status=0x%02x\n",
|
||||
ch->Index, dev->Drive ? "slave" : "master", status);
|
||||
if (AtaStatusIsAbsent(status)) {
|
||||
AtaLogProbeState(dev, "absent after command", NTLSTATUS_NOT_FOUND);
|
||||
KeSignalSemaphore(ch->Lock);
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
st = AtaWaitNotBusy(ch);
|
||||
if (!KSUCCESS(st)) {
|
||||
AtaLogProbeState(dev, "busy timeout/error", st);
|
||||
KeSignalSemaphore(ch->Lock);
|
||||
return st;
|
||||
}
|
||||
|
||||
if (AtaIn8(ch, ATA_REG_LBA1) != 0 || AtaIn8(ch, ATA_REG_LBA2) != 0) {
|
||||
uint8_t lba1 = AtaIn8(ch, ATA_REG_LBA1);
|
||||
uint8_t lba2 = AtaIn8(ch, ATA_REG_LBA2);
|
||||
if (lba1 != 0 || lba2 != 0) {
|
||||
AtaLogProbeState(dev, "non-ATA signature", NTLSTATUS_NOT_SUPPORTED);
|
||||
KeSignalSemaphore(ch->Lock);
|
||||
return NTLSTATUS_NOT_SUPPORTED; // ATAPI or non-ATA signature.
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
st = AtaWaitDrq(ch);
|
||||
if (!KSUCCESS(st)) {
|
||||
AtaLogProbeState(dev, "DRQ timeout/error", st);
|
||||
KeSignalSemaphore(ch->Lock);
|
||||
return st;
|
||||
}
|
||||
@@ -130,7 +213,11 @@ static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
|
||||
for (uint32_t i = 0; i < 256; i++)
|
||||
ident[i] = AtaIn16(ch, ATA_REG_DATA);
|
||||
|
||||
AtaLogProbeState(dev, "data complete", NTLSTATUS_SUCCESS);
|
||||
KeSignalSemaphore(ch->Lock);
|
||||
DbgPrint("ATA: channel %u %s identify lock released capabilities=0x%04x command_sets=0x%04x\n",
|
||||
ch->Index, dev->Drive ? "slave" : "master",
|
||||
ident[ATA_IDENT_CAPABILITIES], ident[ATA_IDENT_COMMAND_SETS]);
|
||||
|
||||
if (!(ident[ATA_IDENT_CAPABILITIES] & ATA_IDENT_LBA_SUPPORTED))
|
||||
return NTLSTATUS_NOT_SUPPORTED;
|
||||
@@ -148,6 +235,9 @@ static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
|
||||
ident[ATA_IDENT_LBA28_SECTORS_LO];
|
||||
}
|
||||
|
||||
DbgPrint("ATA: channel %u %s identify parsed lba48=%u sectors=%llu\n",
|
||||
ch->Index, dev->Drive ? "slave" : "master",
|
||||
dev->SupportsLba48 ? 1u : 0u, (unsigned long long)dev->SectorCount);
|
||||
return dev->SectorCount ? NTLSTATUS_SUCCESS : NTLSTATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -323,8 +413,14 @@ static void AtaWorker(uintptr_t arg) {
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
while (true) {
|
||||
KeWaitSemaphore(dev->IrpQueue.Semaphore, KE_WAIT_INFINITE);
|
||||
DbgPrint("ATA: channel %u %s worker online\n",
|
||||
dev->Channel ? dev->Channel->Index : 0u, dev->Drive ? "slave" : "master");
|
||||
while (dev->WorkerRunning) {
|
||||
KSTATUS waitStatus = KeWaitSemaphore(dev->IrpQueue.Semaphore, KE_WAIT_INFINITE);
|
||||
if (!KSUCCESS(waitStatus))
|
||||
continue;
|
||||
if (!dev->WorkerRunning)
|
||||
break;
|
||||
|
||||
IRP* irp = IrpQueueDequeue(&dev->IrpQueue);
|
||||
if (!irp)
|
||||
@@ -357,6 +453,58 @@ static void AtaWorker(uintptr_t arg) {
|
||||
IoReleaseRemoveLock(&dev->RemoveLock, irp);
|
||||
IoCompleteRequest(irp, st, information);
|
||||
}
|
||||
|
||||
DbgPrint("ATA: channel %u %s worker stopped\n",
|
||||
dev->Channel ? dev->Channel->Index : 0u, dev->Drive ? "slave" : "master");
|
||||
if (dev->WorkerFinished)
|
||||
KeSignalEvent(dev->WorkerFinished);
|
||||
}
|
||||
|
||||
// Stops one ATA disk worker and releases the worker-owned synchronization references.
|
||||
static void AtaStopWorker(ATA_DEVICE* dev) {
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
dev->WorkerRunning = false;
|
||||
if (dev->IrpQueue.Semaphore)
|
||||
KeSignalSemaphore(dev->IrpQueue.Semaphore);
|
||||
if (dev->WorkerThread && dev->WorkerFinished)
|
||||
(void)KeWaitForEvent(dev->WorkerFinished, 0);
|
||||
|
||||
if (dev->WorkerThread) {
|
||||
ObDereferenceObject((OBJECT*)dev->WorkerThread);
|
||||
dev->WorkerThread = (THREAD*)0;
|
||||
}
|
||||
if (dev->WorkerFinished) {
|
||||
ObDereferenceObject(&dev->WorkerFinished->Header);
|
||||
dev->WorkerFinished = (EVENT*)0;
|
||||
}
|
||||
if (dev->IrpQueue.Semaphore) {
|
||||
ObDereferenceObject(&dev->IrpQueue.Semaphore->Header);
|
||||
dev->IrpQueue.Semaphore = (SEMAPHORE*)0;
|
||||
}
|
||||
}
|
||||
|
||||
// Starts one ATA disk worker before the disk is published to synchronous discovery consumers.
|
||||
static KSTATUS AtaStartWorker(ATA_DEVICE* dev) {
|
||||
if (!dev || !dev->IrpQueue.Semaphore)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = KeEventCreate(EventManualReset, 0, &dev->WorkerFinished);
|
||||
if (!KSUCCESS(status))
|
||||
return status;
|
||||
|
||||
dev->WorkerRunning = true;
|
||||
const KE_THREAD_CREATE_PARAMETERS workerParameters =
|
||||
KE_THREAD_CREATE_NAMED_NORMAL(PriorityHigh, "ata.disk");
|
||||
status = KeCreateKernelThread((uintptr_t)AtaWorker, (uintptr_t)dev,
|
||||
&workerParameters, &dev->WorkerThread);
|
||||
if (!KSUCCESS(status)) {
|
||||
dev->WorkerRunning = false;
|
||||
AtaStopWorker(dev);
|
||||
return status;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Dispatches read Write.
|
||||
@@ -461,7 +609,7 @@ static KSTATUS AtaInitChannel(ATA_CONTROLLER* ctl, uint8_t index) {
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
AtaDeviceControl(ch, 0x02u); // nIEN: polled I/O for now.
|
||||
AtaDeviceControl(ch, ATA_DEVICE_CONTROL_NIEN); // nIEN: polled I/O for now.
|
||||
DbgPrint("ATA: channel %u cmd=0x%04x ctl=0x%04x irq=%u mode=%s\n",
|
||||
index,
|
||||
ch->CommandBase,
|
||||
@@ -531,18 +679,33 @@ static KSTATUS AtaProbeDrive(ATA_CONTROLLER* ctl, ATA_CHANNEL* ch, uint8_t drive
|
||||
return st;
|
||||
IrpQueueInit(&dev->IrpQueue, sem);
|
||||
|
||||
dev->Present = true;
|
||||
st = AtaRegisterDisk(dev);
|
||||
DbgPrint("ATA: channel %u %s worker start before disk publication\n",
|
||||
ch->Index, drive ? "slave" : "master");
|
||||
st = AtaStartWorker(dev);
|
||||
if (!KSUCCESS(st)) {
|
||||
dev->Present = false;
|
||||
DbgPrint("ATA: channel %u %s worker start failed (0x%x)\n",
|
||||
ch->Index, drive ? "slave" : "master", st);
|
||||
AtaStopWorker(dev);
|
||||
IoDestroyRemoveLock(&dev->RemoveLock);
|
||||
return st;
|
||||
}
|
||||
|
||||
const KE_THREAD_CREATE_PARAMETERS workerParameters = KE_THREAD_CREATE_NORMAL(PriorityHigh);
|
||||
st = KeCreateKernelThread((uintptr_t)AtaWorker, (uintptr_t)dev,
|
||||
&workerParameters, &dev->WorkerThread);
|
||||
if (!KSUCCESS(st))
|
||||
DbgPrint("ATA: drive %u worker thread create failed (0x%x)\n", dev->DiskIndex, st);
|
||||
dev->Present = true;
|
||||
DbgPrint("ATA: channel %u %s publishing disk sectors=%llu lba48=%u\n",
|
||||
ch->Index, drive ? "slave" : "master",
|
||||
(unsigned long long)dev->SectorCount, dev->SupportsLba48 ? 1u : 0u);
|
||||
st = AtaRegisterDisk(dev);
|
||||
if (!KSUCCESS(st)) {
|
||||
DbgPrint("ATA: channel %u %s disk publication failed (0x%x)\n",
|
||||
ch->Index, drive ? "slave" : "master", st);
|
||||
dev->Present = false;
|
||||
AtaStopWorker(dev);
|
||||
IoDestroyRemoveLock(&dev->RemoveLock);
|
||||
return st;
|
||||
}
|
||||
|
||||
DbgPrint("ATA: channel %u %s probe complete disk=%u\n",
|
||||
ch->Index, drive ? "slave" : "master", dev->DiskIndex);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -598,10 +761,20 @@ static KSTATUS AtaStartController(ATA_CONTROLLER* ctl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
st = AtaResetChannel(ch);
|
||||
if (!KSUCCESS(st))
|
||||
DbgPrint("ATA: channel %u reset did not complete cleanly (0x%x); probing drives with bounded waits\n",
|
||||
chIndex, st);
|
||||
|
||||
for (uint8_t drive = 0; drive < ATA_DRIVES_PER_CHANNEL; drive++) {
|
||||
DbgPrint("ATA: channel %u probing %s\n", chIndex, drive ? "slave" : "master");
|
||||
st = AtaProbeDrive(ctl, ch, drive);
|
||||
if (KSUCCESS(st))
|
||||
if (KSUCCESS(st)) {
|
||||
ctl->DeviceCount++;
|
||||
} else if (st != NTLSTATUS_NOT_FOUND) {
|
||||
DbgPrint("ATA: channel %u %s probe failed (0x%x)\n",
|
||||
chIndex, drive ? "slave" : "master", st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +806,9 @@ static void AtaRemoveControllerDevices(ATA_CONTROLLER* ctl, IO_DEVICE_CHANGE cha
|
||||
if (!dev->Present)
|
||||
continue;
|
||||
|
||||
dev->Present = false;
|
||||
IrpQueueCancelAllWithCallback(&dev->IrpQueue, NTLSTATUS_OBJECT_DEAD, AtaCancelReleaseRemoveLock, dev);
|
||||
AtaStopWorker(dev);
|
||||
if (dev->DiskIndex != 0xFFu) {
|
||||
if (change == IoDeviceSurpriseRemoved)
|
||||
IoNotifyDiskSurpriseRemoved(dev->DiskIndex);
|
||||
@@ -641,7 +816,6 @@ static void AtaRemoveControllerDevices(ATA_CONTROLLER* ctl, IO_DEVICE_CHANGE cha
|
||||
IoUnregisterDiskDevice(dev->DiskIndex);
|
||||
dev->DiskIndex = 0xFFu;
|
||||
}
|
||||
dev->Present = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,12 +875,15 @@ KSTATUS AtaDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
|
||||
device->PnpState = DevicePnpSurpriseRemoved;
|
||||
dev->Present = false;
|
||||
IrpQueueCancelAllWithCallback(&dev->IrpQueue, NTLSTATUS_OBJECT_DEAD, AtaCancelReleaseRemoveLock, dev);
|
||||
AtaStopWorker(dev);
|
||||
return NTLSTATUS_SUCCESS;
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
device->PnpState = DevicePnpDeleted;
|
||||
dev->Present = false;
|
||||
IrpQueueCancelAllWithCallback(&dev->IrpQueue, NTLSTATUS_OBJECT_DEAD, AtaCancelReleaseRemoveLock, dev);
|
||||
AtaStopWorker(dev);
|
||||
IoReleaseRemoveLockAndWait(&dev->RemoveLock, irp);
|
||||
IoDestroyRemoveLock(&dev->RemoveLock);
|
||||
IoDeleteDevice(device);
|
||||
dev->DeviceObject = (DEVICE_OBJECT*)0;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
@@ -748,7 +925,7 @@ KSTATUS AtaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject)
|
||||
// Implements the driver Entry operation.
|
||||
KSTATUS DriverEntry(const NTL_DDK* ddk, NTL_DRIVER_INIT* init) {
|
||||
(void)init;
|
||||
if (!ddk)
|
||||
if (!ddk || !ddk->Timer || !ddk->Timer->QueryTicks || !ddk->Timer->Stall)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
DbgPrint("ATA: driver loading...\n");
|
||||
|
||||
Reference in new issue
Block a user