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
PciGetAdjustedInterruptLine(IN PPCI_PDO_EXTENSION PdoExtension)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
PciReadWriteConfigSpace(IN PPCI_FDO_EXTENSION DeviceExtension,IN PCI_SLOT_NUMBER Slot,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length,IN BOOLEAN Read)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
PciWriteDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)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
PciReadDeviceConfig(IN PPCI_PDO_EXTENSION DeviceExtension,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)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
PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,IN PCI_SLOT_NUMBER Slot,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)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
PciQueryForPciBusInterface(IN PPCI_FDO_EXTENSION FdoExtension)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
PciGetConfigHandlers(IN PPCI_FDO_EXTENSION FdoExtension)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