/*++ Copyright (c) 1995-2000 Microsoft Corporation Module Name: devres.c Abstract: This module contains the high level device resources support routines. Author: Shie-Lin Tzong (shielint) July-27-1995 Environment: Kernel mode only. Revision History: --*/ #include "busp.h" #include "pnpisa.h" #include "pbios.h" #include "pnpcvrt.h" #if ISOLATE_CARDS #define IDBG 0 #if 0 NTSTATUS PipFilterResourceRequirementsList( IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources ); #endif PIO_RESOURCE_REQUIREMENTS_LIST PipCmResourcesToIoResources ( IN PCM_RESOURCE_LIST CmResourceList ); NTSTATUS PipMergeResourceRequirementsLists ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1, IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList ); NTSTATUS PipBuildBootResourceRequirementsList ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoList, IN PCM_RESOURCE_LIST CmList, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList, OUT PBOOLEAN ExactMatch ); VOID PipMergeBootResourcesToRequirementsList( PDEVICE_INFORMATION DeviceInfo, PCM_RESOURCE_LIST BootResources, PIO_RESOURCE_REQUIREMENTS_LIST *IoResources ); #pragma alloc_text(PAGE, PipGetCardIdentifier) #pragma alloc_text(PAGE, PipGetFunctionIdentifier) #pragma alloc_text(PAGE, PipGetCompatibleDeviceId) #pragma alloc_text(PAGE, PipQueryDeviceId) #pragma alloc_text(PAGE, PipQueryDeviceUniqueId) //#pragma alloc_text(PAGE, PipQueryDeviceResources) #pragma alloc_text(PAGE, PipQueryDeviceResourceRequirements) //#pragma alloc_text(PAGE, PipFilterResourceRequirementsList) #pragma alloc_text(PAGE, PipCmResourcesToIoResources) #pragma alloc_text(PAGE, PipMergeResourceRequirementsLists) #pragma alloc_text(PAGE, PipBuildBootResourceRequirementsList) #pragma alloc_text(PAGE, PipMergeBootResourcesToRequirementsList) //#pragma alloc_text(PAGE, PipSetDeviceResources) NTSTATUS PipGetCardIdentifier ( PUCHAR CardData, PWCHAR *Buffer, PULONG BufferLength ) /*++ Routine Description: This function returns the identifier for a pnpisa card. Arguments: CardData - supplies a pointer to the pnp isa device data. Buffer - supplies a pointer to variable to receive a pointer to the Id. BufferLength - supplies a pointer to a variable to receive the size of the id buffer. Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_SUCCESS; UCHAR tag; LONG size, length; UNICODE_STRING unicodeString; ANSI_STRING ansiString; PCHAR ansiBuffer; *Buffer = NULL; *BufferLength = 0; if (CardData == NULL) { return status; } tag = *CardData; // // Make sure CardData does *NOT* point to a Logical Device Id tag // if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) { DbgPrint("PipGetCardIdentifier: CardData is at a Logical Id tag\n"); return status; } // // Find the resource descriptor which describle identifier string // do { // // Do we find the identifer resource tag? // if (tag == TAG_ANSI_ID) { CardData++; length = *(USHORT UNALIGNED *)CardData; CardData += 2; ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1); if (ansiBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlMoveMemory(ansiBuffer, CardData, length); ansiBuffer[length] = 0; RtlInitAnsiString(&ansiString, ansiBuffer); status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); ExFreePool(ansiBuffer); if (!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } *Buffer = unicodeString.Buffer; *BufferLength = unicodeString.Length + sizeof(WCHAR); break; } // // Determine the size of the BIOS resource descriptor and // advance to next resource descriptor. // if (!(tag & LARGE_RESOURCE_TAG)) { size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); size += 1; // length of small tag } else { size = *(USHORT UNALIGNED *)(CardData + 1); size += 3; // length of large tag } CardData += size; tag = *CardData; } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); return status; } NTSTATUS PipGetFunctionIdentifier ( PUCHAR DeviceData, PWCHAR *Buffer, PULONG BufferLength ) /*++ Routine Description: This function returns the desired pnp isa identifier for the specified DeviceData/LogicalFunction. The Identifier for a logical function is optional. If no Identifier available , Buffer is set to NULL. Arguments: DeviceData - supplies a pointer to the pnp isa device data. Buffer - supplies a pointer to variable to receive a pointer to the Id. BufferLength - supplies a pointer to a variable to receive the size of the id buffer. Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_SUCCESS; UCHAR tag; LONG size, length; UNICODE_STRING unicodeString; ANSI_STRING ansiString; PCHAR ansiBuffer; *Buffer = NULL; *BufferLength = 0; if (DeviceData==NULL) { return status; } tag = *DeviceData; #if DBG // // Make sure device data points to Logical Device Id tag // if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { DbgPrint("PipGetFunctionIdentifier: DeviceData is not at a Logical Id tag\n"); } #endif // // Skip all the resource descriptors to find compatible Id descriptor // do { // // Determine the size of the BIOS resource descriptor and // advance to next resource descriptor. // if (!(tag & LARGE_RESOURCE_TAG)) { size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); size += 1; // length of small tag } else { size = *(USHORT UNALIGNED *)(DeviceData + 1); size += 3; // length of large tag } DeviceData += size; tag = *DeviceData; // // Do we find the identifer resource tag? // if (tag == TAG_ANSI_ID) { DeviceData++; length = *(USHORT UNALIGNED *)DeviceData; DeviceData += 2; ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1); if (ansiBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlMoveMemory(ansiBuffer, DeviceData, length); ansiBuffer[length] = 0; RtlInitAnsiString(&ansiString, ansiBuffer); status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); ExFreePool(ansiBuffer); if (!NT_SUCCESS(status)) { status = STATUS_INSUFFICIENT_RESOURCES; break; } *Buffer = unicodeString.Buffer; *BufferLength = unicodeString.Length + sizeof(WCHAR); break; } } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); return status; } NTSTATUS PipGetCompatibleDeviceId ( PUCHAR DeviceData, ULONG IdIndex, PWCHAR *Buffer ) /*++ Routine Description: This function returns the desired pnp isa id for the specified DeviceData and Id index. If Id index = 0, the Hardware ID will be return; if id index = n, the Nth compatible id will be returned. Arguments: DeviceData - supplies a pointer to the pnp isa device data. IdIndex - supplies the index of the compatible id desired. Buffer - supplies a pointer to variable to receive a pointer to the compatible Id. Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_NO_MORE_ENTRIES; UCHAR tag; ULONG count = 0,length; LONG size; UNICODE_STRING unicodeString; ANSI_STRING ansiString; UCHAR eisaId[8]; ULONG id; // // Bail out BEFORE we touch the device data for the RDP // if (IdIndex == -1) { length = 2* sizeof(WCHAR); *Buffer = (PWCHAR) ExAllocatePool(PagedPool, length); if (*Buffer) { RtlZeroMemory (*Buffer,length); }else { return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; } tag = *DeviceData; #if DBG // // Make sure device data points to Logical Device Id tag // if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) { DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n"); } #endif if (IdIndex == 0) { // // Caller is asking for hardware id // DeviceData++; // Skip tag id = *(ULONG UNALIGNED *)DeviceData; status = STATUS_SUCCESS; } else { // // caller is asking for compatible id // IdIndex--; // // Skip all the resource descriptors to find compatible Id descriptor // do { // // Determine the size of the BIOS resource descriptor and // advance to next resource descriptor. // if (!(tag & LARGE_RESOURCE_TAG)) { size = (USHORT)(tag & SMALL_TAG_SIZE_MASK); size += 1; // length of small tag } else { size = *(USHORT UNALIGNED *)(DeviceData + 1); size += 3; // length of large tag } DeviceData += size; tag = *DeviceData; // // Do we reach the compatible ID descriptor? // if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) { if (count == IdIndex) { id = *(ULONG UNALIGNED *)(DeviceData + 1); status = STATUS_SUCCESS; break; } else { count++; } } } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)); } if (NT_SUCCESS(status)) { PipDecompressEisaId(id, eisaId); RtlInitAnsiString(&ansiString, eisaId); status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); if (!NT_SUCCESS(status)) { return status; } *Buffer = (PWCHAR)ExAllocatePool ( PagedPool, sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length ); if (*Buffer) { swprintf(*Buffer, L"*%s", unicodeString.Buffer); } else { status = STATUS_INSUFFICIENT_RESOURCES; } RtlFreeUnicodeString(&unicodeString); } return status; } NTSTATUS PipQueryDeviceUniqueId ( PDEVICE_INFORMATION DeviceInfo, PWCHAR *DeviceId ) /*++ Routine Description: This function returns the unique id for the particular device. Arguments: DeviceData - Device data information for the specificied device. DeviceId - supplies a pointer to a variable to receive device id. Return Value: NTSTATUS code. --*/ { NTSTATUS status = STATUS_SUCCESS; // // Set up device's unique id. // device unique id = SerialNumber of the card // *DeviceId = (PWCHAR)ExAllocatePool ( PagedPool, (8 + 1) * sizeof(WCHAR) // serial number + null ); if (*DeviceId) { if (DeviceInfo->Flags & DF_READ_DATA_PORT) { // // Override the unique ID for the RDP // swprintf (*DeviceId, L"0" ); } else { swprintf (*DeviceId, L"%01X", ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber ); } #if IDBG { ANSI_STRING ansiString; UNICODE_STRING unicodeString; RtlInitUnicodeString(&unicodeString, *DeviceId); RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE); DbgPrint("PnpIsa: return Unique Id = %s\n", ansiString.Buffer); RtlFreeAnsiString(&ansiString); } #endif } else { status = STATUS_INSUFFICIENT_RESOURCES; } return status; } NTSTATUS PipQueryDeviceId ( PDEVICE_INFORMATION DeviceInfo, PWCHAR *DeviceId, ULONG IdIndex ) /*++ Routine Description: This function returns the device id for the particular device. Arguments: DeviceInfo - Device information for the specificied device. DeviceId - supplies a pointer to a variable to receive the device id. IdIndex - specifies device id or compatible id (0 - device id) Return Value: NTSTATUS code. --*/ { NTSTATUS status = STATUS_SUCCESS; PWSTR format; ULONG size,length; UCHAR eisaId[8]; UNICODE_STRING unicodeString; ANSI_STRING ansiString; // // Bail out BEFORE we touch the device data for the RDP // if (DeviceInfo->Flags & DF_READ_DATA_PORT) { length = (sizeof (wReadDataPort)+ + sizeof(WCHAR) +sizeof (L"ISAPNP\\")); *DeviceId = (PWCHAR) ExAllocatePool(PagedPool, length); if (*DeviceId) { _snwprintf(*DeviceId, length, L"ISAPNP\\%s",wReadDataPort); } else { return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; } // // Set up device's id. // device id = VenderId + Logical device number // if (DeviceInfo->CardInformation->NumberLogicalDevices == 1) { format = L"ISAPNP\\%s"; size = sizeof(L"ISAPNP\\*") + sizeof(WCHAR); } else { format = L"ISAPNP\\%s_DEV%04X"; size = sizeof(L"ISAPNP\\_DEV") + 4 * sizeof(WCHAR) + sizeof(WCHAR); } PipDecompressEisaId( ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->VenderId, eisaId ); RtlInitAnsiString(&ansiString, eisaId); status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE); if (!NT_SUCCESS(status)) { return STATUS_INSUFFICIENT_RESOURCES; } size += unicodeString.Length; *DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size); if (*DeviceId) { swprintf (*DeviceId, format, unicodeString.Buffer, DeviceInfo->LogicalDeviceNumber ); #if IDBG { ANSI_STRING dbgAnsiString; UNICODE_STRING dbgUnicodeString; RtlInitUnicodeString(&dbgUnicodeString, *DeviceId); RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE); DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer); RtlFreeAnsiString(&dbgAnsiString); } #endif } else { status = STATUS_INSUFFICIENT_RESOURCES; } RtlFreeUnicodeString(&unicodeString); return status; } NTSTATUS PipQueryDeviceResources ( PDEVICE_INFORMATION DeviceInfo, ULONG BusNumber, PCM_RESOURCE_LIST *CmResources, ULONG *Size ) /*++ Routine Description: This function returns the bus resources being used by the specified device Arguments: DeviceInfo - Device information for the specificied slot BusNumber - should always be 0 CmResources - supplies a pointer to a variable to receive the device resource data. Size - Supplies a pointer to avariable to receive the size of device resource data. Return Value: NTSTATUS code. --*/ { ULONG length; NTSTATUS status = STATUS_SUCCESS; PCM_RESOURCE_LIST cmResources; *CmResources = NULL; *Size = 0; if (DeviceInfo->BootResources){ // && DeviceInfo->LogConfHandle) { *CmResources = ExAllocatePool(PagedPool, DeviceInfo->BootResourcesLength); if (*CmResources) { RtlMoveMemory(*CmResources, DeviceInfo->BootResources, DeviceInfo->BootResourcesLength); *Size = DeviceInfo->BootResourcesLength; } else { status = STATUS_INSUFFICIENT_RESOURCES; } } return status; } NTSTATUS PipQueryDeviceResourceRequirements ( PDEVICE_INFORMATION DeviceInfo, ULONG BusNumber, ULONG Slot, PCM_RESOURCE_LIST BootResources, USHORT IrqFlags, PIO_RESOURCE_REQUIREMENTS_LIST *IoResources, ULONG *Size ) /*++ Routine Description: This function returns the possible bus resources that this device may be satisfied with. Arguments: DeviceData - Device data information for the specificied slot BusNumber - Supplies the bus number Slot - supplies the slot number of the BusNumber IoResources - supplies a pointer to a variable to receive the IO resource requirements list Return Value: The device control is completed --*/ { ULONG length = 0; NTSTATUS status; PUCHAR deviceData; PIO_RESOURCE_REQUIREMENTS_LIST ioResources; deviceData = DeviceInfo->DeviceData; status = PpBiosResourcesToNtResources ( BusNumber, Slot, &deviceData, 0, &ioResources, &length ); // // Return results // if (NT_SUCCESS(status)) { if (length == 0) { ioResources = NULL; // Just to make sure } else { // * Set the irq level/edge requirements to be consistent // with the our determination earlier as to what is // likely to work for this card // // * Make requirements reflect boot configed ROM if any. // // Make these changes across all alternatives. PipTrimResourceRequirements(&ioResources, IrqFlags, BootResources); //PipFilterResourceRequirementsList(&ioResources); PipMergeBootResourcesToRequirementsList(DeviceInfo, BootResources, &ioResources ); ASSERT(ioResources); length = ioResources->ListSize; } *IoResources = ioResources; *Size = length; #if IDBG PipDumpIoResourceList(ioResources); #endif } return status; } NTSTATUS PipSetDeviceResources ( PDEVICE_INFORMATION DeviceInfo, PCM_RESOURCE_LIST CmResources ) /*++ Routine Description: This function configures the device to the specified device setttings Arguments: DeviceInfo - Device information for the specificied slot CmResources - pointer to the desired resource list Return Value: NTSTATUS code. --*/ { NTSTATUS status = STATUS_SUCCESS; if (CmResources && (CmResources->Count != 0)) { // // Set resource settings for the device // status = PipWriteDeviceResources ( DeviceInfo->DeviceData, (PCM_RESOURCE_LIST) CmResources ); // // Put all cards into wait for key state. // DebugPrint((DEBUG_STATE, "SetDeviceResources CSN %d/LDN %d\n", DeviceInfo->CardInformation->CardSelectNumber, DeviceInfo->LogicalDeviceNumber)); // // Delay some time for the newly set resources to be avaiable. // This is required on some slow machines. // KeStallExecutionProcessor(10000); // delay 10 ms } return status; } #if 0 NTSTATUS PipFilterResourceRequirementsList( IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources ) /*++ Routine Description: This routine removes the length zero entries from the input Io resource requirements list. Parameters: IoResources - supplies a pointer to an address to Io resource requirements List. Return Value: NTSTATUS code. --*/ { NTSTATUS status; PIO_RESOURCE_REQUIREMENTS_LIST oldIoResources = *IoResources, newIoResources; PIO_RESOURCE_LIST oldIoResourceList = oldIoResources->List; PIO_RESOURCE_LIST newIoResourceList; PIO_RESOURCE_DESCRIPTOR oldIoResourceDescriptor, newIoResourceDescriptor; PIO_RESOURCE_DESCRIPTOR oldIoResourceDescriptorEnd; #if DBG PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptorEnd; #endif LONG IoResourceListCount = (LONG) oldIoResources->AlternativeLists; ULONG size; PAGED_CODE(); // // Make sure there is some resource requirements to be fulfilled. // if (IoResourceListCount == 0) { return STATUS_SUCCESS; } size = oldIoResources->ListSize; // // Check if there is any length zero descriptor // while (--IoResourceListCount >= 0) { oldIoResourceDescriptor = oldIoResourceList->Descriptors; oldIoResourceDescriptorEnd = oldIoResourceDescriptor + oldIoResourceList->Count; while (oldIoResourceDescriptor < oldIoResourceDescriptorEnd) { switch (oldIoResourceDescriptor->Type) { case CmResourceTypePort: case CmResourceTypeMemory: if (oldIoResourceDescriptor->u.Generic.Length == 0) { size -= sizeof(IO_RESOURCE_DESCRIPTOR); } break; default: break; } oldIoResourceDescriptor++; } ASSERT(oldIoResourceDescriptor == oldIoResourceDescriptorEnd); oldIoResourceList = (PIO_RESOURCE_LIST) oldIoResourceDescriptorEnd; } if (size == oldIoResources->ListSize) { return STATUS_SUCCESS; } // // We have length zero descriptor. Rebuild the resources requirements list // newIoResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool ( PagedPool, size); if (newIoResources == NULL) { return STATUS_NO_MEMORY; } else { RtlMoveMemory(newIoResources, oldIoResources, FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List) ); newIoResources->ListSize = size; newIoResourceList = newIoResources->List; #if DBG newIoResourceDescriptorEnd = (PIO_RESOURCE_DESCRIPTOR) ((PUCHAR)newIoResourceList + size); #endif } // // filter the IO ResReq list // oldIoResourceList = oldIoResources->List; IoResourceListCount = (LONG) oldIoResources->AlternativeLists; while (--IoResourceListCount >= 0) { newIoResourceList->Version = oldIoResourceList->Version; newIoResourceList->Revision = oldIoResourceList->Revision; newIoResourceList->Count = oldIoResourceList->Count; oldIoResourceDescriptor = oldIoResourceList->Descriptors; newIoResourceDescriptor = newIoResourceList->Descriptors; oldIoResourceDescriptorEnd = oldIoResourceDescriptor + oldIoResourceList->Count; while (oldIoResourceDescriptor < oldIoResourceDescriptorEnd) { switch (oldIoResourceDescriptor->Type) { case CmResourceTypePort: case CmResourceTypeMemory: if (oldIoResourceDescriptor->u.Generic.Length == 0) { newIoResourceList->Count--; break; } default: *newIoResourceDescriptor = *oldIoResourceDescriptor; newIoResourceDescriptor++; break; } oldIoResourceDescriptor++; } ASSERT(oldIoResourceDescriptor == oldIoResourceDescriptorEnd); oldIoResourceList = (PIO_RESOURCE_LIST) oldIoResourceDescriptor; newIoResourceList = (PIO_RESOURCE_LIST) newIoResourceDescriptor; } ASSERT(newIoResourceDescriptor <= newIoResourceDescriptorEnd); ExFreePool(oldIoResources); *IoResources = newIoResources; return STATUS_SUCCESS; } #endif PIO_RESOURCE_REQUIREMENTS_LIST PipCmResourcesToIoResources ( IN PCM_RESOURCE_LIST CmResourceList ) /*++ Routine Description: This routines converts the input CmResourceList to IO_RESOURCE_REQUIREMENTS_LIST. Arguments: CmResourceList - the cm resource list to convert. Return Value: returns a IO_RESOURCE_REQUIREMENTS_LISTST if succeeds. Otherwise a NULL value is returned. --*/ { PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList; ULONG count = 0, size, i, j; PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc; PIO_RESOURCE_DESCRIPTOR ioDesc; // // First determine number of descriptors required. // cmFullDesc = &CmResourceList->List[0]; for (i = 0; i < CmResourceList->Count; i++) { count += cmFullDesc->PartialResourceList.Count; cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0]; for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) { size = 0; switch (cmPartDesc->Type) { case CmResourceTypeDeviceSpecific: size = cmPartDesc->u.DeviceSpecificData.DataSize; count--; break; } cmPartDesc++; cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size); } cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc; } if (count == 0) { return NULL; } // // Count the extra descriptors for InterfaceType and BusNumber information. // count += CmResourceList->Count - 1; // // Allocate heap space for IO RESOURCE REQUIREMENTS LIST // count++; // add one for CmResourceTypeConfigData ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool( PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + count * sizeof(IO_RESOURCE_DESCRIPTOR) ); if (!ioResReqList) { return NULL; } // // Parse the cm resource descriptor and build its corresponding IO resource descriptor // ioResReqList->InterfaceType = CmResourceList->List[0].InterfaceType; ioResReqList->BusNumber = CmResourceList->List[0].BusNumber; ioResReqList->SlotNumber = 0; ioResReqList->Reserved[0] = 0; ioResReqList->Reserved[1] = 0; ioResReqList->Reserved[2] = 0; ioResReqList->AlternativeLists = 1; ioResReqList->List[0].Version = 1; ioResReqList->List[0].Revision = 1; ioResReqList->List[0].Count = count; // // Generate a CmResourceTypeConfigData descriptor // ioDesc = &ioResReqList->List[0].Descriptors[0]; ioDesc->Option = IO_RESOURCE_PREFERRED; ioDesc->Type = CmResourceTypeConfigData; ioDesc->ShareDisposition = CmResourceShareShared; ioDesc->Flags = 0; ioDesc->Spare1 = 0; ioDesc->Spare2 = 0; ioDesc->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY; ioDesc++; cmFullDesc = &CmResourceList->List[0]; for (i = 0; i < CmResourceList->Count; i++) { cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0]; for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) { ioDesc->Option = IO_RESOURCE_PREFERRED; ioDesc->Type = cmPartDesc->Type; ioDesc->ShareDisposition = cmPartDesc->ShareDisposition; ioDesc->Flags = cmPartDesc->Flags; ioDesc->Spare1 = 0; ioDesc->Spare2 = 0; size = 0; switch (cmPartDesc->Type) { case CmResourceTypePort: ioDesc->u.Port.MinimumAddress = cmPartDesc->u.Port.Start; ioDesc->u.Port.MaximumAddress.QuadPart = cmPartDesc->u.Port.Start.QuadPart + cmPartDesc->u.Port.Length - 1; ioDesc->u.Port.Alignment = 1; ioDesc->u.Port.Length = cmPartDesc->u.Port.Length; ioDesc++; break; case CmResourceTypeInterrupt: #if defined(_X86_) ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector = cmPartDesc->u.Interrupt.Level; #else ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector = cmPartDesc->u.Interrupt.Vector; #endif ioDesc++; break; case CmResourceTypeMemory: ioDesc->u.Memory.MinimumAddress = cmPartDesc->u.Memory.Start; ioDesc->u.Memory.MaximumAddress.QuadPart = cmPartDesc->u.Memory.Start.QuadPart + cmPartDesc->u.Memory.Length - 1; ioDesc->u.Memory.Alignment = 1; ioDesc->u.Memory.Length = cmPartDesc->u.Memory.Length; ioDesc++; break; case CmResourceTypeDma: ioDesc->u.Dma.MinimumChannel = cmPartDesc->u.Dma.Channel; ioDesc->u.Dma.MaximumChannel = cmPartDesc->u.Dma.Channel; ioDesc++; break; case CmResourceTypeDeviceSpecific: size = cmPartDesc->u.DeviceSpecificData.DataSize; break; case CmResourceTypeBusNumber: ioDesc->u.BusNumber.MinBusNumber = cmPartDesc->u.BusNumber.Start; ioDesc->u.BusNumber.MaxBusNumber = cmPartDesc->u.BusNumber.Start + cmPartDesc->u.BusNumber.Length - 1; ioDesc->u.BusNumber.Length = cmPartDesc->u.BusNumber.Length; ioDesc++; break; default: ioDesc->u.DevicePrivate.Data[0] = cmPartDesc->u.DevicePrivate.Data[0]; ioDesc->u.DevicePrivate.Data[1] = cmPartDesc->u.DevicePrivate.Data[1]; ioDesc->u.DevicePrivate.Data[2] = cmPartDesc->u.DevicePrivate.Data[2]; ioDesc++; break; } cmPartDesc++; cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size); } cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc; } ioResReqList->ListSize = (ULONG)((ULONG_PTR)ioDesc - (ULONG_PTR)ioResReqList); return ioResReqList; } NTSTATUS PipMergeResourceRequirementsLists ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1, IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList ) /*++ Routine Description: This routines merges two IoLists into one. Arguments: IoList1 - supplies the pointer to the first IoResourceRequirementsList IoList2 - supplies the pointer to the second IoResourceRequirementsList MergedList - Supplies a variable to receive the merged resource requirements list. Return Value: A NTSTATUS code to indicate the result of the function. --*/ { NTSTATUS status = STATUS_SUCCESS; PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList; ULONG size; PUCHAR p; PAGED_CODE(); *MergedList = NULL; // // First handle the easy cases that both IO Lists are empty or any one of // them is empty. // if ((IoList1 == NULL || IoList1->AlternativeLists == 0) && (IoList2 == NULL || IoList2->AlternativeLists == 0)) { return status; } ioList = NULL; if (IoList1 == NULL || IoList1->AlternativeLists == 0) { ioList = IoList2; } else if (IoList2 == NULL || IoList2->AlternativeLists == 0) { ioList = IoList1; } if (ioList) { newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, ioList->ListSize); if (newList == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlMoveMemory(newList, ioList, ioList->ListSize); *MergedList = newList; return status; } // // Do real work... // size = IoList1->ListSize + IoList2->ListSize - FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List); newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool( PagedPool, size ); if (newList == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } p = (PUCHAR)newList; RtlMoveMemory(p, IoList1, IoList1->ListSize); p += IoList1->ListSize; RtlMoveMemory(p, &IoList2->List[0], size - IoList1->ListSize ); newList->ListSize = size; newList->AlternativeLists += IoList2->AlternativeLists; *MergedList = newList; return status; } VOID PipMergeBootResourcesToRequirementsList( PDEVICE_INFORMATION DeviceInfo, PCM_RESOURCE_LIST BootResources, PIO_RESOURCE_REQUIREMENTS_LIST *IoResources ) /*++ Routine Description: This routines merges two IoLists into one. Arguments: IoList1 - supplies the pointer to the first IoResourceRequirementsList IoList2 - supplies the pointer to the second IoResourceRequirementsList MergedList - Supplies a variable to receive the merged resource requirements list. Return Value: A NTSTATUS code to indicate the result of the function. --*/ { NTSTATUS status = STATUS_SUCCESS; PIO_RESOURCE_REQUIREMENTS_LIST ioResources = *IoResources, bootResReq = NULL, newList = NULL; BOOLEAN exactMatch; PAGED_CODE(); if (DeviceInfo->BootResources) { PipBuildBootResourceRequirementsList (ioResources, BootResources, &bootResReq, &exactMatch); if (bootResReq) { if (exactMatch && ioResources->AlternativeLists == 1) { ExFreePool(ioResources); *IoResources = bootResReq; } else { PipMergeResourceRequirementsLists (bootResReq, ioResources, &newList); if (newList) { ExFreePool(ioResources); *IoResources = newList; } ExFreePool(bootResReq); } } } } NTSTATUS PipBuildBootResourceRequirementsList ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoList, IN PCM_RESOURCE_LIST CmList, IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList, OUT PBOOLEAN ExactMatch ) /*++ Routine Description: This routines adjusts the input IoList based on input BootConfig. Arguments: IoList - supplies the pointer to an IoResourceRequirementsList CmList - supplies the pointer to a BootConfig. FilteredList - Supplies a variable to receive the filtered resource requirements list. Return Value: A NTSTATUS code to indicate the result of the function. --*/ { NTSTATUS status; PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList; PIO_RESOURCE_LIST ioResourceList, newIoResourceList; PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor, ioResourceDescriptorEnd; PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptor, configDataDescriptor; LONG ioResourceDescriptorCount = 0; USHORT version; PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor; ULONG cmDescriptorCount = 0; ULONG size, i, j, oldCount, phase; LONG k, alternativeLists; BOOLEAN exactMatch; PAGED_CODE(); *FilteredList = NULL; *ExactMatch = FALSE; // // Make sure there is some resource requirements to be filtered. // If no, we will convert CmList/BootConfig to an IoResourceRequirementsList // if (IoList == NULL || IoList->AlternativeLists == 0) { if (CmList && CmList->Count != 0) { *FilteredList = PipCmResourcesToIoResources (CmList); } return STATUS_SUCCESS; } // // Make a copy of the Io Resource Requirements List // ioList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, IoList->ListSize); if (ioList == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlMoveMemory(ioList, IoList, IoList->ListSize); // // If there is no BootConfig, simply return the copy of the input Io list. // if (CmList == NULL || CmList->Count == 0) { *FilteredList = ioList; return STATUS_SUCCESS; } // // First determine minimum number of descriptors required. // cmFullDesc = &CmList->List[0]; for (i = 0; i < CmList->Count; i++) { cmDescriptorCount += cmFullDesc->PartialResourceList.Count; cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0]; for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) { size = 0; switch (cmDescriptor->Type) { case CmResourceTypeConfigData: case CmResourceTypeDevicePrivate: cmDescriptorCount--; break; case CmResourceTypeDeviceSpecific: size = cmDescriptor->u.DeviceSpecificData.DataSize; cmDescriptorCount--; break; default: // // Invalid cmresource list. Ignore it and use io resources // if (cmDescriptor->Type == CmResourceTypeNull || cmDescriptor->Type >= CmResourceTypeMaximum) { cmDescriptorCount--; } } cmDescriptor++; cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size); } cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor; } if (cmDescriptorCount == 0) { *FilteredList = ioList; return STATUS_SUCCESS; } // // cmDescriptorCount is the number of BootConfig Descriptors needs. // // For each IO list Alternative ... // ioResourceList = ioList->List; k = ioList->AlternativeLists; while (--k >= 0) { ioResourceDescriptor = ioResourceList->Descriptors; ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count; while (ioResourceDescriptor < ioResourceDescriptorEnd) { ioResourceDescriptor->Spare1 = 0; ioResourceDescriptor++; } ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd; } ioResourceList = ioList->List; k = alternativeLists = ioList->AlternativeLists; while (--k >= 0) { version = ioResourceList->Version; if (version == 0xffff) { // Convert bogus version to valid number version = 1; } // // We use Version field to store number of BootConfig found. // Count field to store new number of descriptor in the alternative list. // ioResourceList->Version = 0; oldCount = ioResourceList->Count; ioResourceDescriptor = ioResourceList->Descriptors; ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count; if (ioResourceDescriptor == ioResourceDescriptorEnd) { // // An alternative list with zero descriptor count // ioResourceList->Version = 0xffff; // Mark it as invalid ioList->AlternativeLists--; continue; } exactMatch = TRUE; // // For each Cm Resource descriptor ... except DevicePrivate and // DeviceSpecific... // cmFullDesc = &CmList->List[0]; for (i = 0; i < CmList->Count; i++) { cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0]; for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) { size = 0; switch (cmDescriptor->Type) { case CmResourceTypeDevicePrivate: break; case CmResourceTypeDeviceSpecific: size = cmDescriptor->u.DeviceSpecificData.DataSize; break; default: if (cmDescriptor->Type == CmResourceTypeNull || cmDescriptor->Type >= CmResourceTypeMaximum) { break; } // // Check CmDescriptor against current Io Alternative list // for (phase = 0; phase < 2; phase++) { ioResourceDescriptor = ioResourceList->Descriptors; while (ioResourceDescriptor < ioResourceDescriptorEnd) { if ((ioResourceDescriptor->Type == cmDescriptor->Type) && (ioResourceDescriptor->Spare1 == 0)) { ULONGLONG min1, max1, min2, max2; ULONG len1 = 1, len2 = 1, align1, align2; UCHAR share1, share2; share2 = ioResourceDescriptor->ShareDisposition; share1 = cmDescriptor->ShareDisposition; if ((share1 == CmResourceShareUndetermined) || (share1 > CmResourceShareShared)) { share1 = share2; } if ((share2 == CmResourceShareUndetermined) || (share2 > CmResourceShareShared)) { share2 = share1; } align1 = align2 = 1; switch (cmDescriptor->Type) { case CmResourceTypePort: case CmResourceTypeMemory: min1 = cmDescriptor->u.Port.Start.QuadPart; max1 = cmDescriptor->u.Port.Start.QuadPart + cmDescriptor->u.Port.Length - 1; len1 = cmDescriptor->u.Port.Length; min2 = ioResourceDescriptor->u.Port.MinimumAddress.QuadPart; max2 = ioResourceDescriptor->u.Port.MaximumAddress.QuadPart; len2 = ioResourceDescriptor->u.Port.Length; align2 = ioResourceDescriptor->u.Port.Alignment; break; case CmResourceTypeInterrupt: max1 = min1 = cmDescriptor->u.Interrupt.Vector; min2 = ioResourceDescriptor->u.Interrupt.MinimumVector; max2 = ioResourceDescriptor->u.Interrupt.MaximumVector; break; case CmResourceTypeDma: min1 = max1 =cmDescriptor->u.Dma.Channel; min2 = ioResourceDescriptor->u.Dma.MinimumChannel; max2 = ioResourceDescriptor->u.Dma.MaximumChannel; break; case CmResourceTypeBusNumber: min1 = cmDescriptor->u.BusNumber.Start; max1 = cmDescriptor->u.BusNumber.Start + cmDescriptor->u.BusNumber.Length - 1; len1 = cmDescriptor->u.BusNumber.Length; min2 = ioResourceDescriptor->u.BusNumber.MinBusNumber; max2 = ioResourceDescriptor->u.BusNumber.MaxBusNumber; len2 = ioResourceDescriptor->u.BusNumber.Length; break; default: ASSERT(0); break; } if (phase == 0) { if (share1 == share2 && min2 == min1 && max2 >= max1 && len2 >= len1) { // // For phase 0 match, we want near exact match... // if (max2 != max1) { exactMatch = FALSE; } ioResourceList->Version++; ioResourceDescriptor->Spare1 = 0x80; if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) { PIO_RESOURCE_DESCRIPTOR ioDesc; ioDesc = ioResourceDescriptor; ioDesc--; while (ioDesc >= ioResourceList->Descriptors) { ioDesc->Type = CmResourceTypeNull; ioResourceList->Count--; if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) { ioDesc--; } else { break; } } } ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED; if (ioResourceDescriptor->Type == CmResourceTypePort || ioResourceDescriptor->Type == CmResourceTypeMemory) { ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1; ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1; ioResourceDescriptor->u.Port.Alignment = 1; } else if (ioResourceDescriptor->Type == CmResourceTypeBusNumber) { ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1; ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1); } ioResourceDescriptor++; while (ioResourceDescriptor < ioResourceDescriptorEnd) { if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) { ioResourceDescriptor->Type = CmResourceTypeNull; ioResourceDescriptor++; ioResourceList->Count--; } else { break; } } phase = 1; // skip phase 1 break; } else { ioResourceDescriptor++; } } else { exactMatch = FALSE; if (share1 == share2 && min2 <= min1 && max2 >= max1 && len2 >= len1 && (min1 & (align2 - 1)) == 0) { // // Io range covers Cm range ... Change the Io range to what is specified // in BootConfig. // // switch (cmDescriptor->Type) { case CmResourceTypePort: case CmResourceTypeMemory: ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1; ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1; break; case CmResourceTypeInterrupt: case CmResourceTypeDma: ioResourceDescriptor->u.Interrupt.MinimumVector = (ULONG)min1; ioResourceDescriptor->u.Interrupt.MaximumVector = (ULONG)max1; break; case CmResourceTypeBusNumber: ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1; ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1); break; } ioResourceList->Version++; ioResourceDescriptor->Spare1 = 0x80; if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) { PIO_RESOURCE_DESCRIPTOR ioDesc; ioDesc = ioResourceDescriptor; ioDesc--; while (ioDesc >= ioResourceList->Descriptors) { ioDesc->Type = CmResourceTypeNull; ioResourceList->Count--; if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) { ioDesc--; } else { break; } } } ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED; ioResourceDescriptor++; while (ioResourceDescriptor < ioResourceDescriptorEnd) { if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) { ioResourceDescriptor->Type = CmResourceTypeNull; ioResourceList->Count--; ioResourceDescriptor++; } else { break; } } break; } else { ioResourceDescriptor++; } } } else { ioResourceDescriptor++; } } // Don't add any instruction after this ... } // phase } // switch // // Move to next Cm Descriptor // cmDescriptor++; cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size); } // // Move to next Cm List // cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor; } if (ioResourceList->Version != (USHORT)cmDescriptorCount) { // // If the current alternative list does not cover all the boot config // descriptors, make it as invalid. // ioResourceList->Version = 0xffff; ioList->AlternativeLists--; } else { ioResourceDescriptorCount += ioResourceList->Count; ioResourceList->Version = version; ioResourceList->Count = oldCount; // ++ single alternative list break; // ++ single alternative list } ioResourceList->Count = oldCount; // // Move to next Io alternative list. // ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd; } // // If there is not any valid alternative, convert CmList to Io list. // if (ioList->AlternativeLists == 0) { *FilteredList = PipCmResourcesToIoResources (CmList); ExFreePool(ioList); return STATUS_SUCCESS; } // // we have finished filtering the resource requirements list. Now allocate memory // and rebuild a new list. // size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + //sizeof(IO_RESOURCE_LIST) * (ioList->AlternativeLists - 1) + // ++ Single Alternative list sizeof(IO_RESOURCE_DESCRIPTOR) * (ioResourceDescriptorCount); newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size); if (newList == NULL) { ExFreePool(ioList); return STATUS_INSUFFICIENT_RESOURCES; } // // Walk through the io resource requirements list and pick up any valid descriptor. // newList->ListSize = size; newList->InterfaceType = CmList->List->InterfaceType; newList->BusNumber = CmList->List->BusNumber; newList->SlotNumber = ioList->SlotNumber; #if 0 // ++ Single Alternative list newList->AlternativeLists = ioList->AlternativeLists; #else newList->AlternativeLists = 1; #endif ioResourceList = ioList->List; newIoResourceList = newList->List; while (--alternativeLists >= 0) { ioResourceDescriptor = ioResourceList->Descriptors; ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count; if (ioResourceList->Version == 0xffff) { ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd; continue; } newIoResourceList->Version = ioResourceList->Version; newIoResourceList->Revision = ioResourceList->Revision; newIoResourceDescriptor = newIoResourceList->Descriptors; if (ioResourceDescriptor->Type != CmResourceTypeConfigData) { newIoResourceDescriptor->Option = IO_RESOURCE_PREFERRED; newIoResourceDescriptor->Type = CmResourceTypeConfigData; newIoResourceDescriptor->ShareDisposition = CmResourceShareShared; newIoResourceDescriptor->Flags = 0; newIoResourceDescriptor->Spare1 = 0; newIoResourceDescriptor->Spare2 = 0; newIoResourceDescriptor->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY; configDataDescriptor = newIoResourceDescriptor; newIoResourceDescriptor++; } else { newList->ListSize -= sizeof(IO_RESOURCE_DESCRIPTOR); configDataDescriptor = newIoResourceDescriptor; } while (ioResourceDescriptor < ioResourceDescriptorEnd) { if (ioResourceDescriptor->Type != CmResourceTypeNull) { *newIoResourceDescriptor = *ioResourceDescriptor; newIoResourceDescriptor++; } ioResourceDescriptor++; } newIoResourceList->Count = (ULONG)(newIoResourceDescriptor - newIoResourceList->Descriptors); configDataDescriptor->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY; break; } ASSERT((PUCHAR)newIoResourceDescriptor == ((PUCHAR)newList + newList->ListSize)); *FilteredList = newList; *ExactMatch = exactMatch; ExFreePool(ioList); return STATUS_SUCCESS; } PCM_PARTIAL_RESOURCE_DESCRIPTOR PipFindMatchingBootMemResource( IN ULONG Index, IN PIO_RESOURCE_DESCRIPTOR IoDesc, IN PCM_RESOURCE_LIST BootResources ) /*++ Routine Description: This routine finds boot resources that match the i/o descriptor Arguments: Index - Index of memory boot config resource the caller is interested in. IoDesc - I/O descriptor BootResources - boot config Return Value: A pointer to a matching descriptor in the boot config --*/ { PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc; ULONG count = 0, size, i, j, noMem; if (BootResources == NULL) { return NULL; } cmFullDesc = &BootResources->List[0]; for (i = 0; i < BootResources->Count; i++) { cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0]; noMem = 0; for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) { size = 0; if (cmPartDesc->Type == CmResourceTypeMemory) { if (((cmPartDesc->u.Memory.Start.QuadPart >= IoDesc->u.Memory.MinimumAddress.QuadPart) && ((cmPartDesc->u.Memory.Start.QuadPart + cmPartDesc->u.Memory.Length - 1) <= IoDesc->u.Memory.MaximumAddress.QuadPart)) && noMem == Index) { return cmPartDesc; } noMem++; } else if (cmPartDesc->Type == CmResourceTypeDeviceSpecific) { size = cmPartDesc->u.DeviceSpecificData.DataSize; } cmPartDesc++; cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size); } cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc; } return NULL; } NTSTATUS PipTrimResourceRequirements ( IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoList, IN USHORT IrqFlags, IN PCM_RESOURCE_LIST BootResources ) /*++ Routine Description: This routine: * adjusts the irq requirements level/edge to the value decided on in PipCheckBus() * adjusts the memory requirements to reflect the memory boot config. Arguments: IoList - supplies the pointer to an IoResourceRequirementsList IrqFlags - level/edge irq reuirements to be applied to all interrupt requirements in all alternatives. BootResources - Used as a reference. --*/ { PIO_RESOURCE_REQUIREMENTS_LIST newReqList; PIO_RESOURCE_LIST resList, newList; PIO_RESOURCE_DESCRIPTOR resDesc, newDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR bootDesc; ULONG listCount, i, j, pass, size, noMem; BOOLEAN goodAlt; if (IoList == NULL) { return STATUS_SUCCESS; } // The only way to create a new req list only if absolutely // necessary and make it the perfect size is perform this // operation in two passes. // 1. figure out how many alternatives will be eliminated and // compute size of new req list. if all of the alternatives // survived, return the original list (now modified) // // 2. construct new reqlist minus the bad alternatives. listCount = 0; size = 0; for (pass = 0; pass < 2; pass++) { if (pass == 0) { size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - sizeof(IO_RESOURCE_LIST); } else { newReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size); if (newReqList == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } *newReqList = **IoList; newReqList->ListSize = size; newReqList->AlternativeLists = listCount; newList = &newReqList->List[0]; } resList = &(*IoList)->List[0]; for (i = 0; i < (*IoList)->AlternativeLists; i++) { if (pass == 1) { *newList = *resList; newDesc = &newList->Descriptors[0]; } resDesc = &resList->Descriptors[0]; goodAlt = TRUE; noMem = 0; for (j = 0; j < resList->Count; j++) { if (resDesc->Type == CmResourceTypeInterrupt) { resDesc->Flags = IrqFlags; if (resDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) { resDesc->ShareDisposition = CmResourceShareDeviceExclusive; } } else if (resDesc->Type == CmResourceTypeMemory) { resDesc->Flags |= CM_RESOURCE_MEMORY_24; if (BootResources) { bootDesc = PipFindMatchingBootMemResource(noMem, resDesc, BootResources); // have matching boot config resource, can trim requirements if (bootDesc) { if (bootDesc->Flags & CM_RESOURCE_MEMORY_READ_ONLY) { // exact or inclusive ROM match is // converted into a fixed requirement. resDesc->u.Memory.MinimumAddress.QuadPart = bootDesc->u.Memory.Start.QuadPart; if (bootDesc->u.Memory.Length) { resDesc->u.Memory.MaximumAddress.QuadPart = bootDesc->u.Memory.Start.QuadPart + bootDesc->u.Memory.Length - 1; } else { resDesc->u.Memory.MaximumAddress.QuadPart = bootDesc->u.Memory.Start.QuadPart; } resDesc->u.Memory.Length = bootDesc->u.Memory.Length; resDesc->u.Memory.Alignment = 1; resDesc->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; } } else { goodAlt = FALSE; } } else { resDesc->Flags &= ~CM_RESOURCE_MEMORY_READ_ONLY; } noMem++; } if (pass == 1) { *newDesc = *resDesc; PipDumpIoResourceDescriptor(" ", newDesc); newDesc++; } resDesc++; } if (pass == 0) { if (goodAlt) { size += sizeof(IO_RESOURCE_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR) * (resList->Count - 1); listCount++; } } else { if (goodAlt) { newList = (PIO_RESOURCE_LIST) newDesc; } else { DebugPrint((DEBUG_RESOURCE, "An alternative trimmed off of reqlist\n")); } } resList = (PIO_RESOURCE_LIST) resDesc; } // If we have the same number of alternatives as before use // the use existing (modified in-place) requirements list if (!pass && (listCount == (*IoList)->AlternativeLists)) { return STATUS_SUCCESS; } // if all alternatives have been eliminated, then it is better // to use the existing requirements list than to hope to build // one out of the boot config alone. if (!pass && (listCount == 0)) { DebugPrint((DEBUG_RESOURCE, "All alternatives trimmed off of reqlist, going with original\n")); return STATUS_SUCCESS; } } ExFreePool(*IoList); *IoList = newReqList; return STATUS_SUCCESS; } #endif