微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 模拟电路设计 > PCI设备WINDOWS驱动程序的开发

PCI设备WINDOWS驱动程序的开发

时间:04-18 来源:互联网 点击:

设备识别号 供应商识别号
状态寄存器 命令寄存器
分类代码 修改版本
自测试 头标类型 延时计数 Cache
基址寄存器
保留
保留
扩展ROM基址寄存器
保留
保留
Max-Lat Min-Gnt中断引脚 中断干线

图1 配置空间头标区

2、设备初始化
PCI设备驱动程序要完成识别PCI器件、分配PCI硬件资源、响应PCI器件中断等功能,这就需要访问PCI配置空间来获得必需的参数。实现在Windows9x操作系统下访问PCI配置空间可以利用PCI系 统BIOS功能调用,通过供应商识别号(VendorID)和设备识别号 (DeviceID)直接访问设备,也可以利用配置管理器(Configuration Manager)封装的功能函数,根据供应商识别号(VendorID)和设备识别号 (DeviceID)搜索设备结点树,查询PCI设备。由于编写PCI系统BIOS功能调用程序更为简捷,所以本文采用这种方法。
PCI系统BIOS功能提供了BIOS的访问与控制的具体方法,所有软件(设备驱动程序、扩展ROM码)将通过标准中断号1AH调用BIOS功能访问特殊部件。在驱动程序中调用VtoolsD系统服务Exec_VxD_Int()来实现PCI系统BIOS的1AH中断。
首先,通过PCI设备的供应商识别号(VendorID)、 设备识别号 (DeviceID)和索引号(Index)查找特定设备所在的总线号(Bus Num)、设备号(Device NUM)、功能号(Function Num)和寄存器号(Register Num)。总线号是从0到255的数值,在一个系统中,可把多达256条的PCI总线用桥连接在一起。由于编号是从0开始的,所以当系统有N条总线时,总线号会达到N-1;设备号是在0到31之间分配的任意值,并不拘于从0开始按顺序分配;功能号分配从0到7的值。代码如下:

ALLREGS* pRegisters; // pRegisters是指向寄存器结构体的指针
pRegisters->REAX =0xb102; // 0xb102是功能号
pRegisters->RECX =0x1001; // 假设Device ID=0x1001
pRegisters->REDX=0x102b; // 假设Vendor ID=0x102b
Exec_VxD_Int(0x1a,pRegisters); // 调用1AH中断

返回值是pRegisters->REBX。BH寄存器是总线号,BL寄存器的高5位是设备号,低3位是功能号。
然后,向配置空间地址寄存器CF8h写入总线号、设备号、功能号、索引号, 从配置空间数据寄存器CFCh读出配置空间的内容。
配置空间地址寄存器(CF8h)格式如下:
Bit31 30-24 23-16 15-11 10-8 7-2 10
使能位 保 留 总线号 设备号 功能号 寄存器号 00

使能位为“1”表示允许访问

配置空间数据寄存器(CFCh)存放要读写的数据。
代码如下:

DWORD d=0;
d=pRegisters->REBX;
(d=8)|=0x80000000;
for (short i=0;i16;i++) // 读取64字节配置空间
{
_outpd(0xcf8,d+4*i); // 按DWORD类型一次读取四个字节
dprintf("%8x",_inpd(0xcfc)); // 打印输出
}

3、内存的读写
Winsows工作在32位保护模式下,保护模式与实模式的根本区别在于CPU寻址方式上的不同,这也是Windows驱动程序设计中需要着重解决的问题。Windows采用了分段、分页机制,这样使应用程序产生一种错觉,好象程序中可以使用非常大的物理存储空间。这样做最大的好处就是一个程序可以很容易地在物理内存容量不一样的、配置范围差别很大的计算机上运行,编程人员使用虚拟存储器可以写出比任何实际配置的物理存储器都大得多的程序。每个虚拟地址由16位的段选择字和32位段偏移量组成。通过分段机制,系统由虚拟地址产生线性地址。再通过分页机制,由线性地址产生物理地址(如图2)。线性地址被分割成页目录(Page Directory)、页表(Page Table)和页偏移(Offset)三个部分。当建立一个新的Win32进程时,操作系统会为它分配一块内存,并建立它自己的页目录、页表,页目录的地址也同时放入进程的现场信息中。当计算一个地址时,系统首先从CPU控制器CR3中读出页目录所在的地址,然后根据页目录得到页表所在的地址,再根据页表得到实际代码/数据页的页帧,最后再根据页偏移访问特定的单元。硬件设备读写的是物理内存,但应用程序读写的是虚拟地址,所以存在着将物理内存地址映射到用户程序线性地址的问题。

15 0 31 0 31 0 31 0


图2 虚拟地址转换为物理地址

从物理地址到线性地址的转换工作是由驱动程序来完成的。驱动程序的内存映射部分主要是调用VxD的系统服务MapPhysToLinear。在VtoolsD中这个函数的定义如下:

PVOID MapPhysToLineag(CONST VOID * PhysAddr,DWORD nBytes,DWORD Flags);

其中第一个参数PhysAddr就是要映射的内存的物理地址的起始位置,这个物理地址可以从PCI配置空间的基址寄存器中获得,nBytes是内存区域的长度,Flags必须设置为0。这个函数返回的就是这段物理地址映射的线性内存地址。如

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top