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

📄 intrdev.cpp

📁 Windows 2000/XP WDM設備驅動程式開發 使用 Numega 公司出版的軟體快速建置驅動程式
💻 CPP
字号:
// intrdev.cpp - implementation of interrupt demo device class 
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060  USA
//
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================

#include <vdw.h>
#include "common.h"
#include "intrdev.h"

// Class InterruptDemoDevice hooks IRQ 6, which is the floppy
// interrupt on Intel platforms. The device does not hook the
// interrupt until the test application opens it, and member
// Create is called. The ISR takes a time stamp, writes a record to
// a FIFO, and queues a DPC. The DPC notifies the test app that an
// interrupt has occurred by setting an event whose handle had
// been previously sent to the device using DeviceIoControl. The
// DPC does not set the event if the app has not responded to a
// previous event. The app retrieves the records written to the
// FIFO by the ISR using another DeviceIoControl call.

KDebugOnlyTrace T("IntrDemo");

//////////////////////////////////////////////////////////////////
// Device class constructor
//
InterruptDemoDevice::~InterruptDemoDevice()
{
	T << "Deleting device\n";

	if ((PKINTERRUPT)m_Interrupt)
		m_Interrupt.Disconnect();
}

//////////////////////////////////////////////////////////////////
// Begin INIT section code
#pragma code_seg("INIT")

//////////////////////////////////////////////////////////////////
// Device class constructor
//
InterruptDemoDevice::InterruptDemoDevice() :
// Base class
	KDevice(
		L"IntrDemo0", 
		FILE_DEVICE_UNKNOWN, 
		L"IntrDemo0", 
		DO_BUFFERED_IO
		),

// Interrupt object
	m_Interrupt(
		Isa,
		0,
		FLOPPY_IRQ,
		FLOPPY_IRQ,
		Latched,
		TRUE,
		FALSE
	),

// Output fifo
	m_TimeStampFifo(FIFOSIZE, NonPagedPool)

{
	m_File = 0;
	m_Dpc.Setup(LinkTo(Dpc), this);
	m_InterruptCount = 0;
}
#pragma code_seg()

//////////////////////////////////////////////////////////////////
// Create 
//
// This is called when the test app issues a CreateFile
//
NTSTATUS InterruptDemoDevice::Create(KIrp I)
{
	NTSTATUS status;

	if (m_File == 0)
	{
		m_File = I.FileObject();
		status = m_Interrupt.Connect(LinkTo(Isr),this);
	}
	else
		status = STATUS_UNSUCCESSFUL;

	T << "Create status = " << ULONG(status) << "\n";
	
	I.Information() = 0;
	return I.Complete(status);
}

//////////////////////////////////////////////////////////////////
// Close
//
// This is called when the test app closes the handle to the device
//
NTSTATUS InterruptDemoDevice::Close(KIrp I)
{
	NTSTATUS status;

	I.Information() = 0;

	if (m_File == I.FileObject())
	{
		T << "Disconnecting interrupt\n";
		m_Interrupt.Disconnect();
		m_File = 0;
		status = STATUS_SUCCESS;
	}
	else
		status = STATUS_UNSUCCESSFUL;

	return I.Complete(status);
}

//////////////////////////////////////////////////////////////////
// DeviceControl
//
NTSTATUS InterruptDemoDevice::DeviceControl(KIrp I)
{
	switch (I.IoctlCode())
	{
	case IOCTL_GET_TIMESTAMP_DATA:
		{
			PVOID CI = InterlockedCompareExchangePointer( (PVOID*)&CurrentIrp(), PVOID( PIRP(I)), NULL);

			// Allow only one request at a time	
			if ( CI != NULL )
				return I.Complete(STATUS_DEVICE_BUSY);

			CancelSpinLock::Acquire();
			if ( I.WasCanceled() )
			{
				CurrentIrp() = NULL;
				CancelSpinLock::Release();
				return I.Complete(STATUS_CANCELLED);
			}

			I.SetCancelRoutine( LinkTo(Cancel) );
			CancelSpinLock::Release();
			T << "Set CurrentIrp()\n";
			I.MarkPending();
			return STATUS_PENDING;
		}
	default:
		T << "Bad Request: " << I.IoctlCode() << "\n";

		return I.Complete(STATUS_INVALID_PARAMETER);	
	}
}

//////////////////////////////////////////////////////////////////
// Isr
//
// This is the interrupt service routine. Since we always return
// FALSE (to indicate that we did not service the interrupt), there
// is no interaction with the hardware required. The system will
// call the actual floppy interrupt handler. This routine justs
// counts the interrupt (m_InterruptCount), grabs a timestamp,
// and requests queues the DPC object.
//
BOOLEAN InterruptDemoDevice::Isr(void)
{
	TIMESTAMP ts;

	T << "In the ISR\n";

	ts.ts_interrupt_count = ++m_InterruptCount;
	KeQueryTickCount(&ts.ts_time);
	m_TimeStampFifo.Write(&ts, 1);

	m_Dpc.Request();
	return FALSE;
}

//////////////////////////////////////////////////////////////////
// Dpc
// 
// This the callback associated with the device's DPC object. The
// ISR queues the dpc object, resulting in a call to this routine.
//
VOID InterruptDemoDevice::Dpc(PVOID Arg1, PVOID Arg2)
{
	T << "In the DPC\n";
	CancelSpinLock::Acquire();
	if (CurrentIrp() == NULL) {
		CancelSpinLock::Release();
		return;
	};

	KIrp I = CurrentIrp();
	CurrentIrp() = NULL;
	if ( I.WasCanceled() )
	{
		CancelSpinLock::Release();
		I.Information() = 0;
		I.Complete(STATUS_CANCELLED);
		return;
	}

	I.SetCancelRoutine(NULL);
	CancelSpinLock::Release();
	if (SynchronizeInterrupt(&m_Interrupt, LinkTo(ReadTimeFifo), PIRP(I)) )
		I.Complete(STATUS_SUCCESS);
	else
		I.Complete(STATUS_UNSUCCESSFUL);
}

//////////////////////////////////////////////////////////////////
// ReadTimeFifo
// 
// This is a synch critical section member function, called when
// the app requests data from the fifo. (Note: this could be done
// with a KInterruptSafeFifo object.)
//
BOOLEAN InterruptDemoDevice::ReadTimeFifo(PVOID pIrp)
{
	KIrp I = (PIRP)pIrp;
	ULONG MaxReadItems = I.IoctlOutputBufferSize() / sizeof(TIMESTAMP);
	ULONG nItemsRead;

	nItemsRead = m_TimeStampFifo.Read((TIMESTAMP*)I.IoctlBuffer(), MaxReadItems);
	// guaranteed to empty the buffer, because app's read buffer is sizeof the fifo

	I.Information() = nItemsRead * sizeof(TIMESTAMP);

	return TRUE;
}

VOID InterruptDemoDevice::Cancel(KIrp I)
{
	T << "Cancel IRP"<<"\n";
	if ( (PIRP)I == CurrentIrp() )
	{
		CurrentIrp() = NULL;
		CancelSpinLock::Release(I.CancelIrql());
		I.Information() = 0;
		I.Complete(STATUS_CANCELLED);
	}
	else
		CancelSpinLock::Release(I.CancelIrql());
}

⌨️ 快捷键说明

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