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

📄 plugplay.cpp

📁 The PCI Local bus concept was developed to break the PC data I/O bottleneck and clearly opens the d
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*

PlugPlay.cpp

Sheldon Instruments, Inc.

Abstract:

	Plug and Play processors for WDM driver.  Handles calls to IRP_MJ_PNP.

Revision History:

	04Dec1998 - created by Robert Updike
	25Feb2000 - Added exception handling and releasing of resources for errors.  Robert Updike
	20Mar2000 - Added functions for handling of minor PnP calls.  Robert Updike

*/

#include "driver.h"

NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST list);
NTSTATUS QueryStopDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS CancelStopDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS StopDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS QueryRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS CancelRemoveDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
NTSTATUS RemoveDevice(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS SurpriseRemovalDevice(PDEVICE_EXTENSION pdx, PIRP Irp);
VOID ReleaseResources(IN PDEVICE_EXTENSION pdx);
VOID ResetDevice(PDEVICE_EXTENSION pdx);
BOOLEAN DisableDevice(IN PDEVICE_EXTENSION pdx);
BOOLEAN EnableDevice(IN PDEVICE_EXTENSION pdx);

/*

Function name:

	Sheldon_ProcessPnPIrp

Routine Description:

    Handles plug and play requests.  Calls to this function that are not handled by this 
	driver are passed down to the next level driver.

Arguments:

    fdo - pointer to a functional device object

    Irp -  I/O request being serviced

Return Value:

    STATUS_SUCCESS if successful
	NTSTATUS code otherwise

*/
NTSTATUS Sheldon_ProcessPnPIrp(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
	NTSTATUS ntStatus = STATUS_SUCCESS;
	PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
	ULONG minor = IrpStack->MinorFunction;
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	KdPrint(("SIWDM - Entering Sheldon_ProcessPnPIrp: IRP_MJ_PNP\n"));

	switch(minor)
	{
		case IRP_MN_START_DEVICE:
		{
			PCM_PARTIAL_RESOURCE_LIST translated;

			KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: case IRP_MN_START_DEVICE\n"));

			Irp->IoStatus.Status = STATUS_SUCCESS;

			ntStatus = ForwardAndWait(pdx, Irp);

			if(!NT_SUCCESS(ntStatus))
				return CompleteRequest(Irp, ntStatus, 0);
				
			translated = IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated
				? &IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList
				: NULL;

			ntStatus = StartDevice(fdo, translated);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_START_DEVICE (%x)\n", ntStatus));

			return CompleteRequest(Irp, ntStatus, 0);
		}

		case IRP_MN_QUERY_STOP_DEVICE:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: case IRP_MN_QUERY_STOP_DEVICE\n"));
			ntStatus = QueryStopDevice(pdx, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_QUERY_STOP_DEVICE (%x)\n", ntStatus));

			return ntStatus;
		}

		case IRP_MN_CANCEL_STOP_DEVICE:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnpIrp: case IRP_MN_CANCEL_STOP_DEVICE\n"));
			ntStatus = CancelStopDevice(pdx, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_CANCEL_STOP_DEVICE (%x)\n", ntStatus));

			return ntStatus;
		}
		case IRP_MN_STOP_DEVICE:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_STOP_DEVICE\n"));
			ntStatus = StopDevice(pdx, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_STOP_DEVICE (%x)\n", ntStatus));

			return ntStatus;
		}
		case IRP_MN_QUERY_REMOVE_DEVICE:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_QUERY_REMOVE_DEVICE\n"));
			ntStatus = QueryRemoveDevice(pdx, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_QUERY_REMOVE_DEVICE (%x)\n", ntStatus));

			return ntStatus;
		}
		case IRP_MN_CANCEL_REMOVE_DEVICE:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnpIrp: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
			ntStatus = CancelRemoveDevice(pdx, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_CANCEL_REMOVE_DEVICE (%x)\n", ntStatus));

			return ntStatus;
		}
		case IRP_MN_REMOVE_DEVICE:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_REMOVE_DEVICE\n"));
			ntStatus = RemoveDevice(fdo, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_REMOVE_DEVICE (%x)\n", ntStatus));

			return ntStatus;
		}
		case IRP_MN_SURPRISE_REMOVAL:
		{
			KdPrint(("SIWDM - Sheldon_ProcessPnPIrp: IRP_MN_SURPRISE_REMOVAL\n"));
			ntStatus = SurpriseRemovalDevice(pdx, Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: IRP_MN_SURPRISE_REMOVAL (%x)\n", ntStatus));

			return ntStatus;
		}
		default:
			IoSkipCurrentIrpStackLocation(Irp);
			KdPrint(("SIWDM - Exiting Sheldon_ProcessPnPIrp: DEFAULT\n"));

			return IoCallDriver(pdx->LowerDeviceObject, Irp);
	}
}

/*

Function name:

	StartDevice

Routine Description:

    Helper function for IRP_MN_START_DEVICE.

Arguments:

    fdo - pointer to a functional device object

    list - pointer to a translated resource descriptor list

Return Value:

    STATUS_SUCCESS if successful
	NTSTATUS code otherwise

*/
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST list)
{
	NTSTATUS ntStatus = STATUS_SUCCESS;
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
	PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = list->PartialDescriptors;
	ULONG num_of_resources = list->Count;
	
	ULONG vector;				// interrupt vector
	KIRQL irql;					// interrupt level
	KINTERRUPT_MODE mode;		// interrupt mode
	KAFFINITY affinity;			// processor affinity for interrupt

	PHYSICAL_ADDRESS port;		// port address
	ULONG port_len;				// length of port region

	BOOLEAN error = FALSE;		// TRUE if there's an error in the resource descriptions
	BOOLEAN int_used = FALSE;

	ULONG region_cnt = 0;
	ULONG j;

	KdPrint(("SIWDM - Entering StartDevice\n"));

	for(j=0;j<PCI_TYPE0_ADDRESSES;j++)
	{
		pdx->base[j] = NULL;
		pdx->Direct_Baddr[j] = NULL;
	}

	for(ULONG i=0;i<num_of_resources;++i, ++resource)
	{
		switch(resource->Type)
		{
			case CmResourceTypePort:
			{
				KdPrint(("SIWDM - StartDevice: CmResourceTypePort Iteration:%u\n", i));

				port = resource->u.Port.Start;
				port_len = resource->u.Port.Length;

				if((resource->Flags & CM_RESOURCE_PORT_IO) == 0)
				{
					pdx->base[region_cnt] = (PULONG) MmMapIoSpace(port, port_len, MmNonCached);
					pdx->base_len[region_cnt] = port_len;

					if(!pdx->base[region_cnt])
					{
						for(j=0;j<=region_cnt;j++)
							if(pdx->mem_mapped[j])
							{
								MmUnmapIoSpace(pdx->base[j], pdx->base_len[j]);
								pdx->mem_mapped[j] = NULL;
							}

						return STATUS_NO_MEMORY;
					}

					pdx->mem_mapped[region_cnt] = TRUE;
				}
				else
				{
					pdx->base[region_cnt] = (PULONG) port.LowPart;
					pdx->base_len[region_cnt] = port_len;
					pdx->mem_mapped[region_cnt] = FALSE;
				}

				region_cnt++;
				break;
			}

			case CmResourceTypeInterrupt:
			{
				KdPrint(("SIWDM - StartDevice: CmResourceTypeInterrupt Iteration:%u\n", i));

				int_used = TRUE;
				irql = (KIRQL) resource->u.Interrupt.Level;
				vector = resource->u.Interrupt.Vector;
				affinity = resource->u.Interrupt.Affinity;
				mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
					? Latched : LevelSensitive;
				break;
			}
		
			case CmResourceTypeMemory:
			{
				KdPrint(("SIWDM - StartDevice: CmResourceTypeMemory Iteration:%u\n", i));
				
				port = resource->u.Memory.Start;
				port_len = resource->u.Memory.Length;
				pdx->base[region_cnt] = (PULONG) MmMapIoSpace(port, port_len, MmNonCached);
				pdx->base_len[region_cnt] = (ULONG) resource->u.Memory.Length;

				if(!pdx->base[region_cnt])
				{
					for(j=0;j<=region_cnt;j++)
						if(pdx->mem_mapped[j])
						{
							MmUnmapIoSpace(pdx->base[j], pdx->base_len[j]);
							pdx->mem_mapped[j] = NULL;
						}

					return STATUS_NO_MEMORY;
				}

				pdx->mem_mapped[region_cnt] = TRUE;
				region_cnt++;
				
				break;
			}

			case CmResourceTypeDevicePrivate:
				KdPrint(("SIWDM - StartDevice: CmResourceTypeDevicePrivate Iteration:%u\n", i));
				break;

			default:
				KdPrint(("SIWDM - StartDevice: CmResourceTypeUnknown Iteration:%u\n", i));
				error = TRUE;
				break;
		}
	}

	if(error)
	{
		KdPrint(("SIWDM - StartDevice: Device configuration is invalid\n"));

		for(j=0;j<region_cnt;j++)
			if(pdx->mem_mapped[j])
			{
				MmUnmapIoSpace(pdx->base[j], pdx->base_len[j]);
				pdx->mem_mapped[j] = NULL;
			}

		return STATUS_DEVICE_CONFIGURATION_ERROR;
	}

	// Install the interrupt and the ISR, as well as the DPC
	if(int_used)
	{
		// Set up a DPC object for use by interrupts later
		IoInitializeDpcRequest(fdo, SheldonDpcForIsr);

		// Get the Timers, for use with BusMastered Timeouts
		KeInitializeDpc(&(pdx->WriteTransfer.TimerDPC), SheldonTimerRoutine, pdx);
		KeInitializeTimer(&(pdx->WriteTransfer.Timer));
		KeInitializeDpc(&(pdx->ReadTransfer.TimerDPC), SheldonTimerRoutine, pdx);
		KeInitializeTimer(&(pdx->ReadTransfer.Timer));

		DisableDevice(pdx);

		ntStatus = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE) SheldonIsr,
			(PVOID) pdx, NULL, vector, irql, irql, mode, TRUE, affinity, FALSE);

		// unable to connect to interrupt
		if(!NT_SUCCESS(ntStatus))
		{
			KdPrint(("SIWDM - StartDevice: IoConnectInterrupt failed with ntStatus 0x%x\n", ntStatus));

			for(i=0;i<region_cnt;i++)
				if(pdx->mem_mapped[i])
				{
					MmUnmapIoSpace(pdx->base[i], pdx->base_len[i]);
					pdx->mem_mapped[i] = NULL;
				}

			return ntStatus;
		}

		// can't enable device
		if(!KeSynchronizeExecution(pdx->InterruptObject, (PKSYNCHRONIZE_ROUTINE) EnableDevice, (PVOID) pdx))
		{
			KdPrint(("SIWDM - StartDevice: Unable to enable device\n"));
			IoDisconnectInterrupt(pdx->InterruptObject);

			for(i=0;i<region_cnt;i++)
				if(pdx->mem_mapped[i])
				{
					MmUnmapIoSpace(pdx->base[i], pdx->base_len[i]);
					pdx->mem_mapped[i] = NULL;
				}

			return STATUS_INVALID_DEVICE_STATE;
		}
	}

	// Device is ready to run.
	pdx->state = WORKING;
	AllowRequests(&pdx->dqReadWrite);
	RestartRequests(&pdx->dqReadWrite, fdo);

	KdPrint(("SIWDM - Exiting StartDevice (%x)\n", ntStatus));

	return ntStatus;
}

/*

Function name:

	QueryStopDevice

Routine Description:

    Determines if the device can handle a IRP_MN_STOP_DEVICE request.

Arguments:

    pdx - pointer to the device extension

    Irp -  I/O request being serviced

Return Value:

    STATUS_SUCCESS if successful
	NTSTATUS code otherwise

*/
NTSTATUS QueryStopDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;

	if(pdx->state != WORKING)
	{
		IoSkipCurrentIrpStackLocation(Irp);
		return IoCallDriver(pdx->LowerDeviceObject, Irp);
	}

	// Stall the request and wait for the current IRP to finish
	if(&pdx->dqReadWrite)
	{
		StallRequests(&pdx->dqReadWrite);
		WaitForCurrentIrp(&pdx->dqReadWrite);
	}
 	
	pdx->state = PENDINGSTOP;

	IoSkipCurrentIrpStackLocation(Irp);
	return IoCallDriver(pdx->LowerDeviceObject, Irp);
}

/*

Function name:

	CancelStopDevice

Routine Description:

    Cancels the previous query to stop the device IRP_MN_CANCEL_STOP_DEVICE.

Arguments:

    pdx - pointer to the device extension

    Irp -  I/O request being serviced

⌨️ 快捷键说明

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