📄 pnp.c
字号:
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 1995 - 1999 OSR Open Systems Resources, Inc.
// All Rights Reserved
//
// This sofware is supplied for instructional purposes only.
//
// OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
// for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
// THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
// WITH YOU. OSR's entire liability and your exclusive remedy shall not
// exceed the price paid for this material. In no event shall OSR or its
// suppliers be liable for any damages whatsoever (including, without
// limitation, damages for loss of business profit, business interruption,
// loss of business information, or any other pecuniary loss) arising out
// of the use or inability to use this software, even if OSR has been
// advised of the possibility of such damages. Because some states/
// jurisdictions do not allow the exclusion or limitation of liability for
// consequential or incidental damages, the above limitation may not apply
// to you.
//
// OSR Open Systems Resources, Inc.
// 105 Route 101A Suite 19
// Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503
// email bugs to: bugs@osr.com
//
//
// MODULE:
//
// PnP.C -- Plug and Play module for OSR WDM Sample PCI Driver
//
// ABSTRACT:
//
// This file contains the Plug and Play support routines for
// the OSR WDM Sample PCI Driver.
//
// AUTHOR(S):
//
// OSR Open Systems Resources, Inc.
//
// REVISION:
//
//
///////////////////////////////////////////////////////////////////////////////
//
// The GUID needs to be defined SOMEwhere!
//
#define INITGUID // define GUID_SIMPLE
#include "osr-pci.h"
//
// Instantiate the GUID for this device
//
#if !defined(FAR)
#define FAR
#endif // !defined(FAR)
#include <initguid.h>
DEFINE_GUID(OSR_GUID, 0xd0fbbbe6, 0x8631, 0x11d2,0xb1, 0x62, 0x00, 0x60, 0xb0, 0xef, 0xd4, 0xaa);
VOID OsrUnload(PDRIVER_OBJECT DriverObject);
#if DBG
VOID OsrPrintState(POSR_DEVICE_EXT devExt);
#endif
VOID OsrRequestIncrement(POSR_DEVICE_EXT devExt);
VOID OsrRequestDecrement(POSR_DEVICE_EXT devExt);
VOID OsrWaitForStop(POSR_DEVICE_EXT devExt);
VOID OsrWaitForRemove(POSR_DEVICE_EXT devExt);
VOID OsrReturnResources(POSR_DEVICE_EXT devExt);
NTSTATUS OsrStartDevice (IN POSR_DEVICE_EXT devExt,IN PIO_STACK_LOCATION IrpSp);
NTSTATUS OsrCanStopDevice(POSR_DEVICE_EXT devExt, PIRP Irp);
NTSTATUS OsrCanRemoveDevice(POSR_DEVICE_EXT devExt, PIRP Irp);
static NTSTATUS OsrPnpComplete (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context);
extern PUNICODE_STRING OsrWDMSample_RegistryPath;
static PSTR pnpMinorCodes[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"***** FUNCTION 0x0e",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL"
};
#if DBG
VOID OsrPrintResourceList(PCM_RESOURCE_LIST);
VOID OsrPrintConfig(PPCI_COMMON_CONFIG configInfo);
#endif
///////////////////////////////////////////////////////////////////////////////
//
// OsrAddDevice
//
// We are called at this entry point by the Plug and Play Manager
// to add a Functional Device Object for a Physical Device Object.
// Note that we may NOT access the device in this routine, as the
// Plug and Play Manager has not yet given us any hardware resoruces.
// We get these hardware resources via the IRP_MJ_PNP IRP with
// a minor function IRP_MN_START_DEVICE.
//
//
// INPUTS:
//
// DriverObj - Address of our DRIVER_OBJECT.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL_PASSIVE_LEVEL.
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
POSR_DEVICE_EXT devExt;
PDEVICE_OBJECT functionalDeviceObject;
UNICODE_STRING devName;
UNICODE_STRING linkName;
NTSTATUS code = STATUS_SUCCESS;
#if DBG
DbgPrint("OsrAddDevice: entered\n");
#endif
#if DBG
DbgPrint("OsrAddDevice: PDO = 0x%0x\n", PhysicalDeviceObject);
#endif
//
// Initialize the UNICODE device name. This will be the "native NT" name
// for our device.
//
RtlInitUnicodeString(&devName, L"\\Device\\OSRPCI");
//
// Ask the I/O Manager to create the device object and
// device extension. In PnP terms, this is the FUNCTIONAL
// Device Object (FDO) for the device.
//
code = IoCreateDevice(DriverObject,
sizeof(OSR_DEVICE_EXT),
&devName,
FILE_DEVICE_OSR,
0,
FALSE,
&functionalDeviceObject);
if(!NT_SUCCESS(code)) {
#if DBG
DbgPrint("IoCreateDevice failed. Status = 0x%0x\n", code);
#endif
return(STATUS_UNSUCCESSFUL);
}
//
// Get a pointer to our device extension
//
devExt = (POSR_DEVICE_EXT)functionalDeviceObject->DeviceExtension;
#if DBG
DbgPrint("OsrAddDevice: FDO = 0x%0x\n", functionalDeviceObject);
#endif
//
// Zero out the device extension. While not strictly necessary
// (the documentation says the device extension is zeroed) it's
// better to be safe.
//
RtlZeroMemory(devExt, sizeof(OSR_DEVICE_EXT));
//
// Save the device object pointer away for future reference
//
devExt->FunctionalDeviceObject = functionalDeviceObject;
//
// Save the address of the physical device object away for future reference
//
devExt->PhysicalDeviceObject = PhysicalDeviceObject;
//
// Clear the Device Initializing bit since the Device Object was created
// outside of DriverEntry.
//
functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Create a familiar name for this device, so that non-kernel mode
// programs can open the device.
//
// NOTE: WDM Drivers on Win98 MUST create this link in the
// \DosDevices directory. \?? will NOT work.
//
RtlInitUnicodeString(&linkName, L"\\DosDevices\\OSRPCI");
//
// IoCreateSymbolicLink IS a WDM function...
//
code = IoCreateSymbolicLink(&linkName, &devName);
if (!NT_SUCCESS(code))
{
DbgPrint("IoCreateSymbolicLink failed. Status = 0x%x\n", code);
code = STATUS_SUCCESS;
//
// Clean up the mess
//
OsrUnload(DriverObject);
//
// Indicate load failure to the I/O manager; driver image is deleted...
//
return(code);
}
//
// Initialize our IRP queues
//
InitializeListHead(&devExt->ReadQueue);
InitializeListHead(&devExt->WriteQueue);
//
// Initialize our Spin Locks
//
KeInitializeSpinLock(&devExt->ReadQueueLock);
KeInitializeSpinLock(&devExt->WriteQueueLock);
//
// Ask the I/O Manager to use describe user read/write buffers using MDLs
//
functionalDeviceObject->Flags |= DO_DIRECT_IO;
//
// Set up the "Remove Event" and "Stop Event".
//
// Note that we can't use an official "Remove Lock" here, because
// the Remove Lock related calls are not in WDM.
//
KeInitializeEvent(&devExt->RemoveEvent, NotificationEvent, FALSE);
KeInitializeEvent(&devExt->StopEvent, NotificationEvent, TRUE);
//
// Init the count of in-progress I/O requests to zero. We use this
// to keep track of when we can remove the device.
//
devExt->OutstandingIO = 0;
//
// Internal device state flags, used for managing PnP state of device
//
devExt->Started = FALSE;
devExt->HoldNewRequests = TRUE;
devExt->Removed = FALSE;
//
// Set initial state
//
devExt->State = STATE_NEVER_STARTED;
//
// Attach our FDO to the underlying PDO
//
devExt->DeviceToSendIrpsTo =
IoAttachDeviceToDeviceStack(functionalDeviceObject,
PhysicalDeviceObject);
//
// If that didn't work...
//
if (!devExt->DeviceToSendIrpsTo)
{
DbgPrint("IoAttachDeviceToDeviceStack failed to attach to Target Device");
//
// Clean up the mess
//
OsrUnload(DriverObject);
//
// Indicate load failure to the I/O manager; driver image is deleted...
//
return(STATUS_UNSUCCESSFUL);
}
#if DBG
DbgPrint("OsrAddDevice: done\n");
#endif
return code;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrPnp
//
// This is the dispatch entry point for IRP_MJ_PNP requests. The
// driver processes these requets, based on the current state of
// the device.
//
//
// INPUTS:
//
// DeviceObject - Address of the Functional DEVICE_OBJECT for our device.
//
// Irp - Address of the IRP representing the IRP_MJ_PNP request.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
//
// IRQL:
//
// This routine is called at IRQL_PASSIVE_LEVEL.
//
// NOTES:
//
// There are several difficulties implementing Plug and Play.
// Perhaps the greatest difficulty is deciding precisely how you
// want your device to work, given the various requests the driver
// can receive and the states the device can be in. In our driver,
// we've decided to implement the following policies:
//
// 1) When a removal of the device is requested, we will reject
// any new IRPs we receive (completing them with an error
// status in the dispatch routine). We will wait until all IRPs
// that are already present on the device's queue are complete
// and then allow the remove.
//
// 2) When a stop of the device is requested, we'll queue any
// newly received IRPs, but not initiate them. We will wait
// until any IRPs that are presently ACTIVE in progress on the
// device complete, and then allow the stop.
//
// 3) When a SUPRISE removal of the device is indicated, we
// immediately cancel any requests that are queued, reject any
// newly arriving requests.
//
// Of course, the second complexity in implementing plug and play
// is getting the logic in your driver correct, so that it works
// as you intend. According to our experience, this is easier said
// than done.
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS
OsrPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION ioStackLocation;
NTSTATUS code = STATUS_SUCCESS;
POSR_DEVICE_EXT devExt;
KEVENT eventWaitLowerDrivers;
PDEVICE_OBJECT targetDevice;
#if DBG
DbgPrint("OsrPnp: called\n");
#endif
//
// Get a pointer to our (FUNCTIONAL) device object's device
// extension.
//
devExt = (POSR_DEVICE_EXT)DeviceObject->DeviceExtension;
//
// Up the count of in-progress requests
//
OsrRequestIncrement(devExt);
ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
KeInitializeEvent(&eventWaitLowerDrivers, NotificationEvent, FALSE);
#if DBG
DbgPrint("OsrPnp: Current state: ");
OsrPrintState(devExt);
DbgPrint("OsrPnp: *** PNP Minor Function is %s\n",
pnpMinorCodes[ioStackLocation->MinorFunction]);
#endif
switch( devExt->State + ioStackLocation->MinorFunction ) {
//
// STATE: STOPPED or NEVER_STARTED
// IRP_MN: _START_DEVICE
//
// We're here if we've received an AddDevice() call, but we
// do not have a set of hardware resources from the PnP Manager.
//
// The PnP Manager is now giving us a set of resources, and
// asking us to start the device.
//
// In this case, we pass the IRP all the way down. When it's
// done (and our completion routine is called) we can then
// read the list of device resources pointed to in the IRP
// Stack Location.
//
case STATE_STOPPED + IRP_MN_START_DEVICE:
case STATE_NEVER_STARTED + IRP_MN_START_DEVICE:
#if DBG
DbgPrint("OsrPnp: PROCESSING START_DEVICE\n");
#endif
//
// The BUS DRIVER handles this IRP before we do
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// Call OsrPnpComplete() when this IRP is done...
//
IoSetCompletionRoutine(Irp,
OsrPnpComplete,
&eventWaitLowerDrivers,
TRUE,
TRUE,
TRUE);
//
// Send the IRP to the bus driver. Let's see what HE
// thinks.
//
code = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
if (STATUS_PENDING == code) {
KeWaitForSingleObject(&eventWaitLowerDrivers,
Executive,
KernelMode,
FALSE,
NULL);
code = Irp->IoStatus.Status;
}
//
// Can the bus driver do the start?
//
if (NT_SUCCESS (code)) {
//
// Yup. Go initialize the device. The CmResourceLists
// are pointed to by the IoStackLocation.
//
code = OsrStartDevice(devExt, ioStackLocation);
//
// If the our StartDevice function succeeded, the
// device is now "officially" started!
//
if(NT_SUCCESS(code)) {
devExt->State = STATE_STARTED;
}
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -