reactos/drivers/bus/pcix/fdo.c
Sylvain Petreolle 1fb94b1cb5 [CMAKE]
sync with trunk (r49230)

svn path=/branches/cmake-bringup/; revision=49246
2010-10-23 22:14:59 +00:00

643 lines
22 KiB
C

/*
* PROJECT: ReactOS PCI Bus Driver
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: drivers/bus/pci/fdo.c
* PURPOSE: FDO Device Management
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <pci.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
SINGLE_LIST_ENTRY PciFdoExtensionListHead;
BOOLEAN PciBreakOnDefault;
PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] =
{
{IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoWaitWake},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoSetPowerState},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryPower},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
};
PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] =
{
{IRP_UPWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpStartDevice},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryRemoveDevice},
{IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpRemoveDevice},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelRemoveDevice},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpStopDevice},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryStopDevice},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelStopDevice},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryDeviceRelations},
{IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryInterface},
{IRP_UPWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryCapabilities},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
{IRP_UPWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpDeviceUsageNotification},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpSurpriseRemoval},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryLegacyBusInformation},
{IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
};
PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable =
{
IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
PciFdoDispatchPnpTable,
IRP_MN_QUERY_POWER,
PciFdoDispatchPowerTable,
IRP_DOWNWARD,
(PCI_DISPATCH_FUNCTION)PciIrpNotSupported,
IRP_DOWNWARD,
(PCI_DISPATCH_FUNCTION)PciIrpNotSupported
};
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
PciFdoIrpStartDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
NTSTATUS Status;
PCM_RESOURCE_LIST Resources;
PAGED_CODE();
/* The device stack must be starting the FDO in a success path */
if (!NT_SUCCESS(Irp->IoStatus.Status)) return STATUS_NOT_SUPPORTED;
/* Attempt to switch the state machine to the started state */
Status = PciBeginStateTransition(DeviceExtension, PciStarted);
if (!NT_SUCCESS(Status)) return Status;
/* Check for any boot-provided resources */
Resources = IoStackLocation->Parameters.StartDevice.AllocatedResources;
if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
{
/* These resources would only be for non-root FDOs, unhandled for now */
ASSERT(Resources->Count == 1);
UNIMPLEMENTED;
while (TRUE);
}
/* Initialize the arbiter for this FDO */
Status = PciInitializeArbiterRanges(DeviceExtension, Resources);
if (!NT_SUCCESS(Status))
{
/* Cancel the transition if this failed */
PciCancelStateTransition(DeviceExtension, PciStarted);
return Status;
}
/* Again, check for boot-provided resources for non-root FDO */
if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
{
/* Unhandled for now */
ASSERT(Resources->Count == 1);
UNIMPLEMENTED;
while (TRUE);
}
/* Commit the transition to the started state */
PciCommitStateTransition(DeviceExtension, PciStarted);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciFdoIrpQueryRemoveDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpRemoveDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpCancelRemoveDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpStopDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpQueryStopDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpCancelStopDevice(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpQueryDeviceRelations(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
NTSTATUS Status;
PAGED_CODE();
/* Are bus relations being queried? */
if (IoStackLocation->Parameters.QueryDeviceRelations.Type != BusRelations)
{
/* The FDO is a bus, so only bus relations can be obtained */
Status = STATUS_NOT_SUPPORTED;
}
else
{
/* Scan the PCI bus and build the device relations for the caller */
Status = PciQueryDeviceRelations(DeviceExtension,
(PDEVICE_RELATIONS*)
&Irp->IoStatus.Information);
}
/* Return the enumeration status back */
return Status;
}
NTSTATUS
NTAPI
PciFdoIrpQueryInterface(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
NTSTATUS Status;
PAGED_CODE();
ASSERT(DeviceExtension->ExtensionType == PciFdoExtensionType);
/* Deleted extensions don't respond to IRPs */
if (DeviceExtension->DeviceState == PciDeleted)
{
/* Hand it back to try to deal with it */
return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
}
/* Query our driver for this interface */
Status = PciQueryInterface(DeviceExtension,
IoStackLocation->Parameters.QueryInterface.
InterfaceType,
IoStackLocation->Parameters.QueryInterface.
Size,
IoStackLocation->Parameters.QueryInterface.
Version,
IoStackLocation->Parameters.QueryInterface.
InterfaceSpecificData,
IoStackLocation->Parameters.QueryInterface.
Interface,
FALSE);
if (NT_SUCCESS(Status))
{
/* We found it, let the PDO handle it */
Irp->IoStatus.Status = Status;
return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
}
else if (Status == STATUS_NOT_SUPPORTED)
{
/* Otherwise, we can't handle it, let someone else down the stack try */
Status = PciCallDownIrpStack(DeviceExtension, Irp);
if (Status == STATUS_NOT_SUPPORTED)
{
/* They can't either, try a last-resort interface lookup */
Status = PciQueryInterface(DeviceExtension,
IoStackLocation->Parameters.QueryInterface.
InterfaceType,
IoStackLocation->Parameters.QueryInterface.
Size,
IoStackLocation->Parameters.QueryInterface.
Version,
IoStackLocation->Parameters.QueryInterface.
InterfaceSpecificData,
IoStackLocation->Parameters.QueryInterface.
Interface,
TRUE);
}
}
/* Has anyone claimed this interface yet? */
if (Status == STATUS_NOT_SUPPORTED)
{
/* No, return the original IRP status */
Status = Irp->IoStatus.Status;
}
else
{
/* Yes, set the new IRP status */
Irp->IoStatus.Status = Status;
}
/* Complete this IRP */
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
PciFdoIrpQueryCapabilities(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
PDEVICE_CAPABILITIES Capabilities;
PAGED_CODE();
ASSERT_FDO(DeviceExtension);
/* Get the capabilities */
Capabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
/* Inherit wake levels and power mappings from the higher-up capabilities */
DeviceExtension->PowerState.SystemWakeLevel = Capabilities->SystemWake;
DeviceExtension->PowerState.DeviceWakeLevel = Capabilities->DeviceWake;
RtlCopyMemory(DeviceExtension->PowerState.SystemStateMapping,
Capabilities->DeviceState,
sizeof(DeviceExtension->PowerState.SystemStateMapping));
/* Dump the capabilities and return success */
PciDebugDumpQueryCapabilities(Capabilities);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PciFdoIrpDeviceUsageNotification(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpSurpriseRemoval(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp,
IN PIO_STACK_LOCATION IoStackLocation,
IN PPCI_FDO_EXTENSION DeviceExtension)
{
UNIMPLEMENTED;
while (TRUE);
return STATUS_NOT_SUPPORTED;
}
VOID
NTAPI
PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension)
{
ACPI_EVAL_INPUT_BUFFER InputBuffer;
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
ULONG Length;
NTSTATUS Status;
PAGED_CODE();
/* We should receive 4 parameters, per the HPP specification */
Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 4 * sizeof(ACPI_METHOD_ARGUMENT);
/* Allocate the buffer to hold the parameters */
OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
if (!OutputBuffer) return;
/* Initialize the output and input buffers. The method is _HPP */
RtlZeroMemory(OutputBuffer, Length);
*(PULONG)InputBuffer.MethodName = 'PPH_';
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
do
{
/* Send the IOCTL to the ACPI driver */
Status = PciSendIoctl(FdoExtension->PhysicalDeviceObject,
IOCTL_ACPI_EVAL_METHOD,
&InputBuffer,
sizeof(InputBuffer),
OutputBuffer,
Length);
if (!NT_SUCCESS(Status))
{
/* The method failed, check if we can salvage data from parent */
if (!PCI_IS_ROOT_FDO(FdoExtension))
{
/* Copy the root bus' hot plug parameters */
FdoExtension->HotPlugParameters = FdoExtension->ParentFdoExtension->HotPlugParameters;
}
/* Nothing more to do on this path */
break;
}
/* ACPI sent back some data. 4 parameters are expected in the output */
if (OutputBuffer->Count != 4) break;
/* HotPlug PCI Support not yet implemented */
UNIMPLEMENTED;
while (TRUE);
} while (FALSE);
/* Free the buffer and return */
ExFreePoolWithTag(OutputBuffer, 0);
}
VOID
NTAPI
PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension,
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
/* Initialize the extension */
RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
/* Setup the common fields */
FdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
FdoExtension->FunctionalDeviceObject = DeviceObject;
FdoExtension->ExtensionType = PciFdoExtensionType;
FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
/* Initialize the extension locks */
KeInitializeEvent(&FdoExtension->SecondaryExtLock, SynchronizationEvent, TRUE);
KeInitializeEvent(&FdoExtension->ChildListLock, SynchronizationEvent, TRUE);
/* Initialize the default state */
PciInitializeState(FdoExtension);
}
NTSTATUS
NTAPI
PciAddDevice(IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
PCM_RESOURCE_LIST Descriptor;
PDEVICE_OBJECT AttachedTo;
PPCI_FDO_EXTENSION FdoExtension;
PPCI_FDO_EXTENSION ParentExtension;
PPCI_PDO_EXTENSION PdoExtension;
PDEVICE_OBJECT DeviceObject;
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
NTSTATUS Status;
HANDLE KeyHandle;
UNICODE_STRING ValueName;
ULONG ResultLength;
PAGED_CODE();
DPRINT1("PCI - AddDevice (a new bus). PDO: %p (Driver: %wZ)\n",
PhysicalDeviceObject, &PhysicalDeviceObject->DriverObject->DriverName);
/* Zero out variables so failure path knows what to do */
AttachedTo = NULL;
FdoExtension = NULL;
PdoExtension = NULL;
do
{
/* Check if there's already a device extension for this bus */
ParentExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
&PciGlobalLock);
if (ParentExtension)
{
/* Make sure we find a real PDO */
PdoExtension = PhysicalDeviceObject->DeviceExtension;
ASSERT_PDO(PdoExtension);
/* Make sure it's a PCI-to-PCI bridge */
if ((PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) ||
(PdoExtension->SubClass != PCI_SUBCLASS_BR_PCI_TO_PCI))
{
/* This should never happen */
DPRINT1("PCI - PciAddDevice for Non-Root/Non-PCI-PCI bridge,\n"
" Class %02x, SubClass %02x, will not add.\n",
PdoExtension->BaseClass,
PdoExtension->SubClass);
ASSERT((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
/* Enter the failure path */
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
/* Subordinate bus on the bridge */
DPRINT1("PCI - AddDevice (new bus is child of bus 0x%x).\n",
ParentExtension->BaseBus);
/* Make sure PCI bus numbers are configured */
if (!PciAreBusNumbersConfigured(PdoExtension))
{
/* This is a critical failure */
DPRINT1("PCI - Bus numbers not configured for bridge (0x%x.0x%x.0x%x)\n",
ParentExtension->BaseBus,
PdoExtension->Slot.u.bits.DeviceNumber,
PdoExtension->Slot.u.bits.FunctionNumber);
/* Enter the failure path */
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
/* Create the FDO for the bus */
Status = IoCreateDevice(DriverObject,
sizeof(PCI_FDO_EXTENSION),
NULL,
FILE_DEVICE_BUS_EXTENDER,
0,
0,
&DeviceObject);
if (!NT_SUCCESS(Status)) break;
/* Initialize the extension for the FDO */
FdoExtension = DeviceObject->DeviceExtension;
PciInitializeFdoExtensionCommonFields(DeviceObject->DeviceExtension,
DeviceObject,
PhysicalDeviceObject);
/* Attach to the root PDO */
Status = STATUS_NO_SUCH_DEVICE;
AttachedTo = IoAttachDeviceToDeviceStack(DeviceObject,
PhysicalDeviceObject);
ASSERT(AttachedTo != NULL);
if (!AttachedTo) break;
FdoExtension->AttachedDeviceObject = AttachedTo;
/* Check if this is a child bus, or the root */
if (ParentExtension)
{
/* The child inherits root data */
FdoExtension->BaseBus = PdoExtension->Dependent.type1.SecondaryBus;
FdoExtension->BusRootFdoExtension = ParentExtension->BusRootFdoExtension;
PdoExtension->BridgeFdoExtension = FdoExtension;
FdoExtension->ParentFdoExtension = ParentExtension;
}
else
{
/* Query the boot configuration */
Status = PciGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyBootConfiguration,
(PVOID*)&Descriptor);
if (!NT_SUCCESS(Status))
{
/* No configuration has been set */
Descriptor = NULL;
}
else
{
/* Root PDO in ReactOS does not assign boot resources */
UNIMPLEMENTED;
// while (TRUE);
DPRINT1("Encountered during setup\n");
Descriptor = NULL;
}
if (Descriptor)
{
/* Root PDO in ReactOS does not assign boot resources */
UNIMPLEMENTED;
while (TRUE);
}
else
{
/* Default configuration isn't the normal path on Windows */
if (PciBreakOnDefault)
{
/* If a second bus is found and there's still no data, crash */
KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
0xDEAD0010u,
(ULONG_PTR)DeviceObject,
0,
0);
}
/* Warn that a default configuration will be used, and set bus 0 */
DPRINT1("PCI Will use default configuration.\n");
PciBreakOnDefault = TRUE;
FdoExtension->BaseBus = 0;
}
/* This is the root bus */
FdoExtension->BusRootFdoExtension = FdoExtension;
}
/* Get the HAL or ACPI Bus Handler Callbacks for Configuration Access */
Status = PciGetConfigHandlers(FdoExtension);
if (!NT_SUCCESS(Status)) break;
/* Initialize all the supported PCI arbiters */
Status = PciInitializeArbiters(FdoExtension);
if (!NT_SUCCESS(Status)) break;
/* This is a real FDO, insert it into the list */
FdoExtension->Fake = FALSE;
PciInsertEntryAtTail(&PciFdoExtensionListHead,
FdoExtension,
&PciGlobalLock);
/* Open the device registry key so that we can query the errata flags */
IoOpenDeviceRegistryKey(DeviceObject,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&KeyHandle),
/* Open the value that contains errata flags for this bus instance */
RtlInitUnicodeString(&ValueName, L"HackFlags");
Status = ZwQueryValueKey(KeyHandle,
&ValueName,
KeyValuePartialInformation,
ValueInfo,
sizeof(Buffer),
&ResultLength);
ZwClose(KeyHandle);
if (NT_SUCCESS(Status))
{
/* Make sure the data is of expected type and size */
if ((ValueInfo->Type == REG_DWORD) &&
(ValueInfo->DataLength == sizeof(ULONG)))
{
/* Read the flags for this bus */
FdoExtension->BusHackFlags = *(PULONG)&ValueInfo->Data;
}
}
/* Query ACPI for PCI HotPlug Support */
PciGetHotPlugParameters(FdoExtension);
/* The Bus FDO is now initialized */
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
} while (FALSE);
/* This is the failure path */
ASSERT(!NT_SUCCESS(Status));
/* Check if the FDO extension exists */
if (FdoExtension) DPRINT1("Should destroy secondaries\n");
/* Delete device objects */
if (AttachedTo) IoDetachDevice(AttachedTo);
if (DeviceObject) IoDeleteDevice(DeviceObject);
return Status;
}
/* EOF */