📄 umsspnp.c
字号:
/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
Usblspnp.c
Abstract:
USB Mass Storage Device Sample Driver
Plug and Play module
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1999-2001 Microsoft Corporation. All Rights Reserved.
Revision History:
1/13/99: MRB Adapted from the BULKUSB DDK sample.
--*/
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "umss.h"
#include "umssguid.h"
NTSTATUS
UMSS_ProcessPnPIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Dispatch table routine for IRP_MJ_PNP.
Process the Plug and Play IRPs sent to this device.
Arguments:
DeviceObject - pointer to our FDO (Functional Device Object)
Irp - pointer to an I/O Request Packet
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
NTSTATUS waitStatus;
PDEVICE_OBJECT stackDeviceObject;
KEVENT startDeviceEvent;
ENTER(UMSS_ProcessPnPIrp);
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get a pointer to the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
UMSS_KdPrint( DBGLVL_MEDIUM, ( "IRP_MJ_PNP, minor %s\n",
UMSS_StringForPnpMnFunc( irpStack->MinorFunction ) ));
// inc the FDO device extension's pending IO count for this Irp
UMSS_IncrementIoCount(DeviceObject);
UMSS_ASSERT( IRP_MJ_PNP == irpStack->MajorFunction );
switch (irpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
// The PnP Manager sends this IRP after it has assigned resources,
// if any, to the device. The device may have been recently enumerated
// and is being started for the first time, or the device may be
// restarting after being stopped for resource reconfiguration.
// Initialize an event we can wait on for the PDO to be done with this irp
KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
// Set a completion routine so it can signal our event when
// the PDO is done with the Irp
IoSetCompletionRoutine(
Irp,
UMSS_IrpCompletionRoutine,
&startDeviceEvent, // pass the event to the completion routine as the Context
TRUE, // invoke on success
TRUE, // invoke on error
TRUE // invoke on cancellation
);
// let the PDO process the IRP
ntStatus = IoCallDriver(stackDeviceObject, Irp);
// if PDO is not done yet, wait for the event to be set in our completion routine
if (ntStatus == STATUS_PENDING)
{
// wait for irp to complete
waitStatus = KeWaitForSingleObject(
&startDeviceEvent,
Suspended,
KernelMode,
FALSE,
NULL
);
}
// Now we're ready to do our own startup processing.
// USB client drivers such as us set up URBs (USB Request Packets) to send requests
// to the host controller driver (HCD). The URB structure defines a format for all
// possible commands that can be sent to a USB device.
// Here, we request the device descriptor and store it,
// and configure the device.
ntStatus = UMSS_StartDevice(DeviceObject);
// Give the device a second to init, spinup, etc.
KeStallExecutionProcessor(1000);
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
UMSS_DecrementIoCount(DeviceObject);
RETURN(ntStatus, UMSS_ProcessPnPIrp); // end, case IRP_MN_START_DEVICE
case IRP_MN_QUERY_DEVICE_RELATIONS:
// Enumerate our child PDO
ntStatus = UMSS_FdoDeviceQuery(DeviceObject, Irp);
UMSS_DecrementIoCount(DeviceObject);
RETURN(ntStatus, UMSS_ProcessPnPIrp);
case IRP_MN_QUERY_STOP_DEVICE:
// The IRP_MN_QUERY_STOP_DEVICE/IRP_MN_STOP_DEVICE sequence only occurs
// during "polite" shutdowns, such as the user explicitily requesting the
// service be stopped in, or requesting unplug from the Pnp tray icon.
// This sequence is NOT received during "impolite" shutdowns,
// such as someone suddenly yanking the USB cord or otherwise
// unexpectedly disabling/resetting the device.
// If a driver sets STATUS_SUCCESS for this IRP,
// the driver must not start any operations on the device that
// would prevent that driver from successfully completing an IRP_MN_STOP_DEVICE
// for the device.
// For mass storage devices such as disk drives, while the device is in the
// stop-pending state,the driver holds IRPs that require access to the device,
// but for most USB devices, there is no 'persistent storage', so we will just
// refuse any more IO until restarted or the stop is cancelled
// If a driver in the device stack determines that the device cannot be
// stopped for resource reconfiguration, the driver is not required to pass
// the IRP down the device stack. If a query-stop IRP fails,
// the PnP Manager sends an IRP_MN_CANCEL_STOP_DEVICE to the device stack,
// notifying the drivers for the device that the query has been cancelled
// and that the device will not be stopped.
// It is possible to receive this irp when the device has not been started
// ( as on a boot device )
UMSS_KdPrint( DBGLVL_MINIMUM,("IRP_MN_QUERY_STOP_DEVICE\n"));
if (!deviceExtension->DeviceStarted)
{
// if get when never started, just pass on
UMSS_KdPrint( DBGLVL_MEDIUM,("UMSS_ProcessPnPIrp() IRP_MN_QUERY_STOP_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
UMSS_DecrementIoCount(DeviceObject);
RETURN(ntStatus, UMSS_ProcessPnPIrp);
}
// We'll not veto it; pass it on and flag that stop was requested.
// Once StopDeviceRequested is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
deviceExtension->StopDeviceRequested = TRUE;
break; // end, case IRP_MN_QUERY_STOP_DEVICE
case IRP_MN_CANCEL_STOP_DEVICE:
// The PnP Manager uses this IRP to inform the drivers for a device
// that the device will not be stopped for resource reconfiguration.
// This should only be received after a successful IRP_MN_QUERY_STOP_DEVICE.
// It is possible to receive this irp when the device has not been started
if (!deviceExtension->DeviceStarted)
{
// if get when never started, just pass on
UMSS_KdPrint( DBGLVL_MEDIUM,("UMSS_ProcessPnPIrp() IRP_MN_CANCEL_STOP_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
UMSS_DecrementIoCount(DeviceObject);
return ntStatus;
}
// Reset this flag so new IOCTL and IO Irp processing will be re-enabled
deviceExtension->StopDeviceRequested = FALSE;
break; // end, case IRP_MN_CANCEL_STOP_DEVICE
case IRP_MN_STOP_DEVICE:
// The PnP Manager sends this IRP to stop a device so it can reconfigure
// its hardware resources. The PnP Manager only sends this IRP if a prior
// IRP_MN_QUERY_STOP_DEVICE completed successfully.
UMSS_KdPrint( DBGLVL_MINIMUM,("IRP_MN_STOP_DEVICE\n"));
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle, this closes the configuration and puts the device in the 'unconfigured'
// state.
//
ntStatus = UMSS_StopDevice(DeviceObject);
break; // end, case IRP_MN_STOP_DEVICE
case IRP_MN_QUERY_REMOVE_DEVICE:
// In response to this IRP, drivers indicate whether the device can be
// removed without disrupting the system.
// If a driver determines it is safe to remove the device,
// the driver completes any outstanding I/O requests, arranges to hold any subsequent
// read/write requests, and sets Irp->IoStatus.Status to STATUS_SUCCESS. Function
// and filter drivers then pass the IRP to the next-lower driver in the device stack.
// The underlying bus driver calls IoCompleteRequest.
// If a driver sets STATUS_SUCCESS for this IRP, the driver must not start any
// operations on the device that would prevent that driver from successfully completing
// an IRP_MN_REMOVE_DEVICE for the device. If a driver in the device stack determines
// that the device cannot be removed, the driver is not required to pass the
// query-remove IRP down the device stack. If a query-remove IRP fails, the PnP Manager
// sends an IRP_MN_CANCEL_REMOVE_DEVICE to the device stack, notifying the drivers for
// the device that the query has been cancelled and that the device will not be removed.
// It is possible to receive this irp when the device has not been started
UMSS_KdPrint( DBGLVL_MINIMUM,("IRP_MN_QUERY_REMOVE_DEVICE\n"));
if (!deviceExtension->DeviceStarted)
{
// if get when never started, just pass on
UMSS_KdPrint( DBGLVL_MEDIUM,("UMSS_ProcessPnPIrp() IRP_MN_QUERY_STOP_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
UMSS_DecrementIoCount(DeviceObject);
RETURN(ntStatus, UMSS_ProcessPnPIrp);
}
// Once RemoveDeviceRequested is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
deviceExtension->RemoveDeviceRequested = TRUE;
// Wait for any io request pending in our driver to
// complete before returning success.
// This event is set when deviceExtension->PendingIoCount goes to 1
waitStatus = KeWaitForSingleObject(
&deviceExtension->NoPendingIoEvent,
Suspended,
KernelMode,
FALSE,
NULL
);
break; // end, case IRP_MN_QUERY_REMOVE_DEVICE
case IRP_MN_CANCEL_REMOVE_DEVICE:
// The PnP Manager uses this IRP to inform the drivers
// for a device that the device will not be removed.
// It is sent only after a successful IRP_MN_QUERY_REMOVE_DEVICE.
if (!deviceExtension->DeviceStarted)
{
// if get when never started, just pass on
UMSS_KdPrint( DBGLVL_MEDIUM,("UMSS_ProcessPnPIrp() IRP_MN_CANCEL_REMOVE_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
UMSS_DecrementIoCount(DeviceObject);
RETURN(ntStatus, UMSS_ProcessPnPIrp);
}
// Reset this flag so new IOCTL and IO Irp processing will be re-enabled
deviceExtension->RemoveDeviceRequested = FALSE;
break; // end, case IRP_MN_CANCEL_REMOVE_DEVICE
case IRP_MN_SURPRISE_REMOVAL:
UMSS_KdPrint( DBGLVL_MEDIUM,("UMSS_ProcessPnPIrp() IRP_MN_SURPRISE_REMOVAL\n"));
// For a surprise-style device removal ( i.e. sudden cord yank ),
// the physical device has already been removed so the PnP Manager sends
// the remove IRP without a prior query-remove. A device can be in any state
// when it receives a remove IRP as a result of a surprise-style removal.
// match the inc at the begining of the dispatch routine
UMSS_DecrementIoCount(DeviceObject);
//
// Once DeviceRemoved is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
//
deviceExtension->DeviceRemoved = TRUE;
// If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
// This call will also close the pipes; if any user close calls get through,
// they will be noops
UMSS_AbortPipes( DeviceObject );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -