⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plugplay.cpp

📁 一本在讲述USB驱动程式的书 及其范例原码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// Plug and Play handlers for Generic driver
// Copyright (C) 1999 by Walter Oney
// All rights reserved

#include "stddcls.h"
#include "driver.h"
#include "GenericPower.h"

NTSTATUS DefaultPnpHandler(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleCancelRemove(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleCancelStop(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleQueryCapabilities(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleQueryRemove(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleQueryState(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleQueryStop(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleRemoveDevice(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleStartDevice(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleStopDevice(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleSurpriseRemoval(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS HandleUsageNotification(PGENERIC_EXTENSION pdx, PIRP Irp);
NTSTATUS OnNotificationComplete(PDEVICE_OBJECT fdo, PIRP Irp, PGENERIC_EXTENSION pdx);

VOID AdjustDeviceCapabilities(PDEVICE_CAPABILITIES pdc);
VOID AdjustWakeCapabilities(PGENERIC_EXTENSION pdx, PDEVICE_CAPABILITIES pdc, DEVICE_POWER_STATE dstate);
VOID DeregisterInterface(PGENERIC_EXTENSION pdx, PINTERFACE_RECORD ifp);
VOID DeregisterAllInterfaces(PGENERIC_EXTENSION pdx);
VOID EnableAllInterfaces(PGENERIC_EXTENSION pdx, BOOLEAN enable);
PINTERFACE_RECORD FindInterfaceRecord(PGENERIC_EXTENSION pdx, const GUID* guid);

#if DBG
VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list);

static char* statenames[] = {
	"STOPPED",
	"WORKING",
	"PENDINGSTOP",
	"PENDINGREMOVE",
	"SURPRISEREMOVED",
	"REMOVED",
	};

static char* sname[] = {
	"PowerSystemUnspecified",
	"PowerSystemWorking",
	"PowerSystemSleeping1",
	"PowerSystemSleeping2",
	"PowerSystemSleeping3",
	"PowerSystemHibernate",
	"PowerSystemShutdown",
	};

static char* dname[] = {
	"PowerDeviceUnspecified",
	"PowerDeviceD0",
	"PowerDeviceD1",
	"PowerDeviceD2",
	"PowerDeviceD3",
	};

#endif

///////////////////////////////////////////////////////////////////////////////

#pragma PAGEDCODE

GENERICAPI NTSTATUS GENERIC_EXPORT GenericDispatchPnp(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// GenericDispatchPnp
	PAGED_CODE();
	NTSTATUS status = STATUS_SUCCESS;
	if (pdx->RemoveLock && !NT_SUCCESS(status = IoAcquireRemoveLock(pdx->RemoveLock, Irp)))
		return CompleteRequest(Irp, status);

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	ASSERT(stack->MajorFunction == IRP_MJ_PNP);

	static NTSTATUS (*fcntab[])(PGENERIC_EXTENSION pdx, PIRP Irp) = {
		HandleStartDevice,		// IRP_MN_START_DEVICE
		HandleQueryRemove,		// IRP_MN_QUERY_REMOVE_DEVICE
		HandleRemoveDevice,		// IRP_MN_REMOVE_DEVICE
		HandleCancelRemove,		// IRP_MN_CANCEL_REMOVE_DEVICE
		HandleStopDevice,		// IRP_MN_STOP_DEVICE
		HandleQueryStop,		// IRP_MN_QUERY_STOP_DEVICE
		HandleCancelStop,		// IRP_MN_CANCEL_STOP_DEVICE
		DefaultPnpHandler,		// IRP_MN_QUERY_DEVICE_RELATIONS
		DefaultPnpHandler,		// IRP_MN_QUERY_INTERFACE
		HandleQueryCapabilities,// IRP_MN_QUERY_CAPABILITIES
		DefaultPnpHandler,		// IRP_MN_QUERY_RESOURCES
		DefaultPnpHandler,		// IRP_MN_QUERY_RESOURCE_REQUIREMENTS
		DefaultPnpHandler,		// IRP_MN_QUERY_DEVICE_TEXT
		DefaultPnpHandler,		// IRP_MN_FILTER_RESOURCE_REQUIREMENTS
		DefaultPnpHandler,		// 
		DefaultPnpHandler,		// IRP_MN_READ_CONFIG
		DefaultPnpHandler,		// IRP_MN_WRITE_CONFIG
		DefaultPnpHandler,		// IRP_MN_EJECT
		DefaultPnpHandler,		// IRP_MN_SET_LOCK
		DefaultPnpHandler,		// IRP_MN_QUERY_ID
		HandleQueryState,		// IRP_MN_QUERY_PNP_DEVICE_STATE
		DefaultPnpHandler,		// IRP_MN_QUERY_BUS_INFORMATION
		HandleUsageNotification,// IRP_MN_DEVICE_USAGE_NOTIFICATION
		HandleSurpriseRemoval,	// IRP_MN_SURPRISE_REMOVAL
		};

	ULONG fcn = stack->MinorFunction;

	if (fcn >= arraysize(fcntab))
		{						// unknown function
		status = DefaultPnpHandler(pdx, Irp); // some function we don't know about
		if (pdx->RemoveLock)
			IoReleaseRemoveLock(pdx->RemoveLock, Irp);
		return status;
		}						// unknown function

#if DBG
	static char* fcnname[] = {
		"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",
		"",
		"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",
		};

	KdPrint(("%s - PNP Request (%s)\n", pdx->DebugName, fcnname[fcn]));
#endif // DBG

	status = (*fcntab[fcn])(pdx, Irp);
	if (fcn != IRP_MN_REMOVE_DEVICE && pdx->RemoveLock)
		IoReleaseRemoveLock(pdx->RemoveLock, Irp);
	return status;
	}							// GenericDispatchPnp

///////////////////////////////////////////////////////////////////////////////

#pragma PAGEDCODE

GENERICAPI NTSTATUS GENERIC_EXPORT GenericDeregisterInterface(PGENERIC_EXTENSION pdx, const GUID* guid)
	{							// GenericDeregisterInterface
	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
	NTSTATUS status;
	
	KeEnterCriticalRegion();
	KeWaitForSingleObject(&pdx->iflock, Executive, KernelMode, FALSE, NULL);
	PINTERFACE_RECORD ifp = FindInterfaceRecord(pdx, guid);
	if (ifp)
		{
		DeregisterInterface(pdx, ifp);
		status = STATUS_SUCCESS;
		}
	else
		status = STATUS_INVALID_PARAMETER;

	KeSetEvent(&pdx->iflock, EVENT_INCREMENT, FALSE);
	KeLeaveCriticalRegion();
	return status;
	}							// GenericDeregisterInterface

///////////////////////////////////////////////////////////////////////////////

#pragma PAGEDCODE

GENERICAPI NTSTATUS GENERIC_EXPORT GenericEnableInterface(PGENERIC_EXTENSION pdx, const GUID* guid, BOOLEAN enable)
	{							// GenericEnableInterface
	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
	NTSTATUS status;
	
	KeEnterCriticalRegion();
	KeWaitForSingleObject(&pdx->iflock, Executive, KernelMode, FALSE, NULL);
	PINTERFACE_RECORD ifp = FindInterfaceRecord(pdx, guid);
	if (ifp)
		{						// enable/disable this interface
		if (ifp->enabled != enable)
			IoSetDeviceInterfaceState(&ifp->linkname, enable);
		ifp->enabled = enable;
		status = STATUS_SUCCESS;
		}						// enable/disable this interface
	else
		status = STATUS_INVALID_PARAMETER;

	KeSetEvent(&pdx->iflock, EVENT_INCREMENT, FALSE);
	KeLeaveCriticalRegion();
	return status;
	}							// GenericEnableInterface

///////////////////////////////////////////////////////////////////////////////
// GenericGetDeviceCapabilities (added 2.0) returns the device capabilties.
// If necessary, it retrieves them.

#pragma LOCKEDCODE

GENERICAPI PDEVICE_CAPABILITIES GENERIC_EXPORT GenericGetDeviceCapabilities(PGENERIC_EXTENSION pdx)
	{							// GenericGetDeviceCapabilities
	
	// If necessary, ask the bus driver for this device's capabilities. We must be
	// at PASSIVE_LEVEL to do this (requirement for sending the IRP).

	if (!pdx->GotCapabilities)
		{						// fetch capabilities
		if (KeGetCurrentIrql() != PASSIVE_LEVEL)
			return NULL;

		PDEVICE_CAPABILITIES pdc = (PDEVICE_CAPABILITIES) ExAllocatePool(PagedPool, sizeof(DEVICE_CAPABILITIES));
		if (!pdc)
			return NULL;
		RtlZeroMemory(pdc, sizeof(*pdc));
		pdc->Size = sizeof(*pdc);
		pdc->Version = 1;
		pdc->Address = -1;
		pdc->UINumber = -1;

		KEVENT event;
		KeInitializeEvent(&event, NotificationEvent, FALSE);

		IO_STATUS_BLOCK iosb;

		PDEVICE_OBJECT tdo = IoGetAttachedDeviceReference(pdx->Pdo);
		PIRP Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, tdo, NULL, 0, NULL, &event, &iosb);
		if (!Irp)
			return NULL;
		PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
		stack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
		stack->Parameters.DeviceCapabilities.Capabilities = pdc;

		NTSTATUS status = IoCallDriver(tdo, Irp);
		if (status == STATUS_PENDING)
			KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);

		ExFreePool(pdc);
		ObDereferenceObject(tdo);
		}						// fetch capabilities

	return &pdx->devcaps;
	}							// GenericGetDeviceCapabilities

///////////////////////////////////////////////////////////////////////////////

#pragma PAGEDCODE

GENERICAPI NTSTATUS GENERIC_EXPORT GenericRegisterInterface(PGENERIC_EXTENSION pdx, const GUID* guid)
	{							// GenericRegisterInterface
	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
	NTSTATUS status;
	
	KeEnterCriticalRegion();
	KeWaitForSingleObject(&pdx->iflock, Executive, KernelMode, FALSE, NULL);
	PINTERFACE_RECORD ifp = FindInterfaceRecord(pdx, guid);
	if (ifp)
		status = STATUS_INVALID_PARAMETER;
	else
		{						// register new interface
		ifp = (PINTERFACE_RECORD) ExAllocatePool(NonPagedPool, sizeof(INTERFACE_RECORD));
		if (ifp)
			{					// initialize new interface record
			status = IoRegisterDeviceInterface(pdx->Pdo, guid, NULL, &ifp->linkname);
			if (NT_SUCCESS(status))
				{				// interface registered
				ifp->guid = *guid;
				ifp->enabled = FALSE;
				InsertHeadList(&pdx->iflist, &ifp->list);
				}				// interface registered
			else
				ExFreePool(ifp);
			}					// initialize new interface record
		else
			status = STATUS_INSUFFICIENT_RESOURCES;
		}						// register new interface

	KeSetEvent(&pdx->iflock, EVENT_INCREMENT, FALSE);
	KeLeaveCriticalRegion();
	return status;
	}							// GenericRegisterInterface

///////////////////////////////////////////////////////////////////////////////

#pragma LOCKEDCODE

GENERICAPI VOID GENERIC_EXPORT GenericSetDeviceState(PGENERIC_EXTENSION pdx, PNP_DEVICE_STATE pnpstate)
	{							// GenericSetDeviceState
	pdx->pnpstatemask = (pnpstate ^ pdx->pnpstate); // mask for things that changed
	pdx->pnpstate |= pnpstate;

	// Inform PnP manager that our state has changed.

	IoInvalidateDeviceState(pdx->Pdo);
	}							// GenericSetDeviceState

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// AdjustDeviceCapabilities corrects the reported device capabilities to
// workaround the fact that many back-level bus drivers simply don't report
// them correctly. Cf. toaster.sys sample in the DDK and talk given by
// Adrian Oney (no relation) at WinHEC 2002.

#pragma PAGEDCODE

__inline SYSTEM_POWER_STATE& operator++(SYSTEM_POWER_STATE& ss) {ss = (SYSTEM_POWER_STATE) (ss + 1); return ss;}
__inline SYSTEM_POWER_STATE& operator--(SYSTEM_POWER_STATE& ss) {ss = (SYSTEM_POWER_STATE) (ss - 1); return ss;}

VOID AdjustDeviceCapabilities(PGENERIC_EXTENSION pdx, PDEVICE_CAPABILITIES pdc)
	{							// AdjustDeviceCapabilities

	// Make sure that the device state for S0 is D0

	if (pdc->DeviceState[PowerSystemWorking] != PowerDeviceD0)
		{
		KdPrint(("%s - DeviceState[PowerSystemWorking] is D%d instead of D0!\n", pdx->DebugName, pdc->DeviceState[PowerSystemWorking] - 1));
		pdc->DeviceState[PowerSystemWorking] = PowerDeviceD0;
		}

	// Check for silly value of SystemWake

	if (pdc->SystemWake > PowerSystemHibernate)
		{
		KdPrint(("%s - SystemWake has the silly value %s\n", pdx->DebugName, sname[pdc->SystemWake]));
		}

	// Adjust power capabilities to compensate for bus driver written to
	// WDM 1.0 spec. First infer D1 and D2 capabilities from S->D state map.

	for (SYSTEM_POWER_STATE sstate = PowerSystemSleeping1; sstate <= PowerSystemHibernate; ++sstate)
		{					// for each S-state
		if (pdc->DeviceState[sstate] == PowerDeviceD1 && !pdc->DeviceD1)
			{
			KdPrint(("%s - Inferring DeviceD1 from DeviceState[%s]\n", pdx->DebugName, sname[sstate]));
			pdc->DeviceD1 = TRUE;
			}
		if (pdc->DeviceState[sstate] == PowerDeviceD2 && !pdc->DeviceD2)
			{
			KdPrint(("%s - Inferring DeviceD2 from DeviceState[%s]\n", pdx->DebugName, sname[sstate]));
			pdc->DeviceD2 = TRUE;
			}
		}					// for each S-state

	// Set the WakeFromDx flags based on the reported DeviceWake state and
	// on the D-state corresponding to the reported SystemWake state

	AdjustWakeCapabilities(pdx, pdc, pdc->DeviceWake);
	if (pdc->SystemWake != PowerSystemUnspecified)
		AdjustWakeCapabilities(pdx, pdc, pdc->DeviceState[pdc->SystemWake]);

	// Make sure the device state for S5 is D3. Do this after adjusting wakeup capabilities
	// because USBHUB uncritically assumes that a device can be in D2 from S1 through SystemWakeup.
	// So if SystemWakeup happens to be S5 because of some ACPI mistake, changing the device
	// state entry too soon would cause us to pick D3 as the DeviceWake value, which is more wrong
	// than what we were starting with...

	if (pdc->DeviceState[PowerSystemShutdown] != PowerDeviceD3)
		{
		KdPrint(("%s - DeviceState[PowerSystemShutdown] is D%d instead of D3!\n", pdx->DebugName, pdc->DeviceState[PowerSystemShutdown] - 1));
		pdc->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
		}

	// Find the deepest D-state from which this device can wake the system

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -