You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1386 lines
40 KiB
1386 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fdo.c
|
|
|
|
Abstract:
|
|
|
|
This module handles IRPs for PCI FDO's.
|
|
|
|
Author:
|
|
|
|
Adrian J. Oney (adriao) & Andrew Thornton (andrewth) 10-20-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pcip.h"
|
|
|
|
NTSTATUS
|
|
PciFdoIrpStartDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryRemoveDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpRemoveDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpCancelRemoveDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpStopDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryStopDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpCancelStopDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryCapabilities(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryInterface(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryLegacyBusInformation(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpDeviceUsageNotification(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PciFdoIrpSurpriseRemoval(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
);
|
|
|
|
VOID
|
|
PciGetHotPlugParameters(
|
|
IN PPCI_FDO_EXTENSION Fdo
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PciAddDevice)
|
|
#pragma alloc_text(PAGE, PciInitializeFdoExtensionCommonFields)
|
|
#pragma alloc_text(PAGE, PciFdoIrpStartDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpQueryRemoveDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpRemoveDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpCancelRemoveDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpQueryStopDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpStopDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpCancelStopDevice)
|
|
#pragma alloc_text(PAGE, PciFdoIrpQueryDeviceRelations)
|
|
#pragma alloc_text(PAGE, PciFdoIrpQueryInterface)
|
|
#pragma alloc_text(PAGE, PciFdoIrpQueryCapabilities)
|
|
#pragma alloc_text(PAGE, PciFdoIrpDeviceUsageNotification)
|
|
#pragma alloc_text(PAGE, PciFdoIrpSurpriseRemoval)
|
|
#pragma alloc_text(PAGE, PciFdoIrpQueryLegacyBusInformation)
|
|
#pragma alloc_text(PAGE, PciGetHotPlugParameters)
|
|
#endif
|
|
|
|
//
|
|
// The following is used to determine if we failed to get a
|
|
// reasonable configuration from the PDO (in AddDevice) more
|
|
// than once. If only once, we try to guess, if twice, we're
|
|
// in big trouble.
|
|
//
|
|
|
|
static BOOLEAN HaveGuessedConfigOnceAlready = FALSE;
|
|
|
|
/*++
|
|
|
|
The majority of functions in this file are called based on their presence
|
|
in Pnp and Po dispatch tables. In the interests of brevity the arguments
|
|
to all those functions will be described below:
|
|
|
|
NTSTATUS
|
|
PciXxxPdo(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpStack,
|
|
IN PPCI_EXTENSION DeviceExtension
|
|
)
|
|
|
|
Routine Description:
|
|
|
|
This function handles the Xxx requests for a given PCI FDO or PDO.
|
|
|
|
Arguments:
|
|
|
|
Irp - Points to the IRP associated with this request.
|
|
|
|
IrpStack - Points to the current stack location for this request.
|
|
|
|
DeviceExtension - Points to the device's extension.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
STATUS_NOT_SUPPORTED indicates that the IRP should be completed without
|
|
changing the Irp->IoStatus.Status field otherwise it is updated with this
|
|
status.
|
|
|
|
--*/
|
|
|
|
#define PCI_MAX_MINOR_POWER_IRP 0x3
|
|
#define PCI_MAX_MINOR_PNP_IRP 0x18
|
|
|
|
PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] = {
|
|
{ IRP_DISPATCH, PciFdoWaitWake }, // 0x00 - IRP_MN_WAIT_WAKE
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x01 - IRP_MN_POWER_SEQUENCE
|
|
{ IRP_DOWNWARD, PciFdoSetPowerState }, // 0x02 - IRP_MN_SET_POWER
|
|
{ IRP_DOWNWARD, PciFdoIrpQueryPower }, // 0x03 - IRP_MN_QUERY_POWER
|
|
{ IRP_DOWNWARD, PciIrpNotSupported } // - UNHANDLED Power IRP
|
|
};
|
|
|
|
PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] = {
|
|
{ IRP_UPWARD, PciFdoIrpStartDevice }, // 0x00 - IRP_MN_START_DEVICE
|
|
{ IRP_DOWNWARD, PciFdoIrpQueryRemoveDevice }, // 0x01 - IRP_MN_QUERY_REMOVE_DEVICE
|
|
{ IRP_DISPATCH, PciFdoIrpRemoveDevice }, // 0x02 - IRP_MN_REMOVE_DEVICE
|
|
{ IRP_DOWNWARD, PciFdoIrpCancelRemoveDevice }, // 0x03 - IRP_MN_CANCEL_REMOVE_DEVICE
|
|
{ IRP_DOWNWARD, PciFdoIrpStopDevice }, // 0x04 - IRP_MN_STOP_DEVICE
|
|
{ IRP_DOWNWARD, PciFdoIrpQueryStopDevice }, // 0x05 - IRP_MN_QUERY_STOP_DEVICE
|
|
{ IRP_DOWNWARD, PciFdoIrpCancelStopDevice }, // 0x06 - IRP_MN_CANCEL_STOP_DEVICE
|
|
{ IRP_DOWNWARD, PciFdoIrpQueryDeviceRelations }, // 0x07 - IRP_MN_QUERY_DEVICE_RELATIONS
|
|
{ IRP_DISPATCH, PciFdoIrpQueryInterface }, // 0x08 - IRP_MN_QUERY_INTERFACE
|
|
{ IRP_UPWARD, PciFdoIrpQueryCapabilities }, // 0x09 - IRP_MN_QUERY_CAPABILITIES
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x0A - IRP_MN_QUERY_RESOURCES
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x0B - IRP_MN_QUERY_RESOURCE_REQUIREMENTS
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x0C - IRP_MN_QUERY_DEVICE_TEXT
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x0D - IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x0E - NOT USED
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x0F - IRP_MN_READ_CONFIG
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x10 - IRP_MN_WRITE_CONFIG
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x11 - IRP_MN_EJECT
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x12 - IRP_MN_SET_LOCK
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x13 - IRP_MN_QUERY_ID
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x14 - IRP_MN_QUERY_PNP_DEVICE_STATE
|
|
{ IRP_DOWNWARD, PciIrpNotSupported }, // 0x15 - IRP_MN_QUERY_BUS_INFORMATION
|
|
{ IRP_UPWARD, PciFdoIrpDeviceUsageNotification }, // 0x16 - IRP_MN_DEVICE_USAGE_NOTIFICATION
|
|
{ IRP_DOWNWARD, PciFdoIrpSurpriseRemoval }, // 0x17 - IRP_MN_SURPRISE_REMOVAL
|
|
{ IRP_DOWNWARD, PciFdoIrpQueryLegacyBusInformation }, // 0x18 - IRP_MN_QUERY_LEGACY_BUS_INFORMATION
|
|
{ IRP_DOWNWARD, PciIrpNotSupported } // - UNHANDLED PNP IRP
|
|
};
|
|
|
|
//
|
|
// This is the major function dispatch table for Fdo's
|
|
//
|
|
PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable = {
|
|
PCI_MAX_MINOR_PNP_IRP, PciFdoDispatchPnpTable, // Pnp irps
|
|
PCI_MAX_MINOR_POWER_IRP, PciFdoDispatchPowerTable, // Power irps
|
|
IRP_DOWNWARD, PciIrpNotSupported, // SystemControl - just pass down!
|
|
IRP_DOWNWARD, PciIrpNotSupported // DeviceControl - just pass down!
|
|
};
|
|
|
|
NTSTATUS
|
|
PciFdoIrpStartDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler routine for start IRPs. This allows PDO filters to
|
|
modify the allocated resources if they are filtering resource
|
|
requirements. Called after completion.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies the device object
|
|
|
|
Irp - Supplies the IRP_MN_START_DEVICE irp.
|
|
|
|
FdoExtension - Supplies the FDO extension
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful
|
|
|
|
NTSTATUS error code otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PPCI_FDO_EXTENSION fdoExtension;
|
|
PPCI_PDO_EXTENSION pdoExtension = NULL;
|
|
PCM_RESOURCE_LIST resources;
|
|
UCHAR barType[PCI_TYPE1_ADDRESSES] = {0,0};
|
|
ULONG index;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR currentResource;
|
|
PIO_RESOURCE_DESCRIPTOR currentRequirement;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
|
|
|
|
status = PciBeginStateTransition(DeviceExtension, PciStarted);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// If this is a PCI-PCI bridge then check if it has any bars and if so exclude
|
|
// them from the list used to initialize the arbiters.
|
|
//
|
|
|
|
resources = IrpSp->Parameters.StartDevice.AllocatedResources;
|
|
|
|
if (resources && !PCI_IS_ROOT_FDO(fdoExtension)) {
|
|
|
|
PCI_ASSERT(resources->Count == 1);
|
|
|
|
pdoExtension = PCI_BRIDGE_PDO(fdoExtension);
|
|
|
|
if (pdoExtension->Resources) {
|
|
|
|
if (pdoExtension->HeaderType == PCI_BRIDGE_TYPE) {
|
|
|
|
//
|
|
// If there are any bars they are at the beginning of the list
|
|
// so "begin at the beginning which is a very good place to start".
|
|
//
|
|
|
|
currentResource = resources->List[0].PartialResourceList.PartialDescriptors;
|
|
|
|
for (index = 0; index < PCI_TYPE1_ADDRESSES; index++) {
|
|
|
|
//
|
|
// Extract the requirement we asked for to determine if this
|
|
// bridge implements any bars (index 0 and 1 in the Limits
|
|
// array)
|
|
//
|
|
|
|
currentRequirement = &pdoExtension->Resources->Limit[index];
|
|
|
|
//
|
|
// CmResourceTypeNull indicates that we didn't request any
|
|
// resources so the bar is not implemented and there is nothing
|
|
// to prune out.
|
|
//
|
|
|
|
if (currentRequirement->Type != CmResourceTypeNull) {
|
|
|
|
PCI_ASSERT(currentResource->Type == currentRequirement->Type);
|
|
|
|
//
|
|
// Save away the type so we can restore it later
|
|
//
|
|
|
|
barType[index] = currentResource->Type;
|
|
|
|
//
|
|
// Null out the resource so we don't configure the arbiters to
|
|
// use it
|
|
//
|
|
|
|
currentResource->Type = CmResourceTypeNull;
|
|
|
|
//
|
|
// Advance the pointer into the started resources by 2
|
|
// descriptors to skip over the device private
|
|
//
|
|
|
|
PCI_ASSERT((currentResource+1)->Type == CmResourceTypeDevicePrivate);
|
|
|
|
currentResource+=2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize arbiters with these resources.
|
|
//
|
|
status = PciInitializeArbiterRanges(fdoExtension, resources);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Restore the original resource list if we changed it
|
|
//
|
|
|
|
if (resources && !PCI_IS_ROOT_FDO(fdoExtension) && pdoExtension->Resources) {
|
|
|
|
currentResource = resources->List[0].PartialResourceList.PartialDescriptors;
|
|
|
|
for (index = 0; index < PCI_TYPE1_ADDRESSES; index++) {
|
|
|
|
if (barType[index] != CmResourceTypeNull) {
|
|
|
|
currentResource->Type = barType[index];
|
|
|
|
//
|
|
// Advance the pointer into the started resources by 2
|
|
// descriptors to skip over the device private
|
|
//
|
|
|
|
PCI_ASSERT((currentResource+1)->Type == CmResourceTypeDevicePrivate);
|
|
|
|
currentResource+=2;
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
PciCancelStateTransition(DeviceExtension, PciStarted);
|
|
return status;
|
|
}
|
|
|
|
PciCommitStateTransition(DeviceExtension, PciStarted);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryRemoveDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
return PciBeginStateTransition(DeviceExtension, PciDeleted);
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpRemoveDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PPCI_FDO_EXTENSION fdoExtension;
|
|
PPCI_PDO_EXTENSION pdox;
|
|
PDEVICE_OBJECT attachedDevice;
|
|
NTSTATUS status;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
|
|
|
|
ExAcquireFastMutex(&fdoExtension->ChildListMutex);
|
|
|
|
while (fdoExtension->ChildPdoList) {
|
|
|
|
pdox = (PPCI_PDO_EXTENSION) fdoExtension->ChildPdoList;
|
|
#if DBG
|
|
|
|
PciDebugPrint(
|
|
PciDbgVerbose,
|
|
"PCI Killing PDO %p PDOx %p (b=%d, d=%d, f=%d)\n",
|
|
pdox->PhysicalDeviceObject,
|
|
pdox,
|
|
PCI_PARENT_FDOX(pdox)->BaseBus,
|
|
pdox->Slot.u.bits.DeviceNumber,
|
|
pdox->Slot.u.bits.FunctionNumber
|
|
);
|
|
|
|
PCI_ASSERT(pdox->DeviceState == PciNotStarted);
|
|
|
|
#endif
|
|
PciPdoDestroy(pdox->PhysicalDeviceObject);
|
|
}
|
|
|
|
ExReleaseFastMutex(&fdoExtension->ChildListMutex);
|
|
|
|
//
|
|
// Destroy any secondary extensions associated with
|
|
// this FDO.
|
|
//
|
|
while (fdoExtension->SecondaryExtension.Next) {
|
|
|
|
PcipDestroySecondaryExtension(
|
|
&fdoExtension->SecondaryExtension,
|
|
NULL,
|
|
fdoExtension->SecondaryExtension.Next
|
|
);
|
|
}
|
|
|
|
//
|
|
// Destroy the FDO.
|
|
//
|
|
// The IRP needs to go down the device stack but we
|
|
// need to remove the device from the stack so grab
|
|
// the next object first, then detach, then pass it
|
|
// down.
|
|
//
|
|
PciDebugPrint(
|
|
PciDbgInformative,
|
|
"PCI FDOx (%p) destroyed.",
|
|
fdoExtension
|
|
);
|
|
|
|
//
|
|
// Note that a filter above us may have failed Start. If this is so, we get
|
|
// no query because the "devnode" has never been started...
|
|
//
|
|
if (!PciIsInTransitionToState(DeviceExtension, PciDeleted)) {
|
|
|
|
status = PciBeginStateTransition(DeviceExtension, PciDeleted);
|
|
PCI_ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
PciCommitStateTransition(DeviceExtension, PciDeleted);
|
|
|
|
PciRemoveEntryFromList(&PciFdoExtensionListHead,
|
|
&fdoExtension->List,
|
|
&PciGlobalLock);
|
|
|
|
attachedDevice = fdoExtension->AttachedDeviceObject;
|
|
IoDetachDevice(attachedDevice);
|
|
IoDeleteDevice(fdoExtension->FunctionalDeviceObject);
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(attachedDevice, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpCancelRemoveDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
PciCancelStateTransition(DeviceExtension, PciDeleted);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpStopDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
PciCommitStateTransition(DeviceExtension, PciStopped);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryStopDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
PciBeginStateTransition(DeviceExtension, PciStopped);
|
|
|
|
//
|
|
// We don't support multilevel rebalance so we can't stop host bridges.
|
|
//
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpCancelStopDevice(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
PciCancelStateTransition(DeviceExtension, PciStopped);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryDeviceRelations(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (IrpSp->Parameters.QueryDeviceRelations.Type == BusRelations) {
|
|
|
|
return PciQueryDeviceRelations(
|
|
(PPCI_FDO_EXTENSION) DeviceExtension,
|
|
(PDEVICE_RELATIONS *) &Irp->IoStatus.Information
|
|
);
|
|
}
|
|
|
|
//
|
|
// No other relation types need to be handled.
|
|
//
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryCapabilities(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Snoops the results of a QUERY CAPABILITIES IRP that got sent
|
|
downwards. This saves us having to send our own for things
|
|
like the device's power characteristics.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies the device object
|
|
|
|
Irp - Supplies the IRP_MN_QUERY_CAPABILITIES irp.
|
|
|
|
FdoExtension - Supplies the FDO extension
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_CAPABILITIES capabilities;
|
|
PPCI_FDO_EXTENSION fdoExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
|
|
|
|
ASSERT_PCI_FDO_EXTENSION(fdoExtension);
|
|
|
|
PciDebugPrint(
|
|
PciDbgQueryCap,
|
|
"PCI - FdoQueryCapabilitiesCompletion (fdox %08x) child status = %08x\n",
|
|
fdoExtension,
|
|
Irp->IoStatus.Status
|
|
);
|
|
|
|
//
|
|
// Grab a pointer to the capablities for easy referencing
|
|
//
|
|
capabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
//
|
|
// Remember what the system wake and device wake level are
|
|
//
|
|
fdoExtension->PowerState.SystemWakeLevel = capabilities->SystemWake;
|
|
fdoExtension->PowerState.DeviceWakeLevel = capabilities->DeviceWake;
|
|
|
|
//
|
|
// Grab the S-state to D-State mapping
|
|
//
|
|
RtlCopyMemory(
|
|
fdoExtension->PowerState.SystemStateMapping,
|
|
capabilities->DeviceState,
|
|
(PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE)
|
|
);
|
|
|
|
#if DBG
|
|
|
|
if (PciDebug & PciDbgQueryCap) {
|
|
PciDebugDumpQueryCapabilities(capabilities);
|
|
}
|
|
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryLegacyBusInformation(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
return PciQueryLegacyBusInformation(
|
|
(PPCI_FDO_EXTENSION) DeviceExtension,
|
|
(PLEGACY_BUS_INFORMATION *) &Irp->IoStatus.Information
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpDeviceUsageNotification(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PPCI_FDO_EXTENSION fdoExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
return PciLocalDeviceUsage(&fdoExtension->PowerState, Irp);
|
|
|
|
} else {
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpQueryInterface(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PPCI_FDO_EXTENSION fdoExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
|
|
|
|
ASSERT_PCI_FDO_EXTENSION(fdoExtension);
|
|
|
|
|
|
// NTRAID #54671 - 4/20/2000 - andrewth
|
|
//
|
|
// We might want to do a synchronizing state
|
|
// transition here so we don't attempt to get the interface during a
|
|
// stop/remove sequence.
|
|
//
|
|
// We shouldn't hold interfaces when something isn't
|
|
// started. But we won't boot unless we hack the below....
|
|
//
|
|
|
|
//if (fdoExtension->DeviceState != PciStarted) {
|
|
if (fdoExtension->DeviceState == PciDeleted) {
|
|
|
|
return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
|
|
}
|
|
|
|
status = PciQueryInterface(
|
|
fdoExtension,
|
|
IrpSp->Parameters.QueryInterface.InterfaceType,
|
|
IrpSp->Parameters.QueryInterface.Size,
|
|
IrpSp->Parameters.QueryInterface.Version,
|
|
IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
|
|
IrpSp->Parameters.QueryInterface.Interface,
|
|
FALSE
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
|
|
|
|
} else if (status == STATUS_NOT_SUPPORTED) {
|
|
|
|
//
|
|
// Status == STATUS_NOT_SUPPORTED. Pass IRP down the stack
|
|
// and see if anyone else is kind enough to provide this
|
|
// interface.
|
|
//
|
|
status = PciCallDownIrpStack(DeviceExtension, Irp);
|
|
|
|
if (status == STATUS_NOT_SUPPORTED) {
|
|
|
|
//
|
|
// If nobody provided the interface, try again at
|
|
// this level.
|
|
//
|
|
status = PciQueryInterface(
|
|
fdoExtension,
|
|
IrpSp->Parameters.QueryInterface.InterfaceType,
|
|
IrpSp->Parameters.QueryInterface.Size,
|
|
IrpSp->Parameters.QueryInterface.Version,
|
|
IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
|
|
IrpSp->Parameters.QueryInterface.Interface,
|
|
TRUE
|
|
);
|
|
}
|
|
}
|
|
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
} else {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciFdoIrpSurpriseRemoval(
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp,
|
|
IN PPCI_COMMON_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PPCI_FDO_EXTENSION fdoExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
|
|
|
|
status = PciBeginStateTransition(DeviceExtension, PciSurpriseRemoved);
|
|
PCI_ASSERT(NT_SUCCESS(status));
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
PciCommitStateTransition(DeviceExtension, PciSurpriseRemoved);
|
|
status = PciBeginStateTransition(DeviceExtension, PciDeleted);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PciAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a physical device object, this routine creates a functional
|
|
device object for it.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to our driver's DRIVER_OBJECT structure.
|
|
|
|
PhysicalDeviceObject - Pointer to the physical device object for which
|
|
we must create a functional device object.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT functionalDeviceObject = NULL;
|
|
PDEVICE_OBJECT attachedTo = NULL;
|
|
PPCI_FDO_EXTENSION fdoExtension = NULL;
|
|
PPCI_FDO_EXTENSION pciParentFdoExtension;
|
|
PPCI_PDO_EXTENSION pdoExtension = NULL;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
|
|
NTSTATUS status;
|
|
HANDLE deviceRegistryHandle;
|
|
ULONG resultLength;
|
|
UNICODE_STRING hackFlagsString;
|
|
UCHAR infoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1];
|
|
PKEY_VALUE_PARTIAL_INFORMATION info = (PKEY_VALUE_PARTIAL_INFORMATION) infoBuffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
PciDebugPrint(PciDbgAddDevice, "PCI - AddDevice (a new bus).\n");
|
|
|
|
//
|
|
// Find out if the PDO was created by the PCI driver. That is,
|
|
// if it is a child or a root bus. Validate a few things before
|
|
// going any further.
|
|
//
|
|
|
|
pciParentFdoExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
|
|
&PciGlobalLock);
|
|
if (pciParentFdoExtension) {
|
|
|
|
//
|
|
// The PDO was created by this driver, therefore we can look at
|
|
// the extension. Get it and verify it's ours.
|
|
//
|
|
|
|
pdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
|
|
ASSERT_PCI_PDO_EXTENSION(pdoExtension);
|
|
|
|
//
|
|
// The only thing we should get an add device that is a
|
|
// child device is a PCI-PCI bridge.
|
|
//
|
|
|
|
if ((pdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) ||
|
|
(pdoExtension->SubClass != PCI_SUBCLASS_BR_PCI_TO_PCI)) {
|
|
PciDebugPrint(
|
|
PciDbgAlways,
|
|
"PCI - PciAddDevice for Non-Root/Non-PCI-PCI bridge,\n"
|
|
" Class %02x, SubClass %02x, will not add.\n",
|
|
pdoExtension->BaseClass,
|
|
pdoExtension->SubClass
|
|
);
|
|
PCI_ASSERT((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
|
|
(pdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto cleanup;
|
|
}
|
|
|
|
PciDebugPrint(PciDbgAddDevice,
|
|
"PCI - AddDevice (new bus is child of bus 0x%x).\n",
|
|
pciParentFdoExtension->BaseBus
|
|
);
|
|
|
|
if (!PciAreBusNumbersConfigured(pdoExtension)) {
|
|
|
|
//
|
|
// This bridge isn't configured and if we had been able to we would
|
|
// already have done so
|
|
//
|
|
|
|
PciDebugPrint(
|
|
PciDbgAddDevice | PciDbgInformative,
|
|
"PCI - Bus numbers not configured for bridge (0x%x.0x%x.0x%x)\n",
|
|
pciParentFdoExtension->BaseBus,
|
|
pdoExtension->Slot.u.bits.DeviceNumber,
|
|
pdoExtension->Slot.u.bits.FunctionNumber,
|
|
pdoExtension->Dependent.type1.PrimaryBus
|
|
);
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto cleanup;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've been given the PhysicalDeviceObject for a PCI bus. Create the
|
|
// functionalDeviceObject. Our FDO will be nameless.
|
|
//
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // our driver object
|
|
sizeof(PCI_FDO_EXTENSION), // size of our extension
|
|
NULL, // our name
|
|
FILE_DEVICE_BUS_EXTENDER, // device type
|
|
0, // device characteristics
|
|
FALSE, // not exclusive
|
|
&functionalDeviceObject // store new device object here
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
fdoExtension = (PPCI_FDO_EXTENSION)functionalDeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// We have our functionalDeviceObject, initialize it.
|
|
//
|
|
|
|
PciInitializeFdoExtensionCommonFields(
|
|
fdoExtension,
|
|
functionalDeviceObject,
|
|
PhysicalDeviceObject
|
|
);
|
|
|
|
//
|
|
// Now attach to the PDO we were given.
|
|
//
|
|
|
|
attachedTo = IoAttachDeviceToDeviceStack(functionalDeviceObject,
|
|
PhysicalDeviceObject);
|
|
|
|
if (attachedTo == NULL) {
|
|
|
|
PCI_ASSERT(attachedTo != NULL);
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
goto cleanup;
|
|
}
|
|
|
|
fdoExtension->AttachedDeviceObject = attachedTo;
|
|
|
|
//
|
|
// Get the access registers and base bus number for this bus.
|
|
// If this bus was discovered by this driver, then the PDO was
|
|
// created by this driver and will be on one of the PDO lists
|
|
// under one of the FDOs owned by this driver. Otherwise it
|
|
// is a new root,.... use magic.
|
|
//
|
|
|
|
if (pciParentFdoExtension) {
|
|
|
|
//
|
|
// This physical device was discovered by this driver.
|
|
// Get the bus number from the PDO extension.
|
|
//
|
|
|
|
fdoExtension->BaseBus = pdoExtension->Dependent.type1.SecondaryBus;
|
|
|
|
//
|
|
// Copy the access methods from the root fdo and set
|
|
// the root fdo back pointer.
|
|
//
|
|
|
|
fdoExtension->BusRootFdoExtension =
|
|
pciParentFdoExtension->BusRootFdoExtension;
|
|
|
|
//
|
|
// Point the PDOextension to the new FDOextension (also indicates
|
|
// the object is a bridge) and vice versa.
|
|
//
|
|
|
|
pdoExtension->BridgeFdoExtension = fdoExtension;
|
|
fdoExtension->ParentFdoExtension = pciParentFdoExtension;
|
|
|
|
} else {
|
|
|
|
PVOID buffer;
|
|
|
|
//
|
|
// Get the boot configuration (CmResourceList) for
|
|
// this PDO. This gives us the bus number and the
|
|
// ranges covered by this host bridge.
|
|
//
|
|
|
|
status = PciGetDeviceProperty(
|
|
PhysicalDeviceObject,
|
|
DevicePropertyBootConfiguration,
|
|
&buffer
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
#if DBG
|
|
|
|
PciDebugPrint(PciDbgAddDeviceRes,
|
|
"PCI - CM RESOURCE LIST FROM ROOT PDO\n");
|
|
PciDebugPrintCmResList(PciDbgAddDeviceRes,
|
|
buffer);
|
|
|
|
#endif
|
|
|
|
descriptor = PciFindDescriptorInCmResourceList(
|
|
CmResourceTypeBusNumber,
|
|
buffer,
|
|
NULL
|
|
);
|
|
} else {
|
|
|
|
descriptor = NULL;
|
|
}
|
|
|
|
if (descriptor != NULL) {
|
|
|
|
//
|
|
// Sanity check, some servers are aproaching
|
|
// 256 busses but as there is no way to deal with
|
|
// numbering bridges under a bus > 256 and we don't
|
|
// have raw and translated bus numbers yet - it had
|
|
// better be < 0xFF!
|
|
//
|
|
|
|
PCI_ASSERT(descriptor->u.BusNumber.Start <= 0xFF);
|
|
PCI_ASSERT(descriptor->u.BusNumber.Start + descriptor->u.BusNumber.Length - 1 <= 0xFF);
|
|
|
|
fdoExtension->BaseBus =
|
|
(UCHAR)descriptor->u.BusNumber.Start;
|
|
fdoExtension->MaxSubordinateBus =
|
|
(UCHAR)(descriptor->u.BusNumber.Start + descriptor->u.BusNumber.Length - 1);
|
|
PciDebugPrint(PciDbgAddDevice,
|
|
"PCI - Root Bus # 0x%x->0x%x.\n",
|
|
fdoExtension->BaseBus,
|
|
fdoExtension->MaxSubordinateBus
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// HaveGuessedConfigOnceAlready is used to tell
|
|
// if have multiple roots and no config info. If
|
|
// this happens we end up gussing the bus number
|
|
// as zero, doing this more than once is not good.
|
|
//
|
|
|
|
if (HaveGuessedConfigOnceAlready) {
|
|
|
|
KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
|
|
PCI_BUGCODE_TOO_MANY_CONFIG_GUESSES,
|
|
(ULONG_PTR)PhysicalDeviceObject,
|
|
0,
|
|
0);
|
|
}
|
|
PciDebugPrint(
|
|
PciDbgAlways,
|
|
"PCI Will use default configuration.\n"
|
|
);
|
|
|
|
HaveGuessedConfigOnceAlready = TRUE;
|
|
fdoExtension->BaseBus = 0;
|
|
}
|
|
|
|
fdoExtension->BusRootFdoExtension = fdoExtension;
|
|
}
|
|
|
|
//
|
|
// Organise access to config space
|
|
//
|
|
|
|
status = PciGetConfigHandlers(fdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize arbiters for this FDO.
|
|
//
|
|
status = PciInitializeArbiters(fdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Indicate this is a REAL FDO extension that is part of a REAL
|
|
// FDO. (Fake extensions exist to assist in the enumeration of
|
|
// busses which PCI isn't the real controller for (eg CardBus).
|
|
//
|
|
|
|
fdoExtension->Fake = FALSE;
|
|
|
|
//
|
|
// Insert this Fdo in the list of PCI parent Fdos.
|
|
//
|
|
|
|
PciInsertEntryAtTail(&PciFdoExtensionListHead,
|
|
&fdoExtension->List,
|
|
&PciGlobalLock);
|
|
|
|
|
|
#if defined(_WIN64)
|
|
|
|
//
|
|
// Update the legacy hardware tree that would have been build by the ARC
|
|
// firmware or NTDetect which don't exist here.
|
|
//
|
|
|
|
status = PciUpdateLegacyHardwareDescription(fdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Check if there are any hacks to apply to this bus.
|
|
// These are located under the device registry key in a value called HackFlags
|
|
//
|
|
|
|
status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
KEY_ALL_ACCESS,
|
|
&deviceRegistryHandle
|
|
);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
PciConstStringToUnicodeString(&hackFlagsString, L"HackFlags");
|
|
|
|
status = ZwQueryValueKey(deviceRegistryHandle,
|
|
&hackFlagsString,
|
|
KeyValuePartialInformation,
|
|
info,
|
|
sizeof(infoBuffer),
|
|
&resultLength
|
|
);
|
|
|
|
ZwClose(deviceRegistryHandle);
|
|
|
|
//
|
|
// If we have valid data in the registry then remember it
|
|
//
|
|
|
|
if (NT_SUCCESS(status)
|
|
&& (info->Type == REG_DWORD)
|
|
&& (info->DataLength == sizeof(ULONG))) {
|
|
|
|
fdoExtension->BusHackFlags = *((PULONG)(&info->Data));
|
|
}
|
|
|
|
//
|
|
// We can receive IRPs now...
|
|
//
|
|
|
|
functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
|
//
|
|
// Get any hotplug parameters (we send IRPS for this so it must be after
|
|
// DO_DEVICE_INITIALIZING is cleared so we can deal with them)
|
|
//
|
|
PciGetHotPlugParameters(fdoExtension);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
PCI_ASSERT(!NT_SUCCESS(status));
|
|
|
|
//
|
|
// Destroy any secondary extensions associated with
|
|
// this FDO.
|
|
//
|
|
if (fdoExtension) {
|
|
|
|
while (fdoExtension->SecondaryExtension.Next) {
|
|
|
|
PcipDestroySecondaryExtension(
|
|
&fdoExtension->SecondaryExtension,
|
|
NULL,
|
|
fdoExtension->SecondaryExtension.Next
|
|
);
|
|
}
|
|
}
|
|
|
|
if (attachedTo) {
|
|
IoDetachDevice(attachedTo);
|
|
}
|
|
|
|
if (functionalDeviceObject) {
|
|
IoDeleteDevice(functionalDeviceObject);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
PciInitializeFdoExtensionCommonFields(
|
|
IN PPCI_FDO_EXTENSION FdoExtension,
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
{
|
|
RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
|
|
|
|
FdoExtension->ExtensionType = PciFdoExtensionType;
|
|
FdoExtension->PhysicalDeviceObject = Pdo;
|
|
FdoExtension->FunctionalDeviceObject = Fdo;
|
|
FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
|
|
FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
|
|
FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
|
|
ExInitializeFastMutex(&FdoExtension->SecondaryExtMutex);
|
|
ExInitializeFastMutex(&FdoExtension->ChildListMutex);
|
|
PciInitializeState((PPCI_COMMON_EXTENSION) FdoExtension);
|
|
}
|
|
|
|
VOID
|
|
PciGetHotPlugParameters(
|
|
IN PPCI_FDO_EXTENSION Fdo
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Runs the _HPP (described below) on the device and saves the parameters if available
|
|
|
|
Method (_HPP, 0) {
|
|
Return (Package(){
|
|
0x00000008, // CacheLineSize in DWORDS
|
|
0x00000040, // LatencyTimer in PCI clocks
|
|
0x00000001, // Enable SERR (Boolean)
|
|
0x00000001 // Enable PERR (Boolean)
|
|
})
|
|
|
|
Arguments:
|
|
|
|
Fdo - The PDO extension for the bridge
|
|
|
|
Return Value:
|
|
|
|
TRUE - if the parameters are available, FASLE otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ACPI_EVAL_INPUT_BUFFER input;
|
|
PACPI_EVAL_OUTPUT_BUFFER output = NULL;
|
|
ULONG count;
|
|
ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + sizeof(ACPI_METHOD_ARGUMENT) * PCI_HPP_PACKAGE_COUNT;
|
|
|
|
PAGED_CODE();
|
|
|
|
output = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, outputSize);
|
|
|
|
if (!output) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
|
|
RtlZeroMemory(output, outputSize);
|
|
|
|
//
|
|
// Send a IOCTL to ACPI to request it to run the _HPP method on this device
|
|
// if the method it is present
|
|
//
|
|
|
|
input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
|
input.MethodNameAsUlong = (ULONG)'PPH_';
|
|
|
|
//
|
|
// PciSendIoctl deals with sending this from the top of the stack.
|
|
//
|
|
|
|
status = PciSendIoctl(Fdo->PhysicalDeviceObject,
|
|
IOCTL_ACPI_EVAL_METHOD,
|
|
&input,
|
|
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
|
output,
|
|
outputSize
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Inherit them from my parent (If I have one)
|
|
//
|
|
|
|
if (!PCI_IS_ROOT_FDO(Fdo)) {
|
|
RtlCopyMemory(&Fdo->HotPlugParameters,
|
|
&Fdo->ParentFdoExtension->HotPlugParameters,
|
|
sizeof(Fdo->HotPlugParameters)
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (output->Count != PCI_HPP_PACKAGE_COUNT) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Check they are all integers and in the right bounds
|
|
//
|
|
|
|
for (count = 0; count < PCI_HPP_PACKAGE_COUNT; count++) {
|
|
ULONG current;
|
|
|
|
if (output->Argument[count].Type != ACPI_METHOD_ARGUMENT_INTEGER) {
|
|
goto exit;
|
|
}
|
|
|
|
current = output->Argument[count].Argument;
|
|
switch (count) {
|
|
case PCI_HPP_CACHE_LINE_SIZE_INDEX:
|
|
case PCI_HPP_LATENCY_TIMER_INDEX:
|
|
//
|
|
// These registers are only a UCHAR in length
|
|
//
|
|
if (current > 0xFF) {
|
|
goto exit;
|
|
}
|
|
break;
|
|
case PCI_HPP_ENABLE_SERR_INDEX:
|
|
case PCI_HPP_ENABLE_PERR_INDEX:
|
|
//
|
|
// These are booleans - 1 or 0
|
|
//
|
|
if (current > 1) {
|
|
goto exit;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally save them and remember we got them.
|
|
//
|
|
|
|
Fdo->HotPlugParameters.CacheLineSize = (UCHAR)output->Argument[PCI_HPP_CACHE_LINE_SIZE_INDEX].Argument;
|
|
Fdo->HotPlugParameters.LatencyTimer = (UCHAR)output->Argument[PCI_HPP_LATENCY_TIMER_INDEX].Argument;
|
|
Fdo->HotPlugParameters.EnableSERR = (BOOLEAN)output->Argument[PCI_HPP_ENABLE_SERR_INDEX].Argument;
|
|
Fdo->HotPlugParameters.EnablePERR = (BOOLEAN)output->Argument[PCI_HPP_ENABLE_PERR_INDEX].Argument;
|
|
Fdo->HotPlugParameters.Acquired = TRUE;
|
|
}
|
|
|
|
exit:
|
|
|
|
if (output) {
|
|
ExFreePool(output);
|
|
}
|
|
}
|
|
|