摘要:本文主要针对已经研制好的ISA设备通过加上一个简单的PCI接口芯片便能正常工作在PCI模式下,实现由ISA扩展板到PCI扩展板的转换。这时我们必须重新编写设备的驱动程序才能使设备在Windows/Nt操作系统下正常工作。这里主要给出Windows下的解决方案和程序实例。
关键词:ISA设备驱动程序 PCI设备驱动程序 IRQ PCI配置空间
随着计算机和通信技术的高速发展,ISA总线在速度、功能上已经成为系统的瓶颈,而功能更强大的PCI总线成为首选。这时对现有的ISA设备稍加设计就可在PCI总线下工作就显得非常总要,但我们必须重新编写设备的驱动程序才能使设备在Windows/Nt操作系统下正常工作。
开发的驱动程序是Win32 Drivers Mode(WDM)类型,使用的开发工具是微软提供的Device Driver Kit(DDK)和Vc++6.0,在进行驱动程序的调试时使用Numega公司的SoftIce产品。
1 .ISA设备与PCI设备的Windows驱动程序的比较
(1).ISA设备与PCI设备驱动程序获得硬件资源途径不同
一个ISA设备驱动程序的资源是固定不变的,它是通过.inf文件的[logconfig]节来配置的。如下面的例子:
[Xxx.LogConfig]
IOConfig=220-22f
IRQConfig=6
.inf中此节说明此硬件资源的I/O地址范围是220H到22FH,IRQ为6。
一个PCI设备驱动程序的资源是操作系统自动分配的,它是通过设备ID号和厂商ID号获得设备的物理位置:总线号、器件号和功能号,并利用它们寻址PCI配置空间,接着从配置空间获得硬件资源。其中包括:中断号、端口地址等。
(2).ISA设备与PCI设备驱动程序对中断处理不同
一个ISA设备驱动程序的中断模式可以是LevelSensitive也可以是Latched,而且中断向量是否与其它设备共享都可以。
但是一个PCI设备驱动程序的中断模式必须是LevelSensitive,而且中断向量必须是共享的。
(3).ISA设备与PCI设备驱动程序安装时需要编写的.inf文件不同
对于ISA设备,在安装时.inf文件必须有[logconfig]节,而对于PCI设备,在安装时.inf文件必须有[Manufacturer]节,来指明设备ID号和厂商ID号,以便使硬件获取系统资源。如:
[Manufacturer]
%PLX% = PLX.Mfg
[PLX.Mfg]
"PCI 9052RDK-860 Board" =DDInstall_9052,PCIVEN_10b5&DEV_9050
其设备ID号为9050H,厂商ID号为10B5H。
2 驱动程序的实现
通过上面的比较,我们知道只要对原有的ISA设备的驱动程序的获取资源部分作一定的改变,并在安装时对inf文件进行必要的修改就可以完成PCI模式的驱动程序。
以下示例仅供参考。
NTSTATUS StartDevice(PDEVICE_OBJECT fdo,
PCM_PARTIAL_RESOURCE_LIST ResourceListRaw,
PCM_PARTIAL_RESOURCE_LIST ResourceListTranslated)
{
U32 i;
NTSTATUS status;
KIRQL irql; // interrupt level
KINTERRUPT_MODE mode; // interrupt mode
KAFFINITY affinity; // processor affinity for interrupt
PDEVICE_EXTENSION dx=(PDEVICE_EXTENSION)fdo->DeviceExtension;
PCI_COMMON_CONFIG pciRegs;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceRaw;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceTranslated;
ResourceRaw = ResourceListRaw->PartialDescriptors;
ResourceTranslated = ResourceListTranslated->PartialDescriptors;
// Read PCI Config Register
PciConfigRegisterBufferRead(
fdo,
&pciRegs,
0,
sizeof(pciRegs)
);
for (i = 0; i < ResourceListTranslated->Count;++i,++ResourceTranslated++ResourceRaw)
{
switch (ResourceTranslated->Type)
{
case CmResourceTypePort:
dx->PortStartAddress = ResourceTranslated->u.Port.Start;
dx->PortLength = ResourceTranslated->u.Port.Length;
dx->PortNeedsMapping = (ResourceTranslated->Flags&CM_RESOURCE_PORT_IO)==0;
break;
case CmResourceTypeInterrupt:
dx->InterruptIrql = (KIRQL)ResourceTranslated->u.Interrupt.Level;
dx->InterruptVector = ResourceTranslated->u.Interrupt.Vector; dx->
InterruptAffinity = ResourceTranslated->u.Interrupt.Affinity;
dx->InterruptMode = LevelSensitive;
dx->InterruptConnected = false;
break;
case CmResourceTypeNull:
case CmResourceTypeDma:
case CmResourceTypeDeviceSpecific:
case CmResourceTypeBusNumber:
// NonArbitrated & ConfigData are currently #defined as the same number
case CmResourceTypeConfigData:
case CmResourceTypeDevicePrivate:
case CmResourceTypePcCardConfig:
case CmResourceTypeMfCardConfig:
//加入自己的代码
break;
default:
break;
}
}
/* Device has been completely initialized and is ready to run. */
// Get the Vendor and Device ID
status = PciConfigRegisterBufferRead(
fdo,
&i,
0,
sizeof(U32)
);
if (!NT_SUCCESS(status))
{
dx->Device.VendorId = 0xFFFF;
dx->Device.DeviceId = 0xFFFF;
}
else
{
// Record the Vendor and Device ID */
dx->Device.VendorId = i & 0x0000FFFF;
dx->Device.DeviceId = i >> 16;
}
// Get the bus number and the slot number
status = GetBusSlotNumber(
dx->pPhysicalDeviceObject,
dx
);
if (!NT_SUCCESS(status))
{
return status;
}
return STATUS_SUCCESS;
}
共享中断向量只需将IoConnectInterrupt函数的第九个参数值置为TRUE就可以。
实践证明以上方法是可行的。