为了调用操作系统上测量硬件驱动开发工具中的寄存器对象,必须要有一个操作系统的接口总线(iBus)。本文介绍了建立iBus的基本要素和注意事项。
什么是iBus?iBus是操作系统抽象层。它为MHDDK中的示例程序提供了PCI / PXI总线的简单接口。 它为寄存器I / O提供简单的功能,如果支持,它提供DMA缓冲区操作。
操作系统支持的用户定义的iBus功能在RLP示例中,几乎所有与系统相关的代码都在osiUserCode.cpp中。为了使iBus在目标操作系统上工作,即将iBus移植到新的操作系统,需要定义以下两个功能:
- 重新定义getsBoard(...)和releaseBoard(...)。
- 使用void * osSpecific指向需要在getsBoard(...)和releaseBoard(...)之间共享的任何操作系统特定数据。
iBus* acquireBoard(tChar* brdLocation);
此功能创建iBus并将所选PCI设备的基本地址范围(BARs)映射到内存中。 它可以通过在iBus中使用void * osSpecific来存储系统特定的数据, 例如操作系统特定的结构,指针或文件编号。 这是与releaseBoard(...)共享数据的便捷方式。
在大多数系统上,acquireBoard(...)的功能有:
- 创建一个新的iBus。
- 使用VXI格式的资源字符串“PXI :: :: INSTR”找到所选的PCI设备。
- 将PCI设备的物理内存BARs存储在新的iBus中。
- 将PCI设备的BARs映射到内存中。
- 将内存映射的BARs的地址存储在iBus中。
void releaseBoard(iBus* &bus);
此功能删除由acquireBoard(...)创建的iBus。
在大多数系统上,releaseBoard(...)的功能有:
- 取消映射PCI设备的BARs。
- 如有必要,请告诉操作系统程序已完成访问PCI设备。
- 删除iBus。
支持DMA的用户定义iBus功能为了使iBus在目标操作系统上支持DMA,需要定义以下两个功能:
tDMAMemory* iBus::allocDMA (u32 size);
该功能请求一块DMA存储器并将其映射到内存中。 通常情况下,tDMAMemory被划分为子类以存储系统特定的数据,以便可以与freeDMA(...)共享数据。
在大多数系统上,allocDMA(...)的功能有:
- 从内核分配内存。
- 映射内存。
- 创建,构造和返回一个tDMAMemory对象。
void iBus::freeDMA (tDMAMemory *mem);
此函数删除由allocDMA(...)创建的tDMAMemory对象。
在大多数系统上,freeDMA(...)的功能有:
- 取消映射DMA内存。
- 从内核释放内存。
预定义iBus功能这些功能在Chip Objects和RLP范例(osiBus.h和osiBus.cpp)中已运用。在iBus导入新的操作系统的过程中,它们已被定义,不需要修改。
u32 iBus::get(u32 attribute, u32 occurrence);
get(...)允许程序获取PCI设备的属性。 在RLP示例中,唯一需要的属性是BARs的物理地址,用于在某些设备上初始化MITE。
tAddressSpace iBus::createAddressSpace(tBusWindowType windowType);
createAddressSpace(...)返回一个可以读写PCI设备的地址空间。createAddressSpace(...)也可以返回由acquireBoard(...)初始化的任何BARs的地址空间。
void iBus::destroyAddressSpace(tAddressSpace &addressSpace);
destroyAddressSpace(...)释放由createAddressSpace(...)保留的系统资源(如果有)。
通过tAddressSpace访问寄存器使用tAddressSpace函数read8/16/32和write8/16/32来访问PCI寄存器。
write8( ), write16( ), write32( );
写8,16或32位数据。 这个函数是内联的,通常被编译成一个指针。
read8( ), read16( ), read32( );
读取8,16或32位数据。 这个函数是内联的,通常被编译成一个指针。
以下例子来自于RLP范例中的MITE初始化:
iBus* bus = NULL;
tAddressSpace miteSpace;
u32 physicalBar1 = 0;
u32 address = 0xC0;
u32 value = 0;
bus = acquireBoard("PXI::4::2::INSTR");
miteSpace = bus->createAddressSpace(kPCI_BAR0);
physicalBar1 = bus->get(kBusAddressPhysical, kPCI_BAR1);
value = (physicalBar1 & 0xFFFFFF00L) | 0x80;
miteSpace.write32(address, value);
bus->destroyAddressSpace(miteSpace);
releaseBoard(bus);
为什么要使用iBus
- iBus可以方便地移植到新的操作系统。 在iBus中有两个系统特定功能:portBoard(...)和releaseBoard(...)。 而对于支持DMA的系统,还需要分配allocDMA(...)和freeDMA(...)。
- iBus适用于Chip Objects,Chip Objects要求使用iBus进行操作。
- 在大多数编译器中,寄存器使用tAddressSpace和iBus来执行读写,这可以生成快速的执行代码。