今天移植以前用DriverWorks编写的一个驱动到x64平台上,编译时没有什么问题,但链接的时候发现无法找到KPciConfiguration::Enumerate,经过一段时间的探索,找到了一种临时解决方案。
由于KPciConfiguration的构造函数中也使用了这个函数,而且程序中大量使用了KPciConfiguration类,这意味着要大量修改代码,真是头痛
检查DriverWorks的源程序Kpcicfg.cpp后发现,在AMD64模式下,KPciConfiguration::Enumerate函数是不被编译的:
由于KPciConfiguration的构造函数中也使用了这个函数,而且程序中大量使用了KPciConfiguration类,这意味着要大量修改代码,真是头痛
检查DriverWorks的源程序Kpcicfg.cpp后发现,在AMD64模式下,KPciConfiguration::Enumerate函数是不被编译的:
#if ! _WDM_
#if !(defined(_IA64_) || defined(_AMD64_))
BOOLEAN KPciConfiguration::Enumerate(
KPciSlot& slot,
PUSHORT VendorId,
PUSHORT DeviceId)
{
ULONG status;
UCHAR headtype;
struct {
USHORT VendorID;
USHORT DeviceID;
} slotdata;
if ( (slot.Slot() != 0xffffffff) || (slot.Bus() != 0) )
{
// determine if the current slot is single function device
status = HalGetBusDataByOffset(
PCIConfiguration,
slot.Bus(),
slot.Slot(),
&headtype,
HeaderOffset(HeaderType),
1);
if ( (slot.Function() == 0) &&
(status != 0) &&
(status != 2) &&
((headtype & 0x80)==0) ) // bit 7 of header type is 1 for multi
{
slot.IncrementDevice();
}
else
{
slot.Increment();
}
}
else
{
slot.Increment();
}
while (TRUE)
{
status = HalGetBusData(PCIConfiguration, slot.Bus(), slot.Slot(), &slotdata, 4);
if (status == 0)
{
if ( slot.Bus() == 255 )
{
return FALSE;
}
else
{
slot.IncrementBus();
}
continue;
}
else if (status == 2)
{
slot.Increment();
continue;
}
else
{
*VendorId = slotdata.VendorID;
*DeviceId = slotdata.DeviceID;
return TRUE;
}
}
}
#endif
#if !(defined(_IA64_) || defined(_AMD64_))
BOOLEAN KPciConfiguration::Enumerate(
KPciSlot& slot,
PUSHORT VendorId,
PUSHORT DeviceId)
{
ULONG status;
UCHAR headtype;
struct {
USHORT VendorID;
USHORT DeviceID;
} slotdata;
if ( (slot.Slot() != 0xffffffff) || (slot.Bus() != 0) )
{
// determine if the current slot is single function device
status = HalGetBusDataByOffset(
PCIConfiguration,
slot.Bus(),
slot.Slot(),
&headtype,
HeaderOffset(HeaderType),
1);
if ( (slot.Function() == 0) &&
(status != 0) &&
(status != 2) &&
((headtype & 0x80)==0) ) // bit 7 of header type is 1 for multi
{
slot.IncrementDevice();
}
else
{
slot.Increment();
}
}
else
{
slot.Increment();
}
while (TRUE)
{
status = HalGetBusData(PCIConfiguration, slot.Bus(), slot.Slot(), &slotdata, 4);
if (status == 0)
{
if ( slot.Bus() == 255 )
{
return FALSE;
}
else
{
slot.IncrementBus();
}
continue;
}
else if (status == 2)
{
slot.Increment();
continue;
}
else
{
*VendorId = slotdata.VendorID;
*DeviceId = slotdata.DeviceID;
return TRUE;
}
}
}
#endif
如果去掉#if语句强行编译,发现原来是因为HalGetBusData函数不被x64支持,所以不能编译成功。在MSDN的文档中的确提到这个函数是过时的,建议使用即插即用 (PnP) 管理器的 IRP_MN_START_DEVICE 请求来获取这些资源,在中文知识库中还可以找到一个例子:http://support.microsoft.com/?scid=kb;zh-cn;253232。在网上还找到另一个英文的例子http://www.hollistech.com/Resources/Misc%20articles/getbusdata.doc。
不过要全部改写代码,担心时间不够,所以想到另外一个临时解决方案,在x64下HalGetBusDataByOffset仍然是支持的,所以利用HalGetBusDataByOffset代替HalGetBusData,暂时修改函数如下:
#if ! _WDM_
//#if !(defined(_IA64_) || defined(_AMD64_))
BOOLEAN KPciConfiguration::Enumerate(
KPciSlot& slot,
PUSHORT VendorId,
PUSHORT DeviceId)
{
ULONG status;
UCHAR headtype;
struct {
USHORT VendorID;
USHORT DeviceID;
} slotdata;
if ( (slot.Slot() != 0xffffffff) || (slot.Bus() != 0) )
{
// determine if the current slot is single function device
status = HalGetBusDataByOffset(
PCIConfiguration,
slot.Bus(),
slot.Slot(),
&headtype,
HeaderOffset(HeaderType),
1);
if ( (slot.Function() == 0) &&
(status != 0) &&
(status != 2) &&
((headtype & 0x80)==0) ) // bit 7 of header type is 1 for multi
{
slot.IncrementDevice();
}
else
{
slot.Increment();
}
}
else
{
slot.Increment();
}
while (TRUE)
{
// status = HalGetBusData(PCIConfiguration, slot.Bus(), slot.Slot(), &slotdata, 4);
status = HalGetBusDataByOffset(PCIConfiguration, slot.Bus(), slot.Slot(), &slotdata, 0, 4);
if (status == 0)
{
if ( slot.Bus() == 255 )
{
return FALSE;
}
else
{
slot.IncrementBus();
}
continue;
}
else if (status == 2)
{
slot.Increment();
continue;
}
else
{
*VendorId = slotdata.VendorID;
*DeviceId = slotdata.DeviceID;
return TRUE;
}
}
}
//#endif
//#if !(defined(_IA64_) || defined(_AMD64_))
BOOLEAN KPciConfiguration::Enumerate(
KPciSlot& slot,
PUSHORT VendorId,
PUSHORT DeviceId)
{
ULONG status;
UCHAR headtype;
struct {
USHORT VendorID;
USHORT DeviceID;
} slotdata;
if ( (slot.Slot() != 0xffffffff) || (slot.Bus() != 0) )
{
// determine if the current slot is single function device
status = HalGetBusDataByOffset(
PCIConfiguration,
slot.Bus(),
slot.Slot(),
&headtype,
HeaderOffset(HeaderType),
1);
if ( (slot.Function() == 0) &&
(status != 0) &&
(status != 2) &&
((headtype & 0x80)==0) ) // bit 7 of header type is 1 for multi
{
slot.IncrementDevice();
}
else
{
slot.Increment();
}
}
else
{
slot.Increment();
}
while (TRUE)
{
// status = HalGetBusData(PCIConfiguration, slot.Bus(), slot.Slot(), &slotdata, 4);
status = HalGetBusDataByOffset(PCIConfiguration, slot.Bus(), slot.Slot(), &slotdata, 0, 4);
if (status == 0)
{
if ( slot.Bus() == 255 )
{
return FALSE;
}
else
{
slot.IncrementBus();
}
continue;
}
else if (status == 2)
{
slot.Increment();
continue;
}
else
{
*VendorId = slotdata.VendorID;
*DeviceId = slotdata.DeviceID;
return TRUE;
}
}
}
//#endif
目前从测试的结果来看,这样做是可以运行的。但是HalGetBusDataByOffset也是过时的、不推荐使用的函数,将来有时间还是按照微软的建议将程序彻底改写。