📄 class.c
字号:
DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n",
DeviceObject, Irp,
((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
"STOP" : "REMOVE")));
//
// If this device is in use for some reason (paging, etc...)
// then we need to fail the request.
//
if(commonExtension->PagingPathCount != 0) {
DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging "
"path and cannot be removed\n",
DeviceObject, Irp));
status = STATUS_DEVICE_BUSY;
break;
}
//
// Check with the class driver to see if the query operation
// can succeed.
//
if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
status = devInfo->ClassStopDevice(DeviceObject,
irpStack->MinorFunction);
} else {
status = devInfo->ClassRemoveDevice(DeviceObject,
irpStack->MinorFunction);
}
if(NT_SUCCESS(status)) {
//
// ASSERT that we never get two queries in a row, as
// this will severly mess up the state machine
//
ASSERT(commonExtension->CurrentState != irpStack->MinorFunction);
commonExtension->PreviousState = commonExtension->CurrentState;
commonExtension->CurrentState = irpStack->MinorFunction;
if(isFdo) {
DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_"
"%s irp\n", DeviceObject, Irp,
((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
"STOP" : "REMOVE")));
status = ClassForwardIrpSynchronous(commonExtension, Irp);
}
}
DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n",
DeviceObject, Irp, status));
break;
}
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE: {
//
// Check with the class driver to see if the query or cancel
// operation can succeed.
//
if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
status = devInfo->ClassStopDevice(DeviceObject,
irpStack->MinorFunction);
ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should "
"never be failed\n", NT_SUCCESS(status));
} else {
status = devInfo->ClassRemoveDevice(DeviceObject,
irpStack->MinorFunction);
ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should "
"never be failed\n", NT_SUCCESS(status));
}
Irp->IoStatus.Status = status;
//
// We got a CANCEL - roll back to the previous state only
// if the current state is the respective QUERY state.
//
if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) &&
(commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE)
) ||
((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) &&
(commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
)
) {
commonExtension->CurrentState =
commonExtension->PreviousState;
commonExtension->PreviousState = 0xff;
}
if(isFdo) {
IoCopyCurrentIrpStackLocationToNext(Irp);
ClassReleaseRemoveLock(DeviceObject, Irp);
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
completeRequest = FALSE;
} else {
status = STATUS_SUCCESS;
}
break;
}
case IRP_MN_STOP_DEVICE: {
//
// These all mean nothing to the class driver currently. The
// port driver will handle all queueing when necessary.
//
DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n",
DeviceObject, Irp,
(isFdo ? "fdo" : "pdo")
));
ASSERT(commonExtension->PagingPathCount == 0);
//
// ISSUE-2000/02/03-peterwie
// if we stop the timer here then it means no class driver can
// do i/o in its ClassStopDevice routine. This is because the
// retry (among other things) is tied into the tick handler
// and disabling retries could cause the class driver to deadlock.
// Currently no class driver we're aware of issues i/o in its
// Stop routine but this is a case we may want to defend ourself
// against.
//
if (DeviceObject->Timer) {
IoStopTimer(DeviceObject);
}
status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE);
ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should "
"never be failed\n", NT_SUCCESS(status));
if(isFdo) {
status = ClassForwardIrpSynchronous(commonExtension, Irp);
}
if(NT_SUCCESS(status)) {
commonExtension->CurrentState = irpStack->MinorFunction;
commonExtension->PreviousState = 0xff;
}
break;
}
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL: {
PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
UCHAR removeType = irpStack->MinorFunction;
if (commonExtension->PagingPathCount != 0) {
DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
}
//
// Release the lock for this IRP before calling in.
//
ClassReleaseRemoveLock(DeviceObject, Irp);
lockReleased = TRUE;
/*
* Set IsRemoved before propagating the REMOVE down the stack.
* This keeps class-initiated I/O (e.g. the MCN irp) from getting sent
* after we propagate the remove.
*/
commonExtension->IsRemoved = REMOVE_PENDING;
/*
* If a timer was started on the device, stop it.
*/
if (DeviceObject->Timer) {
IoStopTimer(DeviceObject);
}
/*
* "Fire-and-forget" the remove irp to the lower stack.
* Don't touch the irp (or the irp stack!) after this.
*/
if (isFdo) {
IoCopyCurrentIrpStackLocationToNext(Irp);
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
ASSERT(NT_SUCCESS(status));
completeRequest = FALSE;
}
else {
status = STATUS_SUCCESS;
}
/*
* Do our own cleanup and call the class driver's remove
* cleanup routine.
* For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
* so don't touch the extension after this.
*/
commonExtension->PreviousState = commonExtension->CurrentState;
commonExtension->CurrentState = removeType;
ClassRemoveDevice(DeviceObject, removeType);
break;
}
case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
switch(irpStack->Parameters.UsageNotification.Type) {
case DeviceUsageTypePaging: {
BOOLEAN setPagable;
if((irpStack->Parameters.UsageNotification.InPath) &&
(commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
//
// Device isn't started. Don't allow adding a
// paging file, but allow a removal of one.
//
status = STATUS_DEVICE_NOT_READY;
break;
}
ASSERT(commonExtension->IsInitialized);
/*
* Ensure that this user thread is not suspended while we are holding the PathCountEvent.
*/
KeEnterCriticalRegion();
status = KeWaitForSingleObject(&commonExtension->PathCountEvent,
Executive, KernelMode,
FALSE, NULL);
ASSERT(NT_SUCCESS(status));
status = STATUS_SUCCESS;
//
// If the volume is removable we should try to lock it in
// place or unlock it once per paging path count
//
if (commonExtension->IsFdo){
status = ClasspEjectionControl(
DeviceObject,
Irp,
InternalMediaLock,
(BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
}
if (!NT_SUCCESS(status)){
KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
KeLeaveCriticalRegion();
break;
}
//
// if removing last paging device, need to set DO_POWER_PAGABLE
// bit here, and possible re-set it below on failure.
//
setPagable = FALSE;
if (!irpStack->Parameters.UsageNotification.InPath &&
commonExtension->PagingPathCount == 1
) {
//
// removing last paging file
// must have DO_POWER_PAGABLE bits set, but only
// if noone set the DO_POWER_INRUSH bit
//
if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
"paging file removed, but "
"DO_POWER_INRUSH was set, so NOT "
"setting DO_POWER_PAGABLE\n",
DeviceObject, Irp));
} else {
DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
"paging file removed, "
"setting DO_POWER_PAGABLE\n",
DeviceObject, Irp));
SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
setPagable = TRUE;
}
}
//
// forward the irp before finishing handling the
// special cases
//
status = ClassForwardIrpSynchronous(commonExtension, Irp);
//
// now deal with the failure and success cases.
// note that we are not allowed to fail the irp
// once it is sent to the lower drivers.
//
if (NT_SUCCESS(status)) {
IoAdjustPagingPathCount(
&commonExtension->PagingPathCount,
irpStack->Parameters.UsageNotification.InPath);
if (irpStack->Parameters.UsageNotification.InPath) {
if (commonExtension->PagingPathCount == 1) {
DebugPrint((2, "ClassDispatchPnp (%p,%p): "
"Clearing PAGABLE bit\n",
DeviceObject, Irp));
CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
}
}
} else {
//
// cleanup the changes done above
//
if (setPagable == TRUE) {
DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting "
"PAGABLE bit due to irp failure\n",
DeviceObject, Irp));
CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
setPagable = FALSE;
}
//
// relock or unlock the media if needed.
//
if (commonExtension->IsFdo) {
ClasspEjectionControl(
DeviceObject,
Irp,
InternalMediaLock,
(BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
}
}
//
// set the event so the next one can occur.
//
KeSetEvent(&commonExtension->PathCountEvent,
IO_NO_INCREMENT, FALSE);
KeLeaveCriticalRegion();
break;
}
case DeviceUsageTypeHibernation: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -