/*++ Copyright (c) 1990 Microsoft Corporation Module Name: pcienum.c Abstract: Enumerates the PCI bus and puts all the found PCI information into the registery. This is done for debugging & support reasons. Author: Ken Reneris Environment: Notes: Revision History: --*/ #include "stdarg.h" #include "stdio.h" #include "ntddk.h" WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; WCHAR rgzConfigurationData[] = L"Configuration Data"; WCHAR rgzIdentifier[] = L"Identifier"; WCHAR rgzPCIIndetifier[] = L"PCI"; WCHAR rgzPCIDump[] = L"PCI configuration space dump"; WCHAR rgzPCIConfigData[] = L"PCIConfigSpaceData"; NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); BOOLEAN FindRegisterLocation ( PHANDLE RegHandle ) { UNICODE_STRING unicodeString, ConfigName, IdentName; OBJECT_ATTRIBUTES objectAttributes; HANDLE hMFunc, hBus; NTSTATUS status; ULONG i, junk, disposition; WCHAR wstr[8]; PKEY_VALUE_FULL_INFORMATION ValueInfo; UCHAR buffer [200]; PWSTR p; // // Search the hardware description looking for any reported // PCI bus. The first ARC entry for a PCI bus will contain // the PCI_REGISTRY_INFO. // RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter); InitializeObjectAttributes ( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, NULL, // handle NULL); status = ZwOpenKey (&hMFunc, KEY_READ | KEY_WRITE, &objectAttributes); if (!NT_SUCCESS(status)) { return FALSE; } unicodeString.Buffer = wstr; unicodeString.MaximumLength = sizeof (wstr); RtlInitUnicodeString (&ConfigName, rgzConfigurationData); RtlInitUnicodeString (&IdentName, rgzIdentifier); ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer; for (i=0; TRUE; i++) { RtlIntegerToUnicodeString (i, 10, &unicodeString); InitializeObjectAttributes ( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, hMFunc, NULL); status = ZwOpenKey (&hBus, KEY_READ | KEY_WRITE, &objectAttributes); if (!NT_SUCCESS(status)) { // // Out of Multifunction adapter entries... // ZwClose (hMFunc); return FALSE; } // // Check the Indentifier to see if this is a PCI entry // status = ZwQueryValueKey ( hBus, &IdentName, KeyValueFullInformation, ValueInfo, sizeof (buffer), &junk ); if (!NT_SUCCESS (status)) { ZwClose (hBus); continue; } p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset); if (p[0] != L'P' || p[1] != L'C' || p[2] != L'I' || p[3] != 0) { ZwClose (hBus); continue; } // found it... break; } // // Initialize the object for the key. // RtlInitUnicodeString (&unicodeString, rgzPCIDump); InitializeObjectAttributes( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, hBus, (PSECURITY_DESCRIPTOR) NULL ); status = ZwCreateKey ( RegHandle, KEY_READ | KEY_WRITE, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, &disposition ); return NT_SUCCESS(status); } VOID DumpPciConfigSpaceIntoRegistry ( HANDLE RegHandle ) { PCI_SLOT_NUMBER SlotNumber; ULONG BusNo, DeviceNo, FunctionNo, BytesRead; BOOLEAN ScanFlag; PCI_COMMON_CONFIG PciData; HANDLE HBus, HDevice; UNICODE_STRING unicodeString; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; ULONG len, disposition; WCHAR wstr[80]; SlotNumber.u.bits.Reserved = 0; BusNo = 0; ScanFlag = TRUE; while (ScanFlag) { for (DeviceNo=0; ScanFlag && DeviceNo < PCI_MAX_DEVICES; DeviceNo++) { SlotNumber.u.bits.DeviceNumber = DeviceNo; for (FunctionNo = 0; FunctionNo < PCI_MAX_FUNCTION; FunctionNo++) { SlotNumber.u.bits.FunctionNumber = FunctionNo; BytesRead = HalGetBusData ( PCIConfiguration, BusNo, SlotNumber.u.AsULONG, &PciData, PCI_COMMON_HDR_LENGTH ); // // If end-of-scan // if (BytesRead == 0) { ScanFlag = FALSE; break; } // // If not present, next device // if (PciData.VendorID == PCI_INVALID_VENDORID) { break; } // // If Intel Device ID, then read complete state // if (PciData.VendorID == 0x8086) { if (PciData.DeviceID == 0x04A3 || PciData.DeviceID == 0x0482 || PciData.DeviceID == 0x0484) { BytesRead = HalGetBusData ( PCIConfiguration, BusNo, SlotNumber.u.AsULONG, &PciData, sizeof (PciData) ); } } // // Open/Create bus entry in registry // swprintf (wstr, L"PCI bus%d", BusNo); RtlInitUnicodeString (&unicodeString, wstr); InitializeObjectAttributes( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, RegHandle, (PSECURITY_DESCRIPTOR) NULL ); status = ZwCreateKey ( &HBus, KEY_READ | KEY_WRITE, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, &disposition ); if (!NT_SUCCESS(status)) { continue; } // // Open/Create device function key // swprintf (wstr, L"Device %02d Function %d", DeviceNo, FunctionNo); RtlInitUnicodeString (&unicodeString, wstr); InitializeObjectAttributes( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, HBus, (PSECURITY_DESCRIPTOR) NULL ); status = ZwCreateKey ( &HDevice, KEY_READ | KEY_WRITE, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, &disposition ); ZwClose (HBus); if (!NT_SUCCESS(status)) { continue; } // // Write PCI config information to registry // len = swprintf (wstr, L"%04x-%04x rev %x", PciData.VendorID, PciData.DeviceID, PciData.RevisionID ); RtlInitUnicodeString (&unicodeString, L"Device ID"); ZwSetValueKey ( HDevice, &unicodeString, 0L, REG_SZ, wstr, sizeof (WCHAR) * len ); RtlInitUnicodeString (&unicodeString, L"RawData"); ZwSetValueKey ( HDevice, &unicodeString, 0L, REG_BINARY, &PciData, BytesRead ); ZwClose (HDevice); } } BusNo += 1; } } NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: Arguments: DriverObject - Pointer to driver object created by system. RegistryPath - Pointer to the Unicode name of the registry path for this driver. Return Value: The function value is the final status from the initialization operation. --*/ { BOOLEAN flag; HANDLE RegHandle; flag = FindRegisterLocation (&RegHandle); if (flag) { DumpPciConfigSpaceIntoRegistry (RegHandle); ZwClose (RegHandle); } // never load return STATUS_UNSUCCESSFUL; }