Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.\r
\r
(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
-Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
TerminalDevice->RawFiFo->Head = TerminalDevice->RawFiFo->Tail;\r
TerminalDevice->UnicodeFiFo->Head = TerminalDevice->UnicodeFiFo->Tail;\r
TerminalDevice->EfiKeyFiFo->Head = TerminalDevice->EfiKeyFiFo->Tail;\r
+ TerminalDevice->EfiKeyFiFoForNotify->Head = TerminalDevice->EfiKeyFiFoForNotify->Tail;\r
\r
if (EFI_ERROR (Status)) {\r
REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
TranslateRawDataToEfiKey (TerminalDevice);\r
}\r
\r
+/**\r
+ Process key notify.\r
+\r
+ @param Event Indicates the event that invoke this function.\r
+ @param Context Indicates the calling context.\r
+**/\r
+VOID\r
+EFIAPI\r
+KeyNotifyProcessHandler (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ BOOLEAN HasKey;\r
+ TERMINAL_DEV *TerminalDevice;\r
+ EFI_INPUT_KEY Key;\r
+ EFI_KEY_DATA KeyData;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NotifyList;\r
+ TERMINAL_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
+ EFI_TPL OldTpl;\r
+\r
+ TerminalDevice = (TERMINAL_DEV *) Context;\r
+\r
+ //\r
+ // Invoke notification functions.\r
+ //\r
+ NotifyList = &TerminalDevice->NotifyList;\r
+ while (TRUE) {\r
+ //\r
+ // Enter critical section\r
+ // \r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ HasKey = EfiKeyFiFoForNotifyRemoveOneKey (TerminalDevice->EfiKeyFiFoForNotify, &Key);\r
+ CopyMem (&KeyData.Key, &Key, sizeof (EFI_INPUT_KEY));\r
+ KeyData.KeyState.KeyShiftState = 0;\r
+ KeyData.KeyState.KeyToggleState = 0;\r
+ //\r
+ // Leave critical section\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (!HasKey) {\r
+ break;\r
+ }\r
+ for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
+ CurrentNotify = CR (Link, TERMINAL_CONSOLE_IN_EX_NOTIFY, NotifyEntry, TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
+ CurrentNotify->KeyNotificationFn (&KeyData);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
/**\r
Get one key out of serial buffer.\r
\r
return FALSE;\r
}\r
\r
+/**\r
+ Insert one pre-fetched key into the FIFO buffer.\r
+\r
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.\r
+ @param Input The key will be input.\r
+\r
+ @retval TRUE If insert successfully.\r
+ @retval FALSE If FIFO buffer is full before key insertion,\r
+ and the key is lost.\r
+\r
+**/\r
+BOOLEAN\r
+EfiKeyFiFoForNotifyInsertOneKey (\r
+ EFI_KEY_FIFO *EfiKeyFiFo,\r
+ EFI_INPUT_KEY *Input\r
+ )\r
+{\r
+ UINT8 Tail;\r
+\r
+ Tail = EfiKeyFiFo->Tail;\r
+\r
+ if (IsEfiKeyFiFoForNotifyFull (EfiKeyFiFo)) {\r
+ //\r
+ // FIFO is full\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ CopyMem (&EfiKeyFiFo->Data[Tail], Input, sizeof (EFI_INPUT_KEY));\r
+\r
+ EfiKeyFiFo->Tail = (UINT8) ((Tail + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Remove one pre-fetched key out of the FIFO buffer.\r
+\r
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.\r
+ @param Output The key will be removed.\r
+\r
+ @retval TRUE If remove successfully.\r
+ @retval FALSE If FIFO buffer is empty before remove operation.\r
+\r
+**/\r
+BOOLEAN\r
+EfiKeyFiFoForNotifyRemoveOneKey (\r
+ EFI_KEY_FIFO *EfiKeyFiFo,\r
+ EFI_INPUT_KEY *Output\r
+ )\r
+{\r
+ UINT8 Head;\r
+\r
+ Head = EfiKeyFiFo->Head;\r
+ ASSERT (Head < FIFO_MAX_NUMBER + 1);\r
+\r
+ if (IsEfiKeyFiFoForNotifyEmpty (EfiKeyFiFo)) {\r
+ //\r
+ // FIFO is empty\r
+ //\r
+ Output->ScanCode = SCAN_NULL;\r
+ Output->UnicodeChar = 0;\r
+ return FALSE;\r
+ }\r
+\r
+ CopyMem (Output, &EfiKeyFiFo->Data[Head], sizeof (EFI_INPUT_KEY));\r
+\r
+ EfiKeyFiFo->Head = (UINT8) ((Head + 1) % (FIFO_MAX_NUMBER + 1));\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Clarify whether FIFO buffer is empty.\r
+\r
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.\r
+\r
+ @retval TRUE If FIFO buffer is empty.\r
+ @retval FALSE If FIFO buffer is not empty.\r
+\r
+**/\r
+BOOLEAN\r
+IsEfiKeyFiFoForNotifyEmpty (\r
+ EFI_KEY_FIFO *EfiKeyFiFo\r
+ )\r
+{\r
+ if (EfiKeyFiFo->Head == EfiKeyFiFo->Tail) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Clarify whether FIFO buffer is full.\r
+\r
+ @param EfiKeyFiFo Pointer to instance of EFI_KEY_FIFO.\r
+\r
+ @retval TRUE If FIFO buffer is full.\r
+ @retval FALSE If FIFO buffer is not full.\r
+\r
+**/\r
+BOOLEAN\r
+IsEfiKeyFiFoForNotifyFull (\r
+ EFI_KEY_FIFO *EfiKeyFiFo\r
+ )\r
+{\r
+ UINT8 Tail;\r
+ UINT8 Head;\r
+\r
+ Tail = EfiKeyFiFo->Tail;\r
+ Head = EfiKeyFiFo->Head;\r
+\r
+ if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
/**\r
Insert one pre-fetched key into the FIFO buffer.\r
\r
KeyData.KeyState.KeyToggleState = 0;\r
\r
//\r
- // Invoke notification functions if exist\r
+ // Signal KeyNotify process event if this key pressed matches any key registered.\r
//\r
NotifyList = &TerminalDevice->NotifyList;\r
for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList,Link); Link = GetNextNode (NotifyList,Link)) {\r
TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
);\r
if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
- CurrentNotify->KeyNotificationFn (&KeyData);\r
+ //\r
+ // The key notification function needs to run at TPL_CALLBACK\r
+ // while current TPL is TPL_NOTIFY. It will be invoked in\r
+ // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.\r
+ //\r
+ EfiKeyFiFoForNotifyInsertOneKey (TerminalDevice->EfiKeyFiFoForNotify, Key);\r
+ gBS->SignalEvent (TerminalDevice->KeyNotifyProcessEvent);\r
}\r
}\r
if (IsEfiKeyFiFoFull (TerminalDevice)) {\r