2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/fdo.c
5 * PURPOSE: FDO Device Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 SINGLE_LIST_ENTRY PciFdoExtensionListHead
;
18 BOOLEAN PciBreakOnDefault
;
20 PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable
[] =
22 {IRP_DISPATCH
, (PCI_DISPATCH_FUNCTION
)PciFdoWaitWake
},
23 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
24 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoSetPowerState
},
25 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryPower
},
26 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
}
29 PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable
[] =
31 {IRP_UPWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpStartDevice
},
32 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryRemoveDevice
},
33 {IRP_DISPATCH
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpRemoveDevice
},
34 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpCancelRemoveDevice
},
35 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpStopDevice
},
36 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryStopDevice
},
37 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpCancelStopDevice
},
38 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryDeviceRelations
},
39 {IRP_DISPATCH
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryInterface
},
40 {IRP_UPWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryCapabilities
},
41 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
42 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
43 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
44 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
45 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
46 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
47 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
48 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
49 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
50 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
51 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
52 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
53 {IRP_UPWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpDeviceUsageNotification
},
54 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpSurpriseRemoval
},
55 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciFdoIrpQueryLegacyBusInformation
},
56 {IRP_DOWNWARD
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
}
59 PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable
=
61 IRP_MN_QUERY_LEGACY_BUS_INFORMATION
,
62 PciFdoDispatchPnpTable
,
64 PciFdoDispatchPowerTable
,
66 (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
,
68 (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
71 /* FUNCTIONS ******************************************************************/
75 PciFdoIrpStartDevice(IN PIRP Irp
,
76 IN PIO_STACK_LOCATION IoStackLocation
,
77 IN PPCI_FDO_EXTENSION DeviceExtension
)
80 PCM_RESOURCE_LIST Resources
;
83 /* The device stack must be starting the FDO in a success path */
84 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) return STATUS_NOT_SUPPORTED
;
86 /* Attempt to switch the state machine to the started state */
87 Status
= PciBeginStateTransition(DeviceExtension
, PciStarted
);
88 if (!NT_SUCCESS(Status
)) return Status
;
90 /* Check for any boot-provided resources */
91 Resources
= IoStackLocation
->Parameters
.StartDevice
.AllocatedResources
;
92 DPRINT1("Resources: %p\n", Resources
);
93 if ((Resources
) && !(PCI_IS_ROOT_FDO(DeviceExtension
)))
95 /* These resources would only be for non-root FDOs, unhandled for now */
96 ASSERT(Resources
->Count
== 1);
101 /* Initialize the arbiter for this FDO */
102 Status
= PciInitializeArbiterRanges(DeviceExtension
, Resources
);
103 if (!NT_SUCCESS(Status
))
105 /* Cancel the transition if this failed */
106 PciCancelStateTransition(DeviceExtension
, PciStarted
);
110 /* Again, check for boot-provided resources for non-root FDO */
111 if ((Resources
) && !(PCI_IS_ROOT_FDO(DeviceExtension
)))
113 /* Unhandled for now */
114 ASSERT(Resources
->Count
== 1);
119 /* Commit the transition to the started state */
120 PciCommitStateTransition(DeviceExtension
, PciStarted
);
121 return STATUS_SUCCESS
;
126 PciFdoIrpQueryRemoveDevice(IN PIRP Irp
,
127 IN PIO_STACK_LOCATION IoStackLocation
,
128 IN PPCI_FDO_EXTENSION DeviceExtension
)
132 return STATUS_NOT_SUPPORTED
;
137 PciFdoIrpRemoveDevice(IN PIRP Irp
,
138 IN PIO_STACK_LOCATION IoStackLocation
,
139 IN PPCI_FDO_EXTENSION DeviceExtension
)
143 return STATUS_NOT_SUPPORTED
;
148 PciFdoIrpCancelRemoveDevice(IN PIRP Irp
,
149 IN PIO_STACK_LOCATION IoStackLocation
,
150 IN PPCI_FDO_EXTENSION DeviceExtension
)
154 return STATUS_NOT_SUPPORTED
;
159 PciFdoIrpStopDevice(IN PIRP Irp
,
160 IN PIO_STACK_LOCATION IoStackLocation
,
161 IN PPCI_FDO_EXTENSION DeviceExtension
)
165 return STATUS_NOT_SUPPORTED
;
170 PciFdoIrpQueryStopDevice(IN PIRP Irp
,
171 IN PIO_STACK_LOCATION IoStackLocation
,
172 IN PPCI_FDO_EXTENSION DeviceExtension
)
176 return STATUS_NOT_SUPPORTED
;
181 PciFdoIrpCancelStopDevice(IN PIRP Irp
,
182 IN PIO_STACK_LOCATION IoStackLocation
,
183 IN PPCI_FDO_EXTENSION DeviceExtension
)
187 return STATUS_NOT_SUPPORTED
;
192 PciFdoIrpQueryDeviceRelations(IN PIRP Irp
,
193 IN PIO_STACK_LOCATION IoStackLocation
,
194 IN PPCI_FDO_EXTENSION DeviceExtension
)
199 /* Are bus relations being queried? */
200 if (IoStackLocation
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
202 /* The FDO is a bus, so only bus relations can be obtained */
203 Status
= STATUS_NOT_SUPPORTED
;
207 /* Scan the PCI bus and build the device relations for the caller */
208 Status
= PciQueryDeviceRelations(DeviceExtension
,
210 &Irp
->IoStatus
.Information
);
213 /* Return the enumeration status back */
219 PciFdoIrpQueryInterface(IN PIRP Irp
,
220 IN PIO_STACK_LOCATION IoStackLocation
,
221 IN PPCI_FDO_EXTENSION DeviceExtension
)
225 ASSERT(DeviceExtension
->ExtensionType
== PciFdoExtensionType
);
227 /* Deleted extensions don't respond to IRPs */
228 if (DeviceExtension
->DeviceState
== PciDeleted
)
230 /* Hand it bacO try to deal with it */
231 return PciPassIrpFromFdoToPdo(DeviceExtension
, Irp
);
234 /* Query our driver for this interface */
235 Status
= PciQueryInterface(DeviceExtension
,
236 IoStackLocation
->Parameters
.QueryInterface
.
238 IoStackLocation
->Parameters
.QueryInterface
.
240 IoStackLocation
->Parameters
.QueryInterface
.
242 IoStackLocation
->Parameters
.QueryInterface
.
243 InterfaceSpecificData
,
244 IoStackLocation
->Parameters
.QueryInterface
.
247 if (NT_SUCCESS(Status
))
249 /* We found it, let the PDO handle it */
250 Irp
->IoStatus
.Status
= Status
;
251 return PciPassIrpFromFdoToPdo(DeviceExtension
, Irp
);
253 else if (Status
== STATUS_NOT_SUPPORTED
)
255 /* Otherwise, we can't handle it, let someone else down the stack try */
256 Status
= PciCallDownIrpStack(DeviceExtension
, Irp
);
257 if (Status
== STATUS_NOT_SUPPORTED
)
259 /* They can't either, try a last-resort interface lookup */
260 Status
= PciQueryInterface(DeviceExtension
,
261 IoStackLocation
->Parameters
.QueryInterface
.
263 IoStackLocation
->Parameters
.QueryInterface
.
265 IoStackLocation
->Parameters
.QueryInterface
.
267 IoStackLocation
->Parameters
.QueryInterface
.
268 InterfaceSpecificData
,
269 IoStackLocation
->Parameters
.QueryInterface
.
275 /* Has anyone claimed this interface yet? */
276 if (Status
== STATUS_NOT_SUPPORTED
)
278 /* No, return the original IRP status */
279 Status
= Irp
->IoStatus
.Status
;
283 /* Yes, set the new IRP status */
284 Irp
->IoStatus
.Status
= Status
;
287 /* Complete this IRP */
288 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
294 PciFdoIrpQueryCapabilities(IN PIRP Irp
,
295 IN PIO_STACK_LOCATION IoStackLocation
,
296 IN PPCI_FDO_EXTENSION DeviceExtension
)
300 return STATUS_NOT_SUPPORTED
;
305 PciFdoIrpDeviceUsageNotification(IN PIRP Irp
,
306 IN PIO_STACK_LOCATION IoStackLocation
,
307 IN PPCI_FDO_EXTENSION DeviceExtension
)
311 return STATUS_NOT_SUPPORTED
;
316 PciFdoIrpSurpriseRemoval(IN PIRP Irp
,
317 IN PIO_STACK_LOCATION IoStackLocation
,
318 IN PPCI_FDO_EXTENSION DeviceExtension
)
322 return STATUS_NOT_SUPPORTED
;
327 PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp
,
328 IN PIO_STACK_LOCATION IoStackLocation
,
329 IN PPCI_FDO_EXTENSION DeviceExtension
)
333 return STATUS_NOT_SUPPORTED
;
338 PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension
)
340 ACPI_EVAL_INPUT_BUFFER InputBuffer
;
341 PACPI_EVAL_OUTPUT_BUFFER OutputBuffer
;
346 /* We should receive 4 parameters, per the HPP specification */
347 Length
= sizeof(ACPI_EVAL_OUTPUT_BUFFER
) + 4 * sizeof(ACPI_METHOD_ARGUMENT
);
349 /* Allocate the buffer to hold the parameters */
350 OutputBuffer
= ExAllocatePoolWithTag(PagedPool
, Length
, PCI_POOL_TAG
);
351 if (!OutputBuffer
) return;
353 /* Initialize the output and input buffers. The method is _HPP */
354 RtlZeroMemory(OutputBuffer
, Length
);
355 *(PULONG
)InputBuffer
.MethodName
= 'PPH_';
356 InputBuffer
.Signature
= ACPI_EVAL_INPUT_BUFFER_SIGNATURE
;
359 /* Send the IOCTL to the ACPI driver */
360 Status
= PciSendIoctl(FdoExtension
->PhysicalDeviceObject
,
361 IOCTL_ACPI_EVAL_METHOD
,
366 if (!NT_SUCCESS(Status
))
368 /* The method failed, check if we can salvage data from parent */
369 if (!PCI_IS_ROOT_FDO(FdoExtension
))
371 /* Copy the root bus' hot plug parameters */
372 FdoExtension
->HotPlugParameters
= FdoExtension
->ParentFdoExtension
->HotPlugParameters
;
375 /* Nothing more to do on this path */
379 /* ACPI sent back some data. 4 parameters are expected in the output */
380 if (OutputBuffer
->Count
!= 4) break;
382 /* HotPlug PCI Support not yet implemented */
387 /* Free the buffer and return */
388 ExFreePoolWithTag(OutputBuffer
, 0);
393 PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension
,
394 IN PDEVICE_OBJECT DeviceObject
,
395 IN PDEVICE_OBJECT PhysicalDeviceObject
)
397 /* Initialize the extension */
398 RtlZeroMemory(FdoExtension
, sizeof(PCI_FDO_EXTENSION
));
400 /* Setup the common fields */
401 FdoExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
402 FdoExtension
->FunctionalDeviceObject
= DeviceObject
;
403 FdoExtension
->ExtensionType
= PciFdoExtensionType
;
404 FdoExtension
->PowerState
.CurrentSystemState
= PowerSystemWorking
;
405 FdoExtension
->PowerState
.CurrentDeviceState
= PowerDeviceD0
;
406 FdoExtension
->IrpDispatchTable
= &PciFdoDispatchTable
;
408 /* Initialize the extension locks */
409 KeInitializeEvent(&FdoExtension
->SecondaryExtLock
, SynchronizationEvent
, TRUE
);
410 KeInitializeEvent(&FdoExtension
->ChildListLock
, SynchronizationEvent
, TRUE
);
412 /* Initialize the default state */
413 PciInitializeState(FdoExtension
);
418 PciAddDevice(IN PDRIVER_OBJECT DriverObject
,
419 IN PDEVICE_OBJECT PhysicalDeviceObject
)
421 PCM_RESOURCE_LIST Descriptor
;
422 PDEVICE_OBJECT AttachedTo
;
423 PPCI_FDO_EXTENSION FdoExtension
;
424 PPCI_FDO_EXTENSION ParentExtension
;
425 PDEVICE_OBJECT DeviceObject
;
426 UCHAR Buffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
427 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)Buffer
;
430 UNICODE_STRING ValueName
;
433 DPRINT1("PCI - AddDevice (a new bus). PDO: %p (Driver: %wZ)\n",
434 PhysicalDeviceObject
, &PhysicalDeviceObject
->DriverObject
->DriverName
);
436 /* Zero out variables so failure path knows what to do */
440 /* Check if there's already a device extension for this bus */
441 ParentExtension
= PciFindParentPciFdoExtension(PhysicalDeviceObject
,
445 /* More than one PCI bus, this is not expected yet */
450 /* Create the FDO for the bus */
451 Status
= IoCreateDevice(DriverObject
,
452 sizeof(PCI_FDO_EXTENSION
),
454 FILE_DEVICE_BUS_EXTENDER
,
458 if (!NT_SUCCESS(Status
)) break;
460 /* Initialize the extension for the FDO */
461 FdoExtension
= DeviceObject
->DeviceExtension
;
462 PciInitializeFdoExtensionCommonFields(DeviceObject
->DeviceExtension
,
464 PhysicalDeviceObject
);
466 /* Attach to the root PDO */
467 Status
= STATUS_NO_SUCH_DEVICE
;
468 AttachedTo
= IoAttachDeviceToDeviceStack(DeviceObject
,
469 PhysicalDeviceObject
);
470 ASSERT(AttachedTo
!= NULL
);
471 if (!AttachedTo
) break;
472 FdoExtension
->AttachedDeviceObject
= AttachedTo
;
475 /* More than one PCI bus, this is not expected yet */
481 /* Query the boot configuration */
482 Status
= PciGetDeviceProperty(PhysicalDeviceObject
,
483 DevicePropertyBootConfiguration
,
484 (PVOID
*)&Descriptor
);
485 if (!NT_SUCCESS(Status
))
487 /* No configuration has been set */
492 /* Root PDO in ReactOS does not assign boot resources */
499 /* Root PDO in ReactOS does not assign boot resources */
505 /* Default configuration isn't the normal path on Windows */
506 if (PciBreakOnDefault
)
508 /* If a second bus is found and there's still no data, crash */
510 KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL
,
512 (ULONG_PTR
)DeviceObject
,
516 DPRINT1("Windows would crash!\n");
520 /* Warn that a default configuration will be used, and set bus 0 */
521 DPRINT1("PCI Will use default configuration.\n");
522 PciBreakOnDefault
= TRUE
;
523 FdoExtension
->BaseBus
= 0;
526 /* This is the root bus */
527 FdoExtension
->BusRootFdoExtension
= FdoExtension
;
530 /* Get the HAL or ACPI Bus Handler Callbacks for Configuration Access */
531 Status
= PciGetConfigHandlers(FdoExtension
);
532 if (!NT_SUCCESS(Status
)) break;
534 /* Initialize all the supported PCI arbiters */
535 Status
= PciInitializeArbiters(FdoExtension
);
536 if (!NT_SUCCESS(Status
)) break;
538 /* This is a real FDO, insert it into the list */
539 FdoExtension
->Fake
= FALSE
;
540 PciInsertEntryAtTail(&PciFdoExtensionListHead
,
544 /* Open the device registry key so that we can query the errata flags */
545 IoOpenDeviceRegistryKey(DeviceObject
,
546 PLUGPLAY_REGKEY_DEVICE
,
550 /* Open the value that contains errata flags for this bus instance */
551 RtlInitUnicodeString(&ValueName
, L
"HackFlags");
552 Status
= ZwQueryValueKey(KeyHandle
,
554 KeyValuePartialInformation
,
559 if (NT_SUCCESS(Status
))
561 /* Make sure the data is of expected type and size */
562 if ((ValueInfo
->Type
== REG_DWORD
) &&
563 (ValueInfo
->DataLength
== sizeof(ULONG
)))
565 /* Read the flags for this bus */
566 FdoExtension
->BusHackFlags
= *(PULONG
)&ValueInfo
->Data
;
570 /* Query ACPI for PCI HotPlug Support */
571 PciGetHotPlugParameters(FdoExtension
);
573 /* The Bus FDO is now initialized */
574 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
575 DPRINT1("PCI Root FDO Added: %p %p\n", DeviceObject
, FdoExtension
);
576 return STATUS_SUCCESS
;
579 /* This is the failure path */
580 ASSERT(!NT_SUCCESS(Status
));
581 if (AttachedTo
) IoDetachDevice(AttachedTo
);
582 if (DeviceObject
) IoDeleteDevice(DeviceObject
);