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

📄 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 (m_pEvent)
		delete m_pEvent;

	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_pEvent = NULL;
	m_bNotifyApp = TRUE;
	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;

	m_pEvent = NULL;

	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;
		if (m_pEvent) delete m_pEvent;
		m_pEvent = NULL;

		status = STATUS_SUCCESS;
	}
	else
		status = STATUS_UNSUCCESSFUL;

	return I.Complete(status);
}

//////////////////////////////////////////////////////////////////
// DeviceControl
//
// The test app uses a DeviceIoControl call for two purposes:
//
// 1. It passes an event handle to the driver. The driver sets
//    the event when there is something for the app to do, i.e.,
//    when an interrupt occurs, and the app fetches the data.
//
// 2. It fetches the timestamp data for the interrupts.
//
NTSTATUS InterruptDemoDevice::DeviceControl(KIrp I)
{
	T << I;
	
	I.Information() = 0;

	switch (I.IoctlCode())
	{
	case IOCTL_SET_NOTIFICATION_EVENT:
	{
		HANDLE hEvent = *(HANDLE*)I.IoctlBuffer();

		if (m_pEvent)
			delete m_pEvent;

		m_pEvent = new (NonPagedPool) KEvent(hEvent, OBJECT_TYPE_ALL_ACCESS);

		return I.Complete(STATUS_SUCCESS);
	}

	case IOCTL_GET_TIMESTAMP_DATA:
		if (SynchronizeInterrupt(&m_Interrupt, LinkTo(ReadTimeFifo), PIRP(I)) )
			return I.Complete(STATUS_SUCCESS);

		else
			return I.Complete(STATUS_UNSUCCESSFUL);

		break;

	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)
{
	T << "In the ISR\n";

	TIMESTAMP ts;

	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.
// It invokes the synch crit section member function TestAndClearNotifyApp,
// which determines if it is necessary to notify the app of the 
// interrupt. The idea is that we only notify the app when there
// is no outstanding interrupt to which the app has not responded.
//
VOID InterruptDemoDevice::Dpc(PVOID Arg1, PVOID Arg2)
{
	BOOLEAN Notify;
	BOOLEAN SynchStatus;

	if (m_pEvent) 
	{
		SynchStatus = SynchronizeInterrupt(
			&m_Interrupt, 
			LinkTo(TestAndClearNotifyApp), 
			&Notify
			);

		if (SynchStatus)
		{
			T << "DPC, App notify=" << ULONG(Notify) << "\n";
			if (Notify) 
				m_pEvent->Set();
		}
		else
			T << "Dpc error synchronizing\n";
	}
}

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

	m_bNotifyApp = TRUE;

	return TRUE;
}

//////////////////////////////////////////////////////////////////
// TestAndClearNotifyApp
//
// This is a synch critical section member function, called from
// the DPC to determine if the app needs to be notified. The
// parameter is assumed to be a pointer to a boolean that supplies
// the output status.
//
BOOLEAN InterruptDemoDevice::TestAndClearNotifyApp(PVOID p)
{
	*(BOOLEAN*)p = m_bNotifyApp;
	m_bNotifyApp = FALSE;

	T << "TestAndClearNotifyApp previous state was=" << ULONG(m_bNotifyApp) << "\n";

	return TRUE;
}

⌨️ 快捷键说明

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