411 lines
8.2 KiB
C
411 lines
8.2 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
gpeintf.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the "PME" interfaces supported
|
||
by the PCI driver.
|
||
|
||
Author:
|
||
|
||
Stephane Plante (splante) Feb-1-1999
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "pcip.h"
|
||
|
||
NTSTATUS
|
||
PciPmeInterfaceConstructor(
|
||
PVOID DeviceExtension,
|
||
PVOID PciInterface,
|
||
PVOID InterfaceSpecificData,
|
||
USHORT Version,
|
||
USHORT Size,
|
||
PINTERFACE InterfaceReturn
|
||
);
|
||
|
||
VOID
|
||
PciPmeInterfaceDereference(
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
PciPmeInterfaceInitializer(
|
||
IN PPCI_ARBITER_INSTANCE Instance
|
||
);
|
||
|
||
VOID
|
||
PciPmeInterfaceReference(
|
||
IN PVOID Context
|
||
);
|
||
|
||
VOID
|
||
PciPmeUpdateEnable(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN BOOLEAN PmeEnable
|
||
);
|
||
|
||
//
|
||
// Define the Pci PME interface "interface" structure
|
||
//
|
||
PCI_INTERFACE PciPmeInterface = {
|
||
&GUID_PCI_PME_INTERFACE, // Interface Type
|
||
sizeof(PCI_PME_INTERFACE), // Mininum Size
|
||
PCI_PME_INTRF_STANDARD_VER, // Minimum Version
|
||
PCI_PME_INTRF_STANDARD_VER, // Maximum Version
|
||
PCIIF_FDO | PCIIF_ROOT, // Flags
|
||
0, // ReferenceCount
|
||
PciInterface_PmeHandler, // Signature
|
||
PciPmeInterfaceConstructor, // Constructor
|
||
PciPmeInterfaceInitializer // Instance Initializer
|
||
};
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, PciPmeInterfaceConstructor)
|
||
#pragma alloc_text(PAGE, PciPmeInterfaceDereference)
|
||
#pragma alloc_text(PAGE, PciPmeInterfaceInitializer)
|
||
#pragma alloc_text(PAGE, PciPmeInterfaceReference)
|
||
#endif
|
||
|
||
|
||
VOID
|
||
PciPmeAdjustPmeEnable(
|
||
IN PPCI_PDO_EXTENSION PdoExtension,
|
||
IN BOOLEAN Enable,
|
||
IN BOOLEAN ClearStatusOnly
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the only routine in the the PCI driver that is allowed to set
|
||
the PME Enable pin for a device.
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - The device that wants to have the PME enable set
|
||
Enable - Turn on the PME pin or not
|
||
ClearStatusOnly - Only clear the status --- ignore the Enable bit
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
{
|
||
PCI_PM_CAPABILITY pmCap;
|
||
UCHAR pmCapPtr = 0;
|
||
|
||
//
|
||
// Are there any pm capabilities?
|
||
//
|
||
if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS) ) {
|
||
|
||
pmCapPtr = PciReadDeviceCapability(
|
||
PdoExtension,
|
||
PdoExtension->CapabilitiesPtr,
|
||
PCI_CAPABILITY_ID_POWER_MANAGEMENT,
|
||
&pmCap,
|
||
sizeof(pmCap)
|
||
);
|
||
|
||
}
|
||
if (pmCapPtr == 0) {
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// Set or clear the PMEEnable bit depending on the value of Enable
|
||
//
|
||
if (!ClearStatusOnly) {
|
||
|
||
pmCap.PMCSR.ControlStatus.PMEEnable = (Enable != 0);
|
||
|
||
}
|
||
|
||
//
|
||
// Write back what we read to clear the PME Status.
|
||
//
|
||
PciWriteDeviceConfig(
|
||
PdoExtension,
|
||
&(pmCap.PMCSR.ControlStatus),
|
||
pmCapPtr + FIELD_OFFSET(PCI_PM_CAPABILITY, PMCSR.ControlStatus),
|
||
sizeof(pmCap.PMCSR.ControlStatus)
|
||
);
|
||
}
|
||
|
||
VOID
|
||
PciPmeClearPmeStatus(
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine explicitly clears the PME status bit from a device
|
||
|
||
Arguments:
|
||
|
||
Pdo - The device whose pin we are to clear
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
{
|
||
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION) Pdo->DeviceExtension;
|
||
|
||
ASSERT_PCI_PDO_EXTENSION( pdoExtension );
|
||
|
||
//
|
||
// Call the Adjust function to do the actual work. Note that passing
|
||
// in the 3rd argument as TRUE means that the 2nd argument is ignored
|
||
//
|
||
PciPmeAdjustPmeEnable( pdoExtension, FALSE, TRUE );
|
||
}
|
||
|
||
VOID
|
||
PciPmeGetInformation(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT PBOOLEAN PmeCapable,
|
||
OUT PBOOLEAN PmeStatus,
|
||
OUT PBOOLEAN PmeEnable
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Supplies the information regarding a PDO's PME capabilities
|
||
|
||
Arguments:
|
||
|
||
Pdo - The device object whose capabilities we care about
|
||
PmeCapable - Can the device generate a PME?
|
||
PmeStatus - Is the PME status for the device on?
|
||
PmeEnable - Is the PME enable for the device on?
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN pmeCapable = FALSE;
|
||
BOOLEAN pmeEnable = FALSE;
|
||
BOOLEAN pmeStatus = FALSE;
|
||
NTSTATUS status;
|
||
PCI_PM_CAPABILITY pmCap;
|
||
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION) Pdo->DeviceExtension;
|
||
UCHAR pmCapPtr = 0;
|
||
|
||
ASSERT_PCI_PDO_EXTENSION( pdoExtension );
|
||
|
||
//
|
||
// Get the current power management capabilities from the device
|
||
//
|
||
if (!(pdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS) ) {
|
||
|
||
pmCapPtr = PciReadDeviceCapability(
|
||
pdoExtension,
|
||
pdoExtension->CapabilitiesPtr,
|
||
PCI_CAPABILITY_ID_POWER_MANAGEMENT,
|
||
&pmCap,
|
||
sizeof(pmCap)
|
||
);
|
||
|
||
}
|
||
|
||
if (pmCapPtr == 0) {
|
||
|
||
//
|
||
// No Pdo capabilities
|
||
//
|
||
goto PciPmeGetInformationExit;
|
||
|
||
}
|
||
|
||
//
|
||
// At this point, we are found to be PME capable
|
||
//
|
||
pmeCapable = TRUE;
|
||
|
||
//
|
||
// Are enabled for PME?
|
||
//
|
||
if (pmCap.PMCSR.ControlStatus.PMEEnable == 1) {
|
||
|
||
pmeEnable = TRUE;
|
||
|
||
}
|
||
|
||
//
|
||
// Is the PME Status pin set?
|
||
//
|
||
if (pmCap.PMCSR.ControlStatus.PMEStatus == 1) {
|
||
|
||
pmeStatus = TRUE;
|
||
|
||
}
|
||
|
||
PciPmeGetInformationExit:
|
||
|
||
if (PmeCapable != NULL) {
|
||
|
||
*PmeCapable = pmeCapable;
|
||
|
||
}
|
||
if (PmeStatus != NULL) {
|
||
|
||
*PmeStatus = pmeStatus;
|
||
|
||
}
|
||
if (PmeEnable != NULL) {
|
||
|
||
*PmeEnable = pmeEnable;
|
||
|
||
}
|
||
return;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
PciPmeInterfaceConstructor(
|
||
PVOID DeviceExtension,
|
||
PVOID PciInterface,
|
||
PVOID InterfaceSpecificData,
|
||
USHORT Version,
|
||
USHORT Size,
|
||
PINTERFACE InterfaceReturn
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize the PCI_PME_INTERFACE fields.
|
||
|
||
Arguments:
|
||
|
||
PciInterface Pointer to the PciInterface record for this
|
||
interface type.
|
||
InterfaceSpecificData
|
||
|
||
InterfaceReturn
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
|
||
{
|
||
PPCI_PME_INTERFACE standard = (PPCI_PME_INTERFACE) InterfaceReturn;
|
||
|
||
switch(Version) {
|
||
case PCI_PME_INTRF_STANDARD_VER:
|
||
standard->GetPmeInformation = PciPmeGetInformation;
|
||
standard->ClearPmeStatus = PciPmeClearPmeStatus;
|
||
standard->UpdateEnable = PciPmeUpdateEnable;
|
||
break;
|
||
default:
|
||
return STATUS_NOINTERFACE;
|
||
}
|
||
|
||
standard->Size = sizeof( PCI_PME_INTERFACE );
|
||
standard->Version = Version;
|
||
standard->Context = DeviceExtension;
|
||
standard->InterfaceReference = PciPmeInterfaceReference;
|
||
standard->InterfaceDereference = PciPmeInterfaceDereference;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
PciPmeInterfaceDereference(
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
return;
|
||
}
|
||
|
||
NTSTATUS
|
||
PciPmeInterfaceInitializer(
|
||
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 PciPmeInterfaceInitializer, unexpected call.", 0);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
VOID
|
||
PciPmeInterfaceReference(
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
PciPmeUpdateEnable(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN BOOLEAN PmeEnable
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets or clears the PME Enable bit on the specified
|
||
device object
|
||
|
||
Arguments:
|
||
|
||
Pdo - The device object whose PME enable we care about
|
||
PmeEnable - Wether or not we should enable PME on the device
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION) Pdo->DeviceExtension;
|
||
|
||
ASSERT_PCI_PDO_EXTENSION( pdoExtension );
|
||
|
||
//
|
||
// Mark the device as not having its PME managed by PCI any more...
|
||
//
|
||
pdoExtension->NoTouchPmeEnable = 1;
|
||
|
||
//
|
||
// Call the interface that does the real work. Note that we always need
|
||
// to supply the 3rd argument as FALSE --- we don't to just clear the
|
||
// PME Status bit
|
||
//
|
||
PciPmeAdjustPmeEnable( pdoExtension, PmeEnable, FALSE );
|
||
}
|