/** @file\r
\r
-Copyright (c) 2006, Intel Corporation\r
-All rights reserved. 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
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
Module Name:\r
\r
\r
**/\r
\r
-//\r
-// The package level header files this module uses\r
-//\r
-#include <Uefi.h>\r
-#include <WinNtDxe.h>\r
-//\r
-// The protocols, PPI and GUID defintions for this module\r
-//\r
-#include <Guid/EventGroup.h>\r
-#include <Protocol/WinNtIo.h>\r
-#include <Protocol/ComponentName.h>\r
-#include <Protocol/SimpleTextIn.h>\r
-#include <Protocol/DriverBinding.h>\r
-#include <Protocol/GraphicsOutput.h>\r
-//\r
-// The Library classes this module consumes\r
-//\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/UefiDriverEntryPoint.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
\r
#include "WinNtGop.h"\r
\r
**/\r
EFI_STATUS\r
GopPrivateCreateQ (\r
- IN GOP_PRIVATE_DATA *Private\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ IN GOP_QUEUE_FIXED *Queue\r
)\r
{\r
- Private->WinNtThunk->InitializeCriticalSection (&Private->QCriticalSection);\r
-\r
- Private->Queue.Front = 0;\r
- Private->Queue.Rear = MAX_Q - 1;\r
- Private->Queue.Count = 0;\r
+ Private->WinNtThunk->InitializeCriticalSection (&Queue->Cs);\r
+ Queue->Front = 0;\r
+ Queue->Rear = 0;\r
return EFI_SUCCESS;\r
}\r
\r
**/\r
EFI_STATUS\r
GopPrivateDestroyQ (\r
- IN GOP_PRIVATE_DATA *Private\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ IN GOP_QUEUE_FIXED *Queue\r
)\r
{\r
- Private->Queue.Count = 0;\r
- Private->WinNtThunk->DeleteCriticalSection (&Private->QCriticalSection);\r
+ Queue->Front = 0;\r
+ Queue->Rear = 0;\r
+ Private->WinNtThunk->DeleteCriticalSection (&Queue->Cs);\r
return EFI_SUCCESS;\r
}\r
\r
**/\r
EFI_STATUS\r
GopPrivateAddQ (\r
- IN GOP_PRIVATE_DATA *Private,\r
- IN EFI_INPUT_KEY Key\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ IN GOP_QUEUE_FIXED *Queue,\r
+ IN EFI_KEY_DATA *KeyData\r
)\r
{\r
- Private->WinNtThunk->EnterCriticalSection (&Private->QCriticalSection);\r
+ Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);\r
\r
- if (Private->Queue.Count == MAX_Q) {\r
- Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+ if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {\r
+ Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
return EFI_NOT_READY;\r
}\r
\r
- Private->Queue.Rear = (Private->Queue.Rear + 1) % MAX_Q;\r
- Private->Queue.Q[Private->Queue.Rear] = Key;\r
- Private->Queue.Count++;\r
+ CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
+ Queue->Rear = (Queue->Rear + 1) % MAX_Q;\r
\r
- Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+ Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
return EFI_SUCCESS;\r
}\r
\r
EFI_STATUS\r
GopPrivateDeleteQ (\r
IN GOP_PRIVATE_DATA *Private,\r
- OUT EFI_INPUT_KEY *Key\r
+ IN GOP_QUEUE_FIXED *Queue,\r
+ OUT EFI_KEY_DATA *Key\r
)\r
{\r
- Private->WinNtThunk->EnterCriticalSection (&Private->QCriticalSection);\r
+ Private->WinNtThunk->EnterCriticalSection (&Queue->Cs);\r
\r
- if (Private->Queue.Count == 0) {\r
- Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+ if (Queue->Front == Queue->Rear) {\r
+ Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
return EFI_NOT_READY;\r
}\r
\r
- *Key = Private->Queue.Q[Private->Queue.Front];\r
- Private->Queue.Front = (Private->Queue.Front + 1) % MAX_Q;\r
- Private->Queue.Count--;\r
-\r
- Private->WinNtThunk->LeaveCriticalSection (&Private->QCriticalSection);\r
+ CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));\r
+ Queue->Front = (Queue->Front + 1) % MAX_Q;\r
+\r
+ if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {\r
+ if (!Private->IsPartialKeySupport) {\r
+ //\r
+ // If partial keystrok is not enabled, don't return the partial keystroke.\r
+ //\r
+ Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
+ ZeroMem (Key, sizeof (EFI_KEY_DATA));\r
+ return EFI_NOT_READY;\r
+ }\r
+ }\r
+ Private->WinNtThunk->LeaveCriticalSection (&Queue->Cs);\r
return EFI_SUCCESS;\r
}\r
\r
**/\r
EFI_STATUS\r
GopPrivateCheckQ (\r
- IN GOP_PRIVATE_DATA *Private\r
+ IN GOP_QUEUE_FIXED *Queue\r
)\r
{\r
- if (Private->Queue.Count == 0) {\r
+ if (Queue->Front == Queue->Rear) {\r
return EFI_NOT_READY;\r
}\r
\r
return EFI_SUCCESS;\r
}\r
\r
-//\r
-// Simple Text In implementation.\r
-//\r
+BOOLEAN\r
+GopPrivateIsKeyRegistered (\r
+ IN EFI_KEY_DATA *RegsiteredData,\r
+ IN EFI_KEY_DATA *InputData\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+ RegsiteredData - A pointer to a buffer that is filled in with the keystroke\r
+ state data for the key that was registered.\r
+ InputData - A pointer to a buffer that is filled in with the keystroke\r
+ state data for the key that was pressed.\r
+\r
+Returns:\r
+ TRUE - Key be pressed matches a registered key.\r
+ FLASE - Match failed.\r
+\r
+--*/\r
+{\r
+ ASSERT (RegsiteredData != NULL && InputData != NULL);\r
+\r
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||\r
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
+ //\r
+ if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
+ RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
+ return FALSE;\r
+ }\r
+ if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
+ RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+\r
+}\r
+\r
+\r
+VOID\r
+GopPrivateInvokeRegisteredFunction (\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ IN EFI_KEY_DATA *KeyData\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function updates the status light of NumLock, ScrollLock and CapsLock.\r
+\r
+Arguments:\r
\r
+ Private - The private structure of WinNt Gop device.\r
+ KeyData - A pointer to a buffer that is filled in with the keystroke\r
+ state data for the key that was pressed.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The status light is updated successfully.\r
+\r
+--*/\r
+{\r
+ LIST_ENTRY *Link;\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;\r
+\r
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+ CurrentNotify = CR (\r
+ Link,\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,\r
+ NotifyEntry,\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE\r
+ );\r
+ if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
+ CurrentNotify->KeyNotificationFn (KeyData);\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+WinNtGopSimpleTextInTimerHandler (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ GOP_PRIVATE_DATA *Private;\r
+ EFI_KEY_DATA KeyData;\r
+\r
+ Private = (GOP_PRIVATE_DATA *)Context;\r
+ while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS) {\r
+ GopPrivateInvokeRegisteredFunction (Private, &KeyData);\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize the key state.\r
+\r
+ @param Private The GOP_PRIVATE_DATA instance.\r
+ @param KeyState A pointer to receive the key state information.\r
+**/\r
+VOID\r
+InitializeKeyState (\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ IN EFI_KEY_STATE *KeyState\r
+ )\r
+{\r
+ KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;\r
+ KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
+\r
+ //\r
+ // Record Key shift state and toggle state\r
+ //\r
+ if (Private->LeftCtrl) {\r
+ KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;\r
+ }\r
+ if (Private->RightCtrl) {\r
+ KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;\r
+ }\r
+ if (Private->LeftAlt) {\r
+ KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;\r
+ }\r
+ if (Private->RightAlt) {\r
+ KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;\r
+ }\r
+ if (Private->LeftShift) {\r
+ KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;\r
+ }\r
+ if (Private->RightShift) {\r
+ KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;\r
+ }\r
+ if (Private->LeftLogo) {\r
+ KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;\r
+ }\r
+ if (Private->RightLogo) {\r
+ KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;\r
+ }\r
+ if (Private->Menu) {\r
+ KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;\r
+ }\r
+ if (Private->SysReq) {\r
+ KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;\r
+ }\r
+ if (Private->CapsLock) {\r
+ KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
+ }\r
+ if (Private->NumLock) {\r
+ KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
+ }\r
+ if (Private->ScrollLock) {\r
+ KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
+ }\r
+ if (Private->IsPartialKeySupport) {\r
+ KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;\r
+ }\r
+}\r
\r
/**\r
TODO: Add function description\r
\r
- @param This TODO: add argument description\r
- @param ExtendedVerification TODO: add argument description\r
+ @param Private TODO: add argument description\r
+ @param Key TODO: add argument description\r
\r
+ @retval EFI_NOT_READY TODO: Add description for return value\r
@retval EFI_SUCCESS TODO: Add description for return value\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-WinNtGopSimpleTextInReset (\r
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
- IN BOOLEAN ExtendedVerification\r
+GopPrivateAddKey (\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ IN EFI_INPUT_KEY Key\r
)\r
{\r
- GOP_PRIVATE_DATA *Private;\r
- EFI_INPUT_KEY Key;\r
- EFI_TPL OldTpl;\r
+ EFI_KEY_DATA KeyData;\r
\r
- Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);\r
+ KeyData.Key = Key;\r
+ InitializeKeyState (Private, &KeyData.KeyState);\r
+\r
+ //\r
+ // Convert Ctrl+[1-26] to Ctrl+[A-Z]\r
+ //\r
+ if ((Private->LeftCtrl || Private->RightCtrl) &&\r
+ (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)\r
+ ) {\r
+ if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {\r
+ KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);\r
+ } else {\r
+ KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Unmask the Shift bit for printable char\r
+ //\r
+ if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||\r
+ ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))\r
+ ) {\r
+ KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
+ }\r
+\r
+ GopPrivateAddQ (Private, &Private->QueueForNotify, &KeyData);\r
+\r
+ GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GopPrivateUpdateStatusLight (\r
+ IN GOP_PRIVATE_DATA *Private\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function updates the status light of NumLock, ScrollLock and CapsLock.\r
+\r
+Arguments:\r
+\r
+ Private - The private structure of WinNt console In/Out.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The status light is updated successfully.\r
+\r
+--*/\r
+{\r
+ //\r
+ // BUGBUG:Only SendInput/keybd_event function can toggle\r
+ // NumLock, CapsLock and ScrollLock keys.\r
+ // Neither of these functions is included in EFI_WIN_NT_THUNK_PROTOCOL.\r
+ // Thus, return immediately without operation.\r
+ //\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+EFI_STATUS\r
+GopPrivateResetWorker (\r
+ IN GOP_PRIVATE_DATA *Private\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function is a worker function for SimpleTextIn/SimpleTextInEx.Reset().\r
+\r
+Arguments:\r
+\r
+ Private - WinNT GOP private structure\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Reset successfully\r
+\r
+--*/\r
+{\r
+ EFI_KEY_DATA KeyData;\r
+ EFI_TPL OldTpl;\r
\r
//\r
// Enter critical section\r
//\r
// A reset is draining the Queue\r
//\r
- while (GopPrivateDeleteQ (Private, &Key) == EFI_SUCCESS)\r
+ while (GopPrivateDeleteQ (Private, &Private->QueueForRead, &KeyData) == EFI_SUCCESS)\r
+ ;\r
+ while (GopPrivateDeleteQ (Private, &Private->QueueForNotify, &KeyData) == EFI_SUCCESS)\r
;\r
\r
+ Private->LeftShift = FALSE;\r
+ Private->RightShift = FALSE;\r
+ Private->LeftAlt = FALSE;\r
+ Private->RightAlt = FALSE;\r
+ Private->LeftCtrl = FALSE;\r
+ Private->RightCtrl = FALSE;\r
+ Private->LeftLogo = FALSE;\r
+ Private->RightLogo = FALSE;\r
+ Private->Menu = FALSE;\r
+ Private->SysReq = FALSE;\r
+\r
+ Private->CapsLock = FALSE;\r
+ Private->NumLock = FALSE;\r
+ Private->ScrollLock = FALSE;\r
+ Private->IsPartialKeySupport = FALSE;\r
+\r
+ Private->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;\r
+ Private->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
+\r
//\r
// Leave critical section and return\r
//\r
gBS->RestoreTPL (OldTpl);\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+EFI_STATUS\r
+GopPrivateReadKeyStrokeWorker (\r
+ IN GOP_PRIVATE_DATA *Private,\r
+ OUT EFI_KEY_DATA *KeyData\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Reads the next keystroke from the input device. The WaitForKey Event can\r
+ be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+ Arguments:\r
+ Private - The private structure of WinNt Gop device.\r
+ KeyData - A pointer to a buffer that is filled in with the keystroke\r
+ state data for the key that was pressed.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The keystroke information was returned.\r
+ EFI_NOT_READY - There was no keystroke data availiable.\r
+ EFI_DEVICE_ERROR - The keystroke information was not returned due to\r
+ hardware errors.\r
+ EFI_INVALID_PARAMETER - KeyData is NULL.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (KeyData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Enter critical section\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ //\r
+ // Call hot key callback before telling caller there is a key available\r
+ //\r
+ WinNtGopSimpleTextInTimerHandler (NULL, Private);\r
+\r
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+ InitializeKeyState (Private, &KeyData->KeyState);\r
+\r
+ Status = GopPrivateCheckQ (&Private->QueueForRead);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If a Key press exists try and read it.\r
+ //\r
+ Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If partial keystroke is not enabled, check whether it is value key. If not return\r
+ // EFI_NOT_READY.\r
+ //\r
+ if (!Private->IsPartialKeySupport) {\r
+ if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {\r
+ Status = EFI_NOT_READY;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Leave critical section and return\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+//\r
+// Simple Text In implementation.\r
+//\r
+\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param This TODO: add argument description\r
+ @param ExtendedVerification TODO: add argument description\r
+\r
+ @retval EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInReset (\r
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ GOP_PRIVATE_DATA *Private;\r
+\r
+ Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);\r
+\r
+ return GopPrivateResetWorker (Private);\r
+}\r
+\r
\r
/**\r
TODO: Add function description\r
@return TODO: add return values\r
\r
**/\r
-STATIC\r
EFI_STATUS\r
EFIAPI\r
WinNtGopSimpleTextInReadKeyStroke (\r
{\r
GOP_PRIVATE_DATA *Private;\r
EFI_STATUS Status;\r
- EFI_TPL OldTpl;\r
+ EFI_KEY_DATA KeyData;\r
\r
Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_THIS (This);\r
-\r
//\r
- // Enter critical section\r
+ // Considering if the partial keystroke is enabled, there maybe a partial\r
+ // keystroke in the queue, so here skip the partial keystroke and get the\r
+ // next key from the queue\r
//\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- Status = GopPrivateCheckQ (Private);\r
- if (!EFI_ERROR (Status)) {\r
+ while (1) {\r
+ Status = GopPrivateReadKeyStrokeWorker (Private, &KeyData);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {\r
+ continue;\r
+ }\r
//\r
- // If a Key press exists try and read it.\r
+ // Convert Ctrl+[A-Z] to Ctrl+[1-26]\r
//\r
- Status = GopPrivateDeleteQ (Private, Key);\r
- }\r
-\r
- //\r
- // Leave critical section and return\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return Status;\r
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
+ if ((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) {\r
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
+ } else if ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z')) {\r
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
+ }\r
+ }\r
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+ return EFI_SUCCESS;\r
+ } \r
}\r
\r
\r
@return TODO: add return values\r
\r
**/\r
-STATIC\r
VOID\r
EFIAPI\r
WinNtGopSimpleTextInWaitForKey (\r
GOP_PRIVATE_DATA *Private;\r
EFI_STATUS Status;\r
EFI_TPL OldTpl;\r
+ EFI_KEY_DATA KeyData;\r
\r
Private = (GOP_PRIVATE_DATA *) Context;\r
\r
//\r
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
\r
- Status = GopPrivateCheckQ (Private);\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // If a there is a key in the queue signal our event.\r
- //\r
- gBS->SignalEvent (Event);\r
- } else {\r
- //\r
- // We need to sleep or NT will schedule this thread with such high\r
- // priority that WinProc thread will never run and we will not see\r
- // keyboard input. This Sleep makes the syste run 10x faster, so don't\r
- // remove it.\r
- //\r
- Private->WinNtThunk->Sleep (1);\r
+ //\r
+ // Call hot key callback before telling caller there is a key available\r
+ //\r
+ WinNtGopSimpleTextInTimerHandler (NULL, Private);\r
+ \r
+ //\r
+ // WaitforKey doesn't suppor the partial key.\r
+ // Considering if the partial keystroke is enabled, there maybe a partial\r
+ // keystroke in the queue, so here skip the partial keystroke and get the\r
+ // next key from the queue\r
+ //\r
+ while (1) {\r
+ Status = GopPrivateCheckQ (&Private->QueueForRead);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If a there is a key in the queue and it is not partial keystroke, signal event.\r
+ //\r
+ if (Private->QueueForRead.Q[Private->QueueForRead.Front].Key.ScanCode == SCAN_NULL &&\r
+ Private->QueueForRead.Q[Private->QueueForRead.Front].Key.UnicodeChar == CHAR_NULL) {\r
+ GopPrivateDeleteQ (Private,&Private->QueueForRead,&KeyData);\r
+ continue;\r
+ }\r
+ gBS->SignalEvent (Event);\r
+ } else {\r
+ //\r
+ // We need to sleep or NT will schedule this thread with such high\r
+ // priority that WinProc thread will never run and we will not see\r
+ // keyboard input. This Sleep makes the syste run 10x faster, so don't\r
+ // remove it.\r
+ //\r
+ Private->WinNtThunk->Sleep (1);\r
+ }\r
+ break;\r
}\r
\r
//\r
gBS->RestoreTPL (OldTpl);\r
}\r
\r
+//\r
+// Simple Text Input Ex protocol functions\r
+//\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExResetEx (\r
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Reset the input device and optionaly run diagnostics\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ ExtendedVerification - Driver may perform diagnostics on reset.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The device was reset.\r
+\r
+--*/\r
+{\r
+ GOP_PRIVATE_DATA *Private;\r
+\r
+ Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+ return GopPrivateResetWorker (Private);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExReadKeyStrokeEx (\r
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+ OUT EFI_KEY_DATA *KeyData\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Reads the next keystroke from the input device. The WaitForKey Event can\r
+ be used to test for existance of a keystroke via WaitForEvent () call.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ KeyData - A pointer to a buffer that is filled in with the keystroke\r
+ state data for the key that was pressed.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The keystroke information was returned.\r
+ EFI_NOT_READY - There was no keystroke data availiable.\r
+ EFI_DEVICE_ERROR - The keystroke information was not returned due to\r
+ hardware errors.\r
+ EFI_INVALID_PARAMETER - KeyData is NULL.\r
+\r
+--*/\r
+{\r
+ GOP_PRIVATE_DATA *Private;\r
+\r
+ if (KeyData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+ return GopPrivateReadKeyStrokeWorker (Private, KeyData);\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExSetState (\r
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Set certain state for the input device.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
+ state for the input device.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The device state was set successfully.\r
+ EFI_DEVICE_ERROR - The device is not functioning correctly and could\r
+ not have the setting adjusted.\r
+ EFI_UNSUPPORTED - The device does not have the ability to set its state.\r
+ EFI_INVALID_PARAMETER - KeyToggleState is NULL.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ GOP_PRIVATE_DATA *Private;\r
+\r
+ if (KeyToggleState == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+ if (((Private->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||\r
+ ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Private->ScrollLock = FALSE;\r
+ Private->NumLock = FALSE;\r
+ Private->CapsLock = FALSE;\r
+ Private->IsPartialKeySupport = FALSE;\r
+\r
+ if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
+ Private->ScrollLock = TRUE;\r
+ }\r
+ if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
+ Private->NumLock = TRUE;\r
+ }\r
+ if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
+ Private->CapsLock = TRUE;\r
+ }\r
+ if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {\r
+ Private->IsPartialKeySupport = TRUE;\r
+ }\r
+\r
+ Status = GopPrivateUpdateStatusLight (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Private->KeyState.KeyToggleState = *KeyToggleState;\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExRegisterKeyNotify (\r
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+ IN EFI_KEY_DATA *KeyData,\r
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,\r
+ OUT VOID **NotifyHandle\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Register a notification function for a particular keystroke for the input device.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ KeyData - A pointer to a buffer that is filled in with the keystroke\r
+ information data for the key that was pressed.\r
+ KeyNotificationFunction - Points to the function to be called when the key\r
+ sequence is typed specified by KeyData.\r
+ NotifyHandle - Points to the unique handle assigned to the registered notification.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The notification function was registered successfully.\r
+ EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.\r
+ EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.\r
+\r
+--*/\r
+{\r
+ GOP_PRIVATE_DATA *Private;\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;\r
+ LIST_ENTRY *Link;\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *NewNotify;\r
+\r
+ if (KeyData == NULL || KeyNotificationFunction == NULL || NotifyHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+ //\r
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
+ //\r
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+ CurrentNotify = CR (\r
+ Link,\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,\r
+ NotifyEntry,\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE\r
+ );\r
+ if (GopPrivateIsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+ *NotifyHandle = CurrentNotify;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Allocate resource to save the notification function\r
+ //\r
+ NewNotify = (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *) AllocateZeroPool (sizeof (WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY));\r
+ if (NewNotify == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewNotify->Signature = WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE;\r
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
+ InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);\r
+\r
+ *NotifyHandle = NewNotify;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+WinNtGopSimpleTextInExUnregisterKeyNotify (\r
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
+ IN VOID *NotificationHandle\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Remove a registered notification function from a particular keystroke.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ NotificationHandle - The handle of the notification function being unregistered.\r
+\r
+ Returns:\r
+ EFI_SUCCESS - The notification function was unregistered successfully.\r
+ EFI_INVALID_PARAMETER - The NotificationHandle is invalid.\r
+\r
+--*/\r
+{\r
+ GOP_PRIVATE_DATA *Private;\r
+ LIST_ENTRY *Link;\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY *CurrentNotify;\r
+\r
+ if (NotificationHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GOP_PRIVATE_DATA_FROM_TEXT_IN_EX_THIS (This);\r
+\r
+ for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) {\r
+ CurrentNotify = CR (\r
+ Link,\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY,\r
+ NotifyEntry,\r
+ WIN_NT_GOP_SIMPLE_TEXTIN_EX_NOTIFY_SIGNATURE\r
+ );\r
+ if (CurrentNotify == NotificationHandle) {\r
+ //\r
+ // Remove the notification function from NotifyList and free resources\r
+ //\r
+ RemoveEntryList (&CurrentNotify->NotifyEntry);\r
+\r
+ gBS->FreePool (CurrentNotify);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Can not find the specified Notification Handle\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
\r
/**\r
TODO: Add function description\r
{\r
EFI_STATUS Status;\r
\r
- GopPrivateCreateQ (Private);\r
+ GopPrivateCreateQ (Private, &Private->QueueForRead);\r
+ GopPrivateCreateQ (Private, &Private->QueueForNotify);\r
\r
//\r
// Initialize Simple Text In protoocol\r
&Private->SimpleTextIn.WaitForKey\r
);\r
\r
+\r
+ Private->SimpleTextInEx.Reset = WinNtGopSimpleTextInExResetEx;\r
+ Private->SimpleTextInEx.ReadKeyStrokeEx = WinNtGopSimpleTextInExReadKeyStrokeEx;\r
+ Private->SimpleTextInEx.SetState = WinNtGopSimpleTextInExSetState;\r
+ Private->SimpleTextInEx.RegisterKeyNotify = WinNtGopSimpleTextInExRegisterKeyNotify;\r
+ Private->SimpleTextInEx.UnregisterKeyNotify = WinNtGopSimpleTextInExUnregisterKeyNotify;\r
+\r
+ Private->SimpleTextInEx.Reset (&Private->SimpleTextInEx, FALSE);\r
+\r
+ InitializeListHead (&Private->NotifyList);\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_WAIT,\r
+ TPL_NOTIFY,\r
+ WinNtGopSimpleTextInWaitForKey,\r
+ Private,\r
+ &Private->SimpleTextInEx.WaitForKeyEx\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Create the Timer to trigger hot key notifications\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ WinNtGopSimpleTextInTimerHandler,\r
+ Private,\r
+ &Private->TimerEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->SetTimer (\r
+ Private->TimerEvent,\r
+ TimerPeriodic,\r
+ KEYBOARD_TIMER_INTERVAL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
return Status;\r
}\r
\r
\r
+\r
/**\r
TODO: Add function description\r
\r
IN GOP_PRIVATE_DATA *Private\r
)\r
{\r
- GopPrivateDestroyQ (Private);\r
+ gBS->CloseEvent (Private->TimerEvent);\r
+\r
+ GopPrivateDestroyQ (Private, &Private->QueueForRead);\r
+ GopPrivateDestroyQ (Private, &Private->QueueForNotify);\r
+\r
return EFI_SUCCESS;\r
}\r