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