diff options
Diffstat (limited to 'private/ntos/nthals/extender/pci/devres.c')
-rw-r--r-- | private/ntos/nthals/extender/pci/devres.c | 1139 |
1 files changed, 1139 insertions, 0 deletions
diff --git a/private/ntos/nthals/extender/pci/devres.c b/private/ntos/nthals/extender/pci/devres.c new file mode 100644 index 000000000..578c4ac46 --- /dev/null +++ b/private/ntos/nthals/extender/pci/devres.c @@ -0,0 +1,1139 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + devres.c + +Abstract: + + Device Resources + +Author: + + Ken Reneris (kenr) March-13-1885 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "pciport.h" + + +NTSTATUS +PcipQueryResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList + ); + +NTSTATUS +PcipSetResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PCM_RESOURCE_LIST ResourceList, + ULONG ListSize + ); + + +#pragma alloc_text(PAGE,PciCtlQueryDeviceId) +#pragma alloc_text(PAGE,PciCtlQueryDeviceUniqueId) +#pragma alloc_text(PAGE,PciCtlQueryDeviceResources) +#pragma alloc_text(PAGE,PciCtlQueryDeviceResourceRequirements) +#pragma alloc_text(PAGE,PciCtlSetDeviceResources) +#pragma alloc_text(PAGE,PciCtlAssignSlotResources) +#pragma alloc_text(PAGE,PcipQueryResourceRequirements) +#pragma alloc_text(PAGE,PcipSetResources) + + + + +VOID +PciCtlQueryDeviceId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns the device id for the particular slot. + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + NTSTATUS Status; + PPCI_COMMON_CONFIG PciData; + PWCHAR DeviceID; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + ULONG length; + ULONG IDNumber; + + PAGED_CODE(); + + // + // Read the PCI device's info + // + + PciData = (PPCI_COMMON_CONFIG) buffer; + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Determine which device ID the caller wants back + // + + IDNumber = *((PULONG) Context->DeviceControl.Buffer); + + // + // For PCI devices: + // ID #0 is the specific PCI device ID. + // ID #1 is the compatible device ID based on the BaseClass & SubClass fields + // + + Status = STATUS_NO_MORE_ENTRIES; + DeviceID = (PWCHAR) Context->DeviceControl.Buffer; + + if (IDNumber == 0) { + + // + // Return the PCI device ID + // + + swprintf (DeviceID, PCI_ID, PciData->VendorID, PciData->DeviceID); + Status = STATUS_SUCCESS; + } + + if (IDNumber == 1) { + + // + // Return the first compatible device id for the device + // + + if ( (PciData->BaseClass == 0 && + PciData->SubClass == 1 && + PciData->ProgIf == 0) || + + (PciData->BaseClass == 3 && + PciData->SubClass == 0 && + PciData->ProgIf == 0) ) { + + // + // This is an industry standard VGA controller + // + + swprintf (DeviceID, PNP_VGA); + Status = STATUS_SUCCESS; + } + + if (PciData->BaseClass == 1 && + PciData->SubClass == 0 && + PciData->ProgIf == 0) { + + // + // This is an industry standard IDE controller + // + + swprintf (DeviceID, PNP_IDE); + Status = STATUS_SUCCESS; + + } + } + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + +VOID +PciCtlQueryDeviceUniqueId ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function returns a unique device id for the particular slot. + The id is a sequence of numbers separated by dots ('.'). The first + number is the bus number of the root of the heirarchy of PCI buses + that the slot belongs to. The last number in the sequence is the + slot number in question. A possibly empty set of numbers in between + these two, represents the slot numbers of intermediate PCI-PCI bridges + in the hierarchy between the root bus and the slot. + + For example, L"0.1.2.3": + 0 PCI bus number of the root of the heirarchy. + 1 Slot number within PCI bus 0 were a PCI-PCI bridge is + located, the secondary bus that it bridges to is PCI bus X. + 2 Slot number within PCI bus X were a PCI-PCI bridge is + located, the secondary bus that it bridges to is PCI bus Y. + 3 Slot number within PCI bus Y for which we are wanting to + obtain the unique id (i.e. the targer of this control operation). + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + NTSTATUS Status; + PBUS_HANDLER BusHandler; + PBUS_HANDLER ParentHandler; + PWCHAR UniqueDeviceId; + PWCHAR UniqueDeviceIdEnd; + PDEVICE_HANDLER_OBJECT DeviceHandler; + BOOLEAN Done; + UCHAR UidComponent; + PPCIBUSDATA PciBusData; + PWCHAR DelimiterPointer; + WCHAR Delimiter; + + PAGED_CODE(); + + // + // Set [UniqueDeviceId, UniqueDeviceIdEnd) to the range of + // wide characters for which the caller provided storage. + // + + Status = STATUS_SUCCESS; + UniqueDeviceId = (PWCHAR) Context->DeviceControl.Buffer; + UniqueDeviceIdEnd = UniqueDeviceId + + *Context->DeviceControl.BufferLength / sizeof(WCHAR); + DeviceHandler = DeviceData2DeviceHandler(DeviceData); + + // + // Determine the memory required for the unique id. + // Note that this loop exits in the middle and that it will + // always be executed at least 1.5 times. If there are PCI-PCI + // bridges between the slot's bus and the root bus of the PCI + // hierarchy, then an extra iteration of the loop will be done + // for each one of them. + // + // The bus hierarchy is being walked backwards (from leaf to root). + // Finally, note that the rightmost uid component is the slot's + // number (set before we enter the loop). + // + + BusHandler = DeviceHandler->BusHandler; + UidComponent = (UCHAR) DeviceHandler->SlotNumber; + Done = FALSE; + + for (;;) { + + // + // On each iteration, given the value of one of the components of + // the unique id, determine how much memory the swprintf would use + // for it (note that the 2, 3 & 4 below include a +1, which is + // for the nul terminator or for the '.' delimiter between two + // unique id components. + // + + if (UidComponent <= 9) { + UniqueDeviceId += 2; + } else if (UidComponent <= 99) { + UniqueDeviceId += 3; + } else { + UniqueDeviceId += 4; + } + + if (Done) { + break; + } + + // + // If there is no parent bus handler for the current bus, + // or if it is not a PCI bus, then we are at the root of + // this hierarchy of PCI buses. In this case the unique id + // component is the bus number (instead of a slot number), + // furthermore, we are almost done (just account for the + // space required in the unique id for it). + // + // Otherwise, the current bus is a PCI-PCI bridge and its + // unique id component is the slot number of the bridge + // within its parent bus. + // + + ParentHandler = BusHandler->ParentHandler; + if (!ParentHandler || ParentHandler->InterfaceType != PCIBus) { + UidComponent = (UCHAR) BusHandler->BusNumber; + Done = TRUE; + } else { + PciBusData = (PPCIBUSDATA) BusHandler->BusData; + UidComponent = (UCHAR) PciBusData->ParentSlot.u.AsULONG; + BusHandler = ParentHandler; + } + } + + // + // If there is not enough space for the unique id, fail + // and return the size required. + // + + if (UniqueDeviceId > UniqueDeviceIdEnd) { + *Context->DeviceControl.BufferLength = (UniqueDeviceIdEnd + - (PWCHAR) Context->DeviceControl.Buffer) * sizeof(WCHAR); + Status = STATUS_BUFFER_TOO_SMALL; + } else { + + // + // Otherwise, traverse the bus heirarchy again (just like + // above), except that this time we decrement the UniqueDeviceId + // on each iteration and swprintf the uid component. Note that + // for all components except for the right most one we store + // a delimiter after it (i.e. a '.'). + // + + BusHandler = DeviceHandler->BusHandler; + UidComponent = (UCHAR) DeviceHandler->SlotNumber; + Done = FALSE; + Delimiter = L'\0'; + for (;;) { + DelimiterPointer = UniqueDeviceId; + if (UidComponent <= 9) { + UniqueDeviceId -= 2; + } else if (UidComponent <= 99) { + UniqueDeviceId -= 3; + } else { + UniqueDeviceId -= 4; + } + swprintf(UniqueDeviceId, L"%d", UidComponent); + DelimiterPointer[-1] = Delimiter; + Delimiter = L'.'; + + if (Done) { + break; + } + + ParentHandler = BusHandler->ParentHandler; + if (!ParentHandler || ParentHandler->InterfaceType != PCIBus) { + UidComponent = (UCHAR) BusHandler->BusNumber; + Done = TRUE; + } else { + PciBusData = (PPCIBUSDATA) BusHandler->BusData; + UidComponent = (UCHAR) PciBusData->ParentSlot.u.AsULONG; + BusHandler = ParentHandler; + } + } + } + + PcipCompleteDeviceControl(Status, Context, DeviceData); +} + + +VOID +PciCtlQueryDeviceResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the QUERY_DEVICE_RESOURCES DeviceControl + which returns the bus resources being used by the specified device + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG i, j; + PCM_RESOURCE_LIST CompleteList; + PCM_PARTIAL_RESOURCE_LIST PartialList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + LONGLONG base, length, max; + NTSTATUS Status; + PUCHAR WorkingPool; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE(); + +// BUGBUG if the device is a pci-2-pci bus controller, then +// this function should return the addresses which are bridged + + // + // Allocate some pool for working space + // + + i = sizeof (CM_RESOURCE_LIST) + + sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) + + PCI_COMMON_HDR_LENGTH; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + if (!WorkingPool) { + PcipCompleteDeviceControl (STATUS_INSUFFICIENT_RESOURCES, Context, DeviceData); + return ; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PCM_RESOURCE_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // Read the PCI device's info + // + + PciBusData = (PPCIBUSDATA) (Context->Handler->BusData); + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // Build a CM_RESOURCE_LIST for the PCI device + // + + CompleteList->Count = 1; + CompleteList->List[0].InterfaceType = Context->RootHandler->InterfaceType; + CompleteList->List[0].BusNumber = Context->RootHandler->BusNumber; + + PartialList = &CompleteList->List[0].PartialResourceList; + Descriptor = PartialList->PartialDescriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Descriptor->ShareDisposition = CmResourceShareShared; + + PciBusData->Pin2Line ( + Context->Handler, + Context->RootHandler, + SlotNumber, + PciData + ); + + Descriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine; + Descriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine; + Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; + + PartialList->Count++; + Descriptor++; + } + + // + // Add any memory / port resources being used + // + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + + ASSERT (DeviceData->BARBitsSet); + PcipCrackBAR (BaseAddress, DeviceData->BARBits, &j, &base, &length, &max); + + if (base & PCI_ADDRESS_IO_SPACE) { + + if (PciData->Command & PCI_ENABLE_IO_SPACE) { + Descriptor->Type = CmResourceTypePort; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + Descriptor->u.Port.Start.QuadPart = base & ~0x3; + ASSERT (length <= 0xFFFFFFFF); + Descriptor->u.Port.Length = (ULONG) length; + } + + + } else { + + if (PciData->Command & PCI_ENABLE_MEMORY_SPACE) { + Descriptor->Type = CmResourceTypeMemory; + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + if (j == RomIndex) { + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (base & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + + Descriptor->u.Memory.Start.QuadPart = base & ~0xF; + ASSERT (length < 0xFFFFFFFF); + Descriptor->u.Memory.Length = (ULONG) length; + } + } + + PartialList->Count++; + Descriptor++; + } + } + + // + // Return results + // + + i = (ULONG) ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + if (i > *Context->DeviceControl.BufferLength) { + Status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, CompleteList, i); + Status = STATUS_SUCCESS; + } + + *Context->DeviceControl.BufferLength = i; + ExFreePool (WorkingPool); + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + +VOID +PciCtlQueryDeviceResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the QUERY_DEVICE_RESOURCE_REQUIREMENTS DeviceControl + which returns the possible bus resources that this device may be + satisfied with. + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PIO_RESOURCE_REQUIREMENTS_LIST ResourceList; + NTSTATUS Status; + + PAGED_CODE(); + + // + // Get the resource requirements list for the device + // + + Status = PcipQueryResourceRequirements (DeviceData, Context, &ResourceList); + + if (NT_SUCCESS(Status)) { + + // + // Return results + // + + if (ResourceList->ListSize > *Context->DeviceControl.BufferLength) { + Status = STATUS_BUFFER_TOO_SMALL; + } else { + RtlCopyMemory (Context->DeviceControl.Buffer, ResourceList, ResourceList->ListSize); + Status = STATUS_SUCCESS; + } + + *Context->DeviceControl.BufferLength = ResourceList->ListSize; + + } + + if (ResourceList) { + ExFreePool (ResourceList); + } + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + + +NTSTATUS +PcipQueryResourceRequirements ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList + ) +/*++ + +Routine Description: + + This function allocates and returns the specified devices + IO_RESOURCE_REQUIREMENTS_LIST + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG i, j; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + LONGLONG base, length, max; + NTSTATUS Status; + PUCHAR WorkingPool; + + PAGED_CODE(); + + // + // Allocate some pool for working space + // + + i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) + + sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 + + PCI_COMMON_HDR_LENGTH; + + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + *ResourceList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + if (!*ResourceList) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH); + + // + // Read the PCI device's info + // + + PciBusData = (PPCIBUSDATA) (Context->Handler->BusData); + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device + // + + CompleteList->InterfaceType = Context->RootHandler->InterfaceType; + CompleteList->BusNumber = Context->RootHandler->BusNumber; + CompleteList->SlotNumber = DeviceDataSlot(DeviceData); + CompleteList->AlternativeLists = 1; + + CompleteList->List[0].Version = 1; + CompleteList->List[0].Revision = 1; + + Descriptor = CompleteList->List[0].Descriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Descriptor->ShareDisposition = CmResourceShareShared; + + // BUGBUG: this is not correct + Descriptor->u.Interrupt.MinimumVector = 0; + Descriptor->u.Interrupt.MaximumVector = 0xff; + + CompleteList->List[0].Count++; + Descriptor++; + } + + // + // Add any memory / port resources being used + // + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + + PcipCrackBAR (BaseAddress, DeviceData->BARBits, &j, &base, &length, &max); + + // + // Add a descriptor for this address + // + + Descriptor->Option = 0; + if (base & PCI_ADDRESS_IO_SPACE) { + Descriptor->Type = CmResourceTypePort; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + ASSERT (length <= 0xFFFFFFFF); + Descriptor->u.Port.Alignment = (ULONG) length; + Descriptor->u.Port.Length = (ULONG) length; + Descriptor->u.Port.MinimumAddress.QuadPart = 0; + Descriptor->u.Port.MaximumAddress.QuadPart = max; + + } else { + Descriptor->Type = CmResourceTypeMemory; + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + if (j == RomIndex) { + // this is a ROM address + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (base & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + + ASSERT (length <= 0xFFFFFFFF); + Descriptor->u.Memory.Alignment = (ULONG) length; + Descriptor->u.Memory.Length = (ULONG) length; + Descriptor->u.Memory.MinimumAddress.QuadPart = 0; + Descriptor->u.Memory.MaximumAddress.QuadPart = max; + } + + CompleteList->List[0].Count++; + Descriptor++; + } + } + + if (DeviceData->BrokenDevice) { + + // + // This device has something wrong with its base address register implementation + // + + ExFreePool (WorkingPool); + return STATUS_DEVICE_PROTOCOL_ERROR; + } + + // + // Return results + // + + CompleteList->ListSize = (ULONG) ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + *ResourceList = CompleteList; + return STATUS_SUCCESS; +} + +VOID +PciCtlSetDeviceResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the SET_DEVICE_RESOURCES DeviceControl + which configures the device to the specified device setttings + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + NTSTATUS Status; + + PAGED_CODE(); + + // + // Get the resource requirements list for the device + // + + Status = PcipSetResources ( + DeviceData, + Context, + (PCM_RESOURCE_LIST) Context->DeviceControl.Buffer, + *Context->DeviceControl.BufferLength + ); + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} + + +NTSTATUS +PcipSetResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context, + PCM_RESOURCE_LIST ResourceList, + ULONG ListSize + ) +/*++ + +Routine Description: + + This function set the specified device to the CM_RESOURCE_LIST + +Arguments: + +Return Value: + + The slot control is completed + +--*/ +{ + PPCIBUSDATA PciBusData; + PPCI_COMMON_CONFIG PciData, PciOrigData; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + ULONG i, j; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + LONGLONG base, length; + NTSTATUS Status; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PCI_SLOT_NUMBER SlotNumber; + + PAGED_CODE(); + + PciBusData = (PPCIBUSDATA) (Context->Handler->BusData); + SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData); + + // + // If BARBits haven't been deteremined, go do it now + // + + Status = PcipVerifyBarBits (DeviceData, Context->Handler); + if (!NT_SUCCESS(Status)) { + return Status; + } + + + // + // Get current device configuration + // + + if (DeviceData->Power) { + ASSERT (DeviceData->CurrentConfig == NULL); + DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG) + ExAllocatePool (NonPagedPool, PCI_COMMON_HDR_LENGTH); + + if (!DeviceData->CurrentConfig) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + // + // Read the PCI device's info + // + + PciData = DeviceData->CurrentConfig; + PciOrigData = (PPCI_COMMON_CONFIG) buffer; + PcipReadConfig (Context->Handler, DeviceData, PciData); + + // + // Save current config + // + + RtlCopyMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Initialize base addresses base on configuration data type + // + + PcipCalcBaseAddrPointers ( + DeviceData, + PciData, + BaseAddress, + &NoBaseAddress, + &RomIndex + ); + + // + // Slurp the assigments back into the PciData structure and + // perform them + // + + CmDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; + + // + // If PCI device has an interrupt resource then that was + // passed in as the first requested resource + // + + if (PciData->u.type0.InterruptPin) { + + // + // Assign the interrupt line + // + + if (CmDescriptor->Type != CmResourceTypeInterrupt) { + Status = STATUS_INVALID_PARAMETER; + goto CleanUp; + } + + PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector; + + PciBusData->Pin2Line ( + Context->Handler, + Context->RootHandler, + SlotNumber, + PciData + ); + + CmDescriptor++; + } + + for (j=0; j < NoBaseAddress; j++) { + base = *BaseAddress[j]; + if (base) { + // + // Set 32bits and mask + // + + if (base & PCI_ADDRESS_IO_SPACE) { + if (CmDescriptor->Type != CmResourceTypePort) { + Status = STATUS_INVALID_PARAMETER; + goto CleanUp; + } + + *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart; + + } else { + if (CmDescriptor->Type != CmResourceTypeMemory) { + Status = STATUS_INVALID_PARAMETER; + goto CleanUp; + } + + *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart; + } + + if (Is64BitBaseAddress(base)) { + + // + // Set upper 32bits + // + + if (base & PCI_ADDRESS_IO_SPACE) { + *BaseAddress[j+1] = CmDescriptor->u.Port.Start.HighPart; + } else { + *BaseAddress[j+1] = CmDescriptor->u.Memory.Start.HighPart; + } + + j++; + } + + CmDescriptor++; + } + } + + // + // Enabel decodes and set the new addresses + // + + if (DeviceData->EnableRom && *BaseAddress[RomIndex]) { + // a rom address was allocated and should be enabled + *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED; + } + + PciData->Command |= PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER; + + // + // If the device is powered on, flush the cached config information + // to the device; otherwise, leave the new configuration in memory - + // it will get flushed to the device when it's powered on + // + + Status = STATUS_SUCCESS; + if (DeviceData->Power) { + Status = PcipFlushConfig (Context->Handler, DeviceData); + } + +CleanUp: + // + // If there was an error, and the device still has a cached current + // config, put the configuration back as it was when we found it + // + + if (!NT_SUCCESS (Status) && DeviceData->CurrentConfig) { + RtlCopyMemory (DeviceData->CurrentConfig, PciOrigData, PCI_COMMON_HDR_LENGTH); + } + + return Status; +} + + +VOID +PciCtlAssignSlotResources ( + PDEVICE_DATA DeviceData, + PHAL_DEVICE_CONTROL_CONTEXT Context + ) +/*++ + +Routine Description: + + This function completes the internal AssignSlotResources DeviceControl + +Arguments: + + DeviceData - Slot data information for the specificied slot + + Context - Slot control context of the request + +Return Value: + + The slot control is completed + +--*/ +{ + PIO_RESOURCE_REQUIREMENTS_LIST ResourceList; + PCTL_ASSIGN_RESOURCES AssignResources; + PCM_RESOURCE_LIST AllocatedResources; + NTSTATUS Status; + ULONG l; + POWER_STATE PowerControl; + + PAGED_CODE(); + + ResourceList = NULL; + AllocatedResources = NULL; + AssignResources = (PCTL_ASSIGN_RESOURCES) Context->DeviceControl.Buffer; + + // + // If BARBits haven't been deteremined, go do it now + // + + Status = PcipVerifyBarBits (DeviceData, Context->Handler); + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Get the resource requirements list for the device + // + + Status = PcipQueryResourceRequirements (DeviceData, Context, &ResourceList); + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Get device settings from IO + // + + Status = IoAssignResources ( + AssignResources->RegistryPath, + AssignResources->DriverClassName, + AssignResources->DriverObject, + Context->DeviceControl.DeviceObject, + ResourceList, + &AllocatedResources + ); + + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Set the resources into the device + // + + Status = PcipSetResources (DeviceData, Context, AllocatedResources, 0xFFFFFFFF); + if (!NT_SUCCESS(Status)) { + goto CleanUp; + } + + // + // Turn the device on + // + + PowerControl = PowerUp; + l = sizeof (PowerControl); + + Status = HalDeviceControl ( + Context->DeviceControl.DeviceHandler, + Context->DeviceControl.DeviceObject, + BCTL_SET_POWER, + &PowerControl, + &l, + NULL, + NULL + ); + +CleanUp: + *AssignResources->AllocatedResources = AllocatedResources; + + if (!NT_SUCCESS(Status)) { + + // + // Failure, if there are any allocated resources free them + // + + if (AllocatedResources) { + IoAssignResources ( + AssignResources->RegistryPath, + AssignResources->DriverClassName, + AssignResources->DriverObject, + Context->DeviceControl.DeviceObject, + NULL, + NULL + ); + + ExFreePool (AllocatedResources); + *AssignResources->AllocatedResources = NULL; + } + } + + if (ResourceList) { + ExFreePool (ResourceList); + } + + PcipCompleteDeviceControl (Status, Context, DeviceData); +} |