Handling an IRP_MN_QUERY_STOP_DEVICE Request (Windows 98/Me)

An IRP_MN_QUERY_STOP_DEVICE request is handled first by the top driver in the device stack and then by each next lower driver. A driver handles stop IRPs in its DispatchPnP routine.

In response to an IRP_MN_QUERY_STOP_DEVICE, a driver must do the following:

  1. Determine whether the device can be stopped without adverse affects.

    A driver must fail a query-stop IRP if any of the following are true:

    • A driver has been notified (through IRP_MN_DEVICE_USAGE_NOTIFICATION) that the device is in the path of a paging, hibernation, or crash dump file.

    • The device's hardware resources cannot be released.

    • There are open handles to the device.

    A driver might fail a query-stop IRP if the following is true:

    • The driver must not drop I/O requests.
  2. If the device cannot be stopped, fail the query-stop IRP.

    Set Irp->IoStatus.Status to an appropriate error status, call IoCompleteRequest with IO_NO_INCREMENT, and return from the driver's DispatchPnP routine. Do not pass the IRP to the next lower driver.

  3. If the device can be stopped, call IoSetDeviceInterfaceState and IoRegisterDeviceInterface to disable and deregister any user-mode interfaces. Then start failing any incoming I/O requests that require access to the device.

    Alternatively, the drivers for a device can defer completely pausing the device until the drivers receive the subsequent IRP_MN_STOP_DEVICE request. Such drivers, however, should disable and deregister their user-mode interfaces while handling the query-stop request to prevent the opening of any additional handles to the device.

    Furthermore, such drivers must fail any requests that would prevent them from immediately succeeding the stop IRP when it arrives. Until the device is restarted, such drivers must fail requests such as the following:

    • IRP_MN_DEVICE_USAGE_NOTIFICATION requests (for example, to put a paging file on the device).

    • Requests for isochronous transfers.

    • Create requests that would prevent the drivers from succeeding a stop IRP.

  4. If the device cannot allow an IRP in progress to fail, ensure that any outstanding requests that were passed to other driver routines and to lower drivers have completed.

    One way that a driver can achieve this is to use a reference count and an event to ensure that all requests have been completed:

    • In its AddDevice routine, the driver defines an I/O reference count in the device extension and initializes the count to one.

    • Also in its AddDevice routine, the driver creates an event with KeInitializeEvent and initializes the event to the Not-Signaled state with KeClearEvent.

    • Each time it processes an IRP, the driver increments the reference count with InterlockedIncrement.

    • Each time it completes a request, the driver decrements the reference count with InterlockedDecrement.

      The driver decrements the reference count in the IoCompletion routine, if the request has one, or immediately after the call to IoCallDriver if the driver uses no IoCompletion routine for the request.

    • When the driver receives an IRP_MN_QUERY_STOP_DEVICE, it decrements the reference count with InterlockedDecrement. If there are no outstanding requests, this reduces the reference count to zero.

    • When the reference count reaches zero, the driver sets the event with KeSetEvent signaling that the query-stop code can continue.

    As an alternative to the above procedure, a driver can serialize the IRP_MN_QUERY_STOP_DEVICE IRP behind any IRPs in progress.

  5. Perform any other steps required to put the device in the stop-pending state.

    After a driver succeeds a query-stop IRP, it must be ready to succeed an IRP_MN_STOP_DEVICE.

  6. Finish the IRP.

    In a function or filter driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.

    • Set up the next stack location with IoSkipCurrentIrpStackLocation and pass the IRP to the next lower driver with IoCallDriver.

    • Propagate the status from IoCallDriver as the return status from the DispatchPnP routine.

    • Do not complete the IRP.

    In a bus driver:

    • Set Irp->IoStatus.Status to STATUS_SUCCESS.

      If, however, the devices on the bus use hardware resources, reevaluate the resource requirements of the bus and the child devices. If any of the requirements have changed, return STATUS_RESOURCE_REQUIREMENTS_CHANGED instead of STATUS_SUCCESS. This status indicates success but requests that the PnP manager requery your resources before sending the stop IRP.

    • Complete the IRP (IoCompleteRequest) with IO_NO_INCREMENT.

    • Return from the DispatchPnP routine.

If any driver in the device stack fails the IRP_MN_QUERY_STOP_DEVICE, the PnP manager sends an IRP_MN_CANCEL_STOP_DEVICE to the device stack. This prevents drivers from requiring an IoCompletion routine for a query-stop IRP to detect whether a lower driver failed the IRP.