xref: /reactos/drivers/bus/pcix/pci/config.c (revision c2c66aff)
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