e5382bf949f3a6d2163ebf5b0d94d5da543d820c
[reactos.git] / reactos / 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;
69 while (TRUE);
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 PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension,
108 IN PCI_SLOT_NUMBER Slot,
109 IN PVOID Buffer,
110 IN ULONG Offset,
111 IN ULONG Length)
112 {
113 /* Call the generic worker function */
114 PciReadWriteConfigSpace(DeviceExtension, Slot, Buffer, Offset, Length, TRUE);
115 }
116
117 NTSTATUS
118 NTAPI
119 PciQueryForPciBusInterface(IN PPCI_FDO_EXTENSION FdoExtension)
120 {
121 PDEVICE_OBJECT AttachedDevice;
122 IO_STATUS_BLOCK IoStatusBlock;
123 KEVENT Event;
124 NTSTATUS Status;
125 PIRP Irp;
126 PIO_STACK_LOCATION IoStackLocation;
127 PPCI_BUS_INTERFACE_STANDARD PciInterface;
128 PAGED_CODE();
129 ASSERT(PCI_IS_ROOT_FDO(FdoExtension));
130
131 /* Allocate space for the inteface */
132 PciInterface = ExAllocatePoolWithTag(NonPagedPool,
133 sizeof(PCI_BUS_INTERFACE_STANDARD),
134 PCI_POOL_TAG);
135 if (!PciInterface) return STATUS_INSUFFICIENT_RESOURCES;
136
137 /* Get the device the PDO is attached to, should be the Root (ACPI) */
138 AttachedDevice = IoGetAttachedDeviceReference(FdoExtension->PhysicalDeviceObject);
139
140 /* Build an IRP for this request */
141 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
142 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
143 AttachedDevice,
144 NULL,
145 0,
146 NULL,
147 &Event,
148 &IoStatusBlock);
149 if (Irp)
150 {
151 /* Initialize the default PnP response */
152 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
153 Irp->IoStatus.Information = 0;
154
155 /* Make it a Query Interface IRP */
156 IoStackLocation = IoGetNextIrpStackLocation(Irp);
157 ASSERT(IoStackLocation->MajorFunction == IRP_MJ_PNP);
158 IoStackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE;
159 IoStackLocation->Parameters.QueryInterface.InterfaceType = &GUID_PCI_BUS_INTERFACE_STANDARD;
160 IoStackLocation->Parameters.QueryInterface.Size = sizeof(GUID_PCI_BUS_INTERFACE_STANDARD);
161 IoStackLocation->Parameters.QueryInterface.Version = PCI_BUS_INTERFACE_STANDARD_VERSION;
162 IoStackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)PciInterface;
163 IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData = NULL;
164
165 /* Send it to the root PDO */
166 Status = IoCallDriver(AttachedDevice, Irp);
167 if (Status == STATUS_PENDING)
168 {
169 /* Wait for completion */
170 KeWaitForSingleObject(&Event,
171 Executive,
172 KernelMode,
173 FALSE,
174 NULL);
175 Status = Irp->IoStatus.Status;
176 }
177
178 /* Check if an interface was returned */
179 if (!NT_SUCCESS(Status))
180 {
181 /* No interface was returned by the root PDO */
182 FdoExtension->PciBusInterface = NULL;
183 ExFreePoolWithTag(PciInterface, 0);
184 }
185 else
186 {
187 /* An interface was returned, save it */
188 FdoExtension->PciBusInterface = PciInterface;
189 }
190
191 /* Dereference the device object because we took a reference earlier */
192 ObfDereferenceObject(AttachedDevice);
193 }
194 else
195 {
196 /* Failure path, dereference the device object and set failure code */
197 if (AttachedDevice) ObfDereferenceObject(AttachedDevice);
198 ExFreePoolWithTag(PciInterface, 0);
199 Status = STATUS_INSUFFICIENT_RESOURCES;
200 }
201
202 /* Return status code to caller */
203 return Status;
204 }
205
206 NTSTATUS
207 NTAPI
208 PciGetConfigHandlers(IN PPCI_FDO_EXTENSION FdoExtension)
209 {
210 PBUS_HANDLER BusHandler;
211 NTSTATUS Status;
212 ASSERT(FdoExtension->BusHandler == NULL);
213
214 /* Check if this is the FDO for the root bus */
215 if (PCI_IS_ROOT_FDO(FdoExtension))
216 {
217 /* Query the PCI Bus Interface that ACPI exposes */
218 ASSERT(FdoExtension->PciBusInterface == NULL);
219 Status = PciQueryForPciBusInterface(FdoExtension);
220 if (!NT_SUCCESS(Status))
221 {
222 /* No ACPI, so Bus Numbers should be maintained by BIOS */
223 ASSERT(!PciAssignBusNumbers);
224 }
225 else
226 {
227 /* ACPI detected, PCI Bus Driver will reconfigure bus numbers*/
228 PciAssignBusNumbers = TRUE;
229 }
230 }
231 else
232 {
233 /* Check if the root bus already has the interface set up */
234 if (FdoExtension->BusRootFdoExtension->PciBusInterface)
235 {
236 /* Nothing for this FDO to do */
237 return STATUS_SUCCESS;
238 }
239
240 /* Fail into case below so we can query the HAL interface */
241 Status = STATUS_NOT_SUPPORTED;
242 }
243
244 /* If the ACPI PCI Bus Interface couldn't be obtained, try the HAL */
245 if (!NT_SUCCESS(Status))
246 {
247 /* Bus number assignment should be static */
248 ASSERT(Status == STATUS_NOT_SUPPORTED);
249 ASSERT(!PciAssignBusNumbers);
250
251 /* Call the HAL to obtain the bus handler for PCI */
252 BusHandler = HalReferenceHandlerForBus(PCIBus, FdoExtension->BaseBus);
253 FdoExtension->BusHandler = BusHandler;
254
255 /* Fail if the HAL does not have a PCI Bus Handler for this bus */
256 if (!BusHandler) return STATUS_INVALID_DEVICE_REQUEST;
257 }
258
259 /* Appropriate interface was obtained */
260 return STATUS_SUCCESS;
261 }
262
263 /* EOF */