901 lines
21 KiB
C
901 lines
21 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
routintf.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the "Pci Interrupt Routing" interfaces supported
|
||
by the PCI driver.
|
||
|
||
Author:
|
||
|
||
Jake Oshins (jakeo) 19-Jul-1997
|
||
|
||
Revision History:
|
||
|
||
Elliot Shmukler (t-ellios) 7-15-1998 Modified the PCI routing interface to support
|
||
MSI capable devices.
|
||
|
||
--*/
|
||
|
||
#include "pcip.h"
|
||
|
||
#define MSI_SIMULATE 0
|
||
|
||
//
|
||
// Prototypes for routines exposed only thru the "interface"
|
||
// mechanism.
|
||
//
|
||
|
||
NTSTATUS
|
||
routeintrf_Constructor(
|
||
PVOID DeviceExtension,
|
||
PVOID PciInterface,
|
||
PVOID InterfaceSpecificData,
|
||
USHORT Version,
|
||
USHORT Size,
|
||
PINTERFACE InterfaceReturn
|
||
);
|
||
|
||
NTSTATUS
|
||
routeintrf_Initializer(
|
||
IN PPCI_ARBITER_INSTANCE Instance
|
||
);
|
||
|
||
VOID
|
||
routeintrf_Reference(
|
||
IN PVOID Context
|
||
);
|
||
|
||
VOID
|
||
routeintrf_Dereference(
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
PciGetInterruptRoutingInfoEx(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT ULONG *Bus,
|
||
OUT ULONG *PciSlot,
|
||
OUT UCHAR *InterruptLine,
|
||
OUT UCHAR *InterruptPin,
|
||
OUT UCHAR *ClassCode,
|
||
OUT UCHAR *SubClassCode,
|
||
OUT PDEVICE_OBJECT *ParentPdo,
|
||
OUT ROUTING_TOKEN *RoutingToken,
|
||
OUT UCHAR *Flags
|
||
);
|
||
|
||
NTSTATUS
|
||
PciSetRoutingToken(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PROUTING_TOKEN RoutingToken
|
||
);
|
||
|
||
NTSTATUS
|
||
PciSetRoutingTokenEx(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PROUTING_TOKEN RoutingToken
|
||
);
|
||
|
||
VOID
|
||
PciUpdateInterruptLine(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN UCHAR Line
|
||
);
|
||
|
||
NTSTATUS
|
||
PciGetInterruptRoutingInfo(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT ULONG *Bus,
|
||
OUT ULONG *PciSlot,
|
||
OUT UCHAR *InterruptLine,
|
||
OUT UCHAR *InterruptPin,
|
||
OUT UCHAR *ClassCode,
|
||
OUT UCHAR *SubClassCode,
|
||
OUT PDEVICE_OBJECT *ParentPdo,
|
||
OUT ROUTING_TOKEN *RoutingToken
|
||
);
|
||
|
||
NTSTATUS
|
||
PciSetLegacyDeviceToken(
|
||
IN PDEVICE_OBJECT LegacyDO,
|
||
IN PROUTING_TOKEN RoutingToken
|
||
);
|
||
|
||
NTSTATUS
|
||
PciFindLegacyDevice(
|
||
IN PDEVICE_OBJECT LegacyDO,
|
||
OUT ULONG *Bus,
|
||
OUT ULONG *PciSlot,
|
||
OUT UCHAR *InterruptLine,
|
||
OUT UCHAR *InterruptPin,
|
||
OUT UCHAR *ClassCode,
|
||
OUT UCHAR *SubClassCode,
|
||
OUT PDEVICE_OBJECT *ParentPdo,
|
||
OUT ROUTING_TOKEN *RoutingToken
|
||
);
|
||
|
||
typedef struct {
|
||
PCI_SECONDARY_EXTENSION ExtensionHeader;
|
||
ROUTING_TOKEN RoutingToken;
|
||
} ROUTING_EXTENSION, *PROUTING_EXTENSION;
|
||
|
||
//
|
||
// Define the Pci Routing interface "Interface" structure.
|
||
//
|
||
|
||
PCI_INTERFACE PciRoutingInterface = {
|
||
&GUID_INT_ROUTE_INTERFACE_STANDARD, // InterfaceType
|
||
sizeof(INT_ROUTE_INTERFACE_STANDARD), // MinSize
|
||
PCI_INT_ROUTE_INTRF_STANDARD_VER, // MinVersion
|
||
PCI_INT_ROUTE_INTRF_STANDARD_VER, // MaxVersion
|
||
PCIIF_FDO, // Flags
|
||
0, // ReferenceCount
|
||
PciInterface_IntRouteHandler, // Signature
|
||
routeintrf_Constructor, // Constructor
|
||
routeintrf_Initializer // Instance Initializer
|
||
};
|
||
|
||
PLEGACY_DEVICE PciLegacyDeviceHead = NULL;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, routeintrf_Constructor)
|
||
#pragma alloc_text(PAGE, routeintrf_Initializer)
|
||
#pragma alloc_text(PAGE, routeintrf_Reference)
|
||
#pragma alloc_text(PAGE, PciGetInterruptRoutingInfo)
|
||
#pragma alloc_text(PAGE, PciGetInterruptRoutingInfoEx)
|
||
#pragma alloc_text(PAGE, PciSetRoutingToken)
|
||
#pragma alloc_text(PAGE, PciSetRoutingTokenEx)
|
||
#pragma alloc_text(PAGE, PciFindLegacyDevice)
|
||
#pragma alloc_text(PAGE, PciCacheLegacyDeviceRouting)
|
||
#pragma alloc_text(PAGE, PciUpdateInterruptLine)
|
||
#endif
|
||
|
||
VOID
|
||
routeintrf_Reference(
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
return;
|
||
}
|
||
|
||
NTSTATUS
|
||
routeintrf_Constructor(
|
||
PVOID DeviceExtension,
|
||
PVOID PciInterface,
|
||
PVOID InterfaceSpecificData,
|
||
USHORT Version,
|
||
USHORT Size,
|
||
PINTERFACE InterfaceReturn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize the BUS_INTERFACE_STANDARD fields.
|
||
|
||
Arguments:
|
||
|
||
PciInterface Pointer to the PciInterface record for this
|
||
interface type.
|
||
InterfaceSpecificData
|
||
|
||
InterfaceReturn
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
|
||
{
|
||
PINT_ROUTE_INTERFACE_STANDARD standard = (PINT_ROUTE_INTERFACE_STANDARD)InterfaceReturn;
|
||
|
||
switch(Version)
|
||
{
|
||
case PCI_INT_ROUTE_INTRF_STANDARD_VER:
|
||
standard->GetInterruptRouting = PciGetInterruptRoutingInfoEx;
|
||
standard->SetInterruptRoutingToken = PciSetRoutingTokenEx;
|
||
standard->UpdateInterruptLine = PciUpdateInterruptLine;
|
||
break;
|
||
default:
|
||
return STATUS_NOINTERFACE;
|
||
|
||
}
|
||
|
||
standard->Size = sizeof( INT_ROUTE_INTERFACE_STANDARD );
|
||
standard->Version = Version;
|
||
standard->Context = DeviceExtension;
|
||
standard->InterfaceReference = routeintrf_Reference;
|
||
standard->InterfaceDereference = routeintrf_Reference;
|
||
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
routeintrf_Initializer(
|
||
IN PPCI_ARBITER_INSTANCE Instance
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For bus interface, does nothing, shouldn't actually be called.
|
||
|
||
Arguments:
|
||
|
||
Instance Pointer to the PDO extension.
|
||
|
||
Return Value:
|
||
|
||
Returns the status of this operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSERTMSG("PCI routeintrf_Initializer, unexpected call.", 0);
|
||
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
NTSTATUS
|
||
PciGetInterruptRoutingInfo(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT ULONG *Bus,
|
||
OUT ULONG *PciSlot,
|
||
OUT UCHAR *InterruptLine,
|
||
OUT UCHAR *InterruptPin,
|
||
OUT UCHAR *ClassCode,
|
||
OUT UCHAR *SubClassCode,
|
||
OUT PDEVICE_OBJECT *ParentPdo,
|
||
OUT ROUTING_TOKEN *RoutingToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Each PCI device in the system is connected to some
|
||
interrupt pin. And in order to figure out which interrupt
|
||
that device may trigger, an IRQ arbiter must have this
|
||
information. This interface gathers all such information
|
||
for the arbiter.
|
||
|
||
Arguments:
|
||
|
||
Pdo - Device object that the arbiter needs to inquire about
|
||
Bus - Number of the PCI bus in question
|
||
PciSlot - Slot/Function that corresponds to this device
|
||
InterruptLine - Contents of the device's interrupt line register
|
||
InterruptPin - Contents of the device's interrupt pin register
|
||
ClassCode - type of device
|
||
SubClassCode - sub-type of device
|
||
ParentPdo - PDO of parent PCI bus
|
||
RoutingToken - blob of data
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - this is a PCI device and all the fields have been filled
|
||
STATUS_NOT_FOUND - to the knowledge of the PCI driver, this is not a PCI device
|
||
|
||
--*/
|
||
{
|
||
PROUTING_EXTENSION RoutingExtension;
|
||
PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
|
||
NTSTATUS status;
|
||
|
||
ASSERT(Bus);
|
||
ASSERT(PciSlot);
|
||
ASSERT(InterruptLine);
|
||
ASSERT(InterruptPin);
|
||
ASSERT(ClassCode);
|
||
ASSERT(SubClassCode);
|
||
ASSERT(ParentPdo);
|
||
ASSERT(RoutingToken);
|
||
|
||
//
|
||
// Check to see if this is a legacy PCI device that
|
||
// we are tracking.
|
||
//
|
||
|
||
status = PciFindLegacyDevice(Pdo,
|
||
Bus,
|
||
PciSlot,
|
||
InterruptLine,
|
||
InterruptPin,
|
||
ClassCode,
|
||
SubClassCode,
|
||
ParentPdo,
|
||
RoutingToken);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// If so, the fields have been filled in already.
|
||
//
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Verify that this PDO actually belongs to us.
|
||
//
|
||
if (!PdoExt) {
|
||
return STATUS_NOT_FOUND;
|
||
}
|
||
|
||
//
|
||
// Verify that it is actually a PDO.
|
||
//
|
||
if (PdoExt->ExtensionType != PciPdoExtensionType) {
|
||
return STATUS_NOT_FOUND;
|
||
}
|
||
|
||
*Bus = PCI_PARENT_FDOX(PdoExt)->BaseBus;
|
||
*PciSlot = PdoExt->Slot.u.AsULONG;
|
||
*InterruptLine = PdoExt->RawInterruptLine;
|
||
*InterruptPin = PdoExt->InterruptPin;
|
||
*ClassCode = PdoExt->BaseClass;
|
||
*SubClassCode = PdoExt->SubClass;
|
||
*ParentPdo = PCI_PARENT_PDO(PdoExt);
|
||
|
||
RoutingExtension = PciFindSecondaryExtension(PdoExt,
|
||
PciInterface_IntRouteHandler);
|
||
|
||
if (RoutingExtension) {
|
||
|
||
*RoutingToken = RoutingExtension->RoutingToken;
|
||
|
||
} else {
|
||
|
||
RoutingToken->LinkNode = 0;
|
||
RoutingToken->StaticVector = 0;
|
||
RoutingToken->Flags = 0;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
PciGetInterruptRoutingInfoEx(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT ULONG *Bus,
|
||
OUT ULONG *PciSlot,
|
||
OUT UCHAR *InterruptLine,
|
||
OUT UCHAR *InterruptPin,
|
||
OUT UCHAR *ClassCode,
|
||
OUT UCHAR *SubClassCode,
|
||
OUT PDEVICE_OBJECT *ParentPdo,
|
||
OUT ROUTING_TOKEN *RoutingToken,
|
||
OUT UCHAR *Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wrapper for PciGetInterruptroutingInfo that sets
|
||
the Flags parameter to indicate MSI-capable PCI devices.
|
||
|
||
Arguments:
|
||
|
||
Mostly, same as PciGetInterruptRoutingInfo.
|
||
|
||
Flags receives device-specific flags such as whether the device
|
||
supports MSI.
|
||
|
||
Return Value:
|
||
|
||
Same as PciGetInterruptRoutingInfo.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
|
||
|
||
// Call the real function
|
||
|
||
status = PciGetInterruptRoutingInfo(Pdo,
|
||
Bus,
|
||
PciSlot,
|
||
InterruptLine,
|
||
InterruptPin,
|
||
ClassCode,
|
||
SubClassCode,
|
||
ParentPdo,
|
||
RoutingToken);
|
||
|
||
*Flags = 0;
|
||
|
||
|
||
#if MSI_SUPPORTED
|
||
|
||
if (NT_SUCCESS(status)
|
||
|
||
#if !MSI_SIMULATE
|
||
&& PdoExt->CapableMSI
|
||
#endif
|
||
) {
|
||
|
||
|
||
// MSI device?
|
||
*Flags = PCI_MSI_ROUTING;
|
||
|
||
}
|
||
|
||
#endif // MSI_SUPPORTED
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PciSetRoutingToken(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PROUTING_TOKEN RoutingToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stores a blob of data associated with this
|
||
PCI device. This job is foisted off on the PCI driver because
|
||
the PCI driver has a one-to-one correspondence between useful
|
||
data structures and PCI devices.
|
||
|
||
Arguments:
|
||
|
||
Pdo - Device object that the IRQ arbiter is working with
|
||
|
||
RoutingToken - Blob of data that the IRQ arbiter wants to associate with
|
||
the PCI device.
|
||
|
||
Return Value:
|
||
|
||
Returns the status of this operation.
|
||
|
||
--*/
|
||
{
|
||
PROUTING_EXTENSION RoutingExtension;
|
||
PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Check first to see if this is a legacy PCI device.
|
||
//
|
||
|
||
status = PciSetLegacyDeviceToken(Pdo, RoutingToken);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// This isn't in our list of legacy devices. So it must be
|
||
// a PCI PDO.
|
||
//
|
||
|
||
#if DBG
|
||
RoutingExtension = PciFindSecondaryExtension(PdoExt,
|
||
PciInterface_IntRouteHandler);
|
||
|
||
if (RoutingExtension != NULL) {
|
||
DbgPrint("PCI: *** redundant PCI routing extesion being created ***\n");
|
||
}
|
||
ASSERT(RoutingExtension == NULL);
|
||
#endif
|
||
|
||
RoutingExtension = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(ROUTING_EXTENSION));
|
||
|
||
if (!RoutingExtension) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RoutingExtension->RoutingToken = *RoutingToken;
|
||
|
||
PciLinkSecondaryExtension(PdoExt,
|
||
RoutingExtension,
|
||
PciInterface_IntRouteHandler,
|
||
NULL);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
PciSetRoutingTokenEx(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PROUTING_TOKEN RoutingToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
MSI-aware wrapper for PciSetRoutingToken.
|
||
|
||
This function will intercept MSI routing tokens (as indicated by
|
||
the PCI_MSI_ROUTING flag) and store the MSI routing information
|
||
in the PDO extension without caching the token in a secondary extension.
|
||
|
||
Non-MSI routing tokens will be passed to PciSetRoutingToken.
|
||
|
||
Arguments:
|
||
|
||
Same as PciSetRoutingToken.
|
||
|
||
|
||
Return Value:
|
||
|
||
Same as PciSetRoutingToken.
|
||
|
||
--*/
|
||
{
|
||
PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
|
||
#if MSI_SUPPORTED
|
||
|
||
if(
|
||
|
||
#if !MSI_SIMULATE
|
||
PdoExt->CapableMSI &&
|
||
#endif
|
||
|
||
(RoutingToken->Flags & PCI_MSI_ROUTING))
|
||
{
|
||
|
||
// MSI token
|
||
|
||
PciDebugPrint(PciDbgInformative,"PCI: MSI Resources Received for Device %08x\n", Pdo);
|
||
|
||
#ifdef DBG
|
||
|
||
// have we received a new resource assignment?
|
||
|
||
if ((PdoExt->MsiInfo.MessageAddress != (ULONG_PTR)RoutingToken->LinkNode)
|
||
|| (PdoExt->MsiInfo.MessageData != (USHORT)RoutingToken->StaticVector)) {
|
||
|
||
PciDebugPrint(PciDbgPrattling,"PCI: Device %08x will be reprogrammed with Message = %ld @%p\n",
|
||
Pdo, RoutingToken->StaticVector, RoutingToken->LinkNode);
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
// Store MSI info in PdoExt.
|
||
|
||
PdoExt->MsiInfo.MessageAddress = (ULONG_PTR)RoutingToken->LinkNode;
|
||
PdoExt->MsiInfo.MessageData = (USHORT)RoutingToken->StaticVector;
|
||
}
|
||
else
|
||
|
||
#endif // MSI_SUPPORTED
|
||
|
||
{
|
||
// Call the original function on non-MSI tokens.
|
||
|
||
status = PciSetRoutingToken(Pdo, RoutingToken);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
//
|
||
// NT 5.0 has to support non-PnP 4.0-style device drivers. And
|
||
// this driver doesn't create the device objects associated with
|
||
// a PCI device when its driver is 4.0-style. It does, however
|
||
// get a chance to look at those objects when the driver calls
|
||
// HalAssignSlotResources. This collection of functions tracks
|
||
// these foreign device objects.
|
||
//
|
||
|
||
NTSTATUS
|
||
PciFindLegacyDevice(
|
||
IN PDEVICE_OBJECT LegacyDO,
|
||
OUT ULONG *Bus,
|
||
OUT ULONG *PciSlot,
|
||
OUT UCHAR *InterruptLine,
|
||
OUT UCHAR *InterruptPin,
|
||
OUT UCHAR *ClassCode,
|
||
OUT UCHAR *SubClassCode,
|
||
OUT PDEVICE_OBJECT *ParentPdo,
|
||
OUT ROUTING_TOKEN *RoutingToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns all the routing data for a legacy
|
||
device object.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
Returns the status of this operation.
|
||
|
||
--*/
|
||
{
|
||
PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
|
||
NTSTATUS status = STATUS_NOT_FOUND;
|
||
|
||
PAGED_CODE();
|
||
|
||
while (legacyDev) {
|
||
|
||
if (legacyDev->LegacyDeviceObject == LegacyDO) {
|
||
|
||
break;
|
||
|
||
} else if (legacyDev->Bus == *Bus && legacyDev->PciSlot == *PciSlot) {
|
||
|
||
if (legacyDev->LegacyDeviceObject == NULL) {
|
||
|
||
//
|
||
// Cache the LegacyDO in case we matched on the bus and slot info.
|
||
//
|
||
|
||
legacyDev->LegacyDeviceObject = LegacyDO;
|
||
break;
|
||
|
||
} else {
|
||
|
||
PciDebugPrint(PciDbgAlways, "Two PDOs (Legacy = %08x, Pnp = %08x) for device on bus %08x, slot %08x\n", legacyDev->LegacyDeviceObject, LegacyDO, *Bus, *PciSlot);
|
||
ASSERT(legacyDev->LegacyDeviceObject != NULL);
|
||
legacyDev = NULL;
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
|
||
}
|
||
|
||
if (legacyDev) {
|
||
|
||
*Bus = legacyDev->Bus;
|
||
*PciSlot = legacyDev->PciSlot;
|
||
*InterruptLine = legacyDev->InterruptLine;
|
||
*InterruptPin = legacyDev->InterruptPin;
|
||
*ClassCode = legacyDev->ClassCode;
|
||
*SubClassCode = legacyDev->SubClassCode;
|
||
*ParentPdo = legacyDev->ParentPdo;
|
||
*RoutingToken = legacyDev->RoutingToken;
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
PciCacheLegacyDeviceRouting(
|
||
IN PDEVICE_OBJECT LegacyDO,
|
||
IN ULONG Bus,
|
||
IN ULONG PciSlot,
|
||
IN UCHAR InterruptLine,
|
||
IN UCHAR InterruptPin,
|
||
IN UCHAR ClassCode,
|
||
IN UCHAR SubClassCode,
|
||
IN PDEVICE_OBJECT ParentPdo,
|
||
IN PPCI_PDO_EXTENSION PdoExtension,
|
||
OUT PDEVICE_OBJECT *OldLegacyDO
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function stores all the routing data for a legacy
|
||
device object, except the RoutingToken. Caller needs to acquire
|
||
PciGlobalLock before calling this function.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
Returns the status of this operation.
|
||
|
||
--*/
|
||
{
|
||
PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
|
||
|
||
PAGED_CODE();
|
||
|
||
while (legacyDev) {
|
||
|
||
if (Bus == legacyDev->Bus && PciSlot == legacyDev->PciSlot) {
|
||
if (legacyDev->LegacyDeviceObject == LegacyDO) {
|
||
|
||
//
|
||
// This device is already in the list.
|
||
//
|
||
|
||
if (OldLegacyDO) {
|
||
|
||
*OldLegacyDO = LegacyDO;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
|
||
PDEVICE_OBJECT oldDO;
|
||
|
||
//
|
||
// We are overwriting an existing entry.
|
||
//
|
||
|
||
oldDO = legacyDev->LegacyDeviceObject;
|
||
legacyDev->LegacyDeviceObject = LegacyDO;
|
||
|
||
if (OldLegacyDO) {
|
||
|
||
*OldLegacyDO = oldDO;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
|
||
}
|
||
|
||
legacyDev = ExAllocatePool(PagedPool,
|
||
sizeof(LEGACY_DEVICE));
|
||
|
||
if (!legacyDev) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(legacyDev, sizeof(LEGACY_DEVICE));
|
||
|
||
legacyDev->LegacyDeviceObject = LegacyDO;
|
||
legacyDev->Bus = Bus;
|
||
legacyDev->PciSlot = PciSlot;
|
||
legacyDev->InterruptLine = InterruptLine;
|
||
legacyDev->InterruptPin = InterruptPin;
|
||
legacyDev->ClassCode = ClassCode;
|
||
legacyDev->SubClassCode = SubClassCode;
|
||
legacyDev->ParentPdo = ParentPdo;
|
||
legacyDev->PdoExtension = PdoExtension;
|
||
|
||
//
|
||
// Push this one onto the list.
|
||
//
|
||
|
||
legacyDev->List.Next = (PSINGLE_LIST_ENTRY)PciLegacyDeviceHead;
|
||
PciLegacyDeviceHead = legacyDev;
|
||
|
||
if (OldLegacyDO) {
|
||
|
||
*OldLegacyDO = LegacyDO;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
PciSetLegacyDeviceToken(
|
||
IN PDEVICE_OBJECT LegacyDO,
|
||
IN PROUTING_TOKEN RoutingToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function stores the RoutingToken.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
Returns the status of this operation.
|
||
|
||
--*/
|
||
{
|
||
PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
|
||
|
||
PAGED_CODE();
|
||
|
||
while (legacyDev) {
|
||
|
||
if (legacyDev->LegacyDeviceObject == LegacyDO) {
|
||
|
||
//
|
||
// Found it. Copy the token into the structure.
|
||
//
|
||
|
||
legacyDev->RoutingToken = *RoutingToken;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
|
||
}
|
||
|
||
return STATUS_NOT_FOUND;
|
||
}
|
||
|
||
VOID
|
||
PciUpdateInterruptLine(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN UCHAR Line
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PPCI_PDO_EXTENSION pdoExt;
|
||
PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
|
||
PCI_COMMON_HEADER header;
|
||
PPCI_COMMON_CONFIG biosConfig = (PPCI_COMMON_CONFIG) &header;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Work out if this is a legacy PDO or not
|
||
//
|
||
|
||
while (legacyDev) {
|
||
|
||
if (legacyDev->LegacyDeviceObject == Pdo) {
|
||
|
||
//
|
||
// Found it.
|
||
//
|
||
|
||
pdoExt = legacyDev->PdoExtension;
|
||
break;
|
||
}
|
||
|
||
legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
|
||
}
|
||
|
||
|
||
if (legacyDev == NULL) {
|
||
|
||
//
|
||
// Oh well it must be a PCI pdo
|
||
//
|
||
|
||
pdoExt = Pdo->DeviceExtension;
|
||
}
|
||
|
||
ASSERT_PCI_PDO_EXTENSION(pdoExt);
|
||
|
||
//
|
||
// Now we can update the hardware and our internal state!
|
||
//
|
||
|
||
pdoExt->RawInterruptLine = pdoExt->AdjustedInterruptLine = Line;
|
||
|
||
PciWriteDeviceConfig(pdoExt,
|
||
&Line,
|
||
FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.InterruptLine),
|
||
sizeof(Line)
|
||
);
|
||
|
||
//
|
||
// Finally refresh the config space stored in the registry
|
||
//
|
||
|
||
status = PciGetBiosConfig(pdoExt, biosConfig);
|
||
|
||
ASSERT(NT_SUCCESS(status));
|
||
|
||
if (NT_SUCCESS(status)
|
||
&& biosConfig->u.type0.InterruptLine != Line) {
|
||
|
||
biosConfig->u.type0.InterruptLine = Line;
|
||
|
||
status = PciSaveBiosConfig(pdoExt, biosConfig);
|
||
|
||
ASSERT(NT_SUCCESS(status));
|
||
|
||
}
|
||
}
|