📄 pcicfg.c
字号:
}
}
}
PCIRsrc_DelList(BusHead);
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgAllocateMemSpace-(Bus %d)\r\n", Bus));
return TRUE;
}
//
// Find match for device in registry
//
static BOOL
PCICfgFindMatch(
PPCI_DEV_INFO pInfo
)
{
WCHAR SavePath[DEVKEY_LEN];
// Save off registry path
wcsncpy(SavePath, pInfo->RegPath, DEVKEY_LEN - 1);
SavePath[DEVKEY_LEN - 1] = L'\0'; // make sure longest string is terminated
// Fail if key name too long
if (wcslen(SavePath) + wcslen(L"\\") + wcslen(PCIBUS_INSTANCE_KEYNAME) >= DEVKEY_LEN) {
wcscpy(pInfo->RegPath, SavePath);
return FALSE;
}
// Check for exact match under Instance sub-key
wcscat(pInfo->RegPath, L"\\");
wcscat(pInfo->RegPath, PCIBUS_INSTANCE_KEYNAME);
if (RegMatch(pInfo) == PCIBUS_MATCH_ALL) {
// Exact instance match found
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PCICfgFindMatch: Matched device %d/%d/%d with registry key '%s'\r\n",
pInfo->Bus, pInfo->Device, pInfo->Function, pInfo->RegPath));
return TRUE;
}
// Fail if key name too long
if (wcslen(SavePath) + wcslen(L"\\") + wcslen(PCIBUS_TEMPLATE_KEYNAME) >= DEVKEY_LEN) {
wcscpy(pInfo->RegPath, SavePath);
return FALSE;
}
// No exact instance match found, check for match under Template key
wcscpy(pInfo->RegPath, SavePath);
wcscat(pInfo->RegPath, L"\\");
wcscat(pInfo->RegPath, PCIBUS_TEMPLATE_KEYNAME);
if (RegMatch(pInfo) != PCIBUS_MATCH_NONE) {
// Partial template match found
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PCICfgFindMatch: Matched device %d/%d/%d with registry key '%s'\r\n",
pInfo->Bus, pInfo->Device, pInfo->Function, pInfo->RegPath));
return TRUE;
}
// No match found
wcscpy(pInfo->RegPath, SavePath);
return FALSE;
}
//
// Request IRQ from OAL
//
static BOOL
RequestIrq(
PDEVICE_LOCATION pDevLoc,
PDWORD pIrq
)
{
return KernelIoControl(IOCTL_HAL_REQUEST_IRQ, pDevLoc, sizeof(*pDevLoc), pIrq, sizeof(*pIrq), NULL);
}
//
// Read Base Address Registers and size, populate Info struct with this information
//
static BOOL
PCIReadBARs(
PPCI_DEV_INFO pInfo
)
{
DWORD NumberOfRegs;
DWORD Offset;
DWORD i;
DWORD BaseAddress;
DWORD Size;
DWORD Reg;
DWORD IoIndex = 0;
DWORD MemIndex = 0;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCIReadBARs+(Bus %d, Device %d, Function %d)\r\n",
pInfo->Bus, pInfo->Device, pInfo->Function));
// Determine number of BARs to examine from header type
switch (pInfo->Cfg->HeaderType & ~PCI_MULTIFUNCTION) {
case PCI_DEVICE_TYPE:
NumberOfRegs = PCI_TYPE0_ADDRESSES;
break;
case PCI_BRIDGE_TYPE:
NumberOfRegs = PCI_TYPE1_ADDRESSES;
break;
case PCI_CARDBUS_TYPE:
NumberOfRegs = PCI_TYPE2_ADDRESSES;
break;
default:
return FALSE;
}
for (i = 0, Offset = 0x10; i < NumberOfRegs; i++, Offset += 4) {
// Get base address register value
Reg = pInfo->Cfg->u.type0.BaseAddresses[i];
// Get size info
PCIConfig_Write(pInfo->Bus, pInfo->Device, pInfo->Function, Offset, 0xFFFFFFFF);
BaseAddress = PCIConfig_Read(pInfo->Bus, pInfo->Device, pInfo->Function, Offset);
PCIConfig_Write(pInfo->Bus, pInfo->Device, pInfo->Function, Offset, Reg);
if (Reg & PCI_ADDRESS_IO_SPACE) {
// IO space
// Re-adjust BaseAddress if upper 16-bits are 0 (this is allowable in PCI 2.2 spec)
if (((BaseAddress & PCI_ADDRESS_IO_ADDRESS_MASK) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
BaseAddress |= 0xFFFF0000;
}
Size = ~(BaseAddress & PCI_ADDRESS_IO_ADDRESS_MASK);
if ((BaseAddress != 0) && (BaseAddress != 0xFFFFFFFF) && (((Size + 1) & Size) == 0)) {
// BAR has valid format (consecutive high 1's and consecutive low 0's)
pInfo->IoLen.Reg[IoIndex] = Size + 1;
pInfo->IoLen.Num++;
pInfo->IoBase.Reg[IoIndex++] = Reg & PCI_ADDRESS_IO_ADDRESS_MASK;
pInfo->IoBase.Num++;
} else {
// BAR invalid => skip to next one
continue;
}
} else {
// Memory space
if ((Reg & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) {
// PCI 2.2 spec no longer supports this type of memory addressing
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIReadBARs: 20-bit addressing not supported\r\n"));
return FALSE;
}
// Re-adjust BaseAddress if upper 16-bits are 0 (this is allowable in PCI 2.2 spec)
if (((BaseAddress & PCI_ADDRESS_MEMORY_ADDRESS_MASK) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
BaseAddress |= 0xFFFF0000;
}
Size = ~(BaseAddress & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
if ((BaseAddress != 0) && (BaseAddress != 0xFFFFFFFF) && (((Size + 1) & Size) == 0)) {
// BAR has valid format (consecutive high 1's and consecutive low 0's)
pInfo->MemLen.Reg[MemIndex] = Size + 1;
pInfo->MemLen.Num++;
pInfo->MemBase.Reg[MemIndex++] = Reg & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
pInfo->MemBase.Num++;
} else {
// BAR invalid => skip to next one
continue;
}
if ((Reg & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) {
// 64 bit device - BAR is twice as wide, skip upper 32-bits
Offset += 4;
i++;
}
}
}
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCIReadBARs-\r\n"));
return TRUE;
}
//
// Retrieve Base Address Register information from device
//
BOOL
PCIGetBARs(
PPCI_DEV_INFO pInfo
)
{
WCHAR SavePath[DEVKEY_LEN];
BOOL RetVal = TRUE;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCIGetBARs+(Bus %d, Device %d, Function %d)\r\n",
pInfo->Bus, pInfo->Device, pInfo->Function));
// Save off registry path
wcsncpy(SavePath, pInfo->RegPath, DEVKEY_LEN - 1);
SavePath[DEVKEY_LEN - 1] = L'\0'; // make sure longest string is terminated
// Attempt to find match for this device in the registry and get info
if (PCICfgFindMatch(pInfo)) {
if (!RegGetInfo(pInfo)) {
RetVal = FALSE;
goto PCIGetBARs_Exit;
}
if (!pInfo->Configure) {
goto PCIGetBARs_Exit;
}
// Make sure the sum of Base entries is less than or equal to 6
if (pInfo->MemBase.Num + pInfo->IoBase.Num > PCI_TYPE0_ADDRESSES) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIGetBARs: The number of registry values '%s' and '%s' under '%s' must sum to be less than %d.\r\n",
pInfo->RegPath, PCIBUS_MEMBASE_VALNAME, PCIBUS_IOBASE_VALNAME, PCI_TYPE0_ADDRESSES));
RetVal = FALSE;
goto PCIGetBARs_Exit;
}
// Make sure the sum of Len entries is less than or equal to 6
if (pInfo->MemLen.Num + pInfo->IoLen.Num > PCI_TYPE0_ADDRESSES) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIGetBARs: The number of registry values '%s' and '%s' under '%s' must sum to be less than %d.\r\n",
pInfo->RegPath, PCIBUS_MEMLEN_VALNAME, PCIBUS_IOLEN_VALNAME, PCI_TYPE0_ADDRESSES));
RetVal = FALSE;
goto PCIGetBARs_Exit;
}
if (pInfo->MemLen.Num + pInfo->IoLen.Num > 0) {
// If there is any Length info, return
goto PCIGetBARs_Exit;
}
}
// If ConfigEntry point defined, call it to determine BAR lengths
if (pInfo->ConfigEntry) {
DWORD Status;
// Load driver Dll and obtain ConfigEntry function address
if (!LoadConfigEntry(pInfo)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIGetBARs: Failed LoadConfigEntry call\r\n"));
RetVal = FALSE;
goto PCIGetBARs_Exit;
}
Status = ((PFN_CONFIGENTRY)(pInfo->ConfigInfo->ConfigEntryFn))(PCIBUS_CONFIG_SIZE, pInfo, NULL, NULL, NULL, NULL);
// Unload Dll
UnloadConfigEntrys( );
if (Status != ERROR_SUCCESS) {
if (Status == ERROR_NOT_SUPPORTED) {
// ConfigEntry point doesn't support this type of call, so do it here
// Read the base address registers to determine BAR lengths
if (!PCIReadBARs(pInfo)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIGetBARs: Failed PCIReadBARs call\r\n"));
RetVal = FALSE;
}
} else {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIGetBARs: Failed ConfigEntry call\r\n"));
RetVal = FALSE;
}
}
} else {
// Read the base address registers to determine BAR lengths
if (!PCIReadBARs(pInfo)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIGetBARs: Failed PCIReadBARs call\r\n"));
RetVal = FALSE;
}
}
PCIGetBARs_Exit:
// Restore path
wcscpy(pInfo->RegPath, SavePath);
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCIGetBARs-\r\n"));
return RetVal;
}
//
// Call device configuration routine with INIT parameter, if it exists
//
BOOL
PCIInitDevice(
PPCI_DEV_INFO pInfo
)
{
DWORD Status;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCIInitDevice+(Bus %d, Device %d, Function %d)\r\n",
pInfo->Bus, pInfo->Device, pInfo->Function));
// If ConfigEntry point not defined, do nothing
if (!pInfo->ConfigEntry) return TRUE;
// Load driver Dll and obtain ConfigEntry function address
if (!LoadConfigEntry(pInfo)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIInitDevice: Failed LoadConfigEntry call\r\n"));
return FALSE;
}
Status = ((PFN_CONFIGENTRY)(pInfo->ConfigInfo->ConfigEntryFn))(PCIBUS_CONFIG_INIT, pInfo, NULL, NULL, NULL, NULL);
// Unload Dll
UnloadConfigEntrys( );
if ((Status != ERROR_SUCCESS) && (Status != ERROR_NOT_SUPPORTED)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCIInitDevice: Failed ConfigEntry(PCIBUS_CONFIG_INIT) call\r\n"));
return FALSE;
}
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCIInitDevice-\r\n"));
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -