//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// PCIbus bus driver and enumerator.
//
#include <windows.h>
#include <nkintr.h>
#include <pkfuncs.h>
#include <devload.h>
#include <resmgr.h>
#include <ceddk.h>
#include <stdarg.h>
#include <PCIbus.h>
#include "PCIproto.h"
#include "PCIdbg.h"
#ifdef DEBUG
//
// These defines must match the ZONE_* defines in PCIdbg.h
//
#define DBG_ERROR 1
#define DBG_WARNING 2
#define DBG_FUNCTION 4
#define DBG_INIT 8
#define DBG_ENUM 16
#define DBG_ORDER 32
#define DBG_RSRC 64
DBGPARAM dpCurSettings = {
TEXT("PCIBUS"), {
TEXT("Errors"),TEXT("Warnings"),TEXT("Functions"),TEXT("Initialization"),
TEXT("Enumeration"),TEXT("Load Order"),TEXT("Resource"),TEXT("Undefined"),
TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),
TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined") },
DBG_ERROR | DBG_WARNING
};
#endif // DEBUG
//
// Function prototypes
//
static BOOL
Enumerate(
LPCWSTR EnumKey
);
static BOOL
RegGetFlags(
PPCI_DEV_INFO pInfo
);
static VOID
DumpPciConfig(
PPCI_DEV_INFO pInfo
);
static DWORD
MinVal(
DWORD List[],
DWORD Len
);
static BOOL
PCIEnum(
LPCWSTR EnumKey
);
static BOOL
PCIRegClean(
LPCWSTR EnumKey
);
static BOOL
PCIReg(
PPCI_DEV_INFO pInfo
);
static DWORD
RegMatchOne(
PPCI_DEV_INFO pInfo,
HKEY Key,
LPCWSTR DevName
);
static BOOL
RegCopy(
PPCI_DEV_INFO pInfo
);
static BOOL
RegCopyKey(
HKEY TKey,
HKEY IKey
);
static BOOL
RegSetVal(
HKEY Key,
LPCWSTR ValName,
DWORD ValType,
const PBYTE ValData,
DWORD ValLen
);
static BOOL
RegSetList(
HKEY Key,
LPCWSTR ValName,
DWORD Num,
DWORD List[]
);
static BOOL
RegGetList(
HKEY Key,
LPCWSTR ValName,
PDWORD pNum,
DWORD List[]
);
static BOOL
RegSetConfig(
PPCI_DEV_INFO pInfo
);
static BOOL
RequestSysIntr(
DWORD Irq,
DWORD *pSysIntr
);
static PPCI_CFG_INFO
AddConfigInfo(
HMODULE hDll,
PFN_CONFIGENTRY ConfigEntryFn
);
static void
DelConfigInfoList(
void
);
//
// Global variables
//
PPCI_CFG_INFO g_ConfigInfoList = NULL;
//
// Process attach/detach API.
//
BOOL WINAPI
DllMain(
HINSTANCE hinstDll, /*@parm Instance pointer. */
DWORD dwReason, /*@parm Reason routine is called. */
LPVOID lpReserved /*@parm system parameter. */
)
{
if (dwReason == DLL_PROCESS_ATTACH) {
DEBUGREGISTER(hinstDll);
DEBUGMSG(ZONE_INIT, (L"PCIBUS!DllMain: process attach\r\n"));
DisableThreadLibraryCalls((HMODULE)hinstDll);
}
if (dwReason == DLL_PROCESS_DETACH) {
DEBUGMSG(ZONE_INIT, (L"PCIBUS!DllMain: process detach\r\n"));
}
return TRUE;
}
//
// PCIbus driver entry point.
//
HANDLE
Init(
LPCWSTR ActiveKey
)
{
HKEY Key;
DWORD Status;
WCHAR EnumKey[DEVKEY_LEN];
DWORD KeyLen;
//
// Open the Active key and find the client key.
//
Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ActiveKey, 0, 0, &Key);
if (Status != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Init RegOpenKeyEx(%s) returned %d.\r\n", ActiveKey, Status));
return (HANDLE)0;
}
KeyLen = sizeof(EnumKey);
Status = RegQueryValueEx(Key, DEVLOAD_DEVKEY_VALNAME, NULL, NULL, (PUCHAR)EnumKey, &KeyLen);
if (Status != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Init RegQueryValueEx(%s\\%s) returned %d.\r\n", ActiveKey, DEVLOAD_DEVKEY_VALNAME, Status));
RegCloseKey(Key);
return (HANDLE)0;
}
RegCloseKey(Key);
if (Enumerate(EnumKey)) {
// Return any non-zero handle
return (HANDLE)1;
} else {
// A return value of zero indicates failure
return (HANDLE)0;
}
}
//
// De-init entry point.
//
void
Deinit(
HANDLE hInitKey
)
{
return;
}
//
// Enumerate PCIbus.
//
static BOOL
Enumerate(
LPCWSTR EnumKey
)
{
WCHAR RegPath[DEVKEY_LEN];
PCI_DEV_INFO Info;
size_t MaxKeyLen = DEVKEY_LEN - (wcslen(L"\\") + wcslen(PCIBUS_INSTANCE_KEYNAME) + 1);
// If EnumKey too long, return with error
if (wcslen(EnumKey) > MaxKeyLen) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Enumerate: ERROR: EnumKey '%s' exceeds the allowed %d characters\r\n", EnumKey, MaxKeyLen));
return FALSE;
}
PCIInitInfo(EnumKey, 0, 0, 0, NULL, &Info);
if (!RegGetInfo(&Info)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Enumerate: RegGetInfo failed\r\n"));
return FALSE;
}
if (Info.Configure) {
// Configure bus
if (!PCICfg(&Info)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Enumerate: PCICfg failed\r\n"));
return FALSE;
}
}
// Clean out devices from under PCI\Instance sub-key that have no physical device available. This is
// to prevent device drivers from being loaded for devices that have been removed while suspended and while
// retaining the registry settings.
wcscpy(RegPath, EnumKey);
wcscat(RegPath, L"\\");
wcscat(RegPath, PCIBUS_INSTANCE_KEYNAME);
PCIRegClean(RegPath);
// Enumerate bus
if (!PCIEnum(EnumKey)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Enumerate: PCIEnum failed\r\n"));
return FALSE;
}
// Start DLL under PCI\Instance key to load drivers (usually RegEnum.dll)
if (!ActivateDevice(RegPath, 0)) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!Enumerate: ActivateDevice(%s) failed\r\n", RegPath));
return FALSE;
}
return TRUE;
}
//
// Get registry information.
//
BOOL
RegGetInfo(
PPCI_DEV_INFO pInfo
)
{
HKEY Key;
DWORD Status;
DWORD ValLen;
DWORD ValType;
DWORD Val;
BOOL ConfigDllExists = TRUE;
BOOL DllExists = TRUE;
//
// Open key to be enumerated
//
Status = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
pInfo->RegPath,
0,
0,
&Key);
if (Status != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ENUM|ZONE_ERROR,
(TEXT("PCIBUS!RegGetInfo RegOpenKeyEx(%s) returned %d.\r\n"),
pInfo->RegPath, Status));
return FALSE;
}
//
// Read NoConfig value
//
ValLen = sizeof(Val);
Status = RegQueryValueEx(Key, PCIBUS_NOCONFIG_VALNAME, NULL, &ValType, (PUCHAR)&Val, &ValLen);
if ((Status == ERROR_SUCCESS) && (Val != 0)) {
// If NoConfig exists and non-zero, don't configure bus
pInfo->Configure = FALSE;
RegCloseKey(Key);
return TRUE;
} else {
pInfo->Configure = TRUE;
}
//
// Read MemBase and MemLen values.
//
pInfo->MemBase.Num = PCI_TYPE0_ADDRESSES;
if (!RegGetList(Key, PCIBUS_MEMBASE_VALNAME, &pInfo->MemBase.Num, pInfo->MemBase.Reg) && (pInfo->MemBase.Num == PCI_TYPE0_ADDRESSES)) {
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!RegGetInfo: Registry value '%s\\%s' has more than %d items in multi_sz list. Ignoring the additional items.\r\n",
pInfo->RegPath, PCIBUS_MEMBASE_VALNAME, PCI_TYPE0_ADDRESSES));
}
pInfo->MemLen.Num = PCI_TYPE0_ADDR