公司别人写的。
</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
// 定义设备的全局标识符(可用算法随机生成)
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"