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

📄 plugplay.cpp

📁 一本在讲述USB驱动程式的书 及其范例原码
💻 CPP
📖 第 1 页 / 共 3 页
字号:

	DEVICE_POWER_STATE wakestate = PowerDeviceUnspecified;	// assume no wakeup capability

	if (pdc->WakeFromD3)
		wakestate = PowerDeviceD3;
	else if (pdc->WakeFromD2)
		wakestate = PowerDeviceD2;
	else if (pdc->WakeFromD1)
		wakestate = PowerDeviceD1;
	else if (pdc->WakeFromD0)
		wakestate = PowerDeviceD0;

	if (pdc->DeviceWake != wakestate)
		{
		KdPrint(("%s - DeviceWake is %s, but should be %s\n", pdx->DebugName, dname[pdc->DeviceWake], dname[wakestate]));
		pdc->DeviceWake = wakestate;
		}

	// If SystemWake is specified, the corresponding D-state had better be at
	// least as powered as the state we just discovered, or else there's a bug
	// in our bus driver. It may just be that we got a bogus SystemWake value,
	// so don't do anything about it.

	if (pdc->SystemWake != PowerSystemUnspecified)
		{
		if (pdc->DeviceState[pdc->SystemWake] > wakestate)
			{
			KdPrint(("%s - DeviceState[SystemWake] is less powered than minimum wake state (%s)!\n", pdx->DebugName, dname[wakestate]));
			}
		}

	// If SystemWake wasn't specified, infer it from the S->D state map by
	// finding the lowest S-state whose D-state is at least as powered as the
	// lowest D-state from which wakeup is possible (I think I got that right...)

	else if (wakestate != PowerDeviceD0 && wakestate != PowerDeviceUnspecified)
		{						// infer system wake state
		for (sstate = PowerSystemSleeping3; sstate >= PowerSystemWorking; --sstate)
			{					// for each S-state
			if (pdc->DeviceState[sstate] != PowerDeviceUnspecified
				&& pdc->DeviceState[sstate] <= wakestate)
				{				// found the S-state
				KdPrint(("%s - Inferring that wakeup from S%d state possible\n", pdx->DebugName, sstate - 1));
				pdc->SystemWake = sstate;
				break;
				}				// found the S-state
			}					// for each S-state
		}						// infer system wake state
	}							// AdjustDeviceCapabilities

///////////////////////////////////////////////////////////////////////////////
// AdjustWakeCapabilities adjusts the wakeup capabilities for a device.	

VOID AdjustWakeCapabilities(PGENERIC_EXTENSION pdx, PDEVICE_CAPABILITIES pdc, DEVICE_POWER_STATE dstate)
	{							// AdjustWakeCapabilities
	switch (dstate)
		{						// select on D-state
	case PowerDeviceUnspecified:
		break;
	case PowerDeviceD0:
		if (!pdc->WakeFromD0)
			KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD0\n", pdx->DebugName));
		pdc->WakeFromD0 = TRUE;
		break;
	case PowerDeviceD1:
		if (!pdc->WakeFromD1)
			KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD1\n", pdx->DebugName));
		if (!pdc->DeviceD1)
			KdPrint(("%s - AdjustWakeCapabilities Inferring DeviceD1\n", pdx->DebugName));
		pdc->DeviceD1 = TRUE;
		pdc->WakeFromD1 = TRUE;
		break;
	case PowerDeviceD2:
		if (!pdc->WakeFromD2)
			KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD2\n", pdx->DebugName));
		if (!pdc->DeviceD2)
			KdPrint(("%s - AdjustWakeCapabilities Inferring DeviceD2\n", pdx->DebugName));
		pdc->DeviceD2 = TRUE;
		pdc->WakeFromD2 = TRUE;
		break;
	case PowerDeviceD3:
		if (!pdc->WakeFromD3)
			KdPrint(("%s - AdjustWakeCapabilities Inferring WakeFromD3\n", pdx->DebugName));
		pdc->WakeFromD3 = TRUE;
		break;
	default:
		ASSERT(FALSE);
		}						// select on D-state
	}							// AdjustWakeCapabilities

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

VOID CallStopDevice(PGENERIC_EXTENSION pdx)
	{							// CallStopDevice
	GenericWakeupControl(pdx, CancelWaitWake);
	BOOLEAN oktouch = pdx->HardwareWorking;
	pdx->HardwareWorking = FALSE;
	(*pdx->StopDevice)(pdx->DeviceObject, oktouch);
	}							// CallStopDevice

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

VOID CallRemoveDevice(PGENERIC_EXTENSION pdx)
	{							// CallRemoveDevice
	(*pdx->RemoveDevice)(pdx->DeviceObject);
	}							// CallRemoveDevice

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

NTSTATUS DefaultPnpHandler(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// DefaultPnpHandler
	IoSkipCurrentIrpStackLocation(Irp);
	return IoCallDriver(pdx->LowerDeviceObject, Irp);
	}							// DefaultPnpHandler

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

#pragma PAGEDCODE

VOID DeregisterAllInterfaces(PGENERIC_EXTENSION pdx)
	{							// DeregisterAllInterfaces
	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
	
	KeEnterCriticalRegion();
	KeWaitForSingleObject(&pdx->iflock, Executive, KernelMode, FALSE, NULL);

	while (!IsListEmpty(&pdx->iflist))
		{						// for each interface
		PLIST_ENTRY list = RemoveHeadList(&pdx->iflist);
		PINTERFACE_RECORD ifp = CONTAINING_RECORD(list, INTERFACE_RECORD, list);
		DeregisterInterface(pdx, ifp);
		}						// for each interface

	KeSetEvent(&pdx->iflock, EVENT_INCREMENT, FALSE);
	KeLeaveCriticalRegion();
	}							// DeregisterAllInterfaces

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

#pragma PAGEDCODE

VOID DeregisterInterface(PGENERIC_EXTENSION pdx, PINTERFACE_RECORD ifp)
	{							// DeregisterInterface
	if (ifp->enabled)
		IoSetDeviceInterfaceState(&ifp->linkname, FALSE);
	RtlFreeUnicodeString(&ifp->linkname);
	RemoveEntryList(&ifp->list);
	ExFreePool(ifp);
	}							// DeregisterInterface

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

#pragma LOCKEDCODE

VOID EnableAllInterfaces(PGENERIC_EXTENSION pdx, BOOLEAN enable)
	{							// EnableAllInterfaces
	for (PLIST_ENTRY list = pdx->iflist.Flink; list != &pdx->iflist; list = list->Flink)
		{						// search for specified interface record
		PINTERFACE_RECORD ifp = CONTAINING_RECORD(list, INTERFACE_RECORD, list);
		if (ifp->enabled != enable)
			IoSetDeviceInterfaceState(&ifp->linkname, enable);
		ifp->enabled = enable;
		}
	}							// EnableAllInterfaces

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

#pragma PAGEDCODE

PINTERFACE_RECORD FindInterfaceRecord(PGENERIC_EXTENSION pdx, const GUID* guid)
	{							// FindInterfaceRecord
	PAGED_CODE();

	for (PLIST_ENTRY list = pdx->iflist.Flink; list != &pdx->iflist; list = list->Flink)
		{						// search for specified interface record
		PINTERFACE_RECORD ifp = CONTAINING_RECORD(list, INTERFACE_RECORD, list);
		if (ifp->guid == *guid)
			return ifp;
		}
	return NULL;
	}							// FindInterfaceRecord

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

NTSTATUS HandleCancelRemove(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// HandleCancelRemove
	ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE);
	Irp->IoStatus.Status = STATUS_SUCCESS;	// flag that we handled this IRP

	if (pdx->state == PENDINGREMOVE)
		{						// we succeeded earlier query

		// Lower-level drivers are presumably in the pending-remove state as
		// well, so we need to tell them that the remove has been cancelled
		// before we start sending IRPs down to them.

		NTSTATUS status = ForwardAndWait(pdx, Irp); // wait for lower layers
		if (NT_SUCCESS(status))
			{					// completed successfully
			KdPrint(("%s - To %s from PENDINGREMOVE\n", pdx->DebugName, statenames[pdx->prevstate]));
			RestartAllRequests(pdx->queues, pdx->nqueues, pdx->DeviceObject);
			GenericWakeupControl(pdx, ManageWaitWake);	// reissue wait-wake if necessary
			}					// completed successfully
		else
			KdPrint(("%s - Status %8.8lX returned by PDO for IRP_MN_CANCEL_REMOVE_DEVICE", pdx->DebugName, status));

		return CompleteRequest(Irp, status);
		}						// we succeeded earlier query
	
	return DefaultPnpHandler(pdx, Irp); // unexpected cancel
	}							// HandleCancelRemove

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

NTSTATUS HandleCancelStop(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// HandleCancelStop
	ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE);
	Irp->IoStatus.Status = STATUS_SUCCESS;	// flag that we handled this IRP

	if (pdx->state == PENDINGSTOP)
		{						// we succeeded earlier query

		// Lower level drivers are presumably in the pending-stop state as
		// well, so we need to tell them that the stop has been cancelled
		// before we start sending IRPs down to them.

		NTSTATUS status = ForwardAndWait(pdx, Irp); // wait for lower layers
		if (NT_SUCCESS(status))
			{					// completed successfully
			KdPrint(("%s - To WORKING from PENDINGSTOP\n", pdx->DebugName));
			pdx->state = WORKING;
			RestartAllRequests(pdx->queues, pdx->nqueues, pdx->DeviceObject);
			GenericWakeupControl(pdx, ManageWaitWake);	// reissue wait-wake if necessary
			}					// completed successfully
		else
			KdPrint(("%s - Status %8.8lX returned by PDO for IRP_MN_CANCEL_STOP_DEVICE", pdx->DebugName, status));
		
		return CompleteRequest(Irp, status);
		}						// we succeeded earlier query

	return DefaultPnpHandler(pdx, Irp); // unexpected cancel
	}							// HandleCancelStop

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

NTSTATUS HandleQueryCapabilities(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// HandleQueryCapabilities
	ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_CAPABILITIES);

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	PDEVICE_CAPABILITIES pdc = stack->Parameters.DeviceCapabilities.Capabilities;

	// Check to be sure we know how to handle this version of the capabilities structure

	if (pdc->Version < 1)
		return DefaultPnpHandler(pdx, Irp);

	NTSTATUS status = ForwardAndWait(pdx, Irp);
	if (NT_SUCCESS(status))
		{						// IRP succeeded
		stack = IoGetCurrentIrpStackLocation(Irp);
		pdc = stack->Parameters.DeviceCapabilities.Capabilities;
		if (pdx->Flags & GENERIC_SURPRISE_REMOVAL_OK)
			pdc->SurpriseRemovalOK = TRUE;
		AdjustDeviceCapabilities(pdx, pdc);	// compensate for bus driver shortcoming
		pdx->devcaps = *pdc;	// save capabilities for whoever needs to see them
		pdx->GotCapabilities = TRUE;	// flag for GenericGetDeviceCapabilities
		GenericWakeupControl(pdx, ManageWaitWake);	// in case capabilities now allow WAIT_WAKE
		}						// IRP succeeded

	return CompleteRequest(Irp, status);
	}							// HandleQueryCapabilities

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

NTSTATUS HandleQueryRemove(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// HandleQueryRemove
	ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE);
	Irp->IoStatus.Status = STATUS_SUCCESS;	// flag that we handled this IRP

	if (pdx->state == WORKING)
		{						// currently working

	#ifdef _X86_

		// Win98 doesn't check for open handles before allowing a remove to proceed,
		// and it may deadlock in IoReleaseRemoveLockAndWait if handles are still
		// open.

		if (win98 && pdx->DeviceObject->ReferenceCount)
			{
			KdPrint(("%s - Failing removal query due to open handles\n", pdx->DebugName));
			return CompleteRequest(Irp, STATUS_DEVICE_BUSY);
			}

	#endif

		// See if it's okay to remove this device. The test includes asking the client
		// driver. Then stall the queue for the duration of the query. The TOASTER sample
		// in the DDK drains the queue here instead of stalling it, by the way.

		if (!OkayToRemove(pdx))
			return CompleteRequest(Irp, STATUS_UNSUCCESSFUL); // can't remove because busy

		StallAllRequests(pdx->queues, pdx->nqueues);
		if (pdx->FlushPendingIo)
			(*pdx->FlushPendingIo)(pdx->DeviceObject, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE, PowerDeviceUnspecified, PowerDeviceUnspecified);
		WaitForCurrentIrps(pdx->queues, pdx->nqueues);
		GenericWakeupControl(pdx, CancelWaitWake);	// cancel any pending wait-wake

		KdPrint(("%s - To PENDINGREMOVE from %s\n", pdx->DebugName, statenames[pdx->state]));
		}						// currently working

	// Save current state for restoration if the query gets cancelled.
	// (We can now be stopped or working)

	pdx->prevstate = pdx->state;
	pdx->state = PENDINGREMOVE;
	return DefaultPnpHandler(pdx, Irp);
	}							// HandleQueryRemove

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

NTSTATUS HandleQueryState(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// HandleQueryState
	ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE);

	// Note that you can't use sizeof in a #if expression, so it's not possible to use
	// conditional compilation to choose between 32- and 64-bit exchanges in the
	// following statement. If the size of a PNP_DEVICE_STATE changes to be bigger than
	// 32 bits, therefore, you have to change this by hand. The ASSERT will alert you to
	// the problem...

	PNP_DEVICE_STATE mask = InterlockedExchange((PLONG) &pdx->pnpstatemask, 0);
	ASSERT(sizeof(PNP_DEVICE_STATE) == sizeof(LONG));

	if (mask)
		{						// some status flags have changed
		Irp->IoStatus.Status = STATUS_SUCCESS; // indicate we've handled this IRP
		Irp->IoStatus.Information &= ~(ULONG_PTR) mask; // clear all changed flags
		Irp->IoStatus.Information |= pdx->pnpstate & mask; // set all flags that were changed to "1"
		}						// some status flags have changed

	// DDK doc says you handle this IRP on the way down, but TOASTER handles
	// it on the way up. It shouldn't matter, because you're not supposed to
	// overstore the result you find already in IoStatus.Information.

	return DefaultPnpHandler(pdx, Irp);
	}							// HandleQueryState

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

NTSTATUS HandleQueryStop(PGENERIC_EXTENSION pdx, PIRP Irp)
	{							// HandleQueryStop
	ASSERT(IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_QUERY_STOP_DEVICE);
	Irp->IoStatus.Status = STATUS_SUCCESS;	// flag that we handled this IRP
	
	// Boot devices may get this query before they even start, so check to see
	// if we're in the WORKING state before doing anything.

	if (pdx->state != WORKING)
		return DefaultPnpHandler(pdx, Irp);

	// See if it will be okay to stop the device right now. This test includes
	// asking the client driver via a callback routine.

	if (!OkayToStop(pdx))
		return CompleteRequest(Irp, STATUS_UNSUCCESSFUL);

	// Stall the request queue and wait for the current IRP (if any) to finish

⌨️ 快捷键说明

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