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

📄 intrdev.cpp

📁 WINDOW2000/XP下驱动程序开发的实例。对刚开始学驱动设计的人有一定的帮助
💻 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,ISA中断初始化
	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);	//初始化延迟过程调用(DPC)
	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);
			//上面语句意义:若CurrentIrp()=NULL,则CurrentIrp()=PIRP(I)。否则表示当前设备
			//正在忙,不接收新的请求。见第6章中的6.3.5解释。DriverWorks提供的usbtherm范
			//例中采用的是InterlockedExchangePointer,它阻止不了一个应用程序的多次调用,其
			//有致命错误,笔者做过实验。
			// 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);//DDK函数,读自系统启动后间隔定时器的中断次数
	m_TimeStampFifo.Write(&ts, 1);	//写入FIFO

	m_Dpc.Request();	//请求延迟过程调用
	return FALSE;
	//返回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();
	//下面调用中断同步例程ReadTimeFifo,关于中断同步例程,见第13章的13.2.1 
	//KInterrupt解释。
	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
	//读FIFO,nItemsRead为实际读取的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 + -