]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
Update to support EFI_SIMPLE_INPUT_EX protocol
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / TerminalConIn.c
index 2d76e38c3342a6502526d151dcaa8b9505ec3a22..4b3eb370237499f882ca953c2f7dfbbddb3d8af3 100644 (file)
@@ -1,6 +1,6 @@
 /**@file\r
-       Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.\r
-       \r
+  Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.\r
+  \r
 Copyright (c) 2006 - 2007 Intel Corporation. <BR>\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
@@ -15,6 +15,78 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "Terminal.h"\r
 \r
 \r
+STATIC\r
+EFI_STATUS\r
+ReadKeyStrokeWorker (\r
+  IN  TERMINAL_DEV *TerminalDevice,\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
+    TerminalDevice        - Terminal driver private structure\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
+  LIST_ENTRY                      *Link;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }  \r
+\r
+  //\r
+  // Initialize *Key to nonsense value.\r
+  //\r
+  KeyData->Key.ScanCode    = SCAN_NULL;\r
+  KeyData->Key.UnicodeChar = 0;\r
+\r
+  Status = TerminalConInCheckForKey (&TerminalDevice->SimpleInput);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  if (!EfiKeyFiFoRemoveOneKey (TerminalDevice, &KeyData->Key)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  KeyData->KeyState.KeyShiftState  = 0;\r
+  KeyData->KeyState.KeyToggleState = 0;\r
+\r
+  //\r
+  // Invoke notification functions if exist\r
+  //\r
+  for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link, \r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY, \r
+                      NotifyEntry, \r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { \r
+      CurrentNotify->KeyNotificationFn (KeyData);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
 EFI_STATUS\r
 EFIAPI\r
 TerminalConInReset (\r
@@ -111,28 +183,358 @@ TerminalConInReadKeyStroke (
 {\r
   TERMINAL_DEV  *TerminalDevice;\r
   EFI_STATUS    Status;\r
+  EFI_KEY_DATA  KeyData;\r
 \r
-  //\r
-  // Initialize *Key to nonsense value.\r
-  //\r
-  Key->ScanCode     = SCAN_NULL;\r
-  Key->UnicodeChar  = 0;\r
   //\r
   //  get TERMINAL_DEV from "This" parameter.\r
   //\r
   TerminalDevice  = TERMINAL_CON_IN_DEV_FROM_THIS (This);\r
 \r
-  Status          = TerminalConInCheckForKey (This);\r
+  Status = ReadKeyStrokeWorker (TerminalDevice, &KeyData);\r
   if (EFI_ERROR (Status)) {\r
-    return EFI_NOT_READY;\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+BOOLEAN\r
+IsKeyRegistered (\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
+  return TRUE;\r
+}\r
+\r
+\r
+VOID\r
+EFIAPI\r
+TerminalConInWaitForKeyEx (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+/*++\r
+  Routine Description:\r
+  \r
+    Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event\r
+    Signal the event if there is key available     \r
+  \r
+  Arguments:\r
+  \r
+    Event - Indicates the event that invoke this function.\r
+    \r
+    Context - Indicates the calling context.\r
+        \r
+  Returns:\r
+  \r
+    N/A\r
+                \r
+--*/\r
+{\r
+  TERMINAL_DEV            *TerminalDevice;\r
+  \r
+  TerminalDevice  = TERMINAL_CON_IN_EX_DEV_FROM_THIS (Context);\r
+\r
+  TerminalConInWaitForKey (Event, &TerminalDevice->SimpleInput);\r
+\r
+}\r
+\r
+//\r
+// Simple Text Input Ex protocol functions\r
+//\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInResetEx (\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
+    EFI_DEVICE_ERROR      - The device is not functioning properly and could \r
+                            not be reset.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS              Status;\r
+  TERMINAL_DEV            *TerminalDevice;\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  Status = TerminalDevice->SimpleInput.Reset (&TerminalDevice->SimpleInput, ExtendedVerification);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  EfiKeyFiFoRemoveOneKey (TerminalDevice, Key);\r
+  return EFI_SUCCESS;\r
+  \r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInReadKeyStrokeEx (\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
+  TERMINAL_DEV                    *TerminalDevice;\r
+\r
+  if (KeyData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }  \r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  return ReadKeyStrokeWorker (TerminalDevice, KeyData);\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInSetState (\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
+  if (KeyToggleState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
+}\r
 \r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInRegisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_KEY_DATA                       *KeyData,\r
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,\r
+  OUT EFI_HANDLE                        *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
+  EFI_STATUS                      Status;\r
+  TERMINAL_DEV                    *TerminalDevice;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *NewNotify;\r
+  LIST_ENTRY                      *Link;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;  \r
+\r
+  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  //\r
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
+  //\r
+  for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link, \r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY, \r
+                      NotifyEntry, \r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { \r
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
+        *NotifyHandle = CurrentNotify->NotifyHandle;        \r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate resource to save the notification function\r
+  //  \r
+  NewNotify = (TERMINAL_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY));\r
+  if (NewNotify == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }  \r
+\r
+  NewNotify->Signature         = TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE;     \r
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData));\r
+  InsertTailList (&TerminalDevice->NotifyList, &NewNotify->NotifyEntry);\r
+  //\r
+  // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE\r
+  //  \r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &NewNotify->NotifyHandle,\r
+                  &gSimpleTextInExNotifyGuid,\r
+                  NULL,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  *NotifyHandle                = NewNotify->NotifyHandle;  \r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
+EFI_STATUS\r
+EFIAPI\r
+TerminalConInUnregisterKeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,\r
+  IN EFI_HANDLE                         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
+    EFI_NOT_FOUND           - Can not find the matching entry in database.  \r
+                              \r
+--*/   \r
+{\r
+  EFI_STATUS                      Status;\r
+  TERMINAL_DEV                    *TerminalDevice;\r
+  LIST_ENTRY                      *Link;\r
+  TERMINAL_CONSOLE_IN_EX_NOTIFY   *CurrentNotify;\r
+\r
+  if (NotificationHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } \r
+  \r
+  Status = gBS->OpenProtocol (\r
+                  NotificationHandle,\r
+                  &gSimpleTextInExNotifyGuid,\r
+                  NULL,\r
+                  NULL,\r
+                  NULL,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TerminalDevice = TERMINAL_CON_IN_EX_DEV_FROM_THIS (This);\r
+\r
+  for (Link = TerminalDevice->NotifyList.ForwardLink; Link != &TerminalDevice->NotifyList; Link = Link->ForwardLink) {\r
+    CurrentNotify = CR (\r
+                      Link, \r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY, \r
+                      NotifyEntry, \r
+                      TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
+                      );\r
+    if (CurrentNotify->NotifyHandle == NotificationHandle) {\r
+      //\r
+      // Remove the notification function from NotifyList and free resources\r
+      //\r
+      RemoveEntryList (&CurrentNotify->NotifyEntry);      \r
+      Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                      CurrentNotify->NotifyHandle,\r
+                      &gSimpleTextInExNotifyGuid,\r
+                      NULL,\r
+                      NULL\r
+                      );\r
+      ASSERT_EFI_ERROR (Status);\r
+      gBS->FreePool (CurrentNotify);            \r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  \r
+  return EFI_NOT_FOUND;  \r
+}\r
+\r
+\r
 VOID\r
 TranslateRawDataToEfiKey (\r
   IN  TERMINAL_DEV      *TerminalDevice\r
@@ -787,7 +1189,9 @@ Symbols used in table below
 | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |\r
 | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |\r
 | Escape  | 0x17 | ESC       | ESC      | ESC      |\r
-+=========+======+===========+==========+=========+\r
+| F11     | 0x15 |           | ESC !    |          |\r
+| F12     | 0x16 |           | ESC @    |          |\r
++=========+======+===========+==========+==========+\r
 \r
 Special Mappings\r
 ================\r
@@ -882,6 +1286,12 @@ ESC R ESC r ESC R = Reset System
         case '0': \r
           Key.ScanCode = SCAN_F10;        \r
           break;\r
+        case '!':\r
+          Key.ScanCode = SCAN_F11;\r
+          break;\r
+        case '@':\r
+          Key.ScanCode = SCAN_F12;\r
+          break;          \r
         case 'h': \r
           Key.ScanCode = SCAN_HOME;       \r
           break;\r
@@ -1150,6 +1560,10 @@ ESC R ESC r ESC R = Reset System
     if (UnicodeChar == ESC) {\r
       TerminalDevice->InputState = INPUT_STATE_ESC;\r
     }\r
+\r
+    if (UnicodeChar == CSI) {\r
+      TerminalDevice->InputState = INPUT_STATE_CSI;\r
+    }\r
     \r
     if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {\r
       Status = gBS->SetTimer(\r