--- /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-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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->ChildContext = *RegisterContext;\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
+ Record->ChildContext = *RegisterContext;\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
+ 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
+ // 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
+ //\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
+\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
+ Context = RecordToExhaust->ChildContext;\r
+ ContextsMatch = TRUE;\r
+ }\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
+ &Context,\r
+ CommunicationBuffer,\r
+ &BufferSize\r
+ );\r
+\r
+ ChildWasDispatched = TRUE;\r
+ if (RecordToExhaust->ProtocolType == SxType) {\r
+ SxChildWasDispatched = TRUE;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Get next record in DB\r
+ //\r
+ LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link);\r
+ }\r
+\r
+ if (RecordInDb->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
+ RecordInDb->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