+++ /dev/null
-/** @file\r
-This driver is responsible for the registration of child drivers\r
-and the abstraction of the QNC SMI sources.\r
-\r
-Copyright (c) 2013-2017 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-\r
-**/\r
-\r
-//\r
-// Include common header file for this module.\r
-//\r
-#include "CommonHeader.h"\r
-\r
-#include "QNCSmm.h"\r
-#include "QNCSmmHelpers.h"\r
-\r
-//\r
-// /////////////////////////////////////////////////////////////////////////////\r
-// MODULE / GLOBAL DATA\r
-//\r
-// Module variables used by the both the main dispatcher and the source dispatchers\r
-// Declared in QNCSmmSources.h\r
-//\r
-UINT32 mPciData;\r
-UINT32 mPciAddress;\r
-\r
-PRIVATE_DATA mPrivateData = { // for the structure\r
- {\r
- NULL\r
- }, // CallbackDataBase linked list head\r
- NULL, // Handler returned whan calling SmiHandlerRegister\r
- NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces\r
- { // protocol arrays\r
- // elements within the array\r
- //\r
- {\r
- PROTOCOL_SIGNATURE,\r
- SxType,\r
- &gEfiSmmSxDispatch2ProtocolGuid,\r
- {\r
- {\r
- (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
- (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
- }\r
- }\r
- },\r
- {\r
- PROTOCOL_SIGNATURE,\r
- SwType,\r
- &gEfiSmmSwDispatch2ProtocolGuid,\r
- {\r
- {\r
- (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
- (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
- (UINTN) MAXIMUM_SWI_VALUE\r
- }\r
- }\r
- },\r
- {\r
- PROTOCOL_SIGNATURE,\r
- GpiType,\r
- &gEfiSmmGpiDispatch2ProtocolGuid,\r
- {\r
- {\r
- (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
- (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
- (UINTN) 1\r
- }\r
- }\r
- },\r
- {\r
- PROTOCOL_SIGNATURE,\r
- QNCnType,\r
- &gEfiSmmIchnDispatch2ProtocolGuid,\r
- {\r
- {\r
- (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
- (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
- }\r
- }\r
- },\r
- {\r
- PROTOCOL_SIGNATURE,\r
- PowerButtonType,\r
- &gEfiSmmPowerButtonDispatch2ProtocolGuid,\r
- {\r
- {\r
- (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
- (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
- }\r
- }\r
- },\r
- {\r
- PROTOCOL_SIGNATURE,\r
- PeriodicTimerType,\r
- &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,\r
- {\r
- {\r
- (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
- (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
- (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval\r
- }\r
- }\r
- },\r
- }\r
-};\r
-\r
-CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = {\r
- {\r
- SxGetContext,\r
- SxCmpContext,\r
- NULL\r
- },\r
- {\r
- SwGetContext,\r
- SwCmpContext,\r
- SwGetBuffer\r
- },\r
- {\r
- NULL,\r
- NULL,\r
- NULL\r
- },\r
- {\r
- NULL,\r
- NULL,\r
- NULL\r
- },\r
- {\r
- NULL,\r
- NULL,\r
- NULL\r
- },\r
- {\r
- PeriodicTimerGetContext,\r
- PeriodicTimerCmpContext,\r
- PeriodicTimerGetBuffer,\r
- },\r
-};\r
-\r
-//\r
-// /////////////////////////////////////////////////////////////////////////////\r
-// PROTOTYPES\r
-//\r
-// Functions use only in this file\r
-//\r
-EFI_STATUS\r
-QNCSmmCoreDispatcher (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN CONST VOID *Context, OPTIONAL\r
- IN OUT VOID *CommBuffer, OPTIONAL\r
- IN OUT UINTN *CommBufferSize OPTIONAL\r
- );\r
-\r
-\r
-UINTN\r
-DevicePathSize (\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
- );\r
-\r
-//\r
-// /////////////////////////////////////////////////////////////////////////////\r
-// FUNCTIONS\r
-//\r
-// Driver entry point\r
-//\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeQNCSmmDispatcher (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Initializes the QNC SMM Dispatcher\r
-\r
-Arguments:\r
-\r
- ImageHandle - Pointer to the loaded image protocol for this driver\r
- SystemTable - Pointer to the EFI System Table\r
-\r
-Returns:\r
- Status - EFI_SUCCESS\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
-\r
- QNCSmmPublishDispatchProtocols ();\r
-\r
- //\r
- // Register a callback function to handle subsequent SMIs. This callback\r
- // will be called by SmmCoreDispatcher.\r
- //\r
- Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Initialize Callback DataBase\r
- //\r
- InitializeListHead (&mPrivateData.CallbackDataBase);\r
-\r
- //\r
- // Enable SMIs on the QNC now that we have a callback\r
- //\r
- QNCSmmInitHardware ();\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-SaveState (\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Save Index registers to avoid corrupting the foreground environment\r
-\r
-Arguments:\r
- None\r
-\r
-Returns:\r
- Status - EFI_SUCCESS\r
-\r
---*/\r
-{\r
- mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-RestoreState (\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Restore Index registers to avoid corrupting the foreground environment\r
-\r
-Arguments:\r
- None\r
-\r
-Returns:\r
- Status - EFI_SUCCESS\r
-\r
---*/\r
-{\r
- IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-SmiInputValueDuplicateCheck (\r
- UINTN FedSwSmiInputValue\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Check the Fed SwSmiInputValue to see if there is a duplicated one in the database\r
-\r
-Arguments:\r
- None\r
-\r
-Returns:\r
- Status - EFI_SUCCESS, EFI_INVALID_PARAMETER\r
-\r
---*/\r
-// GC_TODO: FedSwSmiInputValue - add argument and description to function comment\r
-{\r
-\r
- DATABASE_RECORD *RecordInDb;\r
- LIST_ENTRY *LinkInDb;\r
-\r
- LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
- while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
- RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
-\r
- if (RecordInDb->ProtocolType == SwType) {\r
- if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
-\r
- LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-QNCSmmCoreRegister (\r
- IN QNC_SMM_GENERIC_PROTOCOL *This,\r
- IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,\r
- IN QNC_SMM_CONTEXT *RegisterContext,\r
- OUT EFI_HANDLE *DispatchHandle\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
---*/\r
-// GC_TODO: This - add argument and description to function comment\r
-// GC_TODO: DispatchFunction - add argument and description to function comment\r
-// GC_TODO: RegisterContext - add argument and description to function comment\r
-// GC_TODO: DispatchHandle - add argument and description to function comment\r
-// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
-// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
-// GC_TODO: EFI_SUCCESS - add return value to function comment\r
-// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
-{\r
- EFI_STATUS Status;\r
- DATABASE_RECORD *Record;\r
- QNC_SMM_QUALIFIED_PROTOCOL *Qualified;\r
- INTN Index;\r
-\r
- //\r
- // Check for invalid parameter\r
- //\r
- if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Create database record and add to database\r
- //\r
- Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));\r
- if (Record == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Gather information about the registration request\r
- //\r
- Record->Callback = DispatchFunction;\r
- Record->CallbackContext = RegisterContext;\r
- CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));\r
-\r
- Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);\r
-\r
- Record->ProtocolType = Qualified->Type;\r
-\r
- CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));\r
- //\r
- // Perform linked list housekeeping\r
- //\r
- Record->Signature = DATABASE_RECORD_SIGNATURE;\r
-\r
- switch (Qualified->Type) {\r
- //\r
- // By the end of this switch statement, we'll know the\r
- // source description the child is registering for\r
- //\r
- case SxType:\r
- //\r
- // Check the validity of Context Type and Phase\r
- //\r
- if ((Record->ChildContext.Sx.Type < SxS0) ||\r
- (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||\r
- (Record->ChildContext.Sx.Phase < SxEntry) ||\r
- (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)\r
- ) {\r
- goto Error;\r
- }\r
-\r
- InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
- CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));\r
- //\r
- // use default clear source function\r
- //\r
- break;\r
-\r
- case SwType:\r
- if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
- //\r
- // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.\r
- //\r
- Status = EFI_NOT_FOUND;\r
- for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {\r
- Status = SmiInputValueDuplicateCheck (Index);\r
- if (!EFI_ERROR (Status)) {\r
- RegisterContext->Sw.SwSmiInputValue = Index;\r
- break;\r
- }\r
- }\r
- if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
- Status = gSmst->SmmFreePool (Record);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Update ChildContext again as SwSmiInputValue has been changed\r
- //\r
- CopyMem (&Record->ChildContext, RegisterContext, sizeof (QNC_SMM_CONTEXT));\r
- }\r
-\r
- //\r
- // Check the validity of Context Value\r
- //\r
- if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {\r
- goto Error;\r
- }\r
-\r
- if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {\r
- goto Error;\r
- }\r
-\r
- InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
- CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));\r
- Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);\r
- //\r
- // use default clear source function\r
- //\r
- break;\r
-\r
- case GpiType:\r
-\r
- InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
- CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));\r
- //\r
- // use default clear source function\r
- //\r
- break;\r
-\r
- case QNCnType:\r
- //\r
- // Check the validity of Context Type\r
- //\r
- if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {\r
- goto Error;\r
- }\r
-\r
- InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
- CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));\r
- Record->ClearSource = QNCSmmQNCnClearSource;\r
- break;\r
-\r
- case PeriodicTimerType:\r
-\r
- Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
-\r
- InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
- Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);\r
- Record->ClearSource = QNCSmmPeriodicTimerClearSource;\r
- break;\r
-\r
- default:\r
- goto Error;\r
- break;\r
- };\r
-\r
- if (Record->ClearSource == NULL) {\r
- //\r
- // Clear the SMI associated w/ the source using the default function\r
- //\r
- QNCSmmClearSource (&Record->SrcDesc);\r
- } else {\r
- //\r
- // This source requires special handling to clear\r
- //\r
- Record->ClearSource (&Record->SrcDesc);\r
- }\r
-\r
- QNCSmmEnableSource (&Record->SrcDesc);\r
-\r
- //\r
- // Child's handle will be the address linked list link in the record\r
- //\r
- *DispatchHandle = (EFI_HANDLE) (&Record->Link);\r
-\r
- return EFI_SUCCESS;\r
-\r
-Error:\r
- FreePool (Record);\r
- //\r
- // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));\r
- //\r
- return EFI_INVALID_PARAMETER;\r
-}\r
-\r
-EFI_STATUS\r
-QNCSmmCoreUnRegister (\r
- IN QNC_SMM_GENERIC_PROTOCOL *This,\r
- IN EFI_HANDLE DispatchHandle\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-Arguments:\r
-\r
-Returns:\r
-\r
---*/\r
-// GC_TODO: This - add argument and description to function comment\r
-// GC_TODO: DispatchHandle - add argument and description to function comment\r
-// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
-// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
-// GC_TODO: EFI_SUCCESS - add return value to function comment\r
-{\r
- BOOLEAN SafeToDisable;\r
- DATABASE_RECORD *RecordToDelete;\r
- DATABASE_RECORD *RecordInDb;\r
- LIST_ENTRY *LinkInDb;\r
-\r
- if (DispatchHandle == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);\r
-\r
- RemoveEntryList (&RecordToDelete->Link);\r
- RecordToDelete->Signature = 0;\r
-\r
- //\r
- // See if we can disable the source, reserved for future use since this might\r
- // not be the only criteria to disable\r
- //\r
- SafeToDisable = TRUE;\r
- LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
- while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
- RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
- if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {\r
- SafeToDisable = FALSE;\r
- break;\r
- }\r
- LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
- }\r
- if (SafeToDisable) {\r
- QNCSmmDisableSource( &RecordToDelete->SrcDesc );\r
-}\r
-\r
- FreePool (RecordToDelete);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is the main entry point for an SMM handler dispatch\r
- or communicate-based callback.\r
-\r
- @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
- @param RegisterContext Points to an optional handler context which was specified when the handler was registered.\r
- @param CommBuffer A pointer to a collection of data in memory that will\r
- be conveyed from a non-SMM environment into an SMM environment.\r
- @param CommBufferSize The size of the CommBuffer.\r
-\r
- @return Status Code\r
-\r
-**/\r
-EFI_STATUS\r
-QNCSmmCoreDispatcher (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN CONST VOID *RegisterContext,\r
- IN OUT VOID *CommBuffer,\r
- IN OUT UINTN *CommBufferSize\r
- )\r
-{\r
- //\r
- // Used to prevent infinite loops\r
- //\r
- UINTN EscapeCount;\r
-\r
- BOOLEAN ContextsMatch;\r
- BOOLEAN ResetListSearch;\r
- BOOLEAN EosSet;\r
- BOOLEAN SxChildWasDispatched;\r
- BOOLEAN ChildWasDispatched;\r
-\r
- DATABASE_RECORD *RecordInDb;\r
- DATABASE_RECORD ActiveRecordInDb;\r
- LIST_ENTRY *LinkInDb;\r
- DATABASE_RECORD *RecordToExhaust;\r
- LIST_ENTRY *LinkToExhaust;\r
-\r
- QNC_SMM_CONTEXT Context;\r
- VOID *CommunicationBuffer;\r
- UINTN BufferSize;\r
-\r
- EFI_STATUS Status;\r
- UINT32 NewValue;\r
-\r
- QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;\r
-\r
- EscapeCount = 100;\r
- ContextsMatch = FALSE;\r
- ResetListSearch = FALSE;\r
- EosSet = FALSE;\r
- SxChildWasDispatched = FALSE;\r
- Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
- ChildWasDispatched = FALSE;\r
-\r
- //\r
- // Mark all child handlers as not processed\r
- //\r
- LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
- while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
- RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
- RecordInDb->Processed = FALSE;\r
- LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);\r
- }\r
-\r
- //\r
- // Preserve Index registers\r
- //\r
- SaveState ();\r
-\r
- if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {\r
- //\r
- // We have children registered w/ us -- continue\r
- //\r
- while ((!EosSet) && (EscapeCount > 0)) {\r
- EscapeCount--;\r
-\r
- //\r
- // Reset this flag in order to be able to process multiple SMI Sources in one loop.\r
- //\r
- ResetListSearch = FALSE;\r
-\r
- LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
-\r
- while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {\r
- RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
- //\r
- // Make a copy of the record that contains an active SMI source,\r
- // because un-register maybe invoked in callback function and\r
- // RecordInDb maybe released\r
- //\r
- CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb));\r
-\r
- //\r
- // look for the first active source\r
- //\r
- if (!SourceIsActive (&RecordInDb->SrcDesc)) {\r
- //\r
- // Didn't find the source yet, keep looking\r
- //\r
- LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
-\r
- } else {\r
- //\r
- // We found a source. If this is a sleep type, we have to go to\r
- // appropriate sleep state anyway.No matter there is sleep child or not\r
- //\r
- if (RecordInDb->ProtocolType == SxType) {\r
- SxChildWasDispatched = TRUE;\r
- }\r
- //\r
- // "cache" the source description and don't query I/O anymore\r
- //\r
- CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));\r
- LinkToExhaust = LinkInDb;\r
-\r
- //\r
- // exhaust the rest of the queue looking for the same source\r
- //\r
- while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {\r
- RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);\r
- LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust);\r
- if (RecordToExhaust->Processed) {\r
- //\r
- // Record has already been processed. Continue with next child handler.\r
- //\r
- continue;\r
- }\r
-\r
- if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {\r
- //\r
- // These source descriptions are equal, so this callback should be\r
- // dispatched.\r
- //\r
- if (RecordToExhaust->ContextFunctions.GetContext != NULL) {\r
- //\r
- // This child requires that we get a calling context from\r
- // hardware and compare that context to the one supplied\r
- // by the child.\r
- //\r
- ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);\r
-\r
- //\r
- // Make sure contexts match before dispatching event to child\r
- //\r
- RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);\r
- ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);\r
-\r
- } else {\r
- //\r
- // This child doesn't require any more calling context beyond what\r
- // it supplied in registration. Simply pass back what it gave us.\r
- //\r
- ASSERT (RecordToExhaust->Callback != NULL);\r
- ContextsMatch = TRUE;\r
- }\r
-\r
- //\r
- // Mark this child handler so it will not be processed again\r
- //\r
- RecordToExhaust->Processed = TRUE;\r
-\r
- if (ContextsMatch) {\r
-\r
- if (RecordToExhaust->BufferSize != 0) {\r
- ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);\r
-\r
- RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);\r
-\r
- CommunicationBuffer = &RecordToExhaust->CommBuffer;\r
- BufferSize = RecordToExhaust->BufferSize;\r
- } else {\r
- CommunicationBuffer = NULL;\r
- BufferSize = 0;\r
- }\r
-\r
- ASSERT (RecordToExhaust->Callback != NULL);\r
-\r
- RecordToExhaust->Callback (\r
- (EFI_HANDLE) & RecordToExhaust->Link,\r
- RecordToExhaust->CallbackContext,\r
- CommunicationBuffer,\r
- &BufferSize\r
- );\r
-\r
- ChildWasDispatched = TRUE;\r
- if (RecordToExhaust->ProtocolType == SxType) {\r
- SxChildWasDispatched = TRUE;\r
- }\r
- }\r
- //\r
- // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb\r
- // Restart processing of SMI handlers from the begining of the linked list because the\r
- // state of the linked listed may have been modified due to unregister actions in the Callback.\r
- //\r
- LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase);\r
- }\r
- }\r
-\r
- if (ActiveRecordInDb.ClearSource == NULL) {\r
- //\r
- // Clear the SMI associated w/ the source using the default function\r
- //\r
- QNCSmmClearSource (&ActiveSource);\r
- } else {\r
- //\r
- // This source requires special handling to clear\r
- //\r
- ActiveRecordInDb.ClearSource (&ActiveSource);\r
- }\r
-\r
- if (ChildWasDispatched) {\r
- //\r
- // The interrupt was handled and quiesced\r
- //\r
- Status = EFI_SUCCESS;\r
- } else {\r
- //\r
- // The interrupt was not handled but quiesced\r
- //\r
- Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
- }\r
-\r
- //\r
- // Queue is empty, reset the search\r
- //\r
- ResetListSearch = TRUE;\r
-\r
- }\r
- }\r
- EosSet = QNCSmmSetAndCheckEos ();\r
- }\r
- }\r
- //\r
- // If you arrive here, there are two possible reasons:\r
- // (1) you've got problems with clearing the SMI status bits in the\r
- // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the\r
- // EOS bit. If this happens too many times, the loop exits.\r
- // (2) there was a SMM communicate for callback messages that was received prior\r
- // to this driver.\r
- // If there is an asynchronous SMI that occurs while processing the Callback, let\r
- // all of the drivers (including this one) have an opportunity to scan for the SMI\r
- // and handle it.\r
- // If not, we don't want to exit and have the foreground app. clear EOS without letting\r
- // these other sources get serviced.\r
- //\r
- ASSERT (EscapeCount > 0);\r
-\r
- //\r
- // Restore Index registers\r
- //\r
- RestoreState ();\r
-\r
- if (SxChildWasDispatched) {\r
- //\r
- // A child of the SmmSxDispatch protocol was dispatched during this call;\r
- // put the system to sleep.\r
- //\r
- QNCSmmSxGoToSleep ();\r
- }\r
-\r
- //\r
- // Ensure that SMI signal pin indicator is clear at the end of SMM handling.\r
- //\r
- NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);\r
- NewValue &= ~(HLEGACY_SMI_PIN_VALUE);\r
- QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);\r
-\r
- return Status;\r
-}\r