📄 plugplay.cpp
字号:
StallAllRequests(pdx->queues, pdx->nqueues);
if (pdx->FlushPendingIo)
(*pdx->FlushPendingIo)(pdx->DeviceObject, IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE, PowerDeviceUnspecified, PowerDeviceUnspecified);
WaitForCurrentIrps(pdx->queues, pdx->nqueues);
GenericWakeupControl(pdx, DisableWakeup);
pdx->state = PENDINGSTOP;
return DefaultPnpHandler(pdx, Irp);
} // HandleQueryStop
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleRemoveDevice(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleRemoveDevice
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_REMOVE_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
// Cancel any queued requests and start rejecting new ones
AbortAllRequests(pdx->queues, pdx->nqueues, STATUS_DELETE_PENDING);
AbortPendingIoctls(pdx, STATUS_DELETE_PENDING);
GenericWakeupControl(pdx, DisableWakeup);
// Disable all device interfaces that were registered through us. This
// triggers PnP notifications that will allow apps to close their handles.
DeregisterAllInterfaces(pdx);
// Release I/O resources
CallStopDevice(pdx);
KdPrint(("%s - To REMOVED from %s\n", pdx->DebugName, statenames[pdx->state]));
pdx->state = REMOVED;
// Let lower-level drivers handle this request. Ignore whatever
// result eventuates.
NTSTATUS status = DefaultPnpHandler(pdx, Irp);
// Wait for all claims against this device to vanish before removing
// the device object
if (pdx->RemoveLock)
IoReleaseRemoveLockAndWait(pdx->RemoveLock, Irp);
// Remove the device object
CallRemoveDevice(pdx);
// Cleanup our device extension
CleanupGenericExtension(pdx);
return status; // lower-level completed IoStatus already
} // HandleRemoveDevice
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleStartDevice(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleStartDevice
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_START_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
NTSTATUS status = ForwardAndWait(pdx, Irp);
if (!NT_SUCCESS(status))
return CompleteRequest(Irp, status);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PCM_PARTIAL_RESOURCE_LIST raw;
if (stack->Parameters.StartDevice.AllocatedResources)
raw = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
else
raw = NULL;
PCM_PARTIAL_RESOURCE_LIST translated;
if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
translated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
else
translated = NULL;
#if DBG
if (raw)
{
KdPrint(("%s - Resources:\n", pdx->DebugName));
ShowResources(raw);
}
if (translated)
{
KdPrint(("%s - Translated Resources:\n", pdx->DebugName));
ShowResources(translated);
}
#endif // DBG
// Assume we are initially in the D0 state
pdx->devpower = PowerDeviceD0;
pdx->syspower = PowerSystemWorking;
POWER_STATE foo;
foo.DeviceState = PowerDeviceD0;
PoSetPowerState(pdx->Pdo, DevicePowerState, foo);
// Call client driver's StartDevice function to initialize the device for I/O
status = (*pdx->StartDevice)(pdx->DeviceObject, raw, translated);
if (NT_SUCCESS(status))
{ // started okay
KdPrint(("%s - To WORKING from %s\n", pdx->DebugName, statenames[pdx->state]));
pdx->HardwareWorking = TRUE;
// If idle detection constants were saved in the registry, register
// this device for idle detection
POWERINFO pi;
if (NT_SUCCESS(GetPowerInfoFromRegistry(pdx, &pi)))
ImplementPowerPolicy(pdx, &pi);
// Enable all registered device interfaces
EnableAllInterfaces(pdx, TRUE);
// Release any stalled IRPs
pdx->state = WORKING;
AllowAllRequests(pdx->queues, pdx->nqueues); // in case we got a bogus STOP
RestartAllRequests(pdx->queues, pdx->nqueues, pdx->DeviceObject);
// If system wakeup is enabled, start a wait-wake IRP
GenericWakeupControl(pdx, ManageWaitWake);
} // started okay
return CompleteRequest(Irp, status);
} // HandleStartDevice
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleStopDevice(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleStopDevice
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_STOP_DEVICE);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
// We're supposed to always get a query before we're stopped, so
// we should already be in the PENDINGSTOP state. There's a Win98 bug that
// can sometimes cause us to get a STOP instead of a REMOVE, in which case
// we should start rejecting IRPs
if (pdx->state != PENDINGSTOP)
{ // no previous query
KdPrint(("%s - STOP with no previous QUERY_STOP!\n", pdx->DebugName));
AbortAllRequests(pdx->queues, pdx->nqueues, STATUS_DELETE_PENDING);
AbortPendingIoctls(pdx, STATUS_DELETE_PENDING);
} // no previous query
GenericWakeupControl(pdx, CancelWaitWake); // cancel any outstanding wait-wake IRP
CallStopDevice(pdx);
KdPrint(("%s - To STOPPED from %s\n", pdx->DebugName, statenames[pdx->state]));
pdx->state = STOPPED;
return DefaultPnpHandler(pdx, Irp);
} // HandleStopDevice
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleSurpriseRemoval(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleSurpriseRemoval
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_SURPRISE_REMOVAL);
Irp->IoStatus.Status = STATUS_SUCCESS; // flag that we handled this IRP
AbortAllRequests(pdx->queues, pdx->nqueues, STATUS_DELETE_PENDING);
AbortPendingIoctls(pdx, STATUS_DELETE_PENDING);
GenericWakeupControl(pdx, DisableWakeup);
KdPrint(("%s - To SURPRISEREMOVED from %s\n", pdx->DebugName, statenames[pdx->state]));
pdx->state = SURPRISEREMOVED;
EnableAllInterfaces(pdx, FALSE); // this triggers notifications so apps can close their handles
CallStopDevice(pdx);
return DefaultPnpHandler(pdx, Irp);
} // HandleSurpriseRemoval
///////////////////////////////////////////////////////////////////////////////
NTSTATUS HandleUsageNotification(PGENERIC_EXTENSION pdx, PIRP Irp)
{ // HandleUsageNotification
ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_USAGE_NOTIFICATION_TYPE type = stack->Parameters.UsageNotification.Type;
BOOLEAN inpath = stack->Parameters.UsageNotification.InPath;
switch (type)
{ // switch on usage type
case DeviceUsageTypeHibernation:
if (!(pdx->Flags & GENERIC_USAGE_HIBERNATE))
return CompleteRequest(Irp, STATUS_UNSUCCESSFUL);
AdjustSpecialFileCounter(pdx, inpath, &pdx->nhibernatefiles);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case DeviceUsageTypePaging:
{ // DeviceUsageTypePaging
if (!(pdx->Flags & GENERIC_USAGE_PAGING))
return CompleteRequest(Irp, STATUS_UNSUCCESSFUL);
if (inpath && pdx->state != WORKING)
return CompleteRequest(Irp, STATUS_DEVICE_NOT_READY); // SP-7, per DDK doc
// Guard against reentrance by waiting on evPagingPath, which is a
// synchronization event that was initialized to the signalled state.
// Therefore, it will be reset once we get past the wait (SP-7, ver 1.6)
KeWaitForSingleObject(&pdx->evPagingPath, Executive, KernelMode, FALSE, NULL);
// Add or substract one from the paging path counter. AdjustSpecialFileCounter
// will also take care of enabling or disabling idle detection.
AdjustSpecialFileCounter(pdx, inpath, &pdx->npagefiles);
// Adjust the power-pagable flag too. (Per AdrianO) we must be careful not to
// have a non-paged power handler sitting on top of a paged handler, so we
// only clear DO_POWER_PAGABLE in our completion routine.
PDEVICE_OBJECT fdo = pdx->DeviceObject;
if (pdx->npagefiles == 0)
{ // resume paging
if (!(fdo->Flags & DO_POWER_INRUSH))
fdo->Flags |= DO_POWER_PAGABLE;
} // resume paging
// TODO Deal with paging of Read, Write, Control requests in minidriver
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
} // DeviceUsageTypePaging
case DeviceUsageTypeDumpFile:
if (!(pdx->Flags & GENERIC_USAGE_DUMP))
return CompleteRequest(Irp, STATUS_UNSUCCESSFUL);
AdjustSpecialFileCounter(pdx, inpath, &pdx->ndumpfiles);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
} // switch on usage type
// Install completion routine so we can recover from a failure and so we can
// clear DO_POWER_PAGABLE at the right time.
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnNotificationComplete, pdx, TRUE, TRUE, TRUE);
IoCopyCurrentIrpStackLocationToNext(Irp);
return IoCallDriver(pdx->LowerDeviceObject, Irp);
} // HandleUsageNotification
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OnNotificationComplete(PDEVICE_OBJECT fdo, PIRP Irp, PGENERIC_EXTENSION pdx)
{ // OnNotificationComplete
if (Irp->PendingReturned)
IoMarkIrpPending(Irp);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_USAGE_NOTIFICATION_TYPE type = stack->Parameters.UsageNotification.Type;
BOOLEAN inpath = stack->Parameters.UsageNotification.InPath;
// If the notification succeeded, and if we're on the path for paging files,
// be sure we start getting power IRPs at DISPATCH_LEVEL.
if (NT_SUCCESS(Irp->IoStatus.Status))
{ // notification succeeded
if (pdx->npagefiles)
fdo->Flags &= ~DO_POWER_PAGABLE;
if (type == DeviceUsageTypePaging)
KeSetEvent(&pdx->evPagingPath, IO_NO_INCREMENT, FALSE); // SP-7
return STATUS_SUCCESS;
} // notification succeeded
// Somebody underneath us failed this usage notification, so undo the steps we
// took in the dispatch routine. Notice how we reverse the sense of "inpath" in
// the following calls to AdjustSpecialFileCounter.
switch (type)
{ // switch on usage type
case DeviceUsageTypeHibernation:
AdjustSpecialFileCounter(pdx, !inpath, &pdx->nhibernatefiles);
break;
case DeviceUsageTypePaging:
{ // DeviceUsageTypePaging
AdjustSpecialFileCounter(pdx, !inpath, &pdx->npagefiles);
if (pdx->npagefiles == 0)
{ // resume paging
if (!(fdo->Flags & DO_POWER_INRUSH))
fdo->Flags |= DO_POWER_PAGABLE;
} // resume paging
else
fdo->Flags &= ~DO_POWER_PAGABLE;
KeSetEvent(&pdx->evPagingPath, IO_NO_INCREMENT, FALSE); // SP-7
break;
} // DeviceUsageTypePaging
case DeviceUsageTypeDumpFile:
AdjustSpecialFileCounter(pdx, !inpath, &pdx->ndumpfiles);
break;
} // switch on usage type
return STATUS_SUCCESS;
} // OnNotificationComplete
///////////////////////////////////////////////////////////////////////////////
#if DBG
VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list)
{ // ShowResources
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = list->PartialDescriptors;
ULONG nres = list->Count;
ULONG i;
for (i = 0; i < nres; ++i, ++resource)
{ // for each resource
ULONG type = resource->Type;
static char* name[] = {
"CmResourceTypeNull",
"CmResourceTypePort",
"CmResourceTypeInterrupt",
"CmResourceTypeMemory",
"CmResourceTypeDma",
"CmResourceTypeDeviceSpecific",
"CmResourceTypeBusNumber",
"CmResourceTypeDevicePrivate",
"CmResourceTypeAssignedResource",
"CmResourceTypeSubAllocateFrom",
};
KdPrint((" type %s", type < arraysize(name) ? name[type] : "unknown"));
switch (type)
{ // select on resource type
case CmResourceTypePort:
case CmResourceTypeMemory:
KdPrint((" start %8X%8.8lX length %X\n",
resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
resource->u.Port.Length));
break;
case CmResourceTypeInterrupt:
KdPrint((" level %X, vector %X, affinity %X\n",
resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
resource->u.Interrupt.Affinity));
break;
case CmResourceTypeDma:
KdPrint((" channel %d, port %X\n",
resource->u.Dma.Channel, resource->u.Dma.Port));
} // select on resource type
} // for each resource
} // ShowResources
#endif // DBG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -