公司别人写的。
</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"