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

📄 readwrite.cpp

📁 Programming the Microsoft Windows Driver Model(2nd)
💻 CPP
字号:
// Read/Write request processors for pci42 driver

// Copyright (C) 1999 by Walter Oney

// All rights reserved



#include "stddcls.h"

#include "driver.h"



VOID OnCancelReadWrite(PDEVICE_OBJECT fdo, PIRP Irp);

VOID TransferFirst(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 DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PDEVICE_EXTENSION pdx)

	{							// DpcForIsr

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

	StartNextPacket(&pdx->dqReadWrite, fdo);

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

	}							// DpcForIsr



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



#pragma LOCKEDCODE



BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pdx)

	{							// OnInterrupt



	// Read interrupt control/status register and see if an interrupt is pending.

	// If not, return FALSE immediately.



	ULONG intcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR));

	if (!(intcsr & INTCSR_INTERRUPT_PENDING))

		return FALSE;



	// See if we're really processing an IRP or if new requests are now being rejected

	// because of some PnP event or another



	BOOLEAN dpc = FALSE;		// assume no DPC needed



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

	NTSTATUS status = -1;



	if (pdx->busy)

		{						// see if we need to terminate this IRP

		ASSERT(Irp);

		

		if (Irp->Cancel)

			status = STATUS_CANCELLED;

		else

			status = AreRequestsBeingAborted(&pdx->dqReadWrite);



		if (!NT_SUCCESS(status))

			dpc = TRUE, pdx->nbytes = 0; // terminate IRP after clearing interrupt

		}						// see if we need to terminate this IRP



	// Process pending interrupts. This particular sample driver is only looking

	// for an incoming mailbox interrupt caused by the addon-simulator putting

	// a data byte into byte-0 of mailbox 1



	while (intcsr & INTCSR_INTERRUPT_PENDING)

		{						// clear all interrupts



		// Process incoming mailbox interrupt by reading a data byte



		if ((intcsr & INTCSR_IMBI) && pdx->nbytes && pdx->busy)

			{					// incoming mailbox interrupt

			*pdx->buffer = READ_PORT_UCHAR(pdx->portbase + IMB1);

			++pdx->buffer;

			++pdx->numxfer;

			if (!--pdx->nbytes)

				{			// request finished

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

				dpc = TRUE;

				status = STATUS_SUCCESS;

				}			// request finished

			}					// incoming mailbox interrupt



		// Interrupt flags on the S5933 are cleared by writing a "1" bit to them,

		// so clear all the interrupts we just examined.



		WRITE_PORT_ULONG((PULONG) (pdx->portbase + INTCSR), intcsr);



		// Check for additional interrupts

		

		intcsr = READ_PORT_ULONG((PULONG) (pdx->portbase + INTCSR));

		}						// clear all interrupts



	// Request a DPC if necessary



	if (dpc)

		{						// request DPC

		pdx->busy = FALSE;

		ASSERT(Irp);

		ASSERT(status != -1);

		Irp->IoStatus.Status = status;

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

		}						// request DPC



	return TRUE;

	}							// OnInterrupt



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



#pragma PAGEDCODE



VOID ResetDevice(PDEVICE_EXTENSION pdx)

	{							// ResetDevice

	PAGED_CODE();



	// Reset the device



	WRITE_PORT_ULONG((PULONG) (pdx->portbase + MCSR), MCSR_RESET);



	// Reset signals to the S5933 itself don't need to be written back as zero. The

	// add-on function reset flag must, however, be cleared. Delay a short period of

	// time to allow the reset to occur, then write back a zero to the add-on reset bit



	LARGE_INTEGER timeout;

	timeout.QuadPart = -10 * 10000; // i.e., 10 milliseconds



	KeDelayExecutionThread(KernelMode, FALSE, &timeout);

	WRITE_PORT_ULONG((PULONG) (pdx->portbase + MCSR), 0);



	// Clear any pending interrupts by writing 1's



	WRITE_PORT_ULONG((PULONG) (pdx->portbase + INTCSR), INTCSR_INTERRUPT_MASK);

	}							// ResetDevice



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



#pragma LOCKEDCODE



VOID SetupDevice(PDEVICE_EXTENSION pdx)

	{							// SetupDevice

	WRITE_PORT_ULONG((PULONG) (pdx->portbase + INTCSR),

		  INTCSR_IMBI_ENABLE									// enable incoming mailbox interrupt

		| (INTCSR_MB1 << INTCSR_IMBI_REG_SELECT_SHIFT)			// namely, on mailbox 1

		| (INTCSR_BYTE0 << INTCSR_IMBI_BYTE_SELECT_SHIFT)		// specifically, when byte 0 fills

		);

	}							// SetupDevice



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



#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



	if (!(TRUE

		&& gotport

		&& gotinterrupt

		))

		{

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

		return STATUS_DEVICE_CONFIGURATION_ERROR;

		}



	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;



	ResetDevice(pdx);			// reset the device



	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;

		}



	// Initialize the device



	KeSynchronizeExecution(pdx->InterruptObject, (PKSYNCHRONIZE_ROUTINE) SetupDevice, pdx);



	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);

	NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);

	if (!NT_SUCCESS(status))

		{

		CompleteRequest(Irp, status, 0);

		return;

		}



	// Short-circuit a read for zero bytes



	if (!stack->Parameters.Read.Length)

		{						// nothing to do

		StartNextPacket(&pdx->dqReadWrite, fdo);

		CompleteRequest(Irp, STATUS_SUCCESS, 0);

		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

		return;

		}						// nothing to do



	// Save description of current request in the device extension



	pdx->buffer = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;

	pdx->nbytes = stack->Parameters.Read.Length;

	pdx->numxfer = 0;



	// See if an input byte is already available. After this first byte, we wait for

	// an interrupt to tell us the next byte is available.



	KeSynchronizeExecution(pdx->InterruptObject, (PKSYNCHRONIZE_ROUTINE) TransferFirst, pdx);

	}							// StartIo



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



#pragma PAGEDCODE



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

	{							// StopDevice

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;



	if (pdx->InterruptObject)

		{						// disconnect interrupt

		if (oktouch)

			ResetDevice(pdx);



		IoDisconnectInterrupt(pdx->InterruptObject);

		pdx->InterruptObject = NULL;

		}						// disconnect interrupt



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

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

	pdx->portbase = NULL;

	}							// StopDevice



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



#pragma LOCKEDCODE



VOID TransferFirst(PDEVICE_EXTENSION pdx)

	{							// TransferFirst



	pdx->busy = TRUE;



	// See if a data byte is already pending in the incoming mailbox



	ULONG mbef = READ_PORT_ULONG((PULONG) (pdx->portbase + MBEF));

	if (!(mbef & MBEF_IN1_0))

		return;					// no pending input byte



	*pdx->buffer = READ_PORT_UCHAR(pdx->portbase + IMB1);

	++pdx->buffer;

	++pdx->numxfer;

	if (--pdx->nbytes != 0)

		return;



	pdx->busy = FALSE;

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

	ASSERT(Irp);

	Irp->IoStatus.Status = STATUS_SUCCESS;

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

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

	}							// TransferFirst

⌨️ 快捷键说明

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