您的位置:首页 > 其它

IO_Card 驱动

2015-07-27 20:00 323 查看
公司别人写的。
</pre><pre name="code" class="cpp">/*
IO_Card 驱动
1、系统找到DriverEntry()函数,初始化驱动程序。
2、系统调用AddDevice例程添加设备对象。
3、FDO收到IRP_MN_START_DEVICE IRP,将其设置完成例程(实际设置在下个IO堆栈)后传递给PDO。接着FDO等待同步。(实际上PDO完成资源分配)
4、当PDO完成IRP_MN_START_DEVICE IRP,设备堆栈回滚时。执行完成例程,并将IRP再次交给FDO。
5、FDO根据IRP提供的IO堆栈得到设备资源,并完成例程。
6、等待各种IRP和中断
6.1、中断(主要用于操作)
6.2、PNP IRP(主要用于配置)
6.3、普通IRP(主要用于操作)
7、当驱动处理完IRP_MN_REMOVE_DEVICE例程后,系统调用HelloWDMUnload例程完成后续工作。
*/

#include <initguid.h>
#include "Guid.h"
#include "IO_Card.h"
#include "Ioctls.h"

#pragma INITCODE
// INIT指明该函数只用于初始化,用完后就释放。(节约内存)
// 代码放在代码段,数据放在数据段。
extern "C" NTSTATUS DriverEntry(
// IN、OUT和INOUT是空宏定义,主要起注释作用。
IN PDRIVER_OBJECT pDriverObject, // I/O管理器传递过来的驱动对象。
IN PUNICODE_STRING pRegistryPath // 驱动对象注册表路径。
)
// extern "C"用于在CPP模式下引用C代码,保证符号链接的正确性。
{
KdPrint(("Enter DriverEntry\n")); // 调试信息打印函数,它只在check版本中生效。

pDriverObject->DriverExtension->AddDevice = IO_CardAddDevice; // 设置添加设备回调函数。
pDriverObject->MajorFunction[IRP_MJ_PNP] = IO_CardPnp; // 设置PNP IRP处理回调函数。
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl; // 设置IO操作回调函数。
pDriverObject->MajorFunction[IRP_MJ_CREATE] = IO_CardDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = IO_CardDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_READ] = IO_CardDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = IO_CardDispatchRoutine; // 设置缺省IRP处理回调函数。
pDriverObject->DriverUnload = IO_CardUnload; // 设置删除设备回调函数(实际上在PNP IRP中就被处理了)。

KdPrint(("Leave DriverEntry\n")); // 调试信息打印函数,它只在check版本中生效。
return STATUS_SUCCESS;
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS IO_CardAddDevice(
// IN、OUT和INOUT是空宏定义,主要起注释作用。
IN PDRIVER_OBJECT DriverObject, // I/O管理器传递过来的驱动对象。
IN PDEVICE_OBJECT PhysicalDeviceObject // 从I/O管理器传递过来的物理设备对象。
)
{
PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
KdPrint(("Enter IO_CardAddDevice\n")); // 调试信息打印函数,它只在check版本中生效。

NTSTATUS status;
PDEVICE_OBJECT fdo;

// 创建设备驱动。
status = IoCreateDevice(DriverObject,sizeof(DEVICE_EXTENSION),NULL,FILE_DEVICE_UNKNOWN,0,FALSE,&fdo);
// 是否创建成功。
if( !NT_SUCCESS(status))
return status;

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; // 获取设备扩展对象的指针。
pdx->fdo = fdo; // 当前设备。
pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); // 附着FDO到PDO上,并且把返回的PDO记录在FDO的扩展对象中。

// 创建设备接口。(不能指定设备名)
status = IoRegisterDeviceInterface(PhysicalDeviceObject, &IO_CARD_DEVICE, NULL, &pdx->interfaceName);
if( !NT_SUCCESS(status))
{
IoDeleteDevice(fdo); // 失败则删除FDO。
return status;
}
IoSetDeviceInterfaceState(&pdx->interfaceName, TRUE); // 使设备名有效。
if( !NT_SUCCESS(status))
{
if( !NT_SUCCESS(status))
{
return status;
}
}
KdPrint(("%wZ\n",&pdx->interfaceName)); // 调试信息打印函数,它只在check版本中生效。

// 设置标志位。
fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
fdo->Flags &= ~DO_DEVICE_INITIALIZING;

KdPrint(("Leave IO_CardAddDevice\n")); // 调试信息打印函数,它只在check版本中生效。
return STATUS_SUCCESS;
}

// 中断响应例程。
BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pdx)
{

// 关中断。
UCHAR HSR  = READ_PORT_UCHAR(pdx->portbase);
HSR = HSR | 0x04;
WRITE_PORT_UCHAR(pdx->portbase,HSR);
KdPrint(("==============interrupt!!!\n"));

// 恢复中断信号电平。
WRITE_REGISTER_UCHAR((PUCHAR)pdx->MemBar0+0x400000,0x10);
IoRequestDpc(pdx->fdo, NULL, pdx); // 中断处理标志,DPC处理事件。

return TRUE;
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS InitMyPCI(IN PDEVICE_EXTENSION pdx,IN PCM_PARTIAL_RESOURCE_LIST list) // 主要用于将系统分配的资源初始化。
{
PHYSICAL_ADDRESS portbase; // 端口物理地址。
BOOLEAN gotport = FALSE;

ULONG vector; // 中断向量。
KIRQL irql; // 中断请求级。
KINTERRUPT_MODE mode; // 中断模式。
KAFFINITY affinity; // CPU的亲缘关系。
BOOLEAN irqshare; // 是否共享中断。
BOOLEAN gotinterrupt = FALSE;

ULONG nres = list->Count; // 资源总数。
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &list->PartialDescriptors[0];

// 每次循环获取一种资源。
for (ULONG i = 0; i < nres; ++i, ++resource)
{
// 判断是何种资源。
switch(resource->Type)
{
// I/O端口资源。
case CmResourceTypePort:
// I/O端口地址。
portbase = resource->u.Port.Start;
// I/O端口地址长度。
pdx->nports = resource->u.Port.Length;
// 是否需要地址映射。
pdx->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0;
// 表示已经得到I/O端口资源。
gotport = TRUE;
break;
// 物理内存资源。
case CmResourceTypeMemory:
pdx->MemBar0 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start,resource->u.Memory.Length,MmNonCached);
pdx->nMem0 = resource->u.Memory.Length;
break;
// 中断资源。
case CmResourceTypeInterrupt:
// 获得中断请求级。
irql = (KIRQL) resource->u.Interrupt.Level;
// 获得中断向量。
vector = resource->u.Interrupt.Vector;
// 获取CPU亲缘关系。
affinity = resource->u.Interrupt.Affinity;
// 获得中断模式。
mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
// 判断是否需要共享中断。
irqshare = resource->ShareDisposition == CmResourceShareShared;
// 表示已经得到中断。
gotinterrupt = TRUE;
break;
default:
KdPrint(("Unexpected I/O resource type %d\n", resource->Type));
break;
}
}
if (!(TRUE&& gotport&& gotinterrupt))
{
KdPrint((" Didn't get expected I/O resources\n"));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
// 判断是够需要I/O端口映射。(为了操作方便,把IO空间映射到MEM空间)
if (pdx->mappedport)
{
// 获得I/O端口地址。
pdx->portbase = (PUCHAR) MmMapIoSpace(portbase, pdx->nports, MmNonCached);
if (!pdx->mappedport)
{
KdPrint(("Unable to map port range %I64X, length %X\n", portbase, pdx->nports));
return STATUS_INSUFFICIENT_RESOURCES;
}
}
else
// 获得I/O端口地址。
pdx->portbase = (PUCHAR) portbase.QuadPart;

// 链接中断。(中断对象与中断响应例程链接)
NTSTATUS status = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE)OnInterrupt, (PVOID)pdx, NULL, vector, irql, irql, LevelSensitive, TRUE, affinity, FALSE);
if (!NT_SUCCESS(status))
{
KdPrint(("IoConnectInterrupt failed - %X\n", status));

if (pdx->portbase && pdx->mappedport)
MmUnmapIoSpace(pdx->portbase, pdx->nports);
pdx->portbase = NULL;

return status;
}

return STATUS_SUCCESS;
}

#pragma LOCKEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS OnRequestComplete(PDEVICE_OBJECT junk, PIRP Irp, PKEVENT pev)
{
KeSetEvent(pev, 0, FALSE); // 把IRP事件设置为完成。

return STATUS_MORE_PROCESSING_REQUIRED; // 再次完成IRP事件 。
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
// 上层设备的完成例程设置在下层设备IO堆栈。
NTSTATUS ForwardAndWait(PDEVICE_EXTENSION pdx, PIRP Irp)
{
PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。

KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE); // 初始化事件,用于同步IPR。

IoCopyCurrentIrpStackLocationToNext(Irp); // 本层对IRP有所处理,故需将本层堆栈拷贝到下一层堆栈。(使下层设备处理环境一样)
// 设置完成例程。
IoSetCompletionRoutine(Irp,(PIO_COMPLETION_ROUTINE) OnRequestComplete,(PVOID) &event, TRUE, TRUE, TRUE);
//调用底层驱动,即PDO。
IoCallDriver(pdx->NextStackDevice, Irp);
//等待PDO完成。
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);

return Irp->IoStatus.Status;
}

#pragma PAGEDCODE
NTSTATUS HandleStartDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
{
PAGED_CODE();
KdPrint(("Enter HandleStartDevice\n"));

// 转发IRP并等待(利用事件同步)返回,IRP_MN_START_DEVICE必须由PDO处理。
NTSTATUS status = ForwardAndWait(pdx,Irp);
if (!NT_SUCCESS(status))
{
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

return status;
}

// 得到当前堆栈。
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

// 从当前堆栈得到翻译信息。
PCM_PARTIAL_RESOURCE_LIST translated;
if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
translated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
else
translated = NULL;

KdPrint(("Init the PCI card!\n"));
InitMyPCI(pdx,translated); // 获取设备资源。

// 完成IRP。
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

KdPrint(("Leave HandleStartDevice\n"));
return status;
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS DefaultPnpHandler(
PDEVICE_EXTENSION pdx, // 扩展对象。
PIRP Irp // IRP包对象。
)
{
PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
KdPrint(("Enter DefaultPnpHandler\n")); // 调试信息打印函数,它只在check版本中生效。

IoSkipCurrentIrpStackLocation(Irp); // 使IRP的IO堆栈指针后退一格,因为FDO没有对IRP处理,故不需要对其记录,将此堆栈留给PDO使用。(节约内存)

KdPrint(("Leave DefaultPnpHandler\n")); // 调试信息打印函数,它只在check版本中生效。
return IoCallDriver(pdx->NextStackDevice, Irp); // 调用下层驱动。
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS HandleRemoveDevice(
PDEVICE_EXTENSION pdx, // 扩展对象。
PIRP Irp // IRP包对象。
)
{
PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
KdPrint(("Enter HandleRemoveDevice\n")); // 调试信息打印函数,它只在check版本中生效。

Irp->IoStatus.Status = STATUS_SUCCESS; // 本层IRP包处理完毕,设置标志。
NTSTATUS status = DefaultPnpHandler(pdx, Irp); // 将修改后的IRP包传递给下层驱动。

IoSetDeviceInterfaceState(&pdx->interfaceName, FALSE); // 使设备名失效。
RtlFreeUnicodeString(&pdx->interfaceName); // 释放UnicodeString。
// 调用IoDetachDevice()把fdo从设备栈中脱开。
if (pdx->NextStackDevice)
IoDetachDevice(pdx->NextStackDevice);
IoDeleteDevice(pdx->fdo); // 删除FDO。
IoDisconnectInterrupt(pdx->InterruptObject); // 删除中断。

KdPrint(("Leave HandleRemoveDevice\n")); // 调试信息打印函数,它只在check版本中生效。
return status;
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS IO_CardPnp(
IN PDEVICE_OBJECT fdo, // 本层FDO设备对象。
IN PIRP Irp // 传进来的IRP对象。
)
{
PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
KdPrint(("Enter IO_CardPnp\n")); // 调试信息打印函数,它只在check版本中生效。

NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; // 获取设备扩展对象的指针。
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); // 获取驱动IO堆栈指针。
static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp) = // 声明函数指针数组。
{
HandleStartDevice,		// IRP_MN_START_DEVICE
DefaultPnpHandler,		// IRP_MN_QUERY_REMOVE_DEVICE
HandleRemoveDevice,		// IRP_MN_REMOVE_DEVICE
DefaultPnpHandler,		// IRP_MN_CANCEL_REMOVE_DEVICE
DefaultPnpHandler,		// IRP_MN_STOP_DEVICE
DefaultPnpHandler,		// IRP_MN_QUERY_STOP_DEVICE
DefaultPnpHandler,		// IRP_MN_CANCEL_STOP_DEVICE
DefaultPnpHandler,		// IRP_MN_QUERY_DEVICE_RELATIONS
DefaultPnpHandler,		// IRP_MN_QUERY_INTERFACE
DefaultPnpHandler,		// IRP_MN_QUERY_CAPABILITIES
DefaultPnpHandler,		// IRP_MN_QUERY_RESOURCES
DefaultPnpHandler,		// IRP_MN_QUERY_RESOURCE_REQUIREMENTS
DefaultPnpHandler,		// IRP_MN_QUERY_DEVICE_TEXT
DefaultPnpHandler,		// IRP_MN_FILTER_RESOURCE_REQUIREMENTS
DefaultPnpHandler,		//
DefaultPnpHandler,		// IRP_MN_READ_CONFIG
DefaultPnpHandler,		// IRP_MN_WRITE_CONFIG
DefaultPnpHandler,		// IRP_MN_EJECT
DefaultPnpHandler,		// IRP_MN_SET_LOCK
DefaultPnpHandler,		// IRP_MN_QUERY_ID
DefaultPnpHandler,		// IRP_MN_QUERY_PNP_DEVICE_STATE
DefaultPnpHandler,		// IRP_MN_QUERY_BUS_INFORMATION
DefaultPnpHandler,		// IRP_MN_DEVICE_USAGE_NOTIFICATION
DefaultPnpHandler,		// IRP_MN_SURPRISE_REMOVAL
};

ULONG fcn = stack->MinorFunction; // 获取IRP的子类型。
if(fcn >= arraysize(fcntab)) // 未知的子类型。
{
status = DefaultPnpHandler(pdx, Irp); // 进行默认操作。

return status;
}

#if DBG // 仅用于调试。
static char* fcnname[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
};

KdPrint(("PNP Request (%s)\n", fcnname[fcn]));
#endif

status = (*fcntab[fcn])(pdx, Irp); // 响应IRP请求。

KdPrint(("Leave IO_CardPnp\n"));
return status;
}

#pragma PAGEDCODE
// IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
// 代码放在代码段,数据放在数据段。
NTSTATUS IO_CardDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
PAGED_CODE();
KdPrint(("Enter IO_CardDispatchRoutine\n"));

Irp->IoStatus.Status = STATUS_SUCCESS; // 设置IRP对象状态。
Irp->IoStatus.Information = 0; // 设置实际传递比特数 。
IoCompleteRequest( Irp, IO_NO_INCREMENT ); // 完成请求。

KdPrint(("Leave IO_CardDispatchRoutine\n"));
return STATUS_SUCCESS;
}

// 完成IRP例程。
NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG_PTR info)
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

return status;
}

// IO处理例程。
// 每个IRP创建时,随之生成一个IO堆栈,IO堆栈与设备堆栈对应。
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp)
{
PAGED_CODE();
NTSTATUS status;

ULONG info = 0;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; // 获取设备扩展对象。
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); // 获取设备IO堆栈。
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; // 获取需要输入字符长度。
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; // 获取需要输出字符长度。
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; // 获取操作码。

// 判断使用何种操作。
switch(code)
{
case IOCTL_READ_BASE_BAR0:
{
ULONG offset = *(ULONG*)(Irp->AssociatedIrp.SystemBuffer);
PUCHAR buff = (PUCHAR)ExAllocatePool(NonPagedPool,cbout);
READ_REGISTER_BUFFER_UCHAR((PUCHAR)pdx->MemBar0+offset,buff,cbout);
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, buff, cbout);
ExFreePool(buff);
info = cbout;
break;
}
case IOCTL_WRITE_BASE_BAR0:
{
int* tempPointer = (int*)Irp->AssociatedIrp.SystemBuffer;
ULONG offset = *(ULONG*)(tempPointer);
tempPointer++;
PUCHAR buff = *(PUCHAR*)(tempPointer);
tempPointer++;
ULONG nInputNumber = *(ULONG*)(tempPointer);
WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)pdx->MemBar0+offset,buff,nInputNumber);
break;
}
case IOCTL_ENABLE_INT:
{
UCHAR HSR = READ_PORT_UCHAR(pdx->portbase);
HSR = HSR & 0xFB;
WRITE_PORT_UCHAR(pdx->portbase,HSR);
break;
}
case IOCTL_DISABLE_INT:
{
UCHAR HSR  = READ_PORT_UCHAR(pdx->portbase);
HSR = HSR | 0x04;
WRITE_PORT_UCHAR(pdx->portbase,HSR);
break;
}
default:
{
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}

return CompleteRequest(Irp, status, info); // 调用完成IRP例程。
}

#pragma PAGEDCODE
// 实际卸载处理在PNP IRP中完成
void IO_CardUnload(IN PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
KdPrint(("Enter IO_CardUnload\n"));
KdPrint(("Leave IO_CardUnload\n"));
}
</pre><pre name="code" class="cpp">
</pre><pre name="code" class="cpp">
</pre><pre name="code" class="cpp">
</pre><pre name="code" class="cpp">
</pre><pre name="code" class="cpp"><pre name="code" class="cpp">/************************************************************************
* 文件名称:IO_Card.h
* 作    者:丁观亮
* 完成日期:2014-1-23
*************************************************************************/

#ifdef __cplusplus
extern "C"
{
#endif

#include <wdm.h>

#ifdef __cplusplus
}
#endif

#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")

#define arraysize(p) (sizeof(p)/sizeof((p)[0])) // 数组大小计算宏

// 扩展结构体,用来存储本层设备需要的信息
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT fdo; // 上层设备
PDEVICE_OBJECT NextStackDevice; // 下层设备
UNICODE_STRING interfaceName; // 设备名(符号链接)

PKINTERRUPT InterruptObject; // 中断对象名
PUCHAR portbase; // IO端口地址
ULONG nports; // IO端口地址的数量
PVOID MemBar0; // 内存基地址0
ULONG nMem0; // 基地址BAR0占用字节数
BOOLEAN mappedport; // 如果为真需要做IO端口映射
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

// 函数声明,在此声明可被外部引用
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath);
NTSTATUS IO_CardAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject);
NTSTATUS IO_CardPnp(IN PDEVICE_OBJECT fdo,IN PIRP Irp);
NTSTATUS IO_CardDispatchRoutine(IN PDEVICE_OBJECT fdo,IN PIRP Irp);
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp);
void IO_CardUnload(IN PDRIVER_OBJECT DriverObject);
Ioctls.h
#ifndef IOCTLS_H
#define IOCTLS_H

#ifndef CTL_CODE
#pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")
#endif

// 读取BAR0基地址
#define IOCTL_READ_BASE_BAR0 CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x800, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)

// 读取BAR0基地址
#define IOCTL_WRITE_BASE_BAR0 CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x801, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)

// 开中断
#define IOCTL_ENABLE_INT CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x802, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)

// 关中断
#define IOCTL_DISABLE_INT CTL_CODE( \
FILE_DEVICE_UNKNOWN, \
0x803, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)

#endif
Guid.h
// 定义设备的全局标识符(可用算法随机生成)
DEFINE_GUID(IO_CARD_DEVICE, 0xe57c50f, 0xccc, 0x4ad2, 0xa8, 0x95, 0x93, 0xc5, 0xed, 0x11, 0x98, 0x60);
<span style="font-family:Microsoft YaHei;font-size:24px;"><strong>IO_Card.inf</strong></span>
<span style="font-family:Microsoft YaHei;font-size:24px;"><strong></strong></span>
<span style="font-family:Microsoft YaHei;font-size:24px;"><strong></strong></span><pre name="code" class="cpp">;-------------------------------------------------------------------------------------------;版本节,INF文件的开始。[Version];inf文件实用的系统,指明驱动程序的签名,其取值为:$Windows NT$、$Windows 95$、$Chicago$。Signature="$CHICAGO$";inf文件的提供商。Provider=CPC_TECH;指明驱动程序的版本信息,其格式为:mm/dd/yyyy,x.y.v.z。DriverVer=23/1/2014,1.0.0.1;指明驱动程序所属的类别。Class=CPC_TECH_DEV;指明设备类的GUID,其格式为:{nnnnnnnn-nnnn-nnnn-nnnnnnnnnnnn}。ClassGUID={EF2962F0-0D55-4bff-B8AA-2221EE8A79B0};指明数字签名文件的文件名,其扩展名为.cat。;CatalogFile=;仅由操作系统内部提供的INF文件使用。;LayoutFile=;-------------------------------------------------------------------------------------------;指明设备驱动程序所在的磁盘或CD-ROM。[SourceDisksNames];格式为diskid=disk-description,tagfile,unused,path。;disked:指出磁盘驱动器的编号;disk-description:表示磁盘的描述信息,他通常为一个字符串。;tagfile:指出磁盘标签文件的文件名。;unused:为保留字段。;path:指出驱动程序所在的路径。1 = "IO_Card",Disk1,,;指明设备驱动程序的文件名。[SourceDisksFiles];格式为filename=diskid,subdir,size。;filename:指出驱动程序的文件名。;diskid:指出磁盘驱动器的编号。;subdir:指出该文件在磁盘上的路径。;size:指出该文件未经压缩时的大小,以字节为单位。IO_Card.sys = 1,,;目的路径[DestinationDirs];格式为File-list-section=dirid,subdir。;file-list-section:指出CopyFiles、DelFiles、RenFiles指令所引用的节。;dirid:指出目标目录值。;subdir:指出dirid目录下的子目录。YouMark_Files_Driver = 10,System32\Drivers;-------------------------------------------------------------------------------------------;安装NT类到注册表中[ClassInstall32]Addreg=Class_AddReg[Class_AddReg]HKR,,,,%DeviceClassName%HKR,,Icon,,"-5";-------------------------------------------------------------------------------------------;指明供应商及其对应Models接的名称。[Manufacturer];格式为%strkey%=models-section-name。;strkey:代表设备制造的名字,其字符串值在String节中定义。;models-section-name:指出Models节的名称。%MfgName%=Mfg0;指明Install/DDInstall节的名称、设备的硬件ID和兼容ID等信息,其节名称由Manufacturer节指定。[Mfg0];格式为device-description=install-section-name,hw-id,compatiable-id…;device-description:指出设备的表述信息,他可以是一个字符串,也可以是一个%strkey%。;install-section-name:指出Install/DDInstall节的名称。;hw-id:指出设备的硬件ID。;compatiable-id:指出设备的兼容ID。%DeviceDesc%=YouMark_DDI, PCI\VEN_10b5&DEV_9054;-------------------------------------------------------------------------------------------;指明需复制的文件、想注册表中添加的内容等信息,其节名称由Models节指定。[YouMark_DDI.NT];格式为CopyFiles=@filename|file-list-section;filename:指出目标文件名。;file-list-section:是其创建的文件列表节。CopyFiles=YouMark_Files_Driver;格式为AddReg=add-registry-section;add-registry-section:创建的添加注册表节。AddReg=YouMark_NT_AddReg;文件列表节。[YouMark_Files_Driver]IO_Card.sys;注册表节。[YouMark_NT_AddReg];格式为reg-root, [subkey], [value-entry-name], [flags], [value]。;reg-root:指出注册表树的根目录。;subkey:指出reg-root下的子目录。;value-entry-name:指出要增加的注册表值。;flags:指出其对注册表的一些处理方。;value:指出新增加注册表值的数据。HKLM, "System\CurrentControlSet\Services\IO_Card\Parameters",\"BreakOnEntry", 0x00010001, 0;用于控制设备驱动程序的安装过程。[YouMark_DDI.NT.Services];格式为AddService=ServiceName,[flags],service-install-section[,event-log-install-section[,[EventLogType][,EventName]]]…。;ServiceName:指出驱动程序的名字。;flags:指出一个或多个系统定义的标识。;service-install-section:是其创建的服务安装节。;event-log-install-section:是其创建的事件日志安装。;EventLogType:指出事件日志的类型。;EventName:指出事件日志的名字。Addservice = IO_Card, 0x00000002, YouMark_AddService;创建的服务安装节。[YouMark_AddService];服务显示名称要和设备名称相同。DisplayName = %SvcDesc%;指明驱动程序的类型。ServiceType = 1 ; SERVICE_KERNEL_DRIVER;指明驱动程序的启动类型。StartType = 3 ; SERVICE_DEMAND_START;指明驱动程序的差错控制级别。ErrorControl = 1 ; SERVICE_ERROR_NORMAL;指明驱动程序的路径。ServiceBinary = %10%\System32\Drivers\IO_Card.sys;-------------------------------------------------------------------------------------------;指明一些列字符串,当某些字符串频繁地出现在INF文件中,为简化输入,可以在该节中定义一个字符串变量,代表该字符串出现在INF文件中。[Strings]ProviderName="Ding Guanliang."MfgName="CPC_TECH"DeviceDesc="IO_Card"DeviceClassName="CPC_TECH_Device"SvcDesc="Ding Guanliang"

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: