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

📄 readwrite.cpp

📁 Programming the Microsoft Windows driver model.2nd 随书光盘。内有很多作者送的实用工具和随书源码。WDM编程
💻 CPP
字号:
// Read/Write request processors for scatgath driver

// Copyright (C) 1999 by Walter Oney

// All rights reserved



#include "stddcls.h"

#include "driver.h"



VOID DmaExecutionRoutine(PDEVICE_OBJECT fdo, PIRP Irp, PSCATTER_GATHER_LIST sglist, PDEVICE_EXTENSION pdx);

VOID OnCancelReadWrite(PDEVICE_OBJECT fdo, PIRP Irp);

BOOLEAN StartNextTransfer(PDEVICE_EXTENSION pdx);



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



#pragma PAGEDCODE



NTSTATUS DispatchCleanup(PDEVICE_OBJECT fdo, PIRP Irp)

	{							// DispatchCleanup

	PAGED_CODE();

	KdPrint((DRIVERNAME " - IRP_MJ_CLEANUP\n"));

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

	CleanupRequests(&pdx->dqReadWrite, stack->FileObject, STATUS_CANCELLED);

	return CompleteRequest(Irp, STATUS_SUCCESS, 0);

	}							// DispatchCleanup



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



#pragma PAGEDCODE



NTSTATUS DispatchCreate(PDEVICE_OBJECT fdo, PIRP Irp)

	{							// DispatchCreate

	PAGED_CODE();

	KdPrint((DRIVERNAME " - IRP_MJ_CREATE\n"));

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;



	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);



	NTSTATUS status = STATUS_SUCCESS;

	InterlockedIncrement(&pdx->handles);

	return CompleteRequest(Irp, status, 0);

	}							// DispatchCreate





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



#pragma PAGEDCODE



NTSTATUS DispatchClose(PDEVICE_OBJECT fdo, PIRP Irp)

	{							// DispatchClose

	PAGED_CODE();

	KdPrint((DRIVERNAME " - IRP_MJ_CLOSE\n"));

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

	InterlockedDecrement(&pdx->handles);

	return CompleteRequest(Irp, STATUS_SUCCESS, 0);

	}							// DispatchClose



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



#pragma PAGEDCODE



NTSTATUS DispatchReadWrite(PDEVICE_OBJECT fdo, PIRP Irp)

	{							// DispatchReadWrite

	PAGED_CODE();

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	IoMarkIrpPending(Irp);

	StartPacket(&pdx->dqReadWrite, fdo, Irp, OnCancelReadWrite);

	return STATUS_PENDING;

	}							// DispatchReadWrite



#pragma LOCKEDCODE



VOID OnCancelReadWrite(IN PDEVICE_OBJECT fdo, IN PIRP Irp)

	{							// OnCancelReadWrite

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	CancelRequest(&pdx->dqReadWrite, Irp);

	}							// OnCancelReadWrite



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



#pragma LOCKEDCODE



VOID DmaExecutionRoutine(PDEVICE_OBJECT fdo, PIRP junk, PSCATTER_GATHER_LIST sglist, PDEVICE_EXTENSION pdx)

	{							// DmaExecutionRoutine

	PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite);

	BOOLEAN isread = IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_READ;

	pdx->sglist = sglist;		// save for deallocation in DPC routine

	pdx->isg = 0;				// index of current scatter gather element

	pdx->sgdone = 0;			// 0 elements processed so far

	pdx->busy = TRUE;			// indicate device is busy



	// Invoke StartNextTransfer as a synch critical section routine to begin the

	// first stage of a possibly multi-stage transfer



	if (!KeSynchronizeExecution(pdx->InterruptObject, (PKSYNCHRONIZE_ROUTINE) StartNextTransfer, pdx))

		IoRequestDpc(fdo, NULL, NULL);	// nothing to do

	}							// DmaExecutionRoutine



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



#pragma LOCKEDCODE



VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PDEVICE_EXTENSION pdx)

	{							// DpcForIsr

	NTSTATUS status;

	PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite);

	status = Irp->IoStatus.Status;	// get ending status left by ISR

	BOOLEAN isread = IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_READ;



	// Release the scatter gather list



	(*pdx->AdapterObject->DmaOperations->PutScatterGatherList)

		(pdx->AdapterObject, pdx->sglist, !isread);



	StartNextPacket(&pdx->dqReadWrite, fdo);

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	}							// DpcForIsr



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



#pragma LOCKEDCODE



BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pdx)

	{							// OnInterrupt

	if (!StartNextTransfer(pdx))

		{

		pdx->busy = FALSE;

		PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite);

		ASSERT(Irp);

		Irp->IoStatus.Status = STATUS_SUCCESS;

		Irp->IoStatus.Information = pdx->nbytes;

		IoRequestDpc(pdx->DeviceObject, NULL, NULL);

		}

	return TRUE;

	}							// OnInterrupt



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



#pragma PAGEDCODE



NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)

	{							// StartDevice

	NTSTATUS status;

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;



	// Identify the I/O resources we're supposed to use.

	

	ULONG vector;

	KIRQL irql;

	KINTERRUPT_MODE mode;

	KAFFINITY affinity;

	BOOLEAN irqshare;

	BOOLEAN gotinterrupt = FALSE;



	PHYSICAL_ADDRESS portbase;

	BOOLEAN gotport = FALSE;

	

	if (!translated)

		return STATUS_DEVICE_CONFIGURATION_ERROR;		// no resources assigned??



	PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = translated->PartialDescriptors;

	ULONG nres = translated->Count;

	for (ULONG i = 0; i < nres; ++i, ++resource)

		{						// for each resource

		switch (resource->Type)

			{					// switch on resource type



		case CmResourceTypePort:

			portbase = resource->u.Port.Start;

			pdx->nports = resource->u.Port.Length;

			pdx->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0;

			gotport = TRUE;

			break;

	

		case CmResourceTypeInterrupt:

			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;

			irqshare = resource->ShareDisposition == CmResourceShareShared;

			gotinterrupt = TRUE;

			break;



		default:

			KdPrint((DRIVERNAME " - Unexpected I/O resource type %d\n", resource->Type));

			break;

			}					// switch on resource type

		}						// for each resource



	// Verify that we got all the resources we were expecting



	if (!(TRUE

		&& gotinterrupt

		&& gotport

		))

		{

		KdPrint((DRIVERNAME " - Didn't get expected I/O resources\n"));

		return STATUS_DEVICE_CONFIGURATION_ERROR;

		}



	// Determine bus type before proceeding, just so we don't have a bunch of cleanup

	// to do if this call fails



	INTERFACE_TYPE bustype;

	ULONG junk;

	status = IoGetDeviceProperty(pdx->Pdo, DevicePropertyLegacyBusType, sizeof(bustype),

		&bustype, &junk);

	if (!NT_SUCCESS(status))

		{

		KdPrint((DRIVERNAME " - IoGetDeviceProperty failed - %X\n", status));

		return status;

		}



	if (pdx->mappedport)

		{						// map port address for RISC platform

		pdx->portbase = (PUCHAR) MmMapIoSpace(portbase, pdx->nports, MmNonCached);

		if (!pdx->portbase)

			{

			KdPrint((DRIVERNAME " - Unable to map port range %I64X, length %X\n", portbase, pdx->nports));

			return STATUS_INSUFFICIENT_RESOURCES;

			}

		}						// map port address for RISC platform

	else

		pdx->portbase = (PUCHAR) portbase.QuadPart;



	// This is a bus-mastering device without scatter/gather capability. Allocate

	// an appropriate adapter object



	DEVICE_DESCRIPTION dd;

	RtlZeroMemory(&dd, sizeof(dd));

	dd.Version = DEVICE_DESCRIPTION_VERSION;

	dd.Master = TRUE;

	dd.InterfaceType = bustype;

	dd.MaximumLength = MAXTRANSFER;		// manifest constant in driver.h

	dd.Dma32BitAddresses = TRUE;



	pdx->AdapterObject = IoGetDmaAdapter(pdx->Pdo, &dd, &pdx->nMapRegisters);

	if (!pdx->AdapterObject)

		{						// unable to creata adapter object

		KdPrint((DRIVERNAME " - Unable to create DMA Adapter Object\n"));

		if (pdx->mappedport)

			MmUnmapIoSpace(pdx->portbase, pdx->nports);

		pdx->portbase = NULL;

		return STATUS_UNSUCCESSFUL;

		}						// unable to create adapter object



	// TODO Temporarily prevent device from interrupt if that's possible.

	// Enable device for interrupts when IoConnectInterrupt returns



	status = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE) OnInterrupt,

		(PVOID) pdx, NULL, vector, irql, irql, mode, irqshare, affinity, FALSE);

	if (!NT_SUCCESS(status))

		{

		KdPrint((DRIVERNAME " - IoConnectInterrupt failed - %X\n", status));

		if (pdx->portbase && pdx->mappedport)

			MmUnmapIoSpace(pdx->portbase, pdx->nports);

		pdx->portbase = NULL;

		return status;

		}



	return STATUS_SUCCESS;

	}							// StartDevice



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



#pragma LOCKEDCODE



VOID StartIo(IN PDEVICE_OBJECT fdo, IN PIRP Irp)

	{							// StartIo

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

	

	PMDL mdl = Irp->MdlAddress;

	pdx->numxfer = 0;

	ULONG nbytes = MmGetMdlByteCount(mdl);

	pdx->nbytes = nbytes;

	PVOID vaddr = MmGetMdlVirtualAddress(mdl);

	BOOLEAN isread = stack->MajorFunction == IRP_MJ_READ;



	// Call the adapter's GetScatterGatherList routine to reserve the adapter and the

	// required map registers and to construct a scatter/gather list for the transfer.

	// If the request length requires more map registers than we're allowed to request,

	// GetScatterGatherList will fail with STATUS_INSUFFICIENT_RESOURCES. If so big a

	// request is possible with your device, you can't use the GetScatterGatherList routine

	// to program DMA -- instead, you must use the older method of calling MapTransfer

	// repeatedly to build up your own scatter/gather list.



	NTSTATUS status = (*pdx->AdapterObject->DmaOperations->GetScatterGatherList)

		(pdx->AdapterObject, fdo, mdl, vaddr, nbytes,

		(PDRIVER_LIST_CONTROL) DmaExecutionRoutine, pdx, !isread);

	if (!NT_SUCCESS(status))

		{

		KdPrint((DRIVERNAME " - GetScatterGatherList failed - %X\n", status));

		CompleteRequest(Irp, status, 0);

		StartNextPacket(&pdx->dqReadWrite, fdo);

		}

	}							// StartIo



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



#pragma LOCKEDCODE



BOOLEAN StartNextTransfer(PDEVICE_EXTENSION pdx)

	{							// StartNextTransfer

	PSCATTER_GATHER_LIST sglist = pdx->sglist;

	ULONG i = pdx->isg += pdx->sgdone;

	ULONG n = sglist->NumberOfElements - i; // # left to do

	if (!n)

		return FALSE;			// request is now finished

	if (n > MAXSG)

		n = MAXSG;				// only do as many as hardware understands

	pdx->sgdone = n;			// save count for next interrupt



	// TODO Program the hardware to transfer data using the address/length pairs

	// sglist->Elements[i].Address and .Length, for the next "n" elements



	return TRUE;

	}							// StartNextTransfer



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



#pragma PAGEDCODE



VOID StopDevice(IN PDEVICE_OBJECT fdo, BOOLEAN oktouch /* = FALSE */)

	{							// StopDevice

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;



	if (pdx->InterruptObject)

		{						// disconnect interrupt



		// TODO prevent device from generating more interrupts if possible



		IoDisconnectInterrupt(pdx->InterruptObject);

		pdx->InterruptObject = NULL;

		}						// disconnect interrupt



	if (pdx->portbase && pdx->mappedport)

		MmUnmapIoSpace(pdx->portbase, pdx->nports);

	pdx->portbase = NULL;

	}							// StopDevice

⌨️ 快捷键说明

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