IO_Card 驱动

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


 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值