Windows NT 操作系统设置的进程模式会使运行在其中的应用程序访问I/O地址的指令引起保护性的失败。这使得应用程序需要附以一个设备驱动程序进行I/O操作。设备驱动程序运行在内核模式,这使得在这种状态的中运行的进程可以执行I/O操作。
---- Windows 95/98 是仅为 Intel 类型机器设计的,没有额外复杂的I/O需求,而Windows NT 被设计成可以在不同机器机构上进行移植。这使得Windows NT 的系统模式要求驱动程序的编写者要考虑一台机器可能有多种类型的总线,这可能需要在总线之间传递地址。这种模式还要区别I/O空间和内存空间。在多总线的机器中每一总线可以既支持内存又支持I/O循环。
---- 根据定义,I/O寄存器或者端口访问是通过I/O循环实现的。然而,在一些系统中外部总线的I/O空间可以被映像到进程内存空间。硬件抽象层(Hardware Abstract Layer)决定这些。要访问I/O寄存器,驱动程序编写者必须知道寄存器在那一总线,它的I/O空间地址在那条总线。一条总线是由其接口类行 (如 ISA 、PCI 等)和编号(从零开始)决定的。
---- 下面是一个假象设备访问I/O的例子,接口类型:ISA 编号 0 地址 0xE700。设备描述如下: Offset Size Usage 0 1 Command register 1 1 Status register 2 2 Word data register 4 4 Dword data register
---- 用开发NT 设备驱动程序的工具包DriverDorks 可以用以下 步骤访问设备:
---- 建立一个KIoRange的对象映像设备寄存器。
KIoRange DeviceIos; Status = DevceIos.Initialize(
Isa, // 总线类型
0, // 总线号
0xE700, // 总线地址
8, // 设备数
TRUE // 映像到系统空间(假如端口是内存映像的)
);
if(NT_SUCCESS(status)) //建立成功
---- 可以用KIoRange 的成员函数访问寄存器:
//寄存器偏移量
#define COMMAND 0
#define STATUS 1
#define WDATA 2
#define DDATA 3
//读状态寄存器
UCHAR DeviceStatus = DeviceIos.inb(STATUS);
//写命令寄存器
DeviceIos.outb(COMMAND,CMD_RESET);
//写20个字到端口
DeviceIos.outw(WDATA,buffer,20);
---- 另外也可以建立KIoRegister 的对象来访问设备:
KIoRegister CommandReg = DeviceIos[COMMAND];
KIoRegister StatusReg = DeviceIos[STATUS];
CommandRge=(UCHAR)RESET; //写 RESET命令
UCHAR status=StatusReg; //读状态寄存器
假如在同一函数中频繁访问寄存器用KioRegiser 比用KIoRange 的成员函数的性能好一些。无论如何,数据类型必须正确(UCHAR,USHORT,ULONG),这些决定了到总线上数据的实际大小.