- IRP_MN_QUERY_RESOURCE_REQUIREMENTS half support now, PciQueryRequirements, PciAlloc...
[reactos.git] / reactos / drivers / bus / pcix / enum.c
index a4d53dd..4e17a7f 100644 (file)
@@ -14,6 +14,8 @@
 
 /* GLOBALS ********************************************************************/
 
+PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
+
 PCI_CONFIGURATOR PciConfigurators[] =
 {
     {
@@ -47,6 +49,345 @@ PCI_CONFIGURATOR PciConfigurators[] =
 
 /* FUNCTIONS ******************************************************************/
 
+PIO_RESOURCE_REQUIREMENTS_LIST
+NTAPI
+PciAllocateIoRequirementsList(IN ULONG Count,
+                              IN ULONG BusNumber,
+                              IN ULONG SlotNumber)
+{
+    SIZE_T Size;
+    PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
+
+    /* Calculate the final size of the list, including each descriptor */
+    Size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
+    if (Count > 1) Size = sizeof(IO_RESOURCE_DESCRIPTOR) * (Count - 1) +
+                          sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
+
+    /* Allocate the list */
+    RequirementsList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
+    if (!RequirementsList) return NULL;
+
+    /* Initialize it */
+    RtlZeroMemory(RequirementsList, Size);
+    RequirementsList->AlternativeLists = 1;
+    RequirementsList->BusNumber = BusNumber;
+    RequirementsList->SlotNumber = SlotNumber;
+    RequirementsList->InterfaceType = PCIBus;
+    RequirementsList->ListSize = Size;
+    RequirementsList->List[0].Count = Count;
+    RequirementsList->List[0].Version = 1;
+    RequirementsList->List[0].Revision = 1;
+
+    /* Return it */
+    return RequirementsList;
+}
+
+PCM_RESOURCE_LIST
+NTAPI
+PciAllocateCmResourceList(IN ULONG Count,
+                          IN ULONG BusNumber)
+{
+    SIZE_T Size;
+    PCM_RESOURCE_LIST ResourceList;
+
+    /* Calculate the final size of the list, including each descriptor */
+    Size = sizeof(CM_RESOURCE_LIST);
+    if (Count > 1) Size = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count - 1) +
+                          sizeof(CM_RESOURCE_LIST);
+
+    /* Allocate the list */
+    ResourceList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
+    if (!ResourceList) return NULL;
+
+    /* Initialize it */
+    RtlZeroMemory(ResourceList, Size);
+    ResourceList->Count = 1;
+    ResourceList->List[0].BusNumber = BusNumber;
+    ResourceList->List[0].InterfaceType = PCIBus;
+    ResourceList->List[0].PartialResourceList.Version = 1;
+    ResourceList->List[0].PartialResourceList.Revision = 1;
+    ResourceList->List[0].PartialResourceList.Count = Count;
+
+    /* Return it */
+    return ResourceList;
+}
+
+NTSTATUS
+NTAPI
+PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
+                  OUT PCM_RESOURCE_LIST *Buffer)
+{
+    PPCI_FUNCTION_RESOURCES PciResources;
+    BOOLEAN HaveVga, HaveMemSpace, HaveIoSpace;
+    USHORT BridgeControl, PciCommand;
+    ULONG Count, i;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, Resource, LastResource;
+    PCM_RESOURCE_LIST ResourceList;
+    UCHAR InterruptLine;
+    PAGED_CODE();
+
+    /* Assume failure */
+    Count = 0;
+    HaveVga = FALSE;
+    *Buffer = NULL;
+
+    /* Make sure there's some resources to query */
+    PciResources = PdoExtension->Resources;
+    if (!PciResources) return STATUS_SUCCESS;
+
+    /* Read the decodes */
+    PciReadDeviceConfig(PdoExtension,
+                        &PciCommand,
+                        FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+                        sizeof(USHORT));
+
+    /* Check which ones are turned on */
+    HaveIoSpace = PciCommand & PCI_ENABLE_IO_SPACE;
+    HaveMemSpace = PciCommand & PCI_ENABLE_MEMORY_SPACE;
+
+    /* Loop maximum possible descriptors */
+    for (i = 0; i < 7; i++)
+    {
+        /* Check if the decode for this descriptor is actually turned on */
+        Partial = &PciResources->Current[i];
+        if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
+            ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
+        {
+            /* One more fully active descriptor */
+            Count++;
+        }
+    }
+
+    /* If there's an interrupt pin associated, check at least one decode is on */
+    if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
+    {
+        /* Read the interrupt line for the pin, add a descriptor if it's valid */
+        InterruptLine = PdoExtension->AdjustedInterruptLine;
+        if ((InterruptLine) && (InterruptLine != -1)) Count++;
+    }
+
+    /* Check for PCI bridge */
+    if (PdoExtension->HeaderType == PCI_BRIDGE_TYPE)
+    {
+        /* Read bridge settings, check if VGA is present */
+        PciReadDeviceConfig(PdoExtension,
+                            &BridgeControl,
+                            FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BridgeControl),
+                            sizeof(USHORT));
+        if (BridgeControl & PCI_ENABLE_BRIDGE_VGA)
+        {
+            /* Remember for later */
+            HaveVga = TRUE;
+
+            /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
+            if (HaveMemSpace) Count++;
+            if (HaveIoSpace) Count += 2;
+        }
+    }
+
+    /* If there's no descriptors in use, there's no resources, so return */
+    if (!Count) return STATUS_SUCCESS;
+
+    /* Allocate a resource list to hold the resources */
+    ResourceList = PciAllocateCmResourceList(Count,
+                                             PdoExtension->ParentFdoExtension->BaseBus);
+    if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* This is where the descriptors will be copied into */
+    Resource = ResourceList->List[0].PartialResourceList.PartialDescriptors;
+    LastResource = Resource + Count + 1;
+
+    /* Loop maximum possible descriptors */
+    for (i = 0; i < 7; i++)
+    {
+        /* Check if the decode for this descriptor is actually turned on */
+        Partial = &PciResources->Current[i];
+        if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
+            ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
+        {
+            /* Copy the descriptor into the resource list */
+            *Resource++ = *Partial;
+        }
+    }
+
+    /* Check if earlier the code detected this was a PCI bridge with VGA on it */
+    if (HaveVga)
+    {
+        /* Are the memory decodes enabled? */
+        if (HaveMemSpace)
+        {
+            /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */
+            Resource->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+            Resource->u.Generic.Start.HighPart = 0;
+            Resource->Type = CmResourceTypeMemory;
+            Resource->u.Generic.Start.LowPart = 0xA0000;
+            Resource->u.Generic.Length = 0x20000;
+            Resource++;
+        }
+
+        /* Are the I/O decodes enabled? */
+        if (HaveIoSpace)
+        {
+            /* Build an I/O descriptor for the graphic ports at 0x3B0 */
+            Resource->Type = CmResourceTypePort;
+            Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
+            Resource->u.Port.Start.QuadPart = 0x3B0u;
+            Resource->u.Port.Length = 0xC;
+            Resource++;
+
+            /* Build an I/O descriptor for the graphic ports at 0x3C0 */
+            Resource->Type = CmResourceTypePort;
+            Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
+            Resource->u.Port.Start.QuadPart = 0x3C0u;
+            Resource->u.Port.Length = 0x20;
+            Resource++;
+        }
+    }
+
+    /* If there's an interrupt pin associated, check at least one decode is on */
+    if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
+    {
+         /* Read the interrupt line for the pin, check if it's valid */
+         InterruptLine = PdoExtension->AdjustedInterruptLine;
+         if ((InterruptLine) && (InterruptLine != -1))
+         {
+             /* Make sure there's still space */
+             ASSERT(Resource < LastResource);
+
+             /* Add the interrupt descriptor */
+             Resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+             Resource->Type = CmResourceTypeInterrupt;
+             Resource->ShareDisposition = CmResourceShareShared;
+             Resource->u.Interrupt.Affinity = -1;
+             Resource->u.Interrupt.Level = InterruptLine;
+             Resource->u.Interrupt.Vector = InterruptLine;
+        }
+    }
+
+    /* Return the resouce list */
+    *Buffer = ResourceList;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
+                              IN OUT PDEVICE_RELATIONS *pDeviceRelations)
+{
+    PDEVICE_RELATIONS DeviceRelations;
+    PAGED_CODE();
+
+    /* If there were existing relations, free them */
+    if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
+
+    /* Allocate a new structure for the relations */
+    DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
+                                            sizeof(DEVICE_RELATIONS),
+                                            'BicP');
+    if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Only one relation: the PDO */
+    DeviceRelations->Count = 1;
+    DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
+    ObReferenceObject(DeviceRelations->Objects[0]);
+
+    /* Return the new relations */
+    *pDeviceRelations = DeviceRelations;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
+                          IN OUT PDEVICE_RELATIONS *pDeviceRelations)
+{
+    /* Not yet implemented */
+    UNIMPLEMENTED;
+    while (TRUE);
+}
+
+NTSTATUS
+NTAPI
+PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,
+                         IN PPCI_COMMON_HEADER PciData,
+                         OUT PIO_RESOURCE_REQUIREMENTS_LIST* Buffer)
+{
+    PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
+    {
+        /* There aren't, so use the zero descriptor */
+        RequirementsList = PciZeroIoResourceRequirements;
+
+        /* Does it actually exist yet? */
+        if (!PciZeroIoResourceRequirements)
+        {
+            /* Allocate it, and use it for future use */
+            RequirementsList = PciAllocateIoRequirementsList(0, 0, 0);
+            PciZeroIoResourceRequirements = RequirementsList;
+            if (!PciZeroIoResourceRequirements) return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Return the zero requirements list to the caller */
+        *Buffer = RequirementsList;
+        DPRINT1("PCI - build resource reqs - early out, 0 resources\n");
+        return STATUS_SUCCESS;
+    }
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
+                     IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
+{
+    NTSTATUS Status;
+    PCI_COMMON_HEADER PciHeader;
+    PAGED_CODE();
+
+    /* Check if the PDO has any resources, or at least an interrupt pin */
+    if ((PdoExtension->Resources) || (PdoExtension->InterruptPin))
+    {
+        /* Read the current PCI header */
+        PciReadDeviceConfig(PdoExtension, &PciHeader, 0, PCI_COMMON_HDR_LENGTH);
+
+        /* Use it to build a list of requirements */
+        Status = PciBuildRequirementsList(PdoExtension, &PciHeader, RequirementsList);
+        if (!NT_SUCCESS(Status)) return Status;
+
+        /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
+        if ((PciHeader.VendorID == 0xE11) &&
+            (PciHeader.DeviceID == 0xA0F7) &&
+            (PciHeader.RevisionID == 17) &&
+            (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
+        {
+            /* Have not tested this on eVb's machine yet */
+            UNIMPLEMENTED;
+            while (TRUE);
+        }
+
+        /* Check if the requirements are actually the zero list */
+        if (*RequirementsList == PciZeroIoResourceRequirements)
+        {
+            /* A simple NULL will sufficie for the PnP Manager */
+            *RequirementsList = NULL;
+            DPRINT1("Returning NULL requirements list\n");
+        }
+        else
+        {
+            /* Otherwise, print out the requirements list */
+            PciDebugPrintIoResReqList(*RequirementsList);
+        }
+    }
+    else
+    {
+        /* There aren't any resources, so simply return NULL */
+        DPRINT1("PciQueryRequirements returning NULL requirements list\n");
+        *RequirementsList = NULL;
+    }
+
+    /* This call always succeeds (but maybe with no requirements) */
+    return STATUS_SUCCESS;
+}
+
 /*
  * 7. The IO/MEM/Busmaster decodes are disabled for the device.
  * 8. The PCI bus driver sets the operating mode bits of the Programming