1431 lines
42 KiB
C
1431 lines
42 KiB
C
/*++
|
||
Copyright (c) 1998-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
PNP.C
|
||
|
||
Abstract:
|
||
|
||
This module contains contains the plugplay calls
|
||
PNP / WDM BUS driver.
|
||
|
||
@@BEGIN_DDKSPLIT
|
||
|
||
Author:
|
||
|
||
Jay Senior
|
||
|
||
@@END_DDKSPLIT
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
@@BEGIN_DDKSPLIT
|
||
|
||
Revision History:
|
||
Louis J. Giliberto, Jr. 22-Mar-1998 Cleanup
|
||
Louis J. Giliberto, Jr. 10-Jan-2000 Cleanup
|
||
|
||
@@END_DDKSPLIT
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text (PAGE, Serenum_AddDevice)
|
||
#pragma alloc_text (PAGE, Serenum_PnP)
|
||
#pragma alloc_text (PAGE, Serenum_FDO_PnP)
|
||
#pragma alloc_text (PAGE, Serenum_PDO_PnP)
|
||
#pragma alloc_text (PAGE, Serenum_PnPRemove)
|
||
//#pragma alloc_text (PAGE, Serenum_Remove)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
Serenum_AddDevice(IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT BusPhysicalDeviceObject)
|
||
/*++
|
||
Routine Description.
|
||
A bus has been found. Attach our FDO to it.
|
||
Allocate any required resources. Set things up. And be prepared for the
|
||
first ``start device.''
|
||
|
||
Arguments:
|
||
BusPhysicalDeviceObject - Device object representing the bus. That to which
|
||
we attach a new FDO.
|
||
|
||
DriverObject - This very self referenced driver.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT deviceObject;
|
||
PFDO_DEVICE_DATA pDeviceData;
|
||
ULONG nameLength;
|
||
HANDLE keyHandle;
|
||
ULONG actualLength;
|
||
|
||
PAGED_CODE();
|
||
|
||
Serenum_KdPrint_Def(SER_DBG_PNP_TRACE, ("Add Device: 0x%x\n",
|
||
BusPhysicalDeviceObject));
|
||
//
|
||
// Create our FDO
|
||
//
|
||
|
||
status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_DATA), NULL,
|
||
FILE_DEVICE_BUS_EXTENDER, 0, TRUE, &deviceObject);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
pDeviceData = (PFDO_DEVICE_DATA)deviceObject->DeviceExtension;
|
||
RtlFillMemory (pDeviceData, sizeof (FDO_DEVICE_DATA), 0);
|
||
|
||
pDeviceData->IsFDO = TRUE;
|
||
pDeviceData->DebugLevel = SER_DEFAULT_DEBUG_OUTPUT_LEVEL;
|
||
pDeviceData->Self = deviceObject;
|
||
pDeviceData->AttachedPDO = NULL;
|
||
pDeviceData->NumPDOs = 0;
|
||
pDeviceData->DeviceState = PowerDeviceD0;
|
||
pDeviceData->SystemState = PowerSystemWorking;
|
||
pDeviceData->PDOForcedRemove = FALSE;
|
||
|
||
pDeviceData->SystemWake=PowerSystemUnspecified;
|
||
pDeviceData->DeviceWake=PowerDeviceUnspecified;
|
||
|
||
pDeviceData->Removed = FALSE;
|
||
|
||
//
|
||
// Set the PDO for use with PlugPlay functions
|
||
//
|
||
|
||
pDeviceData->UnderlyingPDO = BusPhysicalDeviceObject;
|
||
|
||
|
||
//
|
||
// Attach our filter driver to the device stack.
|
||
// the return value of IoAttachDeviceToDeviceStack is the top of the
|
||
// attachment chain. This is where all the IRPs should be routed.
|
||
//
|
||
// Our filter will send IRPs to the top of the stack and use the PDO
|
||
// for all PlugPlay functions.
|
||
//
|
||
|
||
pDeviceData->TopOfStack
|
||
= IoAttachDeviceToDeviceStack(deviceObject, BusPhysicalDeviceObject);
|
||
|
||
//
|
||
// Set the type of IO we do
|
||
//
|
||
|
||
if (pDeviceData->TopOfStack->Flags & DO_BUFFERED_IO) {
|
||
deviceObject->Flags |= DO_BUFFERED_IO;
|
||
} else if (pDeviceData->TopOfStack->Flags & DO_DIRECT_IO) {
|
||
deviceObject->Flags |= DO_DIRECT_IO;
|
||
}
|
||
|
||
//
|
||
// Bias outstanding request to 1 so that we can look for a
|
||
// transition to zero when processing the remove device PlugPlay IRP.
|
||
//
|
||
|
||
pDeviceData->OutstandingIO = 1;
|
||
|
||
KeInitializeEvent(&pDeviceData->RemoveEvent, SynchronizationEvent,
|
||
FALSE);
|
||
KeInitializeSemaphore(&pDeviceData->CreateSemaphore, 1, 1);
|
||
KeInitializeSpinLock(&pDeviceData->EnumerationLock);
|
||
|
||
|
||
|
||
//
|
||
// Tell the PlugPlay system that this device will need an interface
|
||
// device class shingle.
|
||
//
|
||
// It may be that the driver cannot hang the shingle until it starts
|
||
// the device itself, so that it can query some of its properties.
|
||
// (Aka the shingles guid (or ref string) is based on the properties
|
||
// of the device.)
|
||
//
|
||
|
||
status = IoRegisterDeviceInterface(BusPhysicalDeviceObject,
|
||
(LPGUID)&GUID_SERENUM_BUS_ENUMERATOR,
|
||
NULL,
|
||
&pDeviceData->DevClassAssocName);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR,
|
||
("AddDevice: IoRegisterDCA failed (%x)", status));
|
||
IoDetachDevice(pDeviceData->TopOfStack);
|
||
IoDeleteDevice(deviceObject);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// If for any reason you need to save values in a safe location that
|
||
// clients of this DeviceClassAssociate might be interested in reading
|
||
// here is the time to do so, with the function
|
||
// IoOpenDeviceClassRegistryKey
|
||
// the symbolic link name used is was returned in
|
||
// pDeviceData->DevClassAssocName (the same name which is returned by
|
||
// IoGetDeviceClassAssociations and the SetupAPI equivs.
|
||
//
|
||
|
||
#if DBG
|
||
{
|
||
PWCHAR deviceName = NULL;
|
||
|
||
status = IoGetDeviceProperty(BusPhysicalDeviceObject,
|
||
DevicePropertyPhysicalDeviceObjectName, 0,
|
||
NULL, &nameLength);
|
||
|
||
if ((nameLength != 0) && (status == STATUS_BUFFER_TOO_SMALL)) {
|
||
deviceName = ExAllocatePool(NonPagedPool, nameLength);
|
||
|
||
if (NULL == deviceName) {
|
||
goto someDebugStuffExit;
|
||
}
|
||
|
||
IoGetDeviceProperty(BusPhysicalDeviceObject,
|
||
DevicePropertyPhysicalDeviceObjectName,
|
||
nameLength, deviceName, &nameLength);
|
||
|
||
Serenum_KdPrint(pDeviceData, SER_DBG_PNP_TRACE,
|
||
("AddDevice: %x to %x->%x (%ws) \n", deviceObject,
|
||
pDeviceData->TopOfStack, BusPhysicalDeviceObject,
|
||
deviceName));
|
||
}
|
||
|
||
someDebugStuffExit:;
|
||
if (deviceName != NULL) {
|
||
ExFreePool(deviceName);
|
||
}
|
||
}
|
||
#endif // DBG
|
||
|
||
//
|
||
// Turn on the shingle and point it to the given device object.
|
||
//
|
||
status = IoSetDeviceInterfaceState(&pDeviceData->DevClassAssocName,
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR,
|
||
("AddDevice: IoSetDeviceClass failed (%x)", status));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Open the registry and read in our settings
|
||
//
|
||
|
||
status = IoOpenDeviceRegistryKey(pDeviceData->UnderlyingPDO,
|
||
PLUGPLAY_REGKEY_DEVICE,
|
||
STANDARD_RIGHTS_READ, &keyHandle);
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
status
|
||
= Serenum_GetRegistryKeyValue(keyHandle, L"SkipEnumerations",
|
||
sizeof(L"SkipEnumerations"),
|
||
&pDeviceData->SkipEnumerations,
|
||
sizeof(pDeviceData->SkipEnumerations),
|
||
&actualLength);
|
||
|
||
if ((status != STATUS_SUCCESS)
|
||
|| (actualLength != sizeof(pDeviceData->SkipEnumerations))) {
|
||
pDeviceData->SkipEnumerations = 0;
|
||
status = STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
ZwClose(keyHandle);
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
deviceObject->Flags |= DO_POWER_PAGABLE;
|
||
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
Serenum_PnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
||
/*++
|
||
Routine Description:
|
||
Answer the plethora of Irp Major PnP IRPS.
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack;
|
||
NTSTATUS status;
|
||
PCOMMON_DEVICE_DATA commonData;
|
||
KIRQL oldIrq;
|
||
|
||
PAGED_CODE();
|
||
|
||
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
|
||
|
||
commonData = (PCOMMON_DEVICE_DATA)DeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// If removed, fail the request and get out
|
||
//
|
||
|
||
if (commonData->Removed) {
|
||
|
||
Serenum_KdPrint(commonData, SER_DBG_PNP_TRACE,
|
||
("PNP: removed DO: %x got IRP: %x\n", DeviceObject,
|
||
Irp));
|
||
|
||
Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
goto PnPDone;
|
||
}
|
||
|
||
//
|
||
// Call either the FDO or PDO Pnp code
|
||
//
|
||
|
||
if (commonData->IsFDO) {
|
||
Serenum_KdPrint(commonData, SER_DBG_PNP_TRACE,
|
||
("PNP: Functional DO: %x IRP: %x MJ: %X MIN: %X\n",
|
||
DeviceObject, Irp, irpStack->MajorFunction,
|
||
irpStack->MinorFunction));
|
||
|
||
status = Serenum_FDO_PnP(DeviceObject, Irp, irpStack,
|
||
(PFDO_DEVICE_DATA)commonData);
|
||
goto PnPDone;
|
||
|
||
}
|
||
|
||
//
|
||
// PDO
|
||
//
|
||
|
||
Serenum_KdPrint(commonData, SER_DBG_PNP_TRACE,
|
||
("PNP: Physical DO: %x IRP: %x MJ: %X MIN: %X\n",
|
||
DeviceObject, Irp, irpStack->MajorFunction,
|
||
irpStack->MinorFunction));
|
||
|
||
status = Serenum_PDO_PnP(DeviceObject, Irp, irpStack,
|
||
(PPDO_DEVICE_DATA)commonData);
|
||
|
||
PnPDone:;
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SerenumCheckEnumerations(IN PFDO_DEVICE_DATA PFdoData)
|
||
{
|
||
|
||
KIRQL oldIrql;
|
||
NTSTATUS status;
|
||
PIRP pIrp;
|
||
BOOLEAN sameDevice = TRUE;
|
||
|
||
Serenum_KdPrint(PFdoData, SER_DBG_PNP_TRACE, ("Checking enumerations"));
|
||
|
||
//
|
||
// If appropriate, check for new devices or if old devices still there.
|
||
//
|
||
|
||
if (PFdoData->SkipEnumerations == 0) {
|
||
ULONG enumFlags;
|
||
|
||
KeAcquireSpinLock(&PFdoData->EnumerationLock, &oldIrql);
|
||
|
||
if (PFdoData->EnumFlags == SERENUM_ENUMFLAG_CLEAN) {
|
||
Serenum_KdPrint(PFdoData, SER_DBG_PNP_TRACE, ("EnumFlag Clean"));
|
||
|
||
//
|
||
// If nothing is going on, kick off an enumeration
|
||
//
|
||
|
||
PFdoData->EnumFlags |= SERENUM_ENUMFLAG_PENDING;
|
||
KeReleaseSpinLock(&PFdoData->EnumerationLock, oldIrql);
|
||
|
||
|
||
status = SerenumStartProtocolThread(PFdoData);
|
||
} else if ((PFdoData->EnumFlags
|
||
& (SERENUM_ENUMFLAG_REMOVED | SERENUM_ENUMFLAG_PENDING))
|
||
== SERENUM_ENUMFLAG_REMOVED) {
|
||
Serenum_KdPrint(PFdoData, SER_DBG_PNP_TRACE, ("EnumFlag Removed"));
|
||
//
|
||
// Clear the flag and do it synchronously to make sure we
|
||
// get the exact current state
|
||
//
|
||
|
||
PFdoData->EnumFlags &= ~SERENUM_ENUMFLAG_REMOVED;
|
||
|
||
KeReleaseSpinLock(&PFdoData->EnumerationLock, oldIrql);
|
||
|
||
pIrp = IoAllocateIrp(PFdoData->TopOfStack->StackSize + 1, FALSE);
|
||
|
||
if (pIrp == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto SerenumCheckEnumerationsOut;
|
||
}
|
||
|
||
status = Serenum_ReenumerateDevices(pIrp, PFdoData, &sameDevice);
|
||
|
||
if (pIrp != NULL) {
|
||
IoFreeIrp(pIrp);
|
||
}
|
||
|
||
KeAcquireSpinLock(&PFdoData->EnumerationLock, &oldIrql);
|
||
|
||
if (status == STATUS_SUCCESS) {
|
||
PFdoData->AttachedPDO = PFdoData->NewPDO;
|
||
PFdoData->PdoData = PFdoData->NewPdoData;
|
||
PFdoData->NumPDOs = PFdoData->NewNumPDOs;
|
||
PFdoData->PDOForcedRemove = PFdoData->NewPDOForcedRemove;
|
||
}
|
||
|
||
KeReleaseSpinLock(&PFdoData->EnumerationLock, oldIrql);
|
||
|
||
} else if (PFdoData->EnumFlags & SERENUM_ENUMFLAG_DIRTY) {
|
||
|
||
Serenum_KdPrint(PFdoData, SER_DBG_PNP_TRACE, ("EnumFlag Dirty"));
|
||
|
||
//
|
||
// If there is a new value, use the new values
|
||
//
|
||
|
||
PFdoData->AttachedPDO = PFdoData->NewPDO;
|
||
PFdoData->PdoData = PFdoData->NewPdoData;
|
||
PFdoData->NumPDOs = PFdoData->NewNumPDOs;
|
||
PFdoData->PDOForcedRemove = PFdoData->NewPDOForcedRemove;
|
||
PFdoData->EnumFlags &= ~SERENUM_ENUMFLAG_DIRTY;
|
||
|
||
KeReleaseSpinLock(&PFdoData->EnumerationLock, oldIrql);
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
Serenum_KdPrint(PFdoData, SER_DBG_PNP_TRACE, ("EnumFlag default"));
|
||
|
||
//
|
||
// Use the current values
|
||
//
|
||
|
||
KeReleaseSpinLock(&PFdoData->EnumerationLock, oldIrql);
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
} else {
|
||
status = STATUS_SUCCESS;
|
||
|
||
if (PFdoData->SkipEnumerations != 0xffffffff) {
|
||
PFdoData->SkipEnumerations--;
|
||
}
|
||
}
|
||
|
||
SerenumCheckEnumerationsOut:
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
Serenum_FDO_PnP (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack,
|
||
IN PFDO_DEVICE_DATA DeviceData
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Handle requests from the PlugPlay system for the BUS itself
|
||
|
||
NB: the various Minor functions of the PlugPlay system will not be
|
||
overlapped and do not have to be reentrant
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
KIRQL oldIrq;
|
||
KEVENT event;
|
||
ULONG length;
|
||
ULONG i;
|
||
PLIST_ENTRY entry;
|
||
PPDO_DEVICE_DATA pdoData;
|
||
PDEVICE_RELATIONS relations;
|
||
PIO_STACK_LOCATION stack;
|
||
PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
|
||
ULONG DebugLevelDefault = SER_DEFAULT_DEBUG_OUTPUT_LEVEL;
|
||
PVOID threadObj;
|
||
|
||
PAGED_CODE();
|
||
|
||
status = Serenum_IncIoCount (DeviceData);
|
||
if (!NT_SUCCESS (status)) {
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
return status;
|
||
}
|
||
|
||
stack = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
switch (IrpStack->MinorFunction) {
|
||
case IRP_MN_START_DEVICE:
|
||
//
|
||
// BEFORE you are allowed to ``touch'' the device object to which
|
||
// the FDO is attached (that send an irp from the bus to the Device
|
||
// object to which the bus is attached). You must first pass down
|
||
// the start IRP. It might not be powered on, or able to access or
|
||
// something.
|
||
//
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Start Device\n"));
|
||
|
||
if (DeviceData->Started) {
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Device already started\n"));
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
KeInitializeEvent (&event, NotificationEvent, FALSE);
|
||
IoCopyCurrentIrpStackLocationToNext (Irp);
|
||
|
||
IoSetCompletionRoutine (Irp,
|
||
SerenumSyncCompletion,
|
||
&event,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
|
||
if (STATUS_PENDING == status) {
|
||
// wait for it...
|
||
|
||
status = KeWaitForSingleObject (&event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE, // Not allertable
|
||
NULL); // No timeout structure
|
||
|
||
ASSERT (STATUS_SUCCESS == status);
|
||
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Now we can touch the lower device object as it is now started.
|
||
//
|
||
|
||
|
||
|
||
//
|
||
// Get the debug level from the registry
|
||
//
|
||
|
||
if (NULL == (QueryTable = ExAllocatePool(
|
||
PagedPool,
|
||
sizeof(RTL_QUERY_REGISTRY_TABLE)*2
|
||
))) {
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_ERROR,
|
||
("Failed to allocate memory to query registy\n"));
|
||
DeviceData->DebugLevel = DebugLevelDefault;
|
||
} else {
|
||
RtlZeroMemory(
|
||
QueryTable,
|
||
sizeof(RTL_QUERY_REGISTRY_TABLE)*2
|
||
);
|
||
|
||
QueryTable[0].QueryRoutine = NULL;
|
||
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
QueryTable[0].EntryContext = &DeviceData->DebugLevel;
|
||
QueryTable[0].Name = L"DebugLevel";
|
||
QueryTable[0].DefaultType = REG_DWORD;
|
||
QueryTable[0].DefaultData = &DebugLevelDefault;
|
||
QueryTable[0].DefaultLength= sizeof(ULONG);
|
||
|
||
// CIMEXCIMEX: The rest of the table isn't filled in!
|
||
|
||
if (!NT_SUCCESS(RtlQueryRegistryValues(
|
||
RTL_REGISTRY_SERVICES,
|
||
L"Serenum",
|
||
QueryTable,
|
||
NULL,
|
||
NULL))) {
|
||
Serenum_KdPrint (DeviceData,SER_DBG_PNP_ERROR,
|
||
("Failed to get debug level from registry. "
|
||
"Using default\n"));
|
||
DeviceData->DebugLevel = DebugLevelDefault;
|
||
}
|
||
|
||
ExFreePool( QueryTable );
|
||
}
|
||
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Start Device: Device started successfully\n"));
|
||
DeviceData->Started = TRUE;
|
||
}
|
||
|
||
//
|
||
// We must now complete the IRP, since we stopped it in the
|
||
// completetion routine with MORE_PROCESSING_REQUIRED.
|
||
//
|
||
break;
|
||
|
||
case IRP_MN_QUERY_STOP_DEVICE:
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Query Stop Device\n"));
|
||
|
||
//
|
||
// Test to see if there are any PDO created as children of this FDO
|
||
// If there are then conclude the device is busy and fail the
|
||
// query stop.
|
||
//
|
||
// CIMEXCIMEX
|
||
// We could do better, by seing if the children PDOs are actually
|
||
// currently open. If they are not then we could stop, get new
|
||
// resouces, fill in the new resouce values, and then when a new client
|
||
// opens the PDO use the new resources. But this works for now.
|
||
//
|
||
|
||
if (DeviceData->AttachedPDO
|
||
|| (DeviceData->EnumFlags & SERENUM_ENUMFLAG_PENDING)) {
|
||
status = STATUS_UNSUCCESSFUL;
|
||
|
||
} else {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
} else {
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
Serenum_DecIoCount (DeviceData);
|
||
return status;
|
||
|
||
case IRP_MN_CANCEL_STOP_DEVICE:
|
||
//
|
||
// We always succeed a cancel stop
|
||
//
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Cancel Stop Device\n"));
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoSkipCurrentIrpStackLocation(Irp);
|
||
status = IoCallDriver(DeviceData->TopOfStack, Irp);
|
||
|
||
Serenum_DecIoCount (DeviceData);
|
||
return status;
|
||
|
||
case IRP_MN_STOP_DEVICE:
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Stop Device\n"));
|
||
|
||
//
|
||
// Wait for the enum thread to complete if it's running
|
||
//
|
||
|
||
SerenumWaitForEnumThreadTerminate(DeviceData);
|
||
|
||
//
|
||
// After the start IRP has been sent to the lower driver object, the
|
||
// bus may NOT send any more IRPS down ``touch'' until another START
|
||
// has occured.
|
||
// What ever access is required must be done before the Irp is passed
|
||
// on.
|
||
//
|
||
// Stop device means that the resources given durring Start device
|
||
// are no revoked. So we need to stop using them
|
||
//
|
||
|
||
DeviceData->Started = FALSE;
|
||
|
||
//
|
||
// We don't need a completion routine so fire and forget.
|
||
//
|
||
// Set the current stack location to the next stack location and
|
||
// call the next device object.
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
|
||
Serenum_DecIoCount (DeviceData);
|
||
return status;
|
||
|
||
case IRP_MN_REMOVE_DEVICE:
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Remove Device\n"));
|
||
|
||
//
|
||
// The PlugPlay system has detected the removal of this device. We
|
||
// have no choice but to detach and delete the device object.
|
||
// (If we wanted to express and interest in preventing this removal,
|
||
// we should have filtered the query remove and query stop routines.)
|
||
//
|
||
// Note! we might receive a remove WITHOUT first receiving a stop.
|
||
// ASSERT (!DeviceData->Removed);
|
||
|
||
|
||
//
|
||
// Synchronize with the enum thread if it is running and wait
|
||
// for it to finish
|
||
//
|
||
|
||
|
||
SerenumWaitForEnumThreadTerminate(DeviceData);
|
||
|
||
// We will accept no new requests
|
||
//
|
||
DeviceData->Removed = TRUE;
|
||
|
||
//
|
||
// Complete any outstanding IRPs queued by the driver here.
|
||
//
|
||
|
||
//
|
||
// Make the DCA go away. Some drivers may choose to remove the DCA
|
||
// when they receive a stop or even a query stop. We just don't care.
|
||
//
|
||
IoSetDeviceInterfaceState (&DeviceData->DevClassAssocName, FALSE);
|
||
|
||
//
|
||
// Here if we had any outstanding requests in a personal queue we should
|
||
// complete them all now.
|
||
//
|
||
// Note, the device is guarenteed stopped, so we cannot send it any non-
|
||
// PNP IRPS.
|
||
//
|
||
|
||
//
|
||
// Fire and forget
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
|
||
//
|
||
// Wait for any outstanding threads to complete
|
||
//
|
||
|
||
//
|
||
// Wait for all outstanding requests to complete
|
||
//
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Waiting for outstanding requests\n"));
|
||
i = InterlockedDecrement (&DeviceData->OutstandingIO);
|
||
|
||
ASSERT (0 < i);
|
||
|
||
if (0 != InterlockedDecrement (&DeviceData->OutstandingIO)) {
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_INFO,
|
||
("Remove Device waiting for request to complete\n"));
|
||
|
||
KeWaitForSingleObject (&DeviceData->RemoveEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE, // Not Alertable
|
||
NULL); // No timeout
|
||
}
|
||
//
|
||
// Free the associated resources
|
||
//
|
||
|
||
//
|
||
// Detach from the underlying devices.
|
||
//
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_INFO,
|
||
("IoDetachDevice: 0x%x\n", DeviceData->TopOfStack));
|
||
IoDetachDevice (DeviceData->TopOfStack);
|
||
|
||
//
|
||
// Clean up any resources here
|
||
//
|
||
|
||
|
||
ExFreePool (DeviceData->DevClassAssocName.Buffer);
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_INFO,
|
||
("IoDeleteDevice: 0x%x\n", DeviceObject));
|
||
|
||
//
|
||
// Remove any PDO's we ejected
|
||
//
|
||
|
||
if (DeviceData->AttachedPDO != NULL) {
|
||
ASSERT(DeviceData->NumPDOs == 1);
|
||
|
||
Serenum_PnPRemove(DeviceData->AttachedPDO, DeviceData->PdoData);
|
||
DeviceData->PdoData = NULL;
|
||
DeviceData->AttachedPDO = NULL;
|
||
DeviceData->NumPDOs = 0;
|
||
}
|
||
|
||
IoDeleteDevice(DeviceObject);
|
||
|
||
return status;
|
||
|
||
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
||
if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) {
|
||
//
|
||
// We don't support this
|
||
//
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Query Device Relations - Non bus\n"));
|
||
goto SER_FDO_PNP_DEFAULT;
|
||
}
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Query Bus Relations\n"));
|
||
|
||
status = SerenumCheckEnumerations(DeviceData);
|
||
|
||
|
||
//
|
||
// Tell the plug and play system about all the PDOs.
|
||
//
|
||
// There might also be device relations below and above this FDO,
|
||
// so, be sure to propagate the relations from the upper drivers.
|
||
//
|
||
// No Completion routine is needed so long as the status is preset
|
||
// to success. (PDOs complete plug and play irps with the current
|
||
// IoStatus.Status and IoStatus.Information as the default.)
|
||
//
|
||
|
||
//KeAcquireSpinLock (&DeviceData->Spin, &oldIrq);
|
||
|
||
i = (0 == Irp->IoStatus.Information) ? 0 :
|
||
((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count;
|
||
// The current number of PDOs in the device relations structure
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("#PDOS = %d + %d\n", i, DeviceData->NumPDOs));
|
||
|
||
length = sizeof(DEVICE_RELATIONS) +
|
||
((DeviceData->NumPDOs + i) * sizeof (PDEVICE_OBJECT));
|
||
|
||
relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, length);
|
||
|
||
if (NULL == relations) {
|
||
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
Serenum_DecIoCount(DeviceData);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Copy in the device objects so far
|
||
//
|
||
if (i) {
|
||
RtlCopyMemory (
|
||
relations->Objects,
|
||
((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Objects,
|
||
i * sizeof (PDEVICE_OBJECT));
|
||
}
|
||
relations->Count = DeviceData->NumPDOs + i;
|
||
|
||
//
|
||
// For each PDO on this bus add a pointer to the device relations
|
||
// buffer, being sure to take out a reference to that object.
|
||
// The PlugPlay system will dereference the object when it is done with
|
||
// it and free the device relations buffer.
|
||
//
|
||
|
||
if (DeviceData->NumPDOs) {
|
||
relations->Objects[relations->Count-1] = DeviceData->AttachedPDO;
|
||
ObReferenceObject (DeviceData->AttachedPDO);
|
||
}
|
||
|
||
//
|
||
// Set up and pass the IRP further down the stack
|
||
//
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
if (0 != Irp->IoStatus.Information) {
|
||
ExFreePool ((PVOID) Irp->IoStatus.Information);
|
||
}
|
||
Irp->IoStatus.Information = (ULONG_PTR)relations;
|
||
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
|
||
Serenum_DecIoCount (DeviceData);
|
||
|
||
return status;
|
||
|
||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||
//
|
||
// If we were to fail this call then we would need to complete the
|
||
// IRP here. Since we are not, set the status to SUCCESS and
|
||
// call the next driver.
|
||
//
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
|
||
("Query Remove Device\n"));
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
Serenum_DecIoCount (DeviceData);
|
||
return status;
|
||
|
||
|
||
case IRP_MN_QUERY_CAPABILITIES: {
|
||
|
||
PIO_STACK_LOCATION irpSp;
|
||
|
||
//
|
||
// Send this down to the PDO first
|
||
//
|
||
|
||
KeInitializeEvent (&event, NotificationEvent, FALSE);
|
||
IoCopyCurrentIrpStackLocationToNext (Irp);
|
||
|
||
IoSetCompletionRoutine (Irp,
|
||
SerenumSyncCompletion,
|
||
&event,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
|
||
if (STATUS_PENDING == status) {
|
||
// wait for it...
|
||
|
||
status = KeWaitForSingleObject (&event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE, // Not allertable
|
||
NULL); // No timeout structure
|
||
|
||
ASSERT (STATUS_SUCCESS == status);
|
||
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
DeviceData->SystemWake
|
||
= irpSp->Parameters.DeviceCapabilities.Capabilities->SystemWake;
|
||
DeviceData->DeviceWake
|
||
= irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceWake;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
|
||
|
||
SER_FDO_PNP_DEFAULT:
|
||
default:
|
||
//
|
||
// In the default case we merely call the next driver since
|
||
// we don't know what to do.
|
||
//
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Default Case\n"));
|
||
|
||
//
|
||
// Fire and Forget
|
||
//
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
|
||
//
|
||
// Done, do NOT complete the IRP, it will be processed by the lower
|
||
// device object, which will complete the IRP
|
||
//
|
||
|
||
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
||
Serenum_DecIoCount (DeviceData);
|
||
return status;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
|
||
Serenum_DecIoCount (DeviceData);
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
SerenumMarkPdoRemoved(PFDO_DEVICE_DATA PFdoData)
|
||
{
|
||
KIRQL oldIrql;
|
||
|
||
KeAcquireSpinLock(&PFdoData->EnumerationLock, &oldIrql);
|
||
|
||
PFdoData->EnumFlags |= SERENUM_ENUMFLAG_REMOVED;
|
||
|
||
KeReleaseSpinLock(&PFdoData->EnumerationLock, oldIrql);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
Serenum_PDO_PnP (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack, IN PPDO_DEVICE_DATA DeviceData)
|
||
/*++
|
||
Routine Description:
|
||
Handle requests from the PlugPlay system for the devices on the BUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_CAPABILITIES deviceCapabilities;
|
||
ULONG information;
|
||
PWCHAR buffer;
|
||
ULONG length, i, j;
|
||
NTSTATUS status;
|
||
KIRQL oldIrq;
|
||
HANDLE keyHandle;
|
||
UNICODE_STRING keyName;
|
||
PWCHAR returnBuffer = NULL;
|
||
PFDO_DEVICE_DATA pFdoDeviceData;
|
||
|
||
PAGED_CODE();
|
||
|
||
status = Irp->IoStatus.Status;
|
||
|
||
//
|
||
// NB: since we are a bus enumerator, we have no one to whom we could
|
||
// defer these irps. Therefore we do not pass them down but merely
|
||
// return them.
|
||
//
|
||
|
||
switch (IrpStack->MinorFunction) {
|
||
case IRP_MN_QUERY_CAPABILITIES:
|
||
|
||
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Caps \n"));
|
||
|
||
//
|
||
// Get the packet.
|
||
//
|
||
|
||
deviceCapabilities=IrpStack->Parameters.DeviceCapabilities.Capabilities;
|
||
|
||
//
|
||
// Set the capabilities.
|
||
//
|
||
|
||
deviceCapabilities->Version = 1;
|
||
deviceCapabilities->Size = sizeof (DEVICE_CAPABILITIES);
|
||
|
||
//
|
||
// We cannot wake the system.
|
||
//
|
||
|
||
deviceCapabilities->SystemWake
|
||
= ((PFDO_DEVICE_DATA)DeviceData->ParentFdo->DeviceExtension)
|
||
->SystemWake;
|
||
deviceCapabilities->DeviceWake
|
||
= ((PFDO_DEVICE_DATA)DeviceData->ParentFdo->DeviceExtension)
|
||
->DeviceWake;
|
||
|
||
//
|
||
// We have no latencies
|
||
//
|
||
|
||
deviceCapabilities->D1Latency = 0;
|
||
deviceCapabilities->D2Latency = 0;
|
||
deviceCapabilities->D3Latency = 0;
|
||
|
||
deviceCapabilities->UniqueID = FALSE;
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_QUERY_DEVICE_TEXT: {
|
||
if ((IrpStack->Parameters.QueryDeviceText.DeviceTextType
|
||
!= DeviceTextDescription) || DeviceData->DevDesc.Buffer == NULL) {
|
||
break;
|
||
}
|
||
|
||
returnBuffer = ExAllocatePool(PagedPool, DeviceData->DevDesc.Length);
|
||
|
||
if (returnBuffer == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
RtlCopyMemory(returnBuffer, DeviceData->DevDesc.Buffer,
|
||
DeviceData->DevDesc.Length);
|
||
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE,
|
||
("TextID: buf 0x%x\n", returnBuffer));
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR)returnBuffer;
|
||
break;
|
||
}
|
||
|
||
|
||
case IRP_MN_QUERY_ID:
|
||
//
|
||
// Query the IDs of the device
|
||
//
|
||
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE,
|
||
("QueryID: 0x%x\n", IrpStack->Parameters.QueryId.IdType));
|
||
|
||
switch (IrpStack->Parameters.QueryId.IdType) {
|
||
|
||
|
||
case BusQueryInstanceID:
|
||
//
|
||
// Build an instance ID. This is what PnP uses to tell if it has
|
||
// seen this thing before or not. Build it from the first hardware
|
||
// id and the port number.
|
||
//
|
||
// NB since we do not incorperate the port number
|
||
// this method does not produce unique ids;
|
||
//
|
||
// return 0000 for all devices and have the flag set to not unique
|
||
//
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
length = SERENUM_INSTANCE_IDS_LENGTH * sizeof(WCHAR);
|
||
returnBuffer = ExAllocatePool(PagedPool, length);
|
||
|
||
if (returnBuffer != NULL) {
|
||
RtlCopyMemory(returnBuffer, SERENUM_INSTANCE_IDS, length);
|
||
} else {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE,
|
||
("InstanceID: buf 0x%x\n", returnBuffer));
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR)returnBuffer;
|
||
break;
|
||
|
||
|
||
//
|
||
// The other ID's we just copy from the buffers and are done.
|
||
//
|
||
|
||
case BusQueryDeviceID:
|
||
case BusQueryHardwareIDs:
|
||
case BusQueryCompatibleIDs:
|
||
{
|
||
PUNICODE_STRING pId;
|
||
status = STATUS_SUCCESS;
|
||
|
||
switch (IrpStack->Parameters.QueryId.IdType) {
|
||
case BusQueryDeviceID:
|
||
pId = &DeviceData->DeviceIDs;
|
||
break;
|
||
|
||
case BusQueryHardwareIDs:
|
||
pId = &DeviceData->HardwareIDs;
|
||
break;
|
||
|
||
case BusQueryCompatibleIDs:
|
||
pId = &DeviceData->CompIDs;
|
||
break;
|
||
}
|
||
|
||
buffer = pId->Buffer;
|
||
|
||
if (buffer != NULL) {
|
||
length = pId->Length;
|
||
returnBuffer = ExAllocatePool(PagedPool, length);
|
||
if (returnBuffer != NULL) {
|
||
#if DBG
|
||
RtlFillMemory(returnBuffer, length, 0xff);
|
||
#endif
|
||
RtlCopyMemory(returnBuffer, buffer, pId->Length);
|
||
} else {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|
||
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE,
|
||
("ID: Unicode 0x%x\n", pId));
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE,
|
||
("ID: buf 0x%x\n", returnBuffer));
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR)returnBuffer;
|
||
}
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case IRP_MN_QUERY_BUS_INFORMATION: {
|
||
PPNP_BUS_INFORMATION pBusInfo;
|
||
|
||
ASSERTMSG("Serenum appears not to be the sole bus?!?",
|
||
Irp->IoStatus.Information == (ULONG_PTR)NULL);
|
||
|
||
pBusInfo = ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
|
||
|
||
if (pBusInfo == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
pBusInfo->BusTypeGuid = GUID_BUS_TYPE_SERENUM;
|
||
pBusInfo->LegacyBusType = PNPBus;
|
||
|
||
//
|
||
// We really can't track our bus number since we can be torn
|
||
// down with our bus
|
||
//
|
||
|
||
pBusInfo->BusNumber = 0;
|
||
|
||
Irp->IoStatus.Information = (ULONG_PTR)pBusInfo;
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
||
switch (IrpStack->Parameters.QueryDeviceRelations.Type) {
|
||
case TargetDeviceRelation: {
|
||
PDEVICE_RELATIONS pDevRel;
|
||
|
||
//
|
||
// No one else should respond to this since we are the PDO
|
||
//
|
||
|
||
ASSERT(Irp->IoStatus.Information == 0);
|
||
|
||
if (Irp->IoStatus.Information != 0) {
|
||
break;
|
||
}
|
||
|
||
|
||
pDevRel = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
||
|
||
if (pDevRel == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
pDevRel->Count = 1;
|
||
pDevRel->Objects[0] = DeviceObject;
|
||
ObReferenceObject(DeviceObject);
|
||
|
||
status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = (ULONG_PTR)pDevRel;
|
||
break;
|
||
}
|
||
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MN_START_DEVICE:
|
||
|
||
//
|
||
// Save serial number and PnPRev
|
||
//
|
||
|
||
if(DeviceData->PnPRev.Length || DeviceData->SerialNo.Length) {
|
||
UNICODE_STRING keyname;
|
||
HANDLE pnpKey;
|
||
|
||
status = IoOpenDeviceRegistryKey(DeviceObject, PLUGPLAY_REGKEY_DEVICE,
|
||
STANDARD_RIGHTS_WRITE, &pnpKey);
|
||
if(DeviceData->PnPRev.Length) {
|
||
RtlInitUnicodeString(&keyname, NULL);
|
||
keyname.MaximumLength = sizeof(L"PnPRev"+sizeof(WCHAR));
|
||
keyname.Buffer = ExAllocatePool(PagedPool, keyname.MaximumLength);
|
||
|
||
if (keyname.Buffer != NULL) {
|
||
|
||
RtlAppendUnicodeToString(&keyname, L"PnPRev");
|
||
status = ZwSetValueKey(pnpKey, &keyname, 0, REG_SZ, DeviceData->PnPRev.Buffer, DeviceData->PnPRev.Length+sizeof(WCHAR));
|
||
ExFreePool(keyname.Buffer);
|
||
}
|
||
}
|
||
if(DeviceData->SerialNo.Length) {
|
||
RtlInitUnicodeString(&keyname, NULL);
|
||
keyname.MaximumLength = sizeof(L"Serial Number"+sizeof(WCHAR));
|
||
keyname.Buffer = ExAllocatePool(PagedPool, keyname.MaximumLength);
|
||
|
||
if (keyname.Buffer != NULL) {
|
||
|
||
RtlAppendUnicodeToString(&keyname, L"Serial Number");
|
||
status = ZwSetValueKey(pnpKey, &keyname, 0, REG_SZ, DeviceData->SerialNo.Buffer, DeviceData->SerialNo.Length+sizeof(WCHAR));
|
||
ExFreePool(keyname.Buffer);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
DeviceData->Started = TRUE;
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_STOP_DEVICE:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("Stop Device\n"));
|
||
|
||
//
|
||
// Here we shut down the device. The opposite of start.
|
||
//
|
||
|
||
DeviceData->Started = FALSE;
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_REMOVE_DEVICE:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("Remove Device\n"));
|
||
|
||
//
|
||
// Mark as removed so we enumerate devices correctly -- this will
|
||
// cause the next enumeration request to occur synchronously
|
||
//
|
||
|
||
SerenumMarkPdoRemoved((PFDO_DEVICE_DATA)DeviceData->ParentFdo
|
||
->DeviceExtension);
|
||
|
||
//
|
||
// Attached is only set to FALSE by the enumeration process.
|
||
//
|
||
|
||
if (!DeviceData->Attached) {
|
||
|
||
status = Serenum_PnPRemove(DeviceObject, DeviceData);
|
||
}
|
||
else {
|
||
//
|
||
// Succeed the remove
|
||
///
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MN_QUERY_STOP_DEVICE:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("Query Stop Device\n"));
|
||
|
||
//
|
||
// No reason here why we can't stop the device.
|
||
// If there were a reason we should speak now for answering success
|
||
// here may result in a stop device irp.
|
||
//
|
||
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_CANCEL_STOP_DEVICE:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("Cancel Stop Device\n"));
|
||
//
|
||
// The stop was canceled. Whatever state we set, or resources we put
|
||
// on hold in anticipation of the forcoming STOP device IRP should be
|
||
// put back to normal. Someone, in the long list of concerned parties,
|
||
// has failed the stop device query.
|
||
//
|
||
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("Query Remove Device\n"));
|
||
//
|
||
// Just like Query Stop only now the impending doom is the remove irp
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("Cancel Remove Device"
|
||
"\n"));
|
||
//
|
||
// Clean up a remove that did not go through, just like cancel STOP.
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
||
case IRP_MN_READ_CONFIG:
|
||
case IRP_MN_WRITE_CONFIG: // we have no config space
|
||
case IRP_MN_EJECT:
|
||
case IRP_MN_SET_LOCK:
|
||
case IRP_MN_QUERY_INTERFACE: // We do not have any non IRP based interfaces.
|
||
default:
|
||
Serenum_KdPrint(DeviceData, SER_DBG_PNP_TRACE, ("PNP Not handled 0x%x\n",
|
||
IrpStack->MinorFunction));
|
||
// For PnP requests to the PDO that we do not understand we should
|
||
// return the IRP WITHOUT setting the status or information fields.
|
||
// They may have already been set by a filter (eg acpi).
|
||
break;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
Serenum_PnPRemove (PDEVICE_OBJECT Device, PPDO_DEVICE_DATA PdoData)
|
||
/*++
|
||
Routine Description:
|
||
The PlugPlay subsystem has instructed that this PDO should be removed.
|
||
|
||
We should therefore
|
||
- Complete any requests queued in the driver
|
||
- If the device is still attached to the system,
|
||
then complete the request and return.
|
||
- Otherwise, cleanup device specific allocations, memory, events...
|
||
- Call IoDeleteDevice
|
||
- Return from the dispatch routine.
|
||
|
||
Note that if the device is still connected to the bus (IE in this case
|
||
the control panel has not yet told us that the serial device has
|
||
disappeared) then the PDO must remain around, and must be returned during
|
||
any query Device relaions IRPS.
|
||
|
||
--*/
|
||
|
||
{
|
||
Serenum_KdPrint(PdoData, SER_DBG_PNP_TRACE,
|
||
("Serenum_PnPRemove: 0x%x\n", Device));
|
||
|
||
//
|
||
// Complete any outstanding requests with STATUS_DELETE_PENDING.
|
||
//
|
||
// Serenum does not queue any irps at this time so we have nothing to do.
|
||
//
|
||
|
||
if (PdoData->Attached || PdoData->Removed) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
PdoData->Removed = TRUE;
|
||
|
||
//
|
||
// Free any resources.
|
||
//
|
||
|
||
RtlFreeUnicodeString(&PdoData->HardwareIDs);
|
||
RtlFreeUnicodeString(&PdoData->CompIDs);
|
||
RtlFreeUnicodeString(&PdoData->DeviceIDs);
|
||
|
||
Serenum_KdPrint(PdoData, SER_DBG_PNP_INFO,
|
||
("IoDeleteDevice: 0x%x\n", Device));
|
||
|
||
IoDeleteDevice(Device);
|
||
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|