📄 pnp.c
字号:
//
// The bus driver has declined to start the device.
// Oh well...
//
#if DBG
DbgPrint("OsrPnp: IoCallDriver() for START fails! 0x%0x \n", code);
#endif
}
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Status = code;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
//
// STATE: STARTED
// IRP_MN: _QUERY_REMOVE
//
// We're here because we're running, and the PnP Manager wants
// to "nicely" remove our device. This is the orderly way
// PnP Manager handles device disconnections (as opposed to
// doing a SURPRISE_REMOVAL).
//
// What we do here is (a) change the state of the device such
// that newly arriving requests will be rejected, (b) wait for
// all requests to complete on the device, and (c) pass the
// request on down.
//
case STATE_STARTED + IRP_MN_QUERY_REMOVE_DEVICE:
#if DBG
DbgPrint("OsrPnp: PROCESSING QUERY_REMOVE_DEVICE\n");
#endif
//
// WE process this request FIRST
//
//
// See if we're OK with removing the device at this point.
// We do NOT actually RETURN the resources here... we
// just affirm or deny that we're OK with returning them.
//
code = OsrCanRemoveDevice(devExt, Irp);
//
// Replace status code that's in the IRP to indicate our
// opinion about stopping the device. If we're
// OK with returning the resources, this will be
// STATUS_SUCCESS.
//
Irp->IoStatus.Status = code;
if(!NT_SUCCESS(code)) {
//
// NOPE. Can't remove the device because, for some
// reason (perhaps because we can't return our
// resources). Too bad. Tell the PnP Manager that
// stopping right now is not an option for us.
//
// NOTE: NO NEED to pass IRP down if WE can't stop
// it doesn't matter if the Bus Driver can.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
} else {
#if DBG
DbgPrint("OsrPnp: Waiting for pending requests to complete. (%d. remain)\n", devExt->OutstandingIO);
#endif
//
// Set new state -- This state results in any new
// requests received at our dispatch entry points
// being REJECTED... any request still on the queues
// are allowed to complete, however.
//
devExt->State = STATE_REMOVE_PENDING;
//
// Decrement our reference on the device here, and then
// wait until there are no requests active or on the
// device's queues.
//
OsrRequestDecrement(devExt);
OsrWaitForRemove(devExt);
//
// OK. No further requests remain. Let the bus driver
// know.
//
// DECREMENTED REQUEST COUNT above. Return immediately
// below.
//
#if DBG
DbgPrint("OsrPnp: Leaving With state: ");
OsrPrintState(devExt);
#endif
//
// Pass this request on down to the bus driver
//
IoSkipCurrentIrpStackLocation(Irp);
return(IoCallDriver(devExt->DeviceToSendIrpsTo, Irp));
}
break;
//
// STATE: REMOVE_PENDING
// IRP_MN: _REMOVE_DEVICE
//
// We're here because we've previously received notification
// of the intention to remove the device in an orderly way.
// We return our resources here, and then tear down our device
// object. Note that there can be no requests pending at this
// point, because we finished them all during QUERY_REMOVE
// processing (before entering RemovePending state)
//
case STATE_REMOVE_PENDING + IRP_MN_REMOVE_DEVICE:
//
// All queued and active IRPs are complete at this point.
//
//
// Return any resources we're using.
//
OsrReturnResources(devExt);
//
// Fall through...
//
//
// STATE: SURPRISE_REMOVED
// IRP_MN: _REMOVE_DEVICE
//
// We're here because we've previously received notification
// of a "surprise" removal. At this point, we just tear down
// our device object
//
case STATE_SURPRISE_REMOVED + IRP_MN_REMOVE_DEVICE:
//
// Removing the device at this point is NOT optional.
//
#if DBG
DbgPrint("OsrPnp: REMOVE_DEVICE\n");
#endif
//
// Device has been removed
//
devExt->State = STATE_REMOVED;
//
// Decrement our reference on the device here, and then
// wait until we can remove the device. Because we would
// have gotten a prior warning of this removal (via an
// IRP_MN_SUPRISE_REMOVAL or an IRP_MN_QUERY_REMOVE) and
// at that time transitioned state appropriately, there
// should be no requests outstanding here.
//
OsrRequestDecrement(devExt);
#if DBG
DbgPrint("OsrPnp: Waiting for pending requests to complete. %d. remain\n", devExt->OutstandingIO);
#endif
OsrWaitForRemove(devExt);
//
// WE process this request first
//
//
// Detach from the PDO
//
IoDetachDevice(devExt->DeviceToSendIrpsTo);
targetDevice = devExt->DeviceToSendIrpsTo;
#if DBG
devExt->DeviceToSendIrpsTo = NULL;
devExt = NULL;
#endif
//
// Return our device object
//
IoDeleteDevice(devExt->FunctionalDeviceObject);
//
// Indidcate that we've successfully processed the IRP
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Pass this request on down to the bus driver
//
IoSkipCurrentIrpStackLocation(Irp);
code = IoCallDriver(targetDevice, Irp);
ASSERT(code != STATUS_PENDING);
//
// IMPORTANT: We decremented our I/O In Progress count
// above... We don't want to decrement it again, so we
// return right here.
//
#if DBG
DbgPrint("OsrPnp: Leaving with state: STATE_REMOVE");
#endif
return(code);
break;
//
// STATE: STARTED
// IRP_MN: _SURPRISE_REMOVAL
//
// We're here when the device is running, and a device is
// forcibly removed. PnP Manager will send us a remove device
// IRP when we're supposed to actually return our resources
// and the like.
//
// Note that this is a "best effort" activity. It is quite
// possible, due to timing issues etc, that we'll crash the
// system because the device is gone. While we'll TRY not
// to do this, it is within the rules.
//
// THIS IRP IS NOT SENT ON Win9x.
//
case STATE_STARTED + IRP_MN_SURPRISE_REMOVAL:
devExt->State = STATE_SURPRISE_REMOVED;
//
// We handle this request before the bus driver
//
//
// Cancel any pending requests... make sure
// the active requests get stopped within a second (with
// no hardware access, as a result of setting the state
// above).
//
OsrClearQueues(devExt);
//
// We're happy... sort of. Note that it's not "legal"
// to fail this request. Afterall, what woudl that MEAN?
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Pass this request on down to the bus driver
//
IoSkipCurrentIrpStackLocation(Irp);
code = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
break;
//
// STATE: STARTED
// IRP_MN: _REMOVE_DEVICE
//
// We're here when the device is running, and a device is
// forcibly removed.
//
// Note that like getting a SUPRISE_REMOVAL IRP on NT trying
// to handle a removal directly from started state is a "best
// effort" type of activity. We'll do what we can but it's
// possible, due to timing issues etc, that we'll crash the
// system because the device is gone. While we'll TRY not
// to do this, it could be unavoidable. Oh well.
//
// ON NT, we'd get an IRP_MN_SURPRISE_REMOVAL instead of this
// IRP in this state. We get this only on Win9x systems.
//
case STATE_STARTED + IRP_MN_REMOVE_DEVICE:
#if DBG
DbgPrint("OsrPnp: REMOVE_DEVICE\n");
#endif
devExt->State = STATE_REMOVED;
//
// We handle this request before the bus driver
// Note that this is another one of those requests we're
// not "allowed" to fail.
//
//
// Cancel any pending requests... make sure
// the active requests get stopped within a second (with
// no hardware access, as a result of setting the state
// above).
//
OsrClearQueues(devExt);
//
// Removing the device at this point is NOT optional.
//
//
// Detach from the PDO
//
IoDetachDevice(devExt->DeviceToSendIrpsTo);
targetDevice = devExt->DeviceToSendIrpsTo;
#if DBG
devExt->DeviceToSendIrpsTo = NULL;
devExt = NULL;
#endif
//
// Decrement our reference on the device here, and then
// wait until we can remove the device.
//
OsrRequestDecrement(devExt);
#if DBG
DbgPrint("OsrPnp: Waiting for pending requests to complete. %d. remain\n", devExt->OutstandingIO);
#endif
OsrWaitForRemove(devExt);
//
// OK! Now we can return our device object
//
IoDeleteDevice(devExt->FunctionalDeviceObject);
//
// Tell the underlying driver we're cool
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Pass this request on down to the bus driver
//
IoSkipCurrentIrpStackLocation(Irp);
code = IoCallDriver(targetDevice, Irp);
ASSERT(code != STATUS_PENDING);
//
// IMPORTANT: We decremented our I/O In Progress count
// above... We don't want to decrement it again, so we
// return right here.
//
#if DBG
DbgPrint("OsrPnp: Leaving with state: STATE_REMOVED");
#endif
return(code);
break;
//
// STATE: STARTED
// IRP_MN: _QUERY_STOP_DEVICE
//
// We're here if we're running and the PnP Manager sends us
// a QUERY_STOP_DEVICE request. He'll do this if he wants to
// rebalance resources, to see if we're willing to give up the
// hardware resources that were allocated for us when we got
// our IRP_MN_START_DEVICE.
//
// To proess this QUERY_STOP, we check to see if the stop is
// acceptable to us (in this driver it always is), and then
// we just transition the device to STOP_PENDING state. In
// this state, new requests that arrive are queued. When a
// currently in-progress request is completed, a new request
// is NOT started. Thus, ON OUR DEVICE, we sort of hope that
// between the QUERY_STOP IRP arrive and actual STOP IRP arriving
// that any in-progress I/O will complete of its own accord.
// We like this scheme, particularly because at least on NT
// during startup the device seems to get lots of QUERY_STOP
// IRPs, that are just followed by CANCEL_STOP. Thus, we think
// it would be unfortunate to do anything radical with the
// outstanding requests (like cancel them) when we receive a
// QUERY_STOP.
//
case STATE_STARTED + IRP_MN_QUERY_STOP_DEVICE:
#if DBG
DbgPrint("OsrPnp: PROCESSING QUERY_STOP_DEVICE\n");
#endif
//
// WE process this request before the BUS DRIVER
//
//
// See if we're OK with stopping the device at this point.
// We do NOT actually RETURN the resources here... we
// just affirm or deny that we're OK with returning them.
//
code = OsrCanStopDevice(devExt, Irp);
//
// Replace status code that's in the IRP to indicate our
// opinion about stopping the device. If we're
// OK with returning the resources, this will be
// STATUS_SUCCESS.
//
Irp->IoStatus.Status = code;
if(!NT_SUCCESS(code)) {
//
// NOPE. Can't stop the device because, for some
// reason (perhaps because we can't return our
// resources). Too bad. Tell the PnP Manager that
// stopping right now is not an option for us.
//
// NOTE: NO NEED to pass IRP down if WE can't stop
// it doesn't matter if the Bus Driver can.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
} else {
//
// We CAN stop our device and return the resources.
// Pass the IRP down to see if the bus driver is
// equally ammenable to the request.
//
#if DBG
DbgPrint("OsrPnp: Agreeing to stop device.\n");
#endif
//
// Set new state. This state results in no new
// requests being started on the device, but incoming
// requests are still allowed and queued.
//
devExt->State = STATE_STOP_PENDING;
//
// Pass this request on down to the bus driver
//
IoSkipCurrentIrpStackLocation(Irp);
code = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
}
break;
//
// STATE: STOP_PENDING
// IRP_MN: _STOP_DEVICE
//
// We're in this state because we previously received a
// QUERY_STOP_DEVICE, that we agreed that we could grant.
// Thus, we're waiting to receive a STOP_DEVICE request.
// To process this request, we first wait for any in-progress
// requests to complete (note that no NEW requests have been
// started since the transition to STOP_PENDING state as a
// result of receiving the QUERY_STOP IRP). After all in-
// progress requests are complete, we return our resources
// and wait for further instructions from the PnP Manager (
// which better include a START_DEVICE someplace down the line!).
//
// While in this state, any IRPs we receive will be queued
// for processing after we get the START_DEVICE.
//
case STATE_STOP_PENDING + IRP_MN_STOP_DEVICE:
#if DBG
DbgPrint("OsrPnp: PROCESSING STOP_DEVICE\n");
#endif
//
// Assume success
//
devExt->State = STATE_STOPPED;
#if DBG
DbgPrint("OsrPnp: Waiting for in-progress requests to complete\n");
#endif
//
// We process this request before passing it to the bus
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -