📄 plugplay.cpp
字号:
DEVICE_POWER_STATE wakestate = PowerDeviceUnspecified; // assume no wakeup capability
if (pdc->WakeFromD3)
wakestate = PowerDeviceD3;
else if (pdc->WakeFromD2)
wakestate = PowerDeviceD2;
else if (pdc->WakeFromD1)
wakestate = PowerDeviceD1;
else if (pdc->WakeFromD0)
wakestate = PowerDeviceD0;
if (pdc->DeviceWake != wakestate)
{
KdPrint(("%s - DeviceWake is %s, but should be %s\n", pdx->DebugName, dname[pdc->DeviceWake], dname[wakestate]));
pdc->DeviceWake = wakestate;
}
// If SystemWake is specified, the corresponding D-state had better be at
// least as powered as the state we just discovered, or else there's a bug
// in our bus driver. It may just be that we got a bogus SystemWake value,
// so don't do anything about it.
if (pdc->SystemWake != PowerSystemUnspecified)
{
if (pdc->DeviceState[pdc->SystemWake] > wakestate)
{
KdPrint(("%s - DeviceState[SystemWake] is less powered than minimum wake state (%s)!\n", pdx->DebugName, dname[wakestate]));
}
}
// If SystemWake wasn't specified, infer it from the S->D state map by
// finding the lowest S-state whose D-state is at least as powered as the
// lowest D-state from which wakeup is possible (I think I got that right...)
else if (wakestate != PowerDeviceD0 && wakestate != PowerDeviceUnspecified)
{ // infer system wake state
for (sstate = PowerSystemSleeping3; sstate >= PowerSystemWorking; --sstate)
{ // for each S-state
if (pdc->DeviceState[sstate] != PowerDeviceUnspecified
&& pdc->DeviceState[sstate] <= wakestate)
{ // found the S-state
KdPrint(("%s - Inferring that wakeup from S%d state possible\n", pdx->DebugName, sstate - 1));
pdc->SystemWake = sstate;
break;
} // found the S-state
} // for each S-state
} // infer system wake state
} // AdjustDeviceCapabilities
///////////////////////////////////////////////////////////////////////////////
// AdjustWakeCapabilities adjusts the wakeup capabilities for a device.
VOID AdjustWakeCapabilities(PGENERIC_EXTENSION pdx, PDEVICE_CAPABILITIES pdc, DEVICE_POWER_STATE dstate)
{ // AdjustWakeCapabilities
switch (dstate)
{ // select on D-state
case PowerDeviceUnspecified:
break;
case PowerDeviceD0:
if (!pdc->WakeFromD0)
KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD0\n", pdx->DebugName));
pdc->WakeFromD0 = TRUE;
break;
case PowerDeviceD1:
if (!pdc->WakeFromD1)
KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD1\n", pdx->DebugName));
if (!pdc->DeviceD1)
KdPrint(("%s - AdjustWakeCapabilities Inferring DeviceD1\n", pdx->DebugName));
pdc->DeviceD1 = TRUE;
pdc->WakeFromD1 = TRUE;
break;
case PowerDeviceD2:
if (!pdc->WakeFromD2)
KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD2\n", pdx->DebugName));
if (!pdc->DeviceD2)
KdPrint(("%s - AdjustWakeCapabilities Inferring DeviceD2\n", pdx->DebugName));
pdc->DeviceD2 = TRUE;
pdc->WakeFromD2 = TRUE;
break;
case PowerDeviceD3:
if (!pdc->WakeFromD3)
KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD3\n", pdx->DebugName));
pdc->WakeFromD3 = TRUE;
break;
default:
ASSERT(FALSE);
} // select on D-state
} // AdjustWakeCapabilities
///////////////////////////////////////////////////////////////////////////////
VOID CallStopDevice(PGENERIC_EXTENSION pdx)
{ // CallStopDevice
GenericWakeupControl(pdx, CancelWaitWake);
BOOLEAN oktouch = pdx->HardwareWorking;
pdx->HardwareWorking = FALSE;
(*pdx->StopDevice)(pdx->DeviceObject, oktouch);
} // CallStopDevice
///////////////////////////////////////////////////////////////////////////////
VOID CallRemoveDevice(PGENERIC_EXTENSION pdx)
{ // CallRemoveDevice
(*pdx->RemoveDevice)(pdx->DeviceObject);
} // CallRemoveDevice
///////////////////////////////////////////////////////////////////////////////
NTSTATUS DefaultPnpHandler(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // DefaultPnpHandler
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(pdx->LowerDeviceObject, Irp);
} // DefaultPnpHandler
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
VOID DeregisterAllInterfaces(PGENERIC_EXTENSION pdx)
{ // DeregisterAllInterfaces
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
KeEnterCriticalRegion();
KeWaitForSingleObject(&pdx->iflock, Executive, KernelMode, FALSE, NULL);
while (!IsListEmpty(&pdx->iflist))
{ // for each interface
PLIST_ENTRY list = RemoveHeadList(&pdx->iflist);
PINTERFACE_RECORD ifp = CONTAINING_RECORD(list, INTERFACE_RECORD, list);
DeregisterInterface(pdx, ifp);
} // for each interface
KeSetEvent(&pdx->iflock, EVENT_INCREMENT, FALSE);
KeLeaveCriticalRegion();
} // DeregisterAllInterfaces
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
VOID DeregisterInterface(PGENERIC_EXTENSION pdx, PINTERFACE_RECORD ifp)
{ // DeregisterInterface
if (ifp->enabled)
IoSetDeviceInterfaceState(&ifp->linkname, FALSE);
RtlFreeUnicodeString(&ifp->linkname);
RemoveEntryList(&ifp->list);
ExFreePool(ifp);
} // DeregisterInterface
///////////////////////////////////////////////////////////////////////////////
#pragma LOCKEDCODE
VOID EnableAllInterfaces(PGENERIC_EXTENSION pdx, BOOLEAN enable)
{ // EnableAllInterfaces
for (PLIST_ENTRY list = pdx->iflist.Flink; list != &pdx->iflist; list = list->Flink)
{ // search for specified interface record
PINTERFACE_RECORD ifp = CONTAINING_RECORD(list, INTERFACE_RECORD, list);
if (ifp->enabled != enable)
IoSetDeviceInterfaceState(&ifp->linkname, enable);
ifp->enabled = enable;
}
} // EnableAllInterfaces
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
PINTERFACE_RECORD FindInterfaceRecord(PGENERIC_EXTENSION pdx, const GUID* guid)
{ // FindInterfaceRecord
PAGED_CODE();
for (PLIST_ENTRY list = pdx->iflist.Flink; list != &pdx->iflist; list = list->Flink)
{ // search for specified interface record
PINTERFACE_RECORD ifp = CONTAINING_RECORD(list, INTERFACE_RECORD, list);
if (ifp->guid == *guid)
return ifp;
}
return NULL;
} // FindInterfaceRecord
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleCancelRemove(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleCancelRemove
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
if (pdx->state == PENDINGREMOVE)
{ // we succeeded earlier query
// Lower-level drivers are presumably in the pending-remove state as
// well, so we need to tell them that the remove has been cancelled
// before we start sending IRPs down to them.
NTSTATUS status = ForwardAndWait(pdx, Irp); // wait for lower layers
if (NT_SUCCESS(status))
{ // completed successfully
KdPrint(("%s - To %s from PENDINGREMOVE\n", pdx->DebugName, statenames[pdx->prevstate]));
RestartAllRequests(pdx->queues, pdx->nqueues, pdx->DeviceObject);
GenericWakeupControl(pdx, ManageWaitWake); // reissue wait-wake if necessary
} // completed successfully
else
KdPrint(("%s - Status %8.8lX returned by PDO for IRP_MN_CANCEL_REMOVE_DEVICE", pdx->DebugName, status));
return CompleteRequest(Irp, status);
} // we succeeded earlier query
return DefaultPnpHandler(pdx, Irp); // unexpected cancel
} // HandleCancelRemove
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleCancelStop(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleCancelStop
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
if (pdx->state == PENDINGSTOP)
{ // we succeeded earlier query
// Lower level drivers are presumably in the pending-stop state as
// well, so we need to tell them that the stop has been cancelled
// before we start sending IRPs down to them.
NTSTATUS status = ForwardAndWait(pdx, Irp); // wait for lower layers
if (NT_SUCCESS(status))
{ // completed successfully
KdPrint(("%s - To WORKING from PENDINGSTOP\n", pdx->DebugName));
pdx->state = WORKING;
RestartAllRequests(pdx->queues, pdx->nqueues, pdx->DeviceObject);
GenericWakeupControl(pdx, ManageWaitWake); // reissue wait-wake if necessary
} // completed successfully
else
KdPrint(("%s - Status %8.8lX returned by PDO for IRP_MN_CANCEL_STOP_DEVICE", pdx->DebugName, status));
return CompleteRequest(Irp, status);
} // we succeeded earlier query
return DefaultPnpHandler(pdx, Irp); // unexpected cancel
} // HandleCancelStop
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleQueryCapabilities(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleQueryCapabilities
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_CAPABILITIES);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_CAPABILITIES pdc = stack->Parameters.DeviceCapabilities.Capabilities;
// Check to be sure we know how to handle this version of the capabilities structure
if (pdc->Version < 1)
return DefaultPnpHandler(pdx, Irp);
NTSTATUS status = ForwardAndWait(pdx, Irp);
if (NT_SUCCESS(status))
{ // IRP succeeded
stack = IoGetCurrentIrpStackLocation(Irp);
pdc = stack->Parameters.DeviceCapabilities.Capabilities;
if (pdx->Flags & GENERIC_SURPRISE_REMOVAL_OK)
pdc->SurpriseRemovalOK = TRUE;
AdjustDeviceCapabilities(pdx, pdc); // compensate for bus driver shortcoming
pdx->devcaps = *pdc; // save capabilities for whoever needs to see them
pdx->GotCapabilities = TRUE; // flag for GenericGetDeviceCapabilities
GenericWakeupControl(pdx, ManageWaitWake); // in case capabilities now allow WAIT_WAKE
} // IRP succeeded
return CompleteRequest(Irp, status);
} // HandleQueryCapabilities
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleQueryRemove(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleQueryRemove
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
if (pdx->state == WORKING)
{ // currently working
#ifdef _X86_
// Win98 doesn't check for open handles before allowing a remove to proceed,
// and it may deadlock in IoReleaseRemoveLockAndWait if handles are still
// open.
if (win98 && pdx->DeviceObject->ReferenceCount)
{
KdPrint(("%s - Failing removal query due to open handles\n", pdx->DebugName));
return CompleteRequest(Irp, STATUS_DEVICE_BUSY);
}
#endif
// See if it's okay to remove this device. The test includes asking the client
// driver. Then stall the queue for the duration of the query. The TOASTER sample
// in the DDK drains the queue here instead of stalling it, by the way.
if (!OkayToRemove(pdx))
return CompleteRequest(Irp, STATUS_UNSUCCESSFUL); // can't remove because busy
StallAllRequests(pdx->queues, pdx->nqueues);
if (pdx->FlushPendingIo)
(*pdx->FlushPendingIo)(pdx->DeviceObject, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE, PowerDeviceUnspecified, PowerDeviceUnspecified);
WaitForCurrentIrps(pdx->queues, pdx->nqueues);
GenericWakeupControl(pdx, CancelWaitWake); // cancel any pending wait-wake
KdPrint(("%s - To PENDINGREMOVE from %s\n", pdx->DebugName, statenames[pdx->state]));
} // currently working
// Save current state for restoration if the query gets cancelled.
// (We can now be stopped or working)
pdx->prevstate = pdx->state;
pdx->state = PENDINGREMOVE;
return DefaultPnpHandler(pdx, Irp);
} // HandleQueryRemove
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleQueryState(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleQueryState
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE);
// Note that you can't use sizeof in a #if expression, so it's not possible to use
// conditional compilation to choose between 32- and 64-bit exchanges in the
// following statement. If the size of a PNP_DEVICE_STATE changes to be bigger than
// 32 bits, therefore, you have to change this by hand. The ASSERT will alert you to
// the problem...
PNP_DEVICE_STATE mask = InterlockedExchange((PLONG) &pdx->pnpstatemask, 0);
ASSERT(sizeof(PNP_DEVICE_STATE) == sizeof(LONG));
if (mask)
{ // some status flags have changed
Irp->IoStatus.Status = STATUS_SUCCESS; // indicate we've handled this IRP
Irp->IoStatus.Information &= ~(ULONG_PTR) mask; // clear all changed flags
Irp->IoStatus.Information |= pdx->pnpstate & mask; // set all flags that were changed to "1"
} // some status flags have changed
// DDK doc says you handle this IRP on the way down, but TOASTER handles
// it on the way up. It shouldn't matter, because you're not supposed to
// overstore the result you find already in IoStatus.Information.
return DefaultPnpHandler(pdx, Irp);
} // HandleQueryState
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleQueryStop(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleQueryStop
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_STOP_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
// Boot devices may get this query before they even start, so check to see
// if we're in the WORKING state before doing anything.
if (pdx->state != WORKING)
return DefaultPnpHandler(pdx, Irp);
// See if it will be okay to stop the device right now. This test includes
// asking the client driver via a callback routine.
if (!OkayToStop(pdx))
return CompleteRequest(Irp, STATUS_UNSUCCESSFUL);
// Stall the request queue and wait for the current IRP (if any) to finish
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -