/*++ 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; PCI_PM_CAPABILITY pmCap = {0}; 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 power 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. --*/ { PCI_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 ); }