误入豪门老婆让我爱txt:多种开发工具开发的9054驱动源程序比较(下1)转

来源:百度文库 编辑:中财网 时间:2024/04/28 12:23:17

多种开发工具开发的9054驱动源程序比较(下1)转

(2008-09-30 22:05:07) 转载标签:

driver

杂谈

分类: 驱动开发,嵌入式开发

用DDK开发的9054驱动

和S5933比较起来,开发PLX9054比较不幸,可能是第一次开发PCI的缘故吧。因为,很多PCI的例子都是对S5933,就连微软出版的《Programming the Microsoft Windows Driver Model》都提供了一个完整的S5933的例子。
在这篇有关DDK的开发论文里。我将分两个例子来构建PLX9054的驱动,第一个,是对《Windows2000 设备驱动程序设计指南》里的分段DMA例子的扩充,它的结构比较简单,对理解DDK的运作很有帮助;第二个,我将对《Programming the Microsoft Windows Driver Model》里的S5933进行改造,因为这个例子里,涉及的概念较多,但可与前面《武》用DS开发的驱动媲美。以下,我将一面分析程序,一面将程序中涉及的重要概念进行解释。

例一:
//
//为了编程方便,作者提供了一个CUString类。
// Unicode.h
//
// Copyright (C) 2000 by Jerry Lozano
//
//

#pragma once


class CUString {
public:
CUString() {Init(); } // constructor relies on internal Init function
CUString(const char* pAnsiString);
CUString(PCWSTR pWideString);
~CUString(); // destructor gives back buffer allocation
void Init(); // performs "real" initialization
void Free(); // performs real destruct
CUString(const CUString& orig); // copy constructure (required)
CUString operator=(const CUString& rop); // assignment operator overload (required)
BOOLEAN operator==(const CUString& rop) const; // comparison operator overload
CUString operator+(const CUString& rop) const; // concatenation operator
CUString& operator+=(const CUString& rop); // and a convenient concat
operator PWSTR() const; // cast operator into wchar_t
operator UNICODE_STRING&(); // cast into UNICODE_STRING
operator ULONG() const; // cast operator into ULONG
CUString(ULONG value); // converter: ULONG->CUString
WCHAR& operator[](int idx); // buffer access operator
USHORT Length() {return uStr.Length/2;}

protected:
UNICODE_STRING uStr; // W2K kernel structure for Unicode string
enum ALLOC_TYPE {Empty, FromCode, FromPaged, FromNonPaged};
ALLOC_TYPE aType; // where buffer is allocated
};


//以下是Unicode.cpp
#ifdef WIN32DDK_TEST
#include "DDKTestEnv.h"
#else
extern "C" {
#include
}
#endif

#define max(a,b) ((a>b)?a:b)

#include "Unicode.h"

void CUString::Init() {
uStr.Length = 0;
uStr.MaximumLength = 0;
uStr.Buffer = NULL;
aType = Empty;
}

CUString::CUString(const char* pAnsiString) {
ANSI_STRING str;
RtlInitAnsiString(&str, pAnsiString);
uStr.MaximumLength = (USHORT) max(32, RtlAnsiStringToUnicodeSize(&str) );
uStr.Buffer = (PWSTR)
ExAllocatePoolWithTag(PagedPool, uStr.MaximumLength, 1633);
aType = FromPaged;
RtlAnsiStringToUnicodeString(&uStr, &str, FALSE);
}

CUString::CUString(PCWSTR pWideString) {
RtlInitUnicodeString(&uStr, pWideString);
aType = FromCode;
}

CUString::~CUString() {
Free();
}

void CUString::Free() {
if (aType == FromPaged || aType == FromNonPaged)
ExFreePool(uStr.Buffer);
uStr.Buffer = NULL;
uStr.Length = 0;
uStr.MaximumLength = 0;
}

CUString::CUString(const CUString& orig) { // copy constructor (required)
uStr.Length = 0;
uStr.MaximumLength = orig.uStr.MaximumLength;
uStr.Buffer = (PWSTR)
ExAllocatePoolWithTag(PagedPool, uStr.MaximumLength, 1633);
aType = FromPaged;
RtlCopyUnicodeString(&uStr, (PUNICODE_STRING)&orig.uStr);
uStr.Buffer[uStr.Length/2] = UNICODE_NULL;
}

CUString CUString::operator=(const CUString& rop) { // assignment operator overload (required)
if (&rop != this) { // lop == rop ??? why was I called
if (rop.uStr.Length >= uStr.Length || // does it fit?
(aType != FromPaged && aType != FromNonPaged) ) {
// it doesn't fit - free up existing buffer
if (aType == FromPaged || aType == FromNonPaged)
ExFreePool(uStr.Buffer);
uStr.Length = 0;
uStr.MaximumLength = rop.uStr.MaximumLength;
// and allocate fresh space
uStr.Buffer = (PWSTR)
ExAllocatePoolWithTag(PagedPool, uStr.MaximumLength, 1633);
aType = FromPaged;
}
RtlCopyUnicodeString(&uStr, (PUNICODE_STRING)&rop.uStr);
uStr.Buffer[uStr.Length/2] = UNICODE_NULL;
}
return *this;
}
BOOLEAN CUString::operator ==(const CUString& rop) const {
return RtlEqualUnicodeString(&this->uStr, &rop.uStr, FALSE); // case matters
}

CUString::operator PWSTR() const {
return uStr.Buffer;
}

CUString::operator UNICODE_STRING &() {
return uStr;
}

CUString CUString::operator+(const CUString& rop) const {
CUString retVal;
retVal.uStr.Length = this->uStr.Length + rop.uStr.Length;
retVal.uStr.MaximumLength = max(32, retVal.uStr.Length+2);
retVal.uStr.Buffer = (PWSTR)
ExAllocatePoolWithTag(PagedPool, retVal.uStr.MaximumLength, 1633);
RtlCopyUnicodeString(&retVal.uStr, (PUNICODE_STRING)&this->uStr);
RtlAppendUnicodeStringToString(&retVal.uStr, (PUNICODE_STRING)&rop.uStr);
retVal.uStr.Buffer[retVal.uStr.Length/2] = UNICODE_NULL;

return retVal;
}

CUString& CUString::operator+=(const CUString& rop) {
*this = *this + rop;
return *this;
}

CUString::operator ULONG() const {
ULONG retVal;
RtlUnicodeStringToInteger((PUNICODE_STRING)&uStr, 0, &retVal);
return retVal;
}

CUString::CUString(ULONG value) {
// Converts from a ULONG into a CUString
uStr.Length = 0;
uStr.MaximumLength = 32;
uStr.Buffer = (PWSTR)
ExAllocatePoolWithTag(PagedPool, uStr.MaximumLength, 1633);
aType = FromPaged;
RtlIntegerToUnicodeString(value, 0, &uStr);
}

WCHAR& CUString::operator[](int idx) {
// accesses an individual WCHAR in CUString buffer
if (idx >= 0 && idx < uStr.MaximumLength/2)
return uStr.Buffer[idx];
else
return uStr.Buffer[0]; // got to return something
}

//有了CUString整个UNICODE_STRING处理起来就非常方便。
//我喜欢抄程序,真的用手抄,可以感觉一个好的程序的细节之美。
//以下是两个字符串的解释:
// typedef struct _STRING {
// USHORT Length;
// USHORT MaximumLength;
// PCHAR Buffer;
// } ANSI_STRING *PANSI_STRING;
//这是用于ANSI的字符串。
// typedef struct _UNICODE_STRING {
// USHORT Length;
// USHORT MaximumLength;
// PWSTR Buffer; //Pointer to a buffer used to contain a string of wide characters
// } UNICODE_STRING *PUNICODE_STRING;
//这是驱动用的字符串。使用RtlInitUnicodeString()进行初始化。还可以用以下例程:
//RtlAnsiStringToUnicodeSize, RtlAnsiStringToUnicodeString, RtlFreeUnicodeString, //RtlInitUnicodeString, RtlUnicodeStringToAnsiSize, RtlUnicodeStringToAnsiString

接下来,我想通过比较两个DDK驱动,然后,得出自己的驱动。这两个驱动分别是前两经典的例子,为行文方便,我用《WDM》表示取自《Programming the Microsoft Windows Driver Model》的例子(Chap7PKTDMA),用《2000》表示取自《Windows2000 设备驱动程序设计指南》的例子(Chap12 DMASlave)。

一. DEVICE_EXTENSION的比较
《2000》:
enum DRIVER_STATE {Stopped, Started, Removed};

typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT pDevice;
PDEVICE_OBJECT pLowerDevice;
ULONG DeviceNumber;
CUString ustrDeviceName; // internal name
CUString ustrSymLinkName; // external name

PUCHAR portBase; // I/O register address
ULONG portLength;
KIRQL IRQL; // Irq for parallel port
ULONG Vector;
KAFFINITY Affinity;
PKINTERRUPT pIntObj; // the interrupt object
BOOLEAN bInterruptExpected; // TRUE iff this driver is expecting interrupt
DRIVER_STATE state; // current state of driver

PDMA_ADAPTER pDmaAdapter;
ULONG mapRegisterCount;
ULONG dmaChannel;

// This is the "handle" assigned to the map registers
// when the AdapterControl routine is called back
PVOID mapRegisterBase;

ULONG bytesRequested;
ULONG bytesRemaining;
ULONG transferSize;
PUCHAR transferVA;

// This flag is TRUE if writing, FALSE if reading
BOOLEAN bWriting;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
////////////////////////////////////////////////////////////////////
//《WDM》:
typedef struct tagDEVICE_EXTENSION {
PDEVICE_OBJECT DeviceObject; // device object this extension belongs to,同
PDEVICE_OBJECT LowerDeviceObject; // next lower driver in same stack,同
PDEVICE_OBJECT Pdo; // the PDO
IO_REMOVE_LOCK RemoveLock; // removal control locking structure,使用了IO_REMOVE_LOCK.
UNICODE_STRING devname; //内部名称
PGENERIC_EXTENSION pgx; // device extension for GENERIC.SYS
//在《WDM》的构建过程中,大量相同的工作被放在了GENERIC.SYS。
DEVQUEUE dqReadWrite; // queue for reads and writes
//这是用于IRP串行化处理的一个类,在GENERIC.SYS里定义
LONG handles; // # open handles
PKINTERRUPT InterruptObject; // address of interrupt object,同
PUCHAR portbase; // I/O port base address,同
ULONG nports; // number of assigned ports,同
PADAPTER_OBJECT AdapterObject; // DMA adapter object,同
ULONG nMapRegisters; // maximum # mapping registers

ULONG xfer; // # bytes to transfer in this stage,同前bytesRequested;
ULONG numxfer; // # bytes transferred so far,同前transferSize;
ULONG nbytes; // # bytes remaining to transfer,同前bytesRemaining;
ULONG nMapRegistersAllocated; // # map registers allocated for this transfer
PVOID vaddr; // virtual addr for this stage of transfer,同前transferVA;
PVOID regbase; // handle for base of mapping register set,同前mapRegisterBase;
ULONG intcsr; // accumulated interrupt flags
BOOLEAN mappedport; // true if we mapped port addr in StartDevice
BOOLEAN busy; // true if device busy with a request,同前state.
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

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

//我的DEVICE_EXTENSION,参考了前两个定义,并以《WDM》为蓝本。
enum DRIVER_STATE{ Stopped, Started, Removed};
typedef struct tagDEVICE_EXTENSION {
PDEVICE_OBJECT DeviceObject; // device object this extension belongs to,同
PDEVICE_OBJECT LowerDeviceObject; // next lower driver in same stack,同
PDEVICE_OBJECT Pdo; // the PDO,《WDM》
// IO_REMOVE_LOCK RemoveLock; // removal control locking structure,使用了IO_REMOVE_LOCK.
//因为想简单些,所以没用,其实不用也是可以的。
ULONG DeviceNumber; //来自《2000》,用于DeviceObject计数
UNICODE_STRING devname; //内部名称
UNICODE_STRING SymLinkName; //根据《2000》加的。用于外部程序引用。
// PGENERIC_EXTENSION pgx; // device extension for GENERIC.SYS
//在《WDM》的构建过程中,大量相同的工作被放在了GENERIC.SYS。
//因为本驱动,不需要GENERIC.SYS,其中的许多工作将在程序自身中完成。
// DEVQUEUE dqReadWrite; // queue for reads and writes
//这是用于IRP串行化处理的一个类,在GENERIC.SYS里定义
//因为简化程序的控制,本驱动程序不用IRP串行处理。
// LONG handles; // # open handles
PKINTERRUPT InterruptObject; // address of interrupt object,同
PUCHAR portbase; // I/O port base address,同
ULONG nports; // number of assigned ports,同
PADAPTER_OBJECT AdapterObject; // DMA adapter object,同
ULONG nMapRegisters; // maximum # mapping registers

ULONG xfer; // # bytes to transfer in this stage,同前bytesRequested;
ULONG numxfer; // # bytes transferred so far,同前transferSize;
ULONG nbytes; // # bytes remaining to transfer,同前bytesRemaining;
ULONG nMapRegistersAllocated; // # map registers allocated for this transfer
PVOID vaddr; // virtual addr for this stage of transfer,同前transferVA;
PVOID regbase; // handle for base of mapping register set,同前mapRegisterBase;
ULONG intcsr; // accumulated interrupt flags
BOOLEAN mappedport; // true if we mapped port addr in StartDevice
DRIVER_STATE state; // current state of driver.来自《2000》
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
///////////////////////////////////////////////////////////////////////////////////////

二. DriverEntery的比较
《2000》:
//++
// Function: DriverEntry
//
// Description:
// Initializes the driver.
//
// Arguments:
// pDriverObject - Passed from I/O Manager
// pRegistryPath - UNICODE_STRING pointer to
// registry info (service key)
// for this driver
//本例子中没有对注册表进行操作,此pRegistryPath对应的是INF在注册表中设置的驱动注册目录
// Return value:
// NTSTATUS signaling success or failure
//--
extern "C" NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath ) {

ULONG ulDeviceNumber = 0;
NTSTATUS status = STATUS_SUCCESS;

// Announce other driver entry points
pDriverObject->DriverUnload = DriverUnload;

// Announce the PNP AddDevice entry point
pDriverObject->DriverExtension->AddDevice = AddDevice;

// Announce the PNP Major Function entry point
pDriverObject->MajorFunction[IRP_MJ_PNP] = DispPnp;

// This includes Dispatch routines for Create, Write & Read
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;
pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;
pDriverObject->DriverStartIo = StartIo;

// Notice that no device objects are created by DriverEntry.
// Instead, we await the PnP call to AddDevice

return status;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//《WDM》
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{ // DriverEntry
KdPrint((DRIVERNAME " - Entering DriverEntry: DriverObject %8.8lXn", DriverObject));

// Insist that OS support at least the WDM level of the DDK we use

if (!IoIsWdmVersionAvailable(1, 0))
{
KdPrint((DRIVERNAME " - Expected version of WDM (%d.%2.2d) not availablen", 1, 0));
return STATUS_UNSUCCESSFUL;
}

// See if we're running under Win98 or NT:

win98 = IsWin98();

#if DBG
if (win98)
KdPrint((DRIVERNAME " - Running under Windows 98n"));
else
KdPrint((DRIVERNAME " - Running under NTn"));
#endif

// Save the name of the service key

servkey.Buffer = (PWSTR) ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(WCHAR));
if (!servkey.Buffer)
{
KdPrint((DRIVERNAME " - Unable to allocate %d bytes for copy of service key namen", RegistryPath->Length + sizeof(WCHAR)));
return STATUS_INSUFFICIENT_RESOURCES;
}
servkey.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
RtlCopyUnicodeString(&servkey, RegistryPath);

// Initialize function pointers

DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = AddDevice;

DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCleanup;
DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;

return STATUS_SUCCESS;
} // DriverEntry


//比较这两个DriverEntry,基本是相同的。以下就以《2000》为蓝本来构建我的DriverEntery,因其简洁
extern "C" NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath ) {

ULONG ulDeviceNumber = 0;
NTSTATUS status = STATUS_SUCCESS;

// Announce other driver entry points
pDriverObject->DriverUnload = DriverUnload;

// Announce the PNP AddDevice entry point
pDriverObject->DriverExtension->AddDevice = AddDevice;

// Announce the PNP Major Function entry point
pDriverObject->MajorFunction[IRP_MJ_PNP] = DispPnp;

// This includes Dispatch routines for Create, Write & Read
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchReadWrite;
pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchReadWrite;
pDriverObject->DriverStartIo = StartIo;

// Notice that no device objects are created by DriverEntry.
// Instead, we await the PnP call to AddDevice

return status;
}

分享 分享到新浪Qing

0

阅读(310) 评论 (0) 收藏(0) 转载 打印举报 已投稿到: 排行榜 圈子 前一篇:多种开发工具开发的9054驱动源程序比较(上)转后一篇:多种开发工具开发的9054驱动源程序比较(下2)转