Home | History | Annotate | Download | only in Ps2KeyboardDxe
      1 /** @file
      2   Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces
      3   provided by Ps2KbdCtrller.c.
      4 
      5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 #include "Ps2Keyboard.h"
     18 
     19 /**
     20   Check whether the EFI key buffer is empty.
     21 
     22   @param Queue     Pointer to instance of EFI_KEY_QUEUE.
     23 
     24   @retval TRUE    The EFI key buffer is empty.
     25   @retval FALSE   The EFI key buffer isn't empty.
     26 **/
     27 BOOLEAN
     28 IsEfikeyBufEmpty (
     29   IN  EFI_KEY_QUEUE         *Queue
     30   )
     31 {
     32   return (BOOLEAN) (Queue->Head == Queue->Tail);
     33 }
     34 
     35 /**
     36   Read & remove one key data from the EFI key buffer.
     37 
     38   @param Queue     Pointer to instance of EFI_KEY_QUEUE.
     39   @param KeyData   Receive the key data.
     40 
     41   @retval EFI_SUCCESS   The key data is popped successfully.
     42   @retval EFI_NOT_READY There is no key data available.
     43 **/
     44 EFI_STATUS
     45 PopEfikeyBufHead (
     46   IN  EFI_KEY_QUEUE         *Queue,
     47   OUT EFI_KEY_DATA          *KeyData OPTIONAL
     48   )
     49 {
     50   if (IsEfikeyBufEmpty (Queue)) {
     51     return EFI_NOT_READY;
     52   }
     53   //
     54   // Retrieve and remove the values
     55   //
     56   if (KeyData != NULL) {
     57     CopyMem (KeyData, &Queue->Buffer[Queue->Head], sizeof (EFI_KEY_DATA));
     58   }
     59   Queue->Head = (Queue->Head + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;
     60   return EFI_SUCCESS;
     61 }
     62 
     63 /**
     64   Push one key data to the EFI key buffer.
     65 
     66   @param Queue     Pointer to instance of EFI_KEY_QUEUE.
     67   @param KeyData   The key data to push.
     68 **/
     69 VOID
     70 PushEfikeyBufTail (
     71   IN  EFI_KEY_QUEUE         *Queue,
     72   IN  EFI_KEY_DATA          *KeyData
     73   )
     74 {
     75   if ((Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT == Queue->Head) {
     76     //
     77     // If Queue is full, pop the one from head.
     78     //
     79     PopEfikeyBufHead (Queue, NULL);
     80   }
     81   CopyMem (&Queue->Buffer[Queue->Tail], KeyData, sizeof (EFI_KEY_DATA));
     82   Queue->Tail = (Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;
     83 }
     84 
     85 /**
     86   Judge whether is a registed key
     87 
     88   @param RegsiteredData       A pointer to a buffer that is filled in with the keystroke
     89                               state data for the key that was registered.
     90   @param InputData            A pointer to a buffer that is filled in with the keystroke
     91                               state data for the key that was pressed.
     92 
     93   @retval TRUE                Key be pressed matches a registered key.
     94   @retval FLASE               Match failed.
     95 
     96 **/
     97 BOOLEAN
     98 IsKeyRegistered (
     99   IN EFI_KEY_DATA  *RegsiteredData,
    100   IN EFI_KEY_DATA  *InputData
    101   )
    102 
    103 {
    104   ASSERT (RegsiteredData != NULL && InputData != NULL);
    105 
    106   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
    107       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
    108     return FALSE;
    109   }
    110 
    111   //
    112   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
    113   //
    114   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
    115       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
    116     return FALSE;
    117   }
    118   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
    119       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
    120     return FALSE;
    121   }
    122 
    123   return TRUE;
    124 
    125 }
    126 
    127 /**
    128     Reads the next keystroke from the input device. The WaitForKey Event can
    129     be used to test for existance of a keystroke via WaitForEvent () call.
    130 
    131     @param ConsoleInDev          Ps2 Keyboard private structure
    132     @param KeyData               A pointer to a buffer that is filled in with the keystroke
    133                                  state data for the key that was pressed.
    134 
    135 
    136     @retval EFI_SUCCESS             The keystroke information was returned.
    137     @retval EFI_NOT_READY           There was no keystroke data availiable.
    138     @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to
    139                                     hardware errors.
    140     @retval EFI_INVALID_PARAMETER   KeyData is NULL.
    141 
    142 **/
    143 EFI_STATUS
    144 KeyboardReadKeyStrokeWorker (
    145   IN  KEYBOARD_CONSOLE_IN_DEV           *ConsoleInDev,
    146   OUT EFI_KEY_DATA                      *KeyData
    147   )
    148 
    149 {
    150   EFI_STATUS                            Status;
    151   EFI_TPL                               OldTpl;
    152 
    153   if (KeyData == NULL) {
    154     return EFI_INVALID_PARAMETER;
    155   }
    156 
    157   //
    158   // Enter critical section
    159   //
    160   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    161 
    162   KeyboardTimerHandler (NULL, ConsoleInDev);
    163 
    164   if (ConsoleInDev->KeyboardErr) {
    165     Status = EFI_DEVICE_ERROR;
    166   } else {
    167     Status = PopEfikeyBufHead (&ConsoleInDev->EfiKeyQueue, KeyData);
    168   }
    169 
    170   gBS->RestoreTPL (OldTpl);
    171   return Status;
    172 }
    173 
    174 /**
    175   Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()
    176 
    177   @param This                 Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
    178   @param ExtendedVerification Indicate that the driver may perform a more
    179                               exhaustive verification operation of the device during
    180                               reset, now this par is ignored in this driver
    181 
    182 **/
    183 EFI_STATUS
    184 EFIAPI
    185 KeyboardEfiReset (
    186   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
    187   IN  BOOLEAN                         ExtendedVerification
    188   )
    189 {
    190   EFI_STATUS              Status;
    191   KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
    192   EFI_TPL                 OldTpl;
    193 
    194   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    195   if (ConsoleIn->KeyboardErr) {
    196     return EFI_DEVICE_ERROR;
    197   }
    198 
    199   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    200     EFI_PROGRESS_CODE,
    201     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,
    202     ConsoleIn->DevicePath
    203     );
    204 
    205   //
    206   // Enter critical section
    207   //
    208   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    209 
    210   //
    211   // Call InitKeyboard to initialize the keyboard
    212   //
    213   Status = InitKeyboard (ConsoleIn, ExtendedVerification);
    214   if (EFI_ERROR (Status)) {
    215     //
    216     // Leave critical section and return
    217     //
    218     gBS->RestoreTPL (OldTpl);
    219     return EFI_DEVICE_ERROR;
    220   }
    221 
    222   //
    223   // Leave critical section and return
    224   //
    225   gBS->RestoreTPL (OldTpl);
    226 
    227   //
    228   // Report the status If a stuck key was detected
    229   //
    230   if (KeyReadStatusRegister (ConsoleIn) & 0x01) {
    231     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    232       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    233       EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_STUCK_KEY,
    234       ConsoleIn->DevicePath
    235       );
    236   }
    237   //
    238   // Report the status If keyboard is locked
    239   //
    240   if ((KeyReadStatusRegister (ConsoleIn) & 0x10) == 0) {
    241     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    242       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    243       EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_LOCKED,
    244       ConsoleIn->DevicePath
    245       );
    246   }
    247 
    248   return EFI_SUCCESS;
    249 }
    250 
    251 /**
    252   Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().
    253 
    254   @param This    Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
    255   @param Key     The output buffer for key value
    256 
    257   @retval EFI_SUCCESS success to read key stroke
    258 **/
    259 EFI_STATUS
    260 EFIAPI
    261 KeyboardReadKeyStroke (
    262   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
    263   OUT EFI_INPUT_KEY                   *Key
    264   )
    265 {
    266   EFI_STATUS              Status;
    267   KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
    268   EFI_KEY_DATA            KeyData;
    269 
    270   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    271 
    272   //
    273   // Considering if the partial keystroke is enabled, there maybe a partial
    274   // keystroke in the queue, so here skip the partial keystroke and get the
    275   // next key from the queue
    276   //
    277   while (1) {
    278     //
    279     // If there is no pending key, then return.
    280     //
    281     Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData);
    282     if (EFI_ERROR (Status)) {
    283       return Status;
    284     }
    285     //
    286     // If it is partial keystroke, skip it.
    287     //
    288     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
    289       continue;
    290     }
    291     //
    292     // Translate the CTRL-Alpha characters to their corresponding control value
    293     // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
    294     //
    295     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
    296       if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
    297         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
    298       } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
    299         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
    300       }
    301     }
    302 
    303     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
    304     return EFI_SUCCESS;
    305   }
    306 }
    307 
    308 /**
    309   Event notification function for SIMPLE_TEXT_IN.WaitForKey event
    310   Signal the event if there is key available
    311 
    312   @param Event    the event object
    313   @param Context  waitting context
    314 
    315 **/
    316 VOID
    317 EFIAPI
    318 KeyboardWaitForKey (
    319   IN  EFI_EVENT               Event,
    320   IN  VOID                    *Context
    321   )
    322 {
    323   EFI_TPL                     OldTpl;
    324   KEYBOARD_CONSOLE_IN_DEV     *ConsoleIn;
    325   EFI_KEY_DATA                KeyData;
    326 
    327   ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
    328 
    329   //
    330   // Enter critical section
    331   //
    332   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    333 
    334   KeyboardTimerHandler (NULL, ConsoleIn);
    335 
    336   if (!ConsoleIn->KeyboardErr) {
    337     //
    338     // WaitforKey doesn't suppor the partial key.
    339     // Considering if the partial keystroke is enabled, there maybe a partial
    340     // keystroke in the queue, so here skip the partial keystroke and get the
    341     // next key from the queue
    342     //
    343     while (!IsEfikeyBufEmpty (&ConsoleIn->EfiKeyQueue)) {
    344       CopyMem (
    345         &KeyData,
    346         &(ConsoleIn->EfiKeyQueue.Buffer[ConsoleIn->EfiKeyQueue.Head]),
    347         sizeof (EFI_KEY_DATA)
    348         );
    349       if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
    350         PopEfikeyBufHead (&ConsoleIn->EfiKeyQueue, &KeyData);
    351         continue;
    352       }
    353       //
    354       // if there is pending value key, signal the event.
    355       //
    356       gBS->SignalEvent (Event);
    357       break;
    358     }
    359   }
    360   //
    361   // Leave critical section and return
    362   //
    363   gBS->RestoreTPL (OldTpl);
    364 }
    365 
    366 /**
    367   Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
    368   Signal the event if there is key available
    369 
    370   @param Event    event object
    371   @param Context  waiting context
    372 
    373 **/
    374 VOID
    375 EFIAPI
    376 KeyboardWaitForKeyEx (
    377   IN  EFI_EVENT               Event,
    378   IN  VOID                    *Context
    379   )
    380 
    381 {
    382   KeyboardWaitForKey (Event, Context);
    383 }
    384 
    385 /**
    386   Reset the input device and optionaly run diagnostics
    387 
    388   @param This                     Protocol instance pointer.
    389   @param ExtendedVerification     Driver may perform diagnostics on reset.
    390 
    391   @retval EFI_SUCCESS             The device was reset.
    392   @retval EFI_DEVICE_ERROR        The device is not functioning properly and could
    393                                   not be reset.
    394 
    395 **/
    396 EFI_STATUS
    397 EFIAPI
    398 KeyboardEfiResetEx (
    399   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    400   IN BOOLEAN                            ExtendedVerification
    401   )
    402 
    403 {
    404   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
    405 
    406   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    407 
    408   return ConsoleInDev->ConIn.Reset (
    409                                &ConsoleInDev->ConIn,
    410                                ExtendedVerification
    411                                );
    412 }
    413 
    414 /**
    415     Reads the next keystroke from the input device. The WaitForKey Event can
    416     be used to test for existance of a keystroke via WaitForEvent () call.
    417 
    418 
    419     @param This         Protocol instance pointer.
    420     @param KeyData      A pointer to a buffer that is filled in with the keystroke
    421                         state data for the key that was pressed.
    422 
    423     @retval EFI_SUCCESS           The keystroke information was returned.
    424     @retval EFI_NOT_READY         There was no keystroke data availiable.
    425     @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to
    426                                   hardware errors.
    427     @retval EFI_INVALID_PARAMETER KeyData is NULL.
    428 
    429 **/
    430 EFI_STATUS
    431 EFIAPI
    432 KeyboardReadKeyStrokeEx (
    433   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
    434   OUT EFI_KEY_DATA                      *KeyData
    435   )
    436 
    437 {
    438   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
    439 
    440   if (KeyData == NULL) {
    441     return EFI_INVALID_PARAMETER;
    442   }
    443 
    444   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    445   return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData);
    446 }
    447 
    448 /**
    449   Set certain state for the input device.
    450 
    451   @param This               Protocol instance pointer.
    452   @param KeyToggleState     A pointer to the EFI_KEY_TOGGLE_STATE to set the
    453                             state for the input device.
    454 
    455   @retval EFI_SUCCESS           The device state was set successfully.
    456   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could
    457                                 not have the setting adjusted.
    458   @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.
    459   @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
    460 
    461 **/
    462 EFI_STATUS
    463 EFIAPI
    464 KeyboardSetState (
    465   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    466   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
    467   )
    468 
    469 {
    470   EFI_STATUS                            Status;
    471   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
    472   EFI_TPL                               OldTpl;
    473 
    474   if (KeyToggleState == NULL) {
    475     return EFI_INVALID_PARAMETER;
    476   }
    477 
    478   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    479 
    480   //
    481   // Enter critical section
    482   //
    483   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    484 
    485   if (ConsoleInDev->KeyboardErr) {
    486     Status = EFI_DEVICE_ERROR;
    487     goto Exit;
    488   }
    489 
    490   if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
    491     Status = EFI_UNSUPPORTED;
    492     goto Exit;
    493   }
    494 
    495   //
    496   // Update the status light
    497   //
    498   ConsoleInDev->ScrollLock          = FALSE;
    499   ConsoleInDev->NumLock             = FALSE;
    500   ConsoleInDev->CapsLock            = FALSE;
    501   ConsoleInDev->IsSupportPartialKey = FALSE;
    502 
    503   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
    504     ConsoleInDev->ScrollLock = TRUE;
    505   }
    506   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
    507     ConsoleInDev->NumLock = TRUE;
    508   }
    509   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
    510     ConsoleInDev->CapsLock = TRUE;
    511   }
    512   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
    513     ConsoleInDev->IsSupportPartialKey = TRUE;
    514   }
    515 
    516   Status = UpdateStatusLights (ConsoleInDev);
    517   if (EFI_ERROR (Status)) {
    518     Status = EFI_DEVICE_ERROR;
    519   }
    520 
    521 Exit:
    522   //
    523   // Leave critical section and return
    524   //
    525   gBS->RestoreTPL (OldTpl);
    526 
    527   return Status;
    528 
    529 }
    530 
    531 /**
    532     Register a notification function for a particular keystroke for the input device.
    533 
    534     @param This                       Protocol instance pointer.
    535     @param KeyData                    A pointer to a buffer that is filled in with the keystroke
    536                                       information data for the key that was pressed.
    537     @param KeyNotificationFunction    Points to the function to be called when the key
    538                                       sequence is typed specified by KeyData.
    539     @param NotifyHandle               Points to the unique handle assigned to the registered notification.
    540 
    541     @retval EFI_SUCCESS               The notification function was registered successfully.
    542     @retval EFI_OUT_OF_RESOURCES      Unable to allocate resources for necesssary data structures.
    543     @retval EFI_INVALID_PARAMETER     KeyData or NotifyHandle or KeyNotificationFunction is NULL.
    544 
    545 **/
    546 EFI_STATUS
    547 EFIAPI
    548 KeyboardRegisterKeyNotify (
    549   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    550   IN EFI_KEY_DATA                       *KeyData,
    551   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
    552   OUT VOID                              **NotifyHandle
    553   )
    554 {
    555   EFI_STATUS                            Status;
    556   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
    557   EFI_TPL                               OldTpl;
    558   LIST_ENTRY                            *Link;
    559   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;
    560   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *NewNotify;
    561 
    562   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
    563     return EFI_INVALID_PARAMETER;
    564   }
    565 
    566   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    567 
    568   //
    569   // Enter critical section
    570   //
    571   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    572 
    573   //
    574   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
    575   //
    576   for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
    577     CurrentNotify = CR (
    578                       Link,
    579                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
    580                       NotifyEntry,
    581                       KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    582                       );
    583     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
    584       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
    585         *NotifyHandle = CurrentNotify;
    586         Status = EFI_SUCCESS;
    587         goto Exit;
    588       }
    589     }
    590   }
    591 
    592   //
    593   // Allocate resource to save the notification function
    594   //
    595   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
    596   if (NewNotify == NULL) {
    597     Status = EFI_OUT_OF_RESOURCES;
    598     goto Exit;
    599   }
    600 
    601   NewNotify->Signature         = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
    602   NewNotify->KeyNotificationFn = KeyNotificationFunction;
    603   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
    604   InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry);
    605 
    606   *NotifyHandle                = NewNotify;
    607   Status                       = EFI_SUCCESS;
    608 
    609 Exit:
    610   //
    611   // Leave critical section and return
    612   //
    613   gBS->RestoreTPL (OldTpl);
    614   return Status;
    615 
    616 }
    617 
    618 /**
    619     Remove a registered notification function from a particular keystroke.
    620 
    621     @param This                       Protocol instance pointer.
    622     @param NotificationHandle         The handle of the notification function being unregistered.
    623 
    624 
    625     @retval EFI_SUCCESS               The notification function was unregistered successfully.
    626     @retval EFI_INVALID_PARAMETER     The NotificationHandle is invalid.
    627 
    628 **/
    629 EFI_STATUS
    630 EFIAPI
    631 KeyboardUnregisterKeyNotify (
    632   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    633   IN VOID                               *NotificationHandle
    634   )
    635 {
    636   EFI_STATUS                            Status;
    637   KEYBOARD_CONSOLE_IN_DEV               *ConsoleInDev;
    638   EFI_TPL                               OldTpl;
    639   LIST_ENTRY                            *Link;
    640   KEYBOARD_CONSOLE_IN_EX_NOTIFY         *CurrentNotify;
    641 
    642   if (NotificationHandle == NULL) {
    643     return EFI_INVALID_PARAMETER;
    644   }
    645 
    646   ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
    647 
    648   //
    649   // Enter critical section
    650   //
    651   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    652 
    653   for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
    654     CurrentNotify = CR (
    655                       Link,
    656                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
    657                       NotifyEntry,
    658                       KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    659                       );
    660     if (CurrentNotify == NotificationHandle) {
    661       //
    662       // Remove the notification function from NotifyList and free resources
    663       //
    664       RemoveEntryList (&CurrentNotify->NotifyEntry);
    665 
    666       gBS->FreePool (CurrentNotify);
    667       Status = EFI_SUCCESS;
    668       goto Exit;
    669     }
    670   }
    671 
    672   //
    673   // Can not find the specified Notification Handle
    674   //
    675   Status = EFI_INVALID_PARAMETER;
    676 Exit:
    677   //
    678   // Leave critical section and return
    679   //
    680   gBS->RestoreTPL (OldTpl);
    681   return Status;
    682 }
    683 
    684 /**
    685   Process key notify.
    686 
    687   @param  Event                 Indicates the event that invoke this function.
    688   @param  Context               Indicates the calling context.
    689 **/
    690 VOID
    691 EFIAPI
    692 KeyNotifyProcessHandler (
    693   IN  EFI_EVENT                 Event,
    694   IN  VOID                      *Context
    695   )
    696 {
    697   EFI_STATUS                    Status;
    698   KEYBOARD_CONSOLE_IN_DEV       *ConsoleIn;
    699   EFI_KEY_DATA                  KeyData;
    700   LIST_ENTRY                    *Link;
    701   LIST_ENTRY                    *NotifyList;
    702   KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
    703   EFI_TPL                       OldTpl;
    704 
    705   ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
    706 
    707   //
    708   // Invoke notification functions.
    709   //
    710   NotifyList = &ConsoleIn->NotifyList;
    711   while (TRUE) {
    712     //
    713     // Enter critical section
    714     //
    715     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    716     Status = PopEfikeyBufHead (&ConsoleIn->EfiKeyQueueForNotify, &KeyData);
    717     //
    718     // Leave critical section
    719     //
    720     gBS->RestoreTPL (OldTpl);
    721     if (EFI_ERROR (Status)) {
    722       break;
    723     }
    724     for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
    725       CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
    726       if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
    727         CurrentNotify->KeyNotificationFn (&KeyData);
    728       }
    729     }
    730   }
    731 }
    732 
    733