1 /* 2 * PROJECT: ReactOS PCI Bus Driver 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/bus/pci/pci/config.c 5 * PURPOSE: PCI Configuration Space Routines 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <pci.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ********************************************************************/ 17 18 BOOLEAN PciAssignBusNumbers; 19 20 /* FUNCTIONS ******************************************************************/ 21 22 UCHAR 23 NTAPI 24 PciGetAdjustedInterruptLine(IN PPCI_PDO_EXTENSION PdoExtension) 25 { 26 UCHAR InterruptLine = 0, PciInterruptLine; 27 ULONG Length; 28 29 /* Does the device have an interrupt pin? */ 30 if (PdoExtension->InterruptPin) 31 { 32 /* Find the associated line on the parent bus */ 33 Length = HalGetBusDataByOffset(PCIConfiguration, 34 PdoExtension->ParentFdoExtension->BaseBus, 35 PdoExtension->Slot.u.AsULONG, 36 &PciInterruptLine, 37 FIELD_OFFSET(PCI_COMMON_HEADER, 38 u.type0.InterruptLine), 39 sizeof(UCHAR)); 40 if (Length) InterruptLine = PciInterruptLine; 41 } 42 43 /* Either keep the original interrupt line, or the one on the master bus */ 44 return InterruptLine ? PdoExtension->RawInterruptLine : InterruptLine; 45 } 46 47 VOID 48 NTAPI 49 PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension, 50 IN PCI_SLOT_NUMBER Slot, 51 IN PVOID Buffer, 52 IN ULONG Offset, 53 IN ULONG Length, 54 IN BOOLEAN Read) 55 { 56 PPCI_BUS_INTERFACE_STANDARD PciInterface; 57 PBUS_HANDLER BusHandler; 58 PPCIBUSDATA BusData; 59 PciReadWriteConfig HalFunction; 60 61 /* Only the root FDO can access configuration space */ 62 ASSERT(PCI_IS_ROOT_FDO(DeviceExtension->BusRootFdoExtension)); 63 64 /* Get the ACPI-compliant PCI interface */ 65 PciInterface = DeviceExtension->BusRootFdoExtension->PciBusInterface; 66 if (PciInterface) 67 { 68 /* Currently this driver only supports the legacy HAL interface */ 69 UNIMPLEMENTED_DBGBREAK(); 70 } 71 else 72 { 73 /* Make sure there's a registered HAL bus handler */ 74 ASSERT(DeviceExtension->BusHandler); 75 76 /* PCI Bus Number assignment is only valid on ACPI systems */ 77 ASSERT(!PciAssignBusNumbers); 78 79 /* Grab the HAL PCI Bus Handler data */ 80 BusHandler = (PBUS_HANDLER)DeviceExtension->BusHandler; 81 BusData = (PPCIBUSDATA)BusHandler->BusData; 82 83 /* Choose the appropriate read or write function, and call it */ 84 HalFunction = Read ? BusData->ReadConfig : BusData->WriteConfig; 85 HalFunction(BusHandler, Slot, Buffer, Offset, Length); 86 } 87 } 88 89 VOID 90 NTAPI 91 PciWriteDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, 92 IN PVOID Buffer, 93 IN ULONG Offset, 94 IN ULONG Length) 95 { 96 /* Call the generic worker function */ 97 PciReadWriteConfigSpace(DeviceExtension->ParentFdoExtension, 98 DeviceExtension->Slot, 99 Buffer, 100 Offset, 101 Length, 102 FALSE); 103 } 104 105 VOID 106 NTAPI 107 PciReadDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension, 108 IN PVOID Buffer, 109 IN ULONG Offset, 110 IN ULONG Length) 111 { 112 /* Call the generic worker function */ 113 PciReadWriteConfigSpace(DeviceExtension->ParentFdoExtension, 114 DeviceExtension->Slot, 115 Buffer, 116 Offset, 117 Length, 118 TRUE); 119 } 120 121 VOID 122 NTAPI 123 PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension, 124 IN PCI_SLOT_NUMBER Slot, 125 IN PVOID Buffer, 126 IN ULONG Offset, 127 IN ULONG Length) 128 { 129 /* Call the generic worker function */ 130 PciReadWriteConfigSpace(DeviceExtension, Slot, Buffer, Offset, Length, TRUE); 131 } 132 133 NTSTATUS 134 NTAPI 135 PciQueryForPciBusInterface(IN PPCI_FDO_EXTENSION FdoExtension) 136 { 137 PDEVICE_OBJECT AttachedDevice; 138 IO_STATUS_BLOCK IoStatusBlock; 139 KEVENT Event; 140 NTSTATUS Status; 141 PIRP Irp; 142 PIO_STACK_LOCATION IoStackLocation; 143 PPCI_BUS_INTERFACE_STANDARD PciInterface; 144 PAGED_CODE(); 145 ASSERT(PCI_IS_ROOT_FDO(FdoExtension)); 146 147 /* Allocate space for the interface */ 148 PciInterface = ExAllocatePoolWithTag(NonPagedPool, 149 sizeof(PCI_BUS_INTERFACE_STANDARD), 150 PCI_POOL_TAG); 151 if (!PciInterface) return STATUS_INSUFFICIENT_RESOURCES; 152 153 /* Get the device the PDO is attached to, should be the Root (ACPI) */ 154 AttachedDevice = IoGetAttachedDeviceReference(FdoExtension->PhysicalDeviceObject); 155 156 /* Build an IRP for this request */ 157 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 158 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, 159 AttachedDevice, 160 NULL, 161 0, 162 NULL, 163 &Event, 164 &IoStatusBlock); 165 if (Irp) 166 { 167 /* Initialize the default PnP response */ 168 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 169 Irp->IoStatus.Information = 0; 170 171 /* Make it a Query Interface IRP */ 172 IoStackLocation = IoGetNextIrpStackLocation(Irp); 173 ASSERT(IoStackLocation->MajorFunction == IRP_MJ_PNP); 174 IoStackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE; 175 IoStackLocation->Parameters.QueryInterface.InterfaceType = &GUID_PCI_BUS_INTERFACE_STANDARD; 176 IoStackLocation->Parameters.QueryInterface.Size = sizeof(PCI_BUS_INTERFACE_STANDARD); 177 IoStackLocation->Parameters.QueryInterface.Version = PCI_BUS_INTERFACE_STANDARD_VERSION; 178 IoStackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)PciInterface; 179 IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData = NULL; 180 181 /* Send it to the root PDO */ 182 Status = IoCallDriver(AttachedDevice, Irp); 183 if (Status == STATUS_PENDING) 184 { 185 /* Wait for completion */ 186 KeWaitForSingleObject(&Event, 187 Executive, 188 KernelMode, 189 FALSE, 190 NULL); 191 Status = Irp->IoStatus.Status; 192 } 193 194 /* Check if an interface was returned */ 195 if (!NT_SUCCESS(Status)) 196 { 197 /* No interface was returned by the root PDO */ 198 FdoExtension->PciBusInterface = NULL; 199 ExFreePoolWithTag(PciInterface, 0); 200 } 201 else 202 { 203 /* An interface was returned, save it */ 204 FdoExtension->PciBusInterface = PciInterface; 205 } 206 207 /* Dereference the device object because we took a reference earlier */ 208 ObDereferenceObject(AttachedDevice); 209 } 210 else 211 { 212 /* Failure path, dereference the device object and set failure code */ 213 if (AttachedDevice) ObDereferenceObject(AttachedDevice); 214 ExFreePoolWithTag(PciInterface, 0); 215 Status = STATUS_INSUFFICIENT_RESOURCES; 216 } 217 218 /* Return status code to caller */ 219 return Status; 220 } 221 222 NTSTATUS 223 NTAPI 224 PciGetConfigHandlers(IN PPCI_FDO_EXTENSION FdoExtension) 225 { 226 PBUS_HANDLER BusHandler; 227 NTSTATUS Status; 228 ASSERT(FdoExtension->BusHandler == NULL); 229 230 /* Check if this is the FDO for the root bus */ 231 if (PCI_IS_ROOT_FDO(FdoExtension)) 232 { 233 /* Query the PCI Bus Interface that ACPI exposes */ 234 ASSERT(FdoExtension->PciBusInterface == NULL); 235 Status = PciQueryForPciBusInterface(FdoExtension); 236 if (!NT_SUCCESS(Status)) 237 { 238 /* No ACPI, so Bus Numbers should be maintained by BIOS */ 239 ASSERT(!PciAssignBusNumbers); 240 } 241 else 242 { 243 /* ACPI detected, PCI Bus Driver will reconfigure bus numbers*/ 244 PciAssignBusNumbers = TRUE; 245 } 246 } 247 else 248 { 249 /* Check if the root bus already has the interface set up */ 250 if (FdoExtension->BusRootFdoExtension->PciBusInterface) 251 { 252 /* Nothing for this FDO to do */ 253 return STATUS_SUCCESS; 254 } 255 256 /* Fail into case below so we can query the HAL interface */ 257 Status = STATUS_NOT_SUPPORTED; 258 } 259 260 /* If the ACPI PCI Bus Interface couldn't be obtained, try the HAL */ 261 if (!NT_SUCCESS(Status)) 262 { 263 /* Bus number assignment should be static */ 264 ASSERT(Status == STATUS_NOT_SUPPORTED); 265 ASSERT(!PciAssignBusNumbers); 266 267 /* Call the HAL to obtain the bus handler for PCI */ 268 BusHandler = HalReferenceHandlerForBus(PCIBus, FdoExtension->BaseBus); 269 FdoExtension->BusHandler = BusHandler; 270 271 /* Fail if the HAL does not have a PCI Bus Handler for this bus */ 272 if (!BusHandler) return STATUS_INVALID_DEVICE_REQUEST; 273 } 274 275 /* Appropriate interface was obtained */ 276 return STATUS_SUCCESS; 277 } 278 279 /* EOF */ 280