/*++ Copyright (c) 1991-2000 Microsoft Corporation Module Name: misc.c Abstract: This file contains pnp isa bus extender support routines. Author: Shie-Lin Tzong (shielint) 27-July-1995 Environment: Kernel mode only. Revision History: --*/ #include "busp.h" #include "pnpisa.h" #ifdef ALLOC_PRAGMA //#pragma alloc_text(PAGE, PipLockDeviceDatabase) //#pragma alloc_text(PAGE, PipUnlockDeviceDatabase) #pragma alloc_text(PAGE, PipQueryDeviceRelations) //#pragma alloc_text(PAGE, PipIsCardEnumeratedAlready) #pragma alloc_text(PAGE, PipCleanupAcquiredResources) #pragma alloc_text(PAGE, PipMapReadDataPort) #pragma alloc_text(PAGE, PipGetMappedAddress) #pragma alloc_text(PAGE, PipDecompressEisaId) #pragma alloc_text(PAGE, PipLogError) #pragma alloc_text(PAGE, PipOpenRegistryKey) #pragma alloc_text(PAGE, PipGetRegistryValue) #pragma alloc_text(PAGE, PipOpenCurrentHwProfileDeviceInstanceKey) #pragma alloc_text(PAGE, PipGetDeviceInstanceCsConfigFlags) #pragma alloc_text(PAGE, PipDetermineResourceListSize) #pragma alloc_text(PAGE, PipResetGlobals) #pragma alloc_text(PAGE, PipMapAddressAndCmdPort) #pragma alloc_text(PAGE, PiNeedDeferISABridge) #pragma alloc_text(PAGE, PipReleaseDeviceResources) #if DBG //#pragma alloc_text(PAGE, PipDebugPrint) #pragma alloc_text(PAGE, PipDumpIoResourceDescriptor) #pragma alloc_text(PAGE, PipDumpIoResourceList) #pragma alloc_text(PAGE, PipDumpCmResourceDescriptor) #pragma alloc_text(PAGE, PipDumpCmResourceList) #endif #endif #define IRQFLAGS_VALUE_NAME L"IrqFlags" #define BOOTRESOURCES_VALUE_NAME L"BootRes" #if ISOLATE_CARDS UCHAR CurrentCsn = 0; UCHAR CurrentDev = 255; VOID PipWaitForKey(VOID) { ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep)); PipWriteAddress(CONFIG_CONTROL_PORT); PipWriteData(CONTROL_WAIT_FOR_KEY); PipReportStateChange(PiSWaitForKey); CurrentCsn = 0; CurrentDev = 255; } VOID PipConfig( IN UCHAR Csn ) { ASSERT(Csn); ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep)); PipWriteAddress(WAKE_CSN_PORT); PipWriteData(Csn); DebugPrint((DEBUG_STATE, "Wake CSN %u\n", (ULONG) Csn)); CurrentCsn = Csn; CurrentDev = 255; PipReportStateChange(PiSConfig); } VOID PipIsolation( VOID ) { ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep)); PipWriteAddress(WAKE_CSN_PORT); PipWriteData(0); CurrentCsn = 0; CurrentDev = 255; DebugPrint((DEBUG_STATE, "Isolate cards w/o CSN\n")); PipReportStateChange(PiSIsolation); } VOID PipSleep( VOID ) { ASSERT((PipState == PiSConfig) || PipState == PiSIsolation); PipWriteAddress(WAKE_CSN_PORT); PipWriteData(0); CurrentCsn = 0; CurrentDev = 255; DebugPrint((DEBUG_STATE, "Putting all cards to sleep (we think)\n")); PipReportStateChange(PiSSleep); } VOID PipActivateDevice ( ) { UCHAR tmp; PipWriteAddress(IO_RANGE_CHECK_PORT); tmp = PipReadData(); tmp &= ~2; PipWriteAddress(IO_RANGE_CHECK_PORT); PipWriteData(tmp); PipWriteAddress(ACTIVATE_PORT); PipWriteData(1); DebugPrint((DEBUG_STATE, "Activated card CSN %d/LDN %d\n", (ULONG) CurrentCsn, (ULONG) CurrentDev)); } VOID PipDeactivateDevice ( ) { PipWriteAddress(ACTIVATE_PORT); PipWriteData(0); DebugPrint((DEBUG_STATE, "Deactivated card CSN %d/LDN %d\n", (ULONG) CurrentCsn, (ULONG) CurrentDev)); } VOID PipSelectDevice( IN UCHAR Device ) { ASSERT(PipState == PiSConfig); PipWriteAddress(LOGICAL_DEVICE_PORT); PipWriteData(Device); CurrentDev = Device; DebugPrint((DEBUG_STATE, "Selected CSN %d/LDN %d\n", (ULONG) CurrentCsn, (ULONG) Device)); } VOID PipWakeAndSelectDevice( IN UCHAR Csn, IN UCHAR Device ) { PipLFSRInitiation(); PipConfig(Csn); PipSelectDevice(Device); } PDEVICE_INFORMATION PipReferenceDeviceInformation ( IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN ConfigHardware ) /*++ Routine Description: This function locks a device node so it won't go away. Note, this function does not lock the whole device node tree. Arguments: DeviceNode - Supplies a pointer to the device information node Return Value: None. --*/ { PDEVICE_INFORMATION deviceInfo; deviceInfo = (PDEVICE_INFORMATION)DeviceObject->DeviceExtension; if (deviceInfo && !(deviceInfo->Flags & DF_DELETED)) { if ((deviceInfo->Flags & DF_NOT_FUNCTIONING) && ConfigHardware) { PipDereferenceDeviceInformation(NULL, FALSE); return NULL; } if (!(deviceInfo->Flags & DF_READ_DATA_PORT) && ConfigHardware) { PipWakeAndSelectDevice( deviceInfo->CardInformation->CardSelectNumber, deviceInfo->LogicalDeviceNumber); } return deviceInfo; } else { PipDereferenceDeviceInformation(NULL, FALSE); return NULL; } } VOID PipDereferenceDeviceInformation( IN PDEVICE_INFORMATION DeviceInformation, BOOLEAN ConfigedHardware ) /*++ Routine Description: This function releases the enumeration lock of the specified device node. Arguments: DeviceNode - Supplies a pointer to the device node whose lock is to be released. Return Value: None. --*/ { // // Synchronize the dec and set event operations with IopAcquireEnumerationLock. // if (DeviceInformation) { if (!(DeviceInformation->Flags & DF_READ_DATA_PORT) && ConfigedHardware) { if (PipState != PiSWaitForKey) { PipWaitForKey(); } } } } VOID PipLockDeviceDatabase( VOID ) /*++ Routine Description: This function locks the whole device node tree. Currently, eject operation needs to lock the whole device node tree. Arguments: None. Return Value: None. --*/ { KeWaitForSingleObject( &PipDeviceTreeLock, Executive, KernelMode, FALSE, NULL ); } VOID PipUnlockDeviceDatabase ( VOID ) /*++ Routine Description: This function releases the lock of the whole device node tree. Arguments: None. Return Value: None. --*/ { KeSetEvent( &PipDeviceTreeLock, 0, FALSE ); } VOID PipDeleteDevice ( PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine Parameters: P1 - Return Value: Status code that indicates whether or not the function was successful. --*/ { PDEVICE_INFORMATION deviceInfo, devicex, devicep; PCARD_INFORMATION cardInfo, cardx, cardp; PSINGLE_LIST_ENTRY deviceLink, cardLink; NTSTATUS status = STATUS_SUCCESS; PPI_BUS_EXTENSION busExtension; deviceInfo = (PDEVICE_INFORMATION)DeviceObject->DeviceExtension; deviceInfo->Flags |= DF_DELETED; // // Free the pool // if (deviceInfo->ResourceRequirements) { ExFreePool(deviceInfo->ResourceRequirements); deviceInfo->ResourceRequirements = NULL; } if (deviceInfo->BootResources) { ExFreePool(deviceInfo->BootResources); deviceInfo->BootResources = NULL; } if (deviceInfo->AllocatedResources) { ExFreePool(deviceInfo->AllocatedResources); deviceInfo->AllocatedResources = NULL; } if (deviceInfo->LogConfHandle) { ZwClose(deviceInfo->LogConfHandle); deviceInfo->LogConfHandle = NULL; } busExtension = deviceInfo->ParentDeviceExtension; cardInfo = deviceInfo->CardInformation; PipLockDeviceDatabase(); // // Remove the device from device list. // deviceLink = busExtension->DeviceList.Next; devicep = NULL; devicex = NULL; while (deviceLink) { devicex = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList); if (devicex == deviceInfo) { break; } devicep = devicex; deviceLink = devicex->DeviceList.Next; } ASSERT(devicex == deviceInfo); if (devicep == NULL) { busExtension->DeviceList.Next = deviceInfo->DeviceList.Next; } else { devicep->DeviceList.Next = deviceInfo->DeviceList.Next; } // // Remove the device from logical device list of the card // deviceLink = cardInfo->LogicalDeviceList.Next; devicep = NULL; devicex = NULL; while (deviceLink) { devicex = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList); if (devicex == deviceInfo) { break; } devicep = devicex; deviceLink = devicex->LogicalDeviceList.Next; } ASSERT(devicex == deviceInfo); if (devicep == NULL) { cardInfo->LogicalDeviceList.Next = deviceInfo->LogicalDeviceList.Next; } else { devicep->LogicalDeviceList.Next = deviceInfo->LogicalDeviceList.Next; } cardInfo->NumberLogicalDevices--; // // All the devices are gone. That means the card is removed. // Next remove the isapnp card structure. // if (cardInfo->NumberLogicalDevices == 0) { ASSERT(cardInfo->LogicalDeviceList.Next == NULL); cardLink = busExtension->CardList.Next; cardp = NULL; cardx = NULL; while (cardLink) { cardx = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList); if (cardx == cardInfo) { break; } cardp = cardx; cardLink = cardx->CardList.Next; } ASSERT(cardx == cardInfo); if (cardp == NULL) { busExtension->CardList.Next = cardInfo->CardList.Next; } else { cardp->CardList.Next = cardInfo->CardList.Next; } } PipUnlockDeviceDatabase(); // // Remove the card information structure after releasing spin lock. // if (cardInfo->NumberLogicalDevices == 0) { if (cardInfo->CardData) { ExFreePool(cardInfo->CardData); } ExFreePool(cardInfo); deviceInfo->CardInformation = NULL; } IoDeleteDevice(DeviceObject); } NTSTATUS PipQueryDeviceRelations ( PPI_BUS_EXTENSION BusExtension, PDEVICE_RELATIONS *DeviceRelations, BOOLEAN Removal ) /*++ Routine Description: This routine Parameters: P1 - Return Value: Status code that indicates whether or not the function was successful. --*/ { PDEVICE_INFORMATION deviceInfo; PSINGLE_LIST_ENTRY deviceLink; NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT *devicePtr; ULONG count = 0; PDEVICE_RELATIONS deviceRelations; PAGED_CODE(); *DeviceRelations = NULL; // // Go through the card link list to match the card data // deviceLink = BusExtension->DeviceList.Next; while (deviceLink) { deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList); // // if it's the RDP ignore it for removal relations // if ((deviceInfo->Flags & DF_ENUMERATED) && (!(deviceInfo->Flags & DF_READ_DATA_PORT) || !Removal)) { count++; } else { DebugPrint((DEBUG_PNP, "PipQueryDeviceRelations skipping a node, Flags: %x\n",deviceInfo->Flags)); } deviceLink = deviceInfo->DeviceList.Next; } if (count != 0) { deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool( PagedPool, sizeof(DEVICE_RELATIONS) + (count - 1) * sizeof(PDEVICE_OBJECT)); if (deviceRelations) { deviceRelations->Count = count; deviceLink = BusExtension->DeviceList.Next; devicePtr = deviceRelations->Objects; while (deviceLink) { deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList); if ((deviceInfo->Flags & DF_ENUMERATED) && (!(deviceInfo->Flags & DF_READ_DATA_PORT) || !(Removal))) { ObReferenceObject(deviceInfo->PhysicalDeviceObject); *devicePtr = deviceInfo->PhysicalDeviceObject; devicePtr++; } deviceLink = deviceInfo->DeviceList.Next; } *DeviceRelations = deviceRelations; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } return status; } PCARD_INFORMATION PipIsCardEnumeratedAlready( IN PPI_BUS_EXTENSION BusExtension, IN PUCHAR CardData, IN ULONG DataLength ) /*++ Routine Description: This routine finds the card information structure which contains the same CardData. Parameters: CardData - Supplies a pointer to the CardData DataLength - The length of the CardData Return Value: A pointer to the CARD_INFORMATION structure if found. --*/ { PCARD_INFORMATION cardInfo; PSINGLE_LIST_ENTRY cardLink; PSERIAL_IDENTIFIER serialId1, serialId2 = (PSERIAL_IDENTIFIER)CardData; // // Go through the card link list to match the card data // cardLink = BusExtension->CardList.Next; while (cardLink) { cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList); if (cardInfo->CardSelectNumber != 0) { // if == 0, card is no longer present serialId1 = (PSERIAL_IDENTIFIER)cardInfo->CardData; ASSERT(serialId1 && serialId2); if (serialId1->VenderId == serialId2->VenderId && serialId1->SerialNumber == serialId2->SerialNumber) { return cardInfo; } } cardLink = cardInfo->CardList.Next; // Get the next addr before releasing pool } return NULL; } VOID PipCleanupAcquiredResources ( PPI_BUS_EXTENSION BusExtension ) /*++ Routine Description: This routine cleans up the resources assigned to the readdata, command and address ports. Parameters: BusExtension - specifies the isapnp bus to be cleaned up. Return Value: None. --*/ { PAGED_CODE(); // // Release address, command and read data port resources. // if (BusExtension->CommandPort && BusExtension->CmdPortMapped) { MmUnmapIoSpace(BusExtension->CommandPort, 1); BusExtension->CmdPortMapped = FALSE; } BusExtension->CommandPort = NULL; if (BusExtension->AddressPort && BusExtension->AddrPortMapped) { MmUnmapIoSpace(BusExtension->AddressPort, 1); BusExtension->AddrPortMapped = FALSE; } BusExtension->AddressPort = NULL; if (BusExtension->ReadDataPort) { PipReadDataPort = PipCommandPort = PipAddressPort = NULL; } if (BusExtension->ReadDataPort && BusExtension->DataPortMapped) { MmUnmapIoSpace(BusExtension->ReadDataPort - 3, 4); BusExtension->DataPortMapped = FALSE; } BusExtension->ReadDataPort = NULL; } NTSTATUS PipMapReadDataPort ( IN PPI_BUS_EXTENSION BusExtension, IN PHYSICAL_ADDRESS Start, IN ULONG Length ) /*++ Routine Description: This routine maps specified port resources. Arguments: BusExtension - Supplies a pointer to the pnp bus extension. BaseAddressLow, BaseAddressHi - Supplies the read data port base address range to be mapped. Return Value: NTSTATUS code. --*/ { NTSTATUS status; ULONG size; PHYSICAL_ADDRESS physicalAddress; ULONG dumpData[3]; BOOLEAN conflictDetected; PAGED_CODE(); if (BusExtension->ReadDataPort && BusExtension->DataPortMapped) { MmUnmapIoSpace(PipReadDataPort - 3, 4); PipReadDataPort = BusExtension->ReadDataPort = NULL; BusExtension->DataPortMapped = FALSE; } PipReadDataPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, Start, Length, CM_RESOURCE_PORT_IO, &BusExtension->DataPortMapped ); DebugPrint((DEBUG_RDP, "PnpIsa:ReadDataPort is at %x\n",PipReadDataPort+3)); if (PipReadDataPort) { PipReadDataPort += 3; BusExtension->ReadDataPort = PipReadDataPort; status = STATUS_SUCCESS; } else { status = STATUS_INSUFFICIENT_RESOURCES; } return status; } PVOID PipGetMappedAddress( IN INTERFACE_TYPE BusType, IN ULONG BusNumber, IN PHYSICAL_ADDRESS IoAddress, IN ULONG NumberOfBytes, IN ULONG AddressSpace, OUT PBOOLEAN MappedAddress ) /*++ Routine Description: This routine maps an IO address to system address space. Arguments: BusType - Supplies the type of bus - eisa, mca, isa... IoBusNumber - Supplies the bus number. IoAddress - Supplies the base device address to be mapped. NumberOfBytes - Supplies the number of bytes for which the address is valid. AddressSpace - Supplies whether the address is in io space or memory. MappedAddress - Supplies whether the address was mapped. This only has meaning if the address returned is non-null. Return Value: The mapped address. --*/ { PHYSICAL_ADDRESS cardAddress; PVOID address; BOOLEAN returnVal; PAGED_CODE(); returnVal = HalTranslateBusAddress(BusType, BusNumber, IoAddress, &AddressSpace, &cardAddress); if (returnVal == FALSE) { *MappedAddress = FALSE; return NULL; } // // Map the device base address into the virtual address space // if the address is in memory space. // if (!AddressSpace) { address = MmMapIoSpace(cardAddress, NumberOfBytes, FALSE); *MappedAddress = (address ? TRUE : FALSE); } else { address = (PVOID) cardAddress.LowPart; *MappedAddress = FALSE; } return address; } VOID PipDecompressEisaId( IN ULONG CompressedId, OUT PWCHAR EisaId ) /*++ Routine Description: This routine decompressed compressed Eisa Id and returns the Id to caller specified character buffer. Arguments: CompressedId - supplies the compressed Eisa Id. EisaId - supplies a 8-wchar buffer to receive the decompressed Eisa Id. Return Value: None. --*/ { USHORT c1, c2; LONG i; PAGED_CODE(); CompressedId &= 0xffffff7f; // remove the reserved bit (bit 7 of byte 0) c1 = c2 = (USHORT)CompressedId; c1 = (c1 & 0xff) << 8; c2 = (c2 & 0xff00) >> 8; c1 |= c2; for (i = 2; i >= 0; i--) { *(EisaId + i) = (WCHAR)(c1 & 0x1f) + 0x40; c1 >>= 5; } EisaId += 3; c1 = c2 = (USHORT)(CompressedId >> 16); c1 = (c1 & 0xff) << 8; c2 = (c2 & 0xff00) >> 8; c1 |= c2; StringCchPrintf(EisaId, 5, L"%04x", c1 ); } VOID PipLogError( IN NTSTATUS ErrorCode, IN ULONG UniqueErrorValue, IN NTSTATUS FinalStatus, IN PULONG DumpData, IN ULONG DumpCount, IN USHORT StringLength, IN PWCHAR String ) /*++ Routine Description: This routine contains common code to write an error log entry. It is called from other routines to avoid duplication of code. This routine only allows caller to supply one insertion string to the error log. Arguments: ErrorCode - The error code for the error log packet. UniqueErrorValue - The unique error value for the error log packet. FinalStatus - The final status of the operation for the error log packet. DumpData - Pointer to an array of dump data for the error log packet. DumpCount - The number of entries in the dump data array. StringLength - The length of insertion string *NOT* including the NULL terminater. String - The pointer to the insertion string Return Value: None. --*/ { PIO_ERROR_LOG_PACKET errorLogEntry; ULONG i, size; PUCHAR p; size = sizeof(IO_ERROR_LOG_PACKET) + DumpCount * sizeof(ULONG) + StringLength + sizeof(UNICODE_NULL) - sizeof(ULONG); ASSERT(size <= MAXUCHAR); if (size > MAXUCHAR) { return; } errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry( PipDriverObject, (UCHAR) size ); if (errorLogEntry != NULL) { RtlZeroMemory(errorLogEntry, size); errorLogEntry->ErrorCode = ErrorCode; errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG)); errorLogEntry->UniqueErrorValue = UniqueErrorValue; errorLogEntry->FinalStatus = FinalStatus; for (i = 0; i < DumpCount; i++) errorLogEntry->DumpData[i] = DumpData[i]; if (String) { errorLogEntry->NumberOfStrings = 1; errorLogEntry->StringOffset = (USHORT)(sizeof(IO_ERROR_LOG_PACKET) + DumpCount * sizeof(ULONG) - sizeof(ULONG)); p= (PUCHAR)errorLogEntry + errorLogEntry->StringOffset; StringCbCopy((PWCHAR)p, StringLength + sizeof(UNICODE_NULL), String ); } IoWriteErrorLogEntry(errorLogEntry); } } NTSTATUS PipOpenCurrentHwProfileDeviceInstanceKey( OUT PHANDLE Handle, IN PUNICODE_STRING DeviceInstanceName, IN ACCESS_MASK DesiredAccess ) /*++ Routine Description: This routine sets the csconfig flags for the specified device which is specified by the instance number under ServiceKeyName\Enum. Arguments: ServiceKeyName - Supplies a pointer to the name of the subkey in the system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services) that caused the driver to load. This is the RegistryPath parameter to the DriverEntry routine. Instance - Supplies the instance value under ServiceKeyName\Enum key DesiredAccess - Specifies the desired access that the caller needs to the key. Create - Determines if the key is to be created if it does not exist. Return Value: status --*/ { NTSTATUS status; UNICODE_STRING unicodeString; HANDLE profileEnumHandle; // // See if we can open the device instance key of current hardware profile // RtlInitUnicodeString ( &unicodeString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT\\SYSTEM\\CURRENTCONTROLSET\\ENUM" ); status = PipOpenRegistryKey(&profileEnumHandle, NULL, &unicodeString, KEY_READ, FALSE ); if (NT_SUCCESS(status)) { status = PipOpenRegistryKey(Handle, profileEnumHandle, DeviceInstanceName, DesiredAccess, FALSE ); ZwClose(profileEnumHandle); } return status; } NTSTATUS PipGetDeviceInstanceCsConfigFlags( IN PUNICODE_STRING DeviceInstance, OUT PULONG CsConfigFlags ) /*++ Routine Description: This routine retrieves the csconfig flags for the specified device which is specified by the instance number under ServiceKeyName\Enum. Arguments: ServiceKeyName - Supplies a pointer to the name of the subkey in the system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services) that caused the driver to load. // Instance - Supplies the instance value under ServiceKeyName\Enum key // CsConfigFlags - Supplies a variable to receive the device's CsConfigFlags Return Value: status --*/ { NTSTATUS status; HANDLE handle; PKEY_VALUE_FULL_INFORMATION keyValueInformation; *CsConfigFlags = 0; status = PipOpenCurrentHwProfileDeviceInstanceKey(&handle, DeviceInstance, KEY_READ ); if(NT_SUCCESS(status)) { status = PipGetRegistryValue(handle, L"CsConfigFlags", &keyValueInformation ); if(NT_SUCCESS(status)) { if((keyValueInformation->Type == REG_DWORD) && (keyValueInformation->DataLength >= sizeof(ULONG))) { *CsConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation); } ExFreePool(keyValueInformation); } ZwClose(handle); } return status; } ULONG PipDetermineResourceListSize( IN PCM_RESOURCE_LIST ResourceList ) /*++ Routine Description: This routine determines size of the passed in ResourceList structure. Arguments: Configuration1 - Supplies a pointer to the resource list. Return Value: size of the resource list structure. --*/ { ULONG totalSize, listSize, descriptorSize, i, j; PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor; if (!ResourceList) { totalSize = 0; } else { totalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List); fullResourceDesc = &ResourceList->List[0]; for (i = 0; i < ResourceList->Count; i++) { listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) + FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors); partialDescriptor = &fullResourceDesc->PartialResourceList.PartialDescriptors[0]; for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) { descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) { descriptorSize += partialDescriptor->u.DeviceSpecificData.DataSize; } listSize += descriptorSize; partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)partialDescriptor + descriptorSize); } totalSize += listSize; fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)fullResourceDesc + listSize); } } return totalSize; } NTSTATUS PipMapAddressAndCmdPort ( IN PPI_BUS_EXTENSION BusExtension ) { NTSTATUS status = STATUS_SUCCESS; ULONG dumpData[3]; PHYSICAL_ADDRESS physicalAddress; // // Map port addr to memory addr if necessary. // if (PipAddressPort == NULL) { physicalAddress.LowPart = ADDRESS_PORT; physicalAddress.HighPart = 0; BusExtension->AddressPort = PipAddressPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, physicalAddress, 1, CM_RESOURCE_PORT_IO, &BusExtension->AddrPortMapped ); if (PipAddressPort == NULL) { dumpData[0] = ADDRESS_PORT; dumpData[1] = 1; dumpData[2] = CM_RESOURCE_PORT_IO; PipLogError(PNPISA_REGISTER_NOT_MAPPED, PNPISA_ACQUIREPORTRESOURCE_1, STATUS_INSUFFICIENT_RESOURCES, dumpData, 3, 0, NULL ); status = STATUS_UNSUCCESSFUL; } } if (PipCommandPort == NULL) { physicalAddress.LowPart = COMMAND_PORT; physicalAddress.HighPart = 0; BusExtension->CommandPort = PipCommandPort = PipGetMappedAddress( Isa, // InterfaceType 0, // BusNumber, physicalAddress, 1, CM_RESOURCE_PORT_IO, &BusExtension->CmdPortMapped ); if (PipCommandPort == NULL) { dumpData[0] = COMMAND_PORT; dumpData[1] = 1; dumpData[2] = CM_RESOURCE_PORT_IO; PipLogError(PNPISA_REGISTER_NOT_MAPPED, PNPISA_ACQUIREPORTRESOURCE_2, STATUS_INSUFFICIENT_RESOURCES, dumpData, 3, 0, NULL ); status = STATUS_UNSUCCESSFUL; } } return status; } VOID PipReleaseDeviceResources ( PDEVICE_INFORMATION DeviceInfo ) { UNICODE_STRING unicodeString; // This code is here rather than in the following conditional as // this best reflects how the code used to work before this code // was moved here from PDO stop/remove/surprise remove. if (DeviceInfo->LogConfHandle) { RtlInitUnicodeString(&unicodeString, L"AllocConfig"); ZwDeleteValueKey (DeviceInfo->LogConfHandle, &unicodeString); } if (DeviceInfo->AllocatedResources) { ExFreePool (DeviceInfo->AllocatedResources); DeviceInfo->AllocatedResources=NULL; if (DeviceInfo->LogConfHandle) { // As it stands now it we will close the logconf handle if // the device gets removed, surprise removed, or stopped. // When we get started, we'll try to re-create the // AllocConfig value but fail because of the lack of the // logconf handle. This is not a change in behavior. // // The ZwDeleteKey() was definitely bogus though. ZwClose(DeviceInfo->LogConfHandle); DeviceInfo->LogConfHandle=NULL; } } } VOID PipReportStateChange( PNPISA_STATE State ) { DebugPrint((DEBUG_STATE, "State transition: %d to %d\n", PipState, State)); PipState = State; } ULONG PipGetCardFlags( PCARD_INFORMATION CardInfo ) /*++ Description: Look in the registry for any flags for this CardId Arguments: CardId First 4 bytes of ISAPNP config space Return Value: 32 bit flags value from registry or 0 if not found. --*/ { HANDLE serviceHandle, paramHandle; NTSTATUS status; ULONG flags, returnedLength; UNICODE_STRING nameString; WCHAR nameBuffer[9]; WCHAR eisaId[8]; const PWCHAR paramKey = L"Parameters"; struct { KEY_VALUE_PARTIAL_INFORMATION Header; // // The header contains enough space for one UCHAR, pad // it out by a ULONG, this will ensure the structure // is large enough for at lease the ULONG we need. // // N.B. Natural alignment will get it out far enough that // this ULONG is 4 bytes to many. // ULONG Pad; } returnedData; status = PipOpenRegistryKey(&serviceHandle, NULL, &PipRegistryPath, KEY_READ, FALSE); if (!NT_SUCCESS(status)) { return 0; } RtlInitUnicodeString(&nameString, paramKey); status = PipOpenRegistryKey(¶mHandle, serviceHandle, &nameString, KEY_READ, FALSE); if (!NT_SUCCESS(status)) { ZwClose(serviceHandle); return 0; } PipDecompressEisaId( ((PSERIAL_IDENTIFIER) (CardInfo->CardData))->VenderId, eisaId ); RtlInitUnicodeString(&nameString, eisaId); // // Get the "value" of this value. // status = ZwQueryValueKey( paramHandle, &nameString, KeyValuePartialInformation, &returnedData, sizeof(returnedData), &returnedLength ); ZwClose(paramHandle); ZwClose(serviceHandle); if (NT_SUCCESS(status) && (returnedData.Header.Type == REG_DWORD) && (returnedData.Header.DataLength == sizeof(ULONG))) { flags = *(PULONG)(returnedData.Header.Data); DebugPrint((DEBUG_WARN, "Retrieving card flags for %ws: %x\n", nameString.Buffer, flags)); } else { flags = 0; } return flags; } NTSTATUS PipBuildValueName( IN PDEVICE_INFORMATION DeviceInfo, IN PWSTR Suffix, OUT PWSTR *ValuePath ) /*++ Description: Builds a name describing the device via the device id and unique id. Used to store per-device info in our parent's BiosConfig key Arguments: DeviceInfo Pointer to the PDO Extension for this device. Suffix Suffix for value name IrqFlags The edge or level setting of the boot config Return Value: Status --*/ { NTSTATUS status; PWSTR DeviceId = NULL, Instance = NULL; PWSTR Buffer, Current; ULONG length, deviceIdLength, instanceIdLength; status = PipQueryDeviceId(DeviceInfo, &DeviceId, &deviceIdLength, 0); if (!NT_SUCCESS(status)) { goto cleanup; } status = PipQueryDeviceUniqueId(DeviceInfo, &Instance, &instanceIdLength); if (!NT_SUCCESS(status)) { goto cleanup; } length = deviceIdLength + instanceIdLength + (wcslen(Suffix) + 1) * sizeof(WCHAR); Buffer = ExAllocatePool(PagedPool, length); if (Buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } StringCbCopy(Buffer, length, DeviceId ); StringCbCat(Buffer, length, Instance ); StringCbCat(Buffer, length, Suffix ); Current = Buffer; while (*Current != UNICODE_NULL) { if (*Current == L'\\') { *Current = L'_'; } Current++; } cleanup: if (Instance) { ExFreePool(Instance); } if (DeviceId) { ExFreePool(DeviceId); } if (NT_SUCCESS(status)) { *ValuePath = Buffer; } else { *ValuePath = NULL; } return status; } NTSTATUS PipSaveBootResources( IN PDEVICE_INFORMATION DeviceInfo ) /*++ Description: This saves the per-boot configuration of a device in the registry Arguments: DeviceInfo Pointer to the PDO Extension for this device. Return Value: Status --*/ { NTSTATUS status; OBJECT_ATTRIBUTES attributes; UNICODE_STRING unicodeString; HANDLE deviceHandle, configHandle; PWSTR Buffer = NULL; ULONG Flags; PAGED_CODE(); status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice, PLUGPLAY_REGKEY_DEVICE, KEY_WRITE, &deviceHandle ); if (!NT_SUCCESS(status)) { goto cleanup; } RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME); InitializeObjectAttributes(&attributes, &unicodeString, OBJ_KERNEL_HANDLE, deviceHandle, NULL ); status = ZwCreateKey(&configHandle, KEY_WRITE, &attributes, 0, NULL, REG_OPTION_VOLATILE, NULL ); ZwClose(deviceHandle); if (!NT_SUCCESS(status)) { goto cleanup; } status = PipBuildValueName(DeviceInfo, BOOTRESOURCES_VALUE_NAME, &Buffer); if (!NT_SUCCESS(status)) { Buffer = NULL; goto cleanup; } RtlInitUnicodeString(&unicodeString, Buffer); status = ZwSetValueKey(configHandle, &unicodeString, 0, REG_BINARY, DeviceInfo->BootResources, DeviceInfo->BootResourcesLength ); ZwClose(configHandle); cleanup: if (Buffer != NULL) { ExFreePool(Buffer); } return status; } NTSTATUS PipSaveBootIrqFlags( IN PDEVICE_INFORMATION DeviceInfo, IN USHORT IrqFlags ) /*++ Description: This saves the per-boot irq configuration of a device in the registry Arguments: DeviceInfo Pointer to the PDO Extension for this device. IrqFlags The edge or level setting of the boot config Return Value: Status --*/ { NTSTATUS status; OBJECT_ATTRIBUTES attributes; UNICODE_STRING unicodeString; HANDLE deviceHandle, configHandle; PWSTR Buffer = NULL; ULONG Flags; PAGED_CODE(); Flags = (ULONG) IrqFlags; status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice, PLUGPLAY_REGKEY_DEVICE, KEY_WRITE, &deviceHandle ); if (!NT_SUCCESS(status)) { goto cleanup; } RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME); InitializeObjectAttributes(&attributes, &unicodeString, OBJ_KERNEL_HANDLE, deviceHandle, NULL ); status = ZwCreateKey(&configHandle, KEY_WRITE, &attributes, 0, NULL, REG_OPTION_VOLATILE, NULL ); ZwClose(deviceHandle); if (!NT_SUCCESS(status)) { goto cleanup; } status = PipBuildValueName(DeviceInfo, IRQFLAGS_VALUE_NAME, &Buffer); if (!NT_SUCCESS(status)) { Buffer = NULL; goto cleanup; } RtlInitUnicodeString(&unicodeString, Buffer); status = ZwSetValueKey(configHandle, &unicodeString, 0, REG_DWORD, &Flags, sizeof(ULONG) ); ZwClose(configHandle); cleanup: if (Buffer != NULL) { ExFreePool(Buffer); } return status; } NTSTATUS PipGetSavedBootResources( IN PDEVICE_INFORMATION DeviceInfo, OUT PCM_RESOURCE_LIST *BootResources ) /* Description: This retrieves the saved boot resources Arguments: DeviceInfo Pointer to the PDO Extension for this device. Return Value: Status --*/ { UNICODE_STRING unicodeString; NTSTATUS status; OBJECT_ATTRIBUTES attributes; HANDLE deviceHandle, configHandle; PWSTR Buffer = NULL; PKEY_VALUE_PARTIAL_INFORMATION info = NULL; ULONG resultLength; PAGED_CODE(); *BootResources = NULL; status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice, PLUGPLAY_REGKEY_DEVICE, KEY_READ | KEY_WRITE, &deviceHandle ); if (!NT_SUCCESS(status)) { goto cleanup; } RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME); InitializeObjectAttributes(&attributes, &unicodeString, OBJ_KERNEL_HANDLE, deviceHandle, NULL ); status = ZwOpenKey(&configHandle, KEY_READ, &attributes ); ZwClose(deviceHandle); if (!NT_SUCCESS(status)) { goto cleanup; } status = PipBuildValueName(DeviceInfo, BOOTRESOURCES_VALUE_NAME, &Buffer); if (!NT_SUCCESS(status)) { ZwClose(configHandle); Buffer = NULL; goto cleanup; } RtlInitUnicodeString(&unicodeString,Buffer); status = ZwQueryValueKey(configHandle, &unicodeString, KeyValuePartialInformation, NULL, 0, &resultLength ); if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) { ZwClose(configHandle); goto cleanup; } info = ExAllocatePool(PagedPool, resultLength); if (info == NULL) { ZwClose(configHandle); status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } status = ZwQueryValueKey(configHandle, &unicodeString, KeyValuePartialInformation, info, resultLength, &resultLength ); ZwClose(configHandle); if (!NT_SUCCESS(status)) { DebugPrint((DEBUG_PNP, "Failed to get boot resources from registry for %ws\n", Buffer)); goto cleanup; } status = PipValidateResourceList((PCM_RESOURCE_LIST)info->Data, info->DataLength); if (!NT_SUCCESS(status)) { *BootResources = NULL; goto cleanup; } *BootResources = ExAllocatePool(PagedPool, info->DataLength); if (*BootResources) { RtlCopyMemory(*BootResources, info->Data, info->DataLength); DebugPrint((DEBUG_PNP, "Got boot resources from registry for %ws\n", Buffer)); } else { status = STATUS_INSUFFICIENT_RESOURCES; } cleanup: if (info != NULL) { ExFreePool(info); } if (Buffer != NULL) { ExFreePool(Buffer); } return status; } NTSTATUS PipGetBootIrqFlags( IN PDEVICE_INFORMATION DeviceInfo, OUT PUSHORT IrqFlags ) /* Description: This retrieves the per-boot irq configuration of a device from the registry Arguments: DeviceInfo Pointer to the PDO Extension for this device. IrqFlags - flags we originally derived from the device's boot config on this boot Return Value: Status --*/ { NTSTATUS status; OBJECT_ATTRIBUTES attributes; UNICODE_STRING unicodeString; HANDLE deviceHandle, configHandle; PWSTR Buffer = NULL; CHAR returnBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1]; PKEY_VALUE_PARTIAL_INFORMATION info; ULONG resultLength; PAGED_CODE(); status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice, PLUGPLAY_REGKEY_DEVICE, KEY_READ, &deviceHandle ); if (!NT_SUCCESS(status)) { goto cleanup; } RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME); InitializeObjectAttributes(&attributes, &unicodeString, OBJ_KERNEL_HANDLE, deviceHandle, NULL ); status = ZwOpenKey(&configHandle, KEY_READ, &attributes ); ZwClose(deviceHandle); if (!NT_SUCCESS(status)) { goto cleanup; } status = PipBuildValueName(DeviceInfo, IRQFLAGS_VALUE_NAME, &Buffer); if (!NT_SUCCESS(status)) { ZwClose(configHandle); Buffer = NULL; goto cleanup; } RtlInitUnicodeString(&unicodeString,Buffer); status = ZwQueryValueKey(configHandle, &unicodeString, KeyValuePartialInformation, returnBuffer, sizeof(returnBuffer), &resultLength ); ZwClose(configHandle); if (NT_SUCCESS(status)) { ULONG Temp; info = (PKEY_VALUE_PARTIAL_INFORMATION) returnBuffer; ASSERT(info->DataLength == sizeof(ULONG)); Temp = *((PULONG) info->Data); ASSERT(!(Temp & 0xFFFF0000)); *IrqFlags = (USHORT) Temp; DebugPrint((DEBUG_IRQ, "Got Irq Flags of %d for %ws\n", (ULONG) *IrqFlags, unicodeString.Buffer)); } else { DebugPrint((DEBUG_IRQ, "Failed to get irq flags for %ws\n", unicodeString.Buffer)); } cleanup: if (Buffer != NULL) { ExFreePool(Buffer); } return status; } VOID PipResetGlobals ( VOID ) { PipReadDataPort = PipCommandPort = PipAddressPort = NULL; PipRDPNode = NULL; } #endif NTSTATUS PipOpenRegistryKey( OUT PHANDLE Handle, IN HANDLE BaseHandle OPTIONAL, IN PUNICODE_STRING KeyName, IN ACCESS_MASK DesiredAccess, IN BOOLEAN Create ) /*++ Routine Description: Opens or creates a VOLATILE registry key using the name passed in based at the BaseHandle node. Arguments: Handle - Pointer to the handle which will contain the registry key that was opened. BaseHandle - Handle to the base path from which the key must be opened. KeyName - Name of the Key that must be opened/created. DesiredAccess - Specifies the desired access that the caller needs to the key. Create - Determines if the key is to be created if it does not exist. Return Value: The function value is the final status of the operation. --*/ { OBJECT_ATTRIBUTES objectAttributes; ULONG disposition; PAGED_CODE(); // // Initialize the object for the key. // InitializeObjectAttributes( &objectAttributes, KeyName, OBJ_CASE_INSENSITIVE, BaseHandle, (PSECURITY_DESCRIPTOR) NULL ); // // Create the key or open it, as appropriate based on the caller's // wishes. // if (Create) { return ZwCreateKey( Handle, DesiredAccess, &objectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, &disposition ); } else { return ZwOpenKey( Handle, DesiredAccess, &objectAttributes ); } } NTSTATUS PipGetRegistryValue( IN HANDLE KeyHandle, IN PWSTR ValueName, OUT PKEY_VALUE_FULL_INFORMATION *Information ) /*++ Routine Description: This routine is invoked to retrieve the data for a registry key's value. This is done by querying the value of the key with a zero-length buffer to determine the size of the value, and then allocating a buffer and actually querying the value into the buffer. It is the responsibility of the caller to free the buffer. Arguments: KeyHandle - Supplies the key handle whose value is to be queried ValueName - Supplies the null-terminated Unicode name of the value. Information - Returns a pointer to the allocated data buffer. Return Value: The function value is the final status of the query operation. --*/ { UNICODE_STRING unicodeString; NTSTATUS status; PKEY_VALUE_FULL_INFORMATION infoBuffer; ULONG keyValueLength; PAGED_CODE(); *Information = NULL; RtlInitUnicodeString( &unicodeString, ValueName ); // // Figure out how big the data value is so that a buffer of the // appropriate size can be allocated. // status = ZwQueryValueKey( KeyHandle, &unicodeString, KeyValueFullInformation, (PVOID) NULL, 0, &keyValueLength ); if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) { return status; } // // Allocate a buffer large enough to contain the entire key data value. // infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength ); if (!infoBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } // // Query the data for the key value. // status = ZwQueryValueKey( KeyHandle, &unicodeString, KeyValueFullInformation, infoBuffer, keyValueLength, &keyValueLength ); if (!NT_SUCCESS( status )) { ExFreePool( infoBuffer ); return status; } // // Everything worked, so simply return the address of the allocated // buffer to the caller, who is now responsible for freeing it. // *Information = infoBuffer; return STATUS_SUCCESS; } BOOLEAN PiNeedDeferISABridge( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject ) { BOOLEAN defer=FALSE; NTSTATUS status; HANDLE hKey; ULONG value; PKEY_VALUE_FULL_INFORMATION keyValueInformation; status = IoOpenDeviceRegistryKey (DeviceObject,PLUGPLAY_REGKEY_DEVICE,KEY_READ,&hKey); if (NT_SUCCESS (status)) { status = PipGetRegistryValue (hKey,&BRIDGE_CHECK_KEY,&keyValueInformation); if (NT_SUCCESS (status)) { if((keyValueInformation->Type == REG_DWORD) && (keyValueInformation->DataLength >= sizeof(ULONG))) { value = *(PULONG)KEY_VALUE_DATA(keyValueInformation); // // Assume that if the value !0 then the bridge is 'broken' // defer = (value == 0)?FALSE:TRUE; } } ZwClose(hKey); } return defer; } NTSTATUS PipValidateResourceList( IN PCM_RESOURCE_LIST ResourceList, IN ULONG Length ) /*++ Routine Description: This routine verifies that a resource list structure is properly formated and the buffer containing it is large enough. Arguments: ResourceList - The CM_RESOURCE_LIST to verify. Length - The length of the ResourceList buffer. Return Value: STATUS_SUCCESS if the resource list is valid STATUS_UNSUCCESSFUL otherwise. --*/ { ULONG requiredLength; if (Length < sizeof(CM_RESOURCE_LIST)) { return STATUS_UNSUCCESSFUL; } if (ResourceList->Count != 1) { return STATUS_UNSUCCESSFUL; } requiredLength = sizeof(CM_RESOURCE_LIST); if (ResourceList->List[0].PartialResourceList.Count > 1) { requiredLength += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (ResourceList->List[0].PartialResourceList.Count - 1); } if (requiredLength > Length) { return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } #if DBG VOID PipDebugPrintContinue ( ULONG Level, PCCHAR DebugMessage, ... ) /*++ Routine Description: This routine displays debugging message or causes a break. Arguments: Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only. DEBUG_BREAK - displays message and break. DebugMessage - supplies a pointer to the debugging message. Return Value: None. --*/ { va_list ap; va_start(ap, DebugMessage); vDbgPrintEx(DPFLTR_ISAPNP_ID, Level, DebugMessage, ap ); if (Level & DEBUG_BREAK) { DbgBreakPoint(); } va_end(ap); } VOID PipDebugPrint ( ULONG Level, PCCHAR DebugMessage, ... ) /*++ Routine Description: This routine displays debugging message or causes a break. Arguments: Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only. DEBUG_BREAK - displays message and break. DebugMessage - supplies a pointer to the debugging message. Return Value: None. --*/ { va_list ap; va_start(ap, DebugMessage); vDbgPrintExWithPrefix("ISAPNP: ", DPFLTR_ISAPNP_ID, Level, DebugMessage, ap ); if (Level & DEBUG_BREAK) { DbgBreakPoint(); } va_end(ap); } #endif VOID PipDumpIoResourceDescriptor ( IN PUCHAR Indent, IN PIO_RESOURCE_DESCRIPTOR Desc ) /*++ Routine Description: This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. Arguments: Indent - # char of indentation. Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. Return Value: None. --*/ { UCHAR c = ' '; if (Desc->Option == IO_RESOURCE_ALTERNATIVE) { c = 'A'; } else if (Desc->Option == IO_RESOURCE_PREFERRED) { c = 'P'; } switch (Desc->Type) { case CmResourceTypePort: DebugPrint (( DEBUG_RESOURCE, "%sIO %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", Indent, c, Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart, Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart, Desc->u.Port.Alignment, Desc->u.Port.Length )); break; case CmResourceTypeMemory: DebugPrint (( DEBUG_RESOURCE, "%sMEM %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", Indent, c, Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart, Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart, Desc->u.Memory.Alignment, Desc->u.Memory.Length )); break; case CmResourceTypeInterrupt: DebugPrint (( DEBUG_RESOURCE, "%sINT %c Min: %x, Max: %x\n", Indent, c, Desc->u.Interrupt.MinimumVector, Desc->u.Interrupt.MaximumVector )); break; case CmResourceTypeDma: DebugPrint (( DEBUG_RESOURCE, "%sDMA %c Min: %x, Max: %x\n", Indent, c, Desc->u.Dma.MinimumChannel, Desc->u.Dma.MaximumChannel )); break; } } VOID PipDumpIoResourceList ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoList ) /*++ Routine Description: This routine displays Io resource requirements list. Arguments: IoList - supplies a pointer to the Io resource requirements list to be displayed. Return Value: None. --*/ { PIO_RESOURCE_LIST resList; PIO_RESOURCE_DESCRIPTOR resDesc; ULONG listCount, count, i, j; if (IoList == NULL) { return; } DebugPrint((DEBUG_RESOURCE, "Pnp Bios IO Resource Requirements List for Slot %x -\n", IoList->SlotNumber )); DebugPrint((DEBUG_RESOURCE, " List Count = %x, Bus Number = %x\n", IoList->AlternativeLists, IoList->BusNumber )); listCount = IoList->AlternativeLists; resList = &IoList->List[0]; for (i = 0; i < listCount; i++) { DebugPrint((DEBUG_RESOURCE, " Version = %x, Revision = %x, Desc count = %x\n", resList->Version, resList->Revision, resList->Count )); resDesc = &resList->Descriptors[0]; count = resList->Count; for (j = 0; j < count; j++) { PipDumpIoResourceDescriptor(" ", resDesc); resDesc++; } resList = (PIO_RESOURCE_LIST) resDesc; } } VOID PipDumpCmResourceDescriptor ( IN PUCHAR Indent, IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc ) /*++ Routine Description: This routine processes a IO_RESOURCE_DESCRIPTOR and displays it. Arguments: Indent - # char of indentation. Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed. Return Value: None. --*/ { switch (Desc->Type) { case CmResourceTypePort: DebugPrint (( DEBUG_RESOURCE, "%sIO Start: %x:%08x, Length: %x\n", Indent, Desc->u.Port.Start.HighPart, Desc->u.Port.Start.LowPart, Desc->u.Port.Length )); break; case CmResourceTypeMemory: DebugPrint (( DEBUG_RESOURCE, "%sMEM Start: %x:%08x, Length: %x\n", Indent, Desc->u.Memory.Start.HighPart, Desc->u.Memory.Start.LowPart, Desc->u.Memory.Length )); break; case CmResourceTypeInterrupt: DebugPrint (( DEBUG_RESOURCE, "%sINT Level: %x, Vector: %x, Affinity: %x\n", Indent, Desc->u.Interrupt.Level, Desc->u.Interrupt.Vector, Desc->u.Interrupt.Affinity )); break; case CmResourceTypeDma: DebugPrint (( DEBUG_RESOURCE, "%sDMA Channel: %x, Port: %x\n", Indent, Desc->u.Dma.Channel, Desc->u.Dma.Port )); break; } } VOID PipDumpCmResourceList ( IN PCM_RESOURCE_LIST CmList ) /*++ Routine Description: This routine displays CM resource list. Arguments: CmList - supplies a pointer to CM resource list Return Value: None. --*/ { PCM_FULL_RESOURCE_DESCRIPTOR fullDesc; PCM_PARTIAL_RESOURCE_LIST partialDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; ULONG count, i; if (CmList) { fullDesc = &CmList->List[0]; DebugPrint((DEBUG_RESOURCE, "Pnp Bios Cm Resource List -\n" )); DebugPrint((DEBUG_RESOURCE, " List Count = %x, Bus Number = %x\n", CmList->Count, fullDesc->BusNumber )); partialDesc = &fullDesc->PartialResourceList; DebugPrint((DEBUG_RESOURCE, " Version = %x, Revision = %x, Desc count = %x\n", partialDesc->Version, partialDesc->Revision, partialDesc->Count )); count = partialDesc->Count; desc = &partialDesc->PartialDescriptors[0]; for (i = 0; i < count; i++) { PipDumpCmResourceDescriptor(" ", desc); desc++; } } }