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