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