📄 pnp.c
字号:
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
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.
Module Name:
PNP.C
Abstract:
This module handles plug & play calls for the toaster bus controller FDO.
Author:
Eliyas Yakub Sep 11, 1998
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include <ntddk.h>
#include <initguid.h>
#include "..\inc\driver.h"
#include "busenum.h"
#include "stdio.h"
#include <wdmguid.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, Bus_AddDevice)
#pragma alloc_text (PAGE, Bus_PnP)
#pragma alloc_text (PAGE, Bus_PlugInDevice)
#pragma alloc_text (PAGE, Bus_InitializePdo)
#pragma alloc_text (PAGE, Bus_UnPlugDevice)
#pragma alloc_text (PAGE, Bus_DestroyPdo)
#pragma alloc_text (PAGE, Bus_RemoveFdo)
#pragma alloc_text (PAGE, Bus_FDO_PnP)
#pragma alloc_text (PAGE, Bus_StartFdo)
#pragma alloc_text (PAGE, Bus_SendIrpSynchronously)
#endif
NTSTATUS
Bus_AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description.
Our Toaster bus has been found. Attach our FDO to it.
Allocate any required resources. Set things up.
And be prepared for the ``start device''
Arguments:
DriverObject - pointer to driver object.
PhysicalDeviceObject - Device object representing the bus to which we
will attach a new FDO.
--*/
{
NTSTATUS status;
PDEVICE_OBJECT deviceObject;
PFDO_DEVICE_DATA deviceData;
#if DBG
PWCHAR deviceName;
ULONG nameLength;
#endif
PAGED_CODE ();
Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Add Device: 0x%x\n",
PhysicalDeviceObject));
status = IoCreateDevice (
DriverObject, // our driver object
sizeof (FDO_DEVICE_DATA), // device object extension size
NULL, // FDOs do not have names
FILE_DEVICE_BUS_EXTENDER, // We are a bus
FILE_DEVICE_SECURE_OPEN, //
TRUE, // our FDO is exclusive
&deviceObject); // The device object created
if (!NT_SUCCESS (status))
{
return status;
}
deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
RtlZeroMemory (deviceData, sizeof (FDO_DEVICE_DATA));
//
// Set the initial state of the FDO
//
INITIALIZE_PNP_STATE(deviceData);
deviceData->DebugLevel = BusEnumDebugLevel;
deviceData->IsFDO = TRUE;
deviceData->Self = deviceObject;
ExInitializeFastMutex (&deviceData->Mutex);
InitializeListHead (&deviceData->ListOfPDOs);
// Set the PDO for use with PlugPlay functions
deviceData->UnderlyingPDO = PhysicalDeviceObject;
//
// Set the initial powerstate of the FDO
//
deviceData->DevicePowerState = PowerDeviceUnspecified;
deviceData->SystemPowerState = PowerSystemWorking;
//
// Biased to 1. Transition to zero during remove device
// means IO is finished. Transition to 1 means the device
// can be stopped.
//
deviceData->OutstandingIO = 1;
//
// Initialize the remove event to Not-Signaled. This event
// will be set when the OutstandingIO will become 0.
//
KeInitializeEvent(&deviceData->RemoveEvent,
SynchronizationEvent,
FALSE);
//
// Initialize the stop event to Signaled:
// there are no Irps that prevent the device from being
// stopped. This event will be set when the OutstandingIO
// will become 0.
//
KeInitializeEvent(&deviceData->StopEvent,
SynchronizationEvent,
TRUE);
deviceObject->Flags |= DO_POWER_PAGABLE;
//
// Tell the Plug & Play system that this device will need a
// device interface.
//
status = IoRegisterDeviceInterface (
PhysicalDeviceObject,
(LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER,
NULL,
&deviceData->InterfaceName);
if (!NT_SUCCESS (status)) {
Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR,
("AddDevice: IoRegisterDeviceInterface failed (%x)", status));
IoDeleteDevice (deviceObject);
return status;
}
//
// 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.
//
deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack (
deviceObject,
PhysicalDeviceObject);
if(NULL == deviceData->NextLowerDriver) {
IoDeleteDevice(deviceObject);
return STATUS_NO_SUCH_DEVICE;
}
#if DBG
//
// We will demonstrate here the step to retrieve the name of the PDO
//
status = IoGetDeviceProperty (PhysicalDeviceObject,
DevicePropertyPhysicalDeviceObjectName,
0,
NULL,
&nameLength);
if (status != STATUS_BUFFER_TOO_SMALL)
{
Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR,
("AddDevice:IoGDP failed (0x%x)\n", status));
goto Error;
}
deviceName = ExAllocatePoolWithTag (NonPagedPool,
nameLength, BUSENUM_POOL_TAG);
if (NULL == deviceName) {
Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR,
("AddDevice: no memory to alloc for deviceName(0x%x)\n", nameLength));
status = STATUS_INSUFFICIENT_RESOURCES;
goto Error;
}
status = IoGetDeviceProperty (PhysicalDeviceObject,
DevicePropertyPhysicalDeviceObjectName,
nameLength,
deviceName,
&nameLength);
if (!NT_SUCCESS (status)) {
Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR,
("AddDevice:IoGDP(2) failed (0x%x)", status));
goto Error;
}
Bus_KdPrint (deviceData, BUS_DBG_SS_TRACE,
("AddDevice: %x to %x->%x (%ws) \n",
deviceObject,
deviceData->NextLowerDriver,
PhysicalDeviceObject,
deviceName));
ExFreePool(deviceName);
#endif
//
// Register with WMI
//
status = Bus_WmiRegistration(deviceData);
if (!NT_SUCCESS (status)) {
Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR,
("AddDevice: Bus_WmiRegistration failed (%x)\n", status));
goto Error;
}
//
// We are done with initializing, so let's indicate that and return.
// This should be the final step in the AddDevice process.
//
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return status;
Error:
IoDetachDevice (deviceData->NextLowerDriver);
IoDeleteDevice (deviceObject);
return status;
}
NTSTATUS
Bus_PnP (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Handles PnP Irps sent to both FDO and child PDOs.
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
Return Value:
NT Status is returned.
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PCOMMON_DEVICE_DATA commonData;
PAGED_CODE ();
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
//
// If the device has been removed, the driver should
// not pass the IRP down to the next lower driver.
//
if (commonData->DevicePnPState == Deleted) {
Irp->IoStatus.Status = status = STATUS_DELETE_PENDING;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
if (commonData->IsFDO) {
Bus_KdPrint (commonData, BUS_DBG_PNP_TRACE,
("FDO %s IRP:0x%x\n",
PnPMinorFunctionString(irpStack->MinorFunction),
Irp));
//
// Request is for the bus FDO
//
status = Bus_FDO_PnP (
DeviceObject,
Irp,
irpStack,
(PFDO_DEVICE_DATA) commonData);
} else {
Bus_KdPrint (commonData, BUS_DBG_PNP_TRACE,
("PDO %s IRP: 0x%x\n",
PnPMinorFunctionString(irpStack->MinorFunction),
Irp));
//
// Request is for the child PDO.
//
status = Bus_PDO_PnP (
DeviceObject,
Irp,
irpStack,
(PPDO_DEVICE_DATA) commonData);
}
return status;
}
NTSTATUS
Bus_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 Plug & Play system for the BUS itself
--*/
{
NTSTATUS status;
ULONG length, prevcount, numPdosPresent;
PLIST_ENTRY entry, listHead, nextEntry;
PPDO_DEVICE_DATA pdoData;
PDEVICE_RELATIONS relations, oldRelations;
PAGED_CODE ();
Bus_IncIoCount (DeviceData);
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// Send the Irp down and wait for it to come back.
// Do not touch the hardware until then.
//
status = Bus_SendIrpSynchronously (DeviceData->NextLowerDriver, Irp);
if (NT_SUCCESS(status)) {
//
// Initialize your device with the resources provided
// by the PnP manager to your device.
//
status = Bus_StartFdo (DeviceData, Irp);
}
//
// We must now complete the IRP, since we stopped it in the
// completion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
Bus_DecIoCount (DeviceData);
return status;
case IRP_MN_QUERY_STOP_DEVICE:
//
// The PnP manager is trying to stop the device
// for resource rebalancing. Fail this now if you
// cannot stop the device in response to STOP_DEVICE.
//
SET_NEW_PNP_STATE(DeviceData, StopPending);
Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP.
break;
case IRP_MN_CANCEL_STOP_DEVICE:
//
// The PnP Manager sends this IRP, at some point after an
// IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a
// device that the device will not be stopped for
// resource reconfiguration.
//
//
// First check to see whether you have received cancel-stop
// without first receiving a query-stop. This could happen if
// someone above us fails a query-stop and passes down the subsequent
// cancel-stop.
//
if(StopPending == DeviceData->DevicePnPState)
{
//
// We did receive a query-stop, so restore.
//
RESTORE_PREVIOUS_PNP_STATE(DeviceData);
ASSERT(DeviceData->DevicePnPState == Started);
}
Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP.
break;
case IRP_MN_STOP_DEVICE:
//
// Stop device means that the resources given during Start device
// are now revoked. Note: You must not fail this Irp.
// But before you relieve resources make sure there are no I/O in
// progress. Wait for the existing ones to be finished.
// To do that, first we will decrement this very operation.
// When the counter goes to 1, Stop event is set.
//
Bus_DecIoCount(DeviceData);
KeWaitForSingleObject(
&DeviceData->StopEvent,
Executive, // Waiting reason of a driver
KernelMode, // Waiting in kernel mode
FALSE, // No allert
NULL); // No timeout
//
// Increment the counter back because this IRP has to
// be sent down to the lower stack.
//
Bus_IncIoCount (DeviceData);
//
// Free resources given by start device.
//
SET_NEW_PNP_STATE(DeviceData, Stopped);
//
// 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;
break;
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.
//
SET_NEW_PNP_STATE(DeviceData, RemovePending);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_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.
//
//
// First check to see whether you have received cancel-remove
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -