📄 intrdev.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 + -