Home | History | Annotate | Download | only in UsbKbDxe
      1 /** @file
      2   USB Keyboard Driver that manages USB keyboard and produces Simple Text Input
      3   Protocol and Simple Text Input Ex Protocol.
      4 
      5 Copyright (c) 2004 - 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 #include "EfiKey.h"
     17 #include "KeyBoard.h"
     18 
     19 //
     20 // USB Keyboard Driver Global Variables
     21 //
     22 EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = {
     23   USBKeyboardDriverBindingSupported,
     24   USBKeyboardDriverBindingStart,
     25   USBKeyboardDriverBindingStop,
     26   0xa,
     27   NULL,
     28   NULL
     29 };
     30 
     31 /**
     32   Entrypoint of USB Keyboard Driver.
     33 
     34   This function is the entrypoint of USB Keyboard Driver. It installs Driver Binding
     35   Protocols together with Component Name Protocols.
     36 
     37   @param  ImageHandle       The firmware allocated handle for the EFI image.
     38   @param  SystemTable       A pointer to the EFI System Table.
     39 
     40   @retval EFI_SUCCESS       The entry point is executed successfully.
     41 
     42 **/
     43 EFI_STATUS
     44 EFIAPI
     45 USBKeyboardDriverBindingEntryPoint (
     46   IN EFI_HANDLE           ImageHandle,
     47   IN EFI_SYSTEM_TABLE     *SystemTable
     48   )
     49 {
     50   EFI_STATUS              Status;
     51 
     52   Status = EfiLibInstallDriverBindingComponentName2 (
     53              ImageHandle,
     54              SystemTable,
     55              &gUsbKeyboardDriverBinding,
     56              ImageHandle,
     57              &gUsbKeyboardComponentName,
     58              &gUsbKeyboardComponentName2
     59              );
     60   ASSERT_EFI_ERROR (Status);
     61 
     62   return EFI_SUCCESS;
     63 }
     64 
     65 /**
     66   Check whether USB keyboard driver supports this device.
     67 
     68   @param  This                   The USB keyboard driver binding protocol.
     69   @param  Controller             The controller handle to check.
     70   @param  RemainingDevicePath    The remaining device path.
     71 
     72   @retval EFI_SUCCESS            The driver supports this controller.
     73   @retval other                  This device isn't supported.
     74 
     75 **/
     76 EFI_STATUS
     77 EFIAPI
     78 USBKeyboardDriverBindingSupported (
     79   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
     80   IN EFI_HANDLE                     Controller,
     81   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
     82   )
     83 {
     84   EFI_STATUS          Status;
     85   EFI_USB_IO_PROTOCOL *UsbIo;
     86 
     87   //
     88   // Check if USB I/O Protocol is attached on the controller handle.
     89   //
     90   Status = gBS->OpenProtocol (
     91                   Controller,
     92                   &gEfiUsbIoProtocolGuid,
     93                   (VOID **) &UsbIo,
     94                   This->DriverBindingHandle,
     95                   Controller,
     96                   EFI_OPEN_PROTOCOL_BY_DRIVER
     97                   );
     98   if (EFI_ERROR (Status)) {
     99     return Status;
    100   }
    101 
    102   //
    103   // Use the USB I/O Protocol interface to check whether Controller is
    104   // a keyboard device that can be managed by this driver.
    105   //
    106   Status = EFI_SUCCESS;
    107 
    108   if (!IsUSBKeyboard (UsbIo)) {
    109     Status = EFI_UNSUPPORTED;
    110   }
    111 
    112   gBS->CloseProtocol (
    113          Controller,
    114          &gEfiUsbIoProtocolGuid,
    115          This->DriverBindingHandle,
    116          Controller
    117          );
    118 
    119   return Status;
    120 }
    121 
    122 /**
    123   Starts the keyboard device with this driver.
    124 
    125   This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol,
    126   initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage
    127   this keyboard device.
    128 
    129   @param  This                   The USB keyboard driver binding instance.
    130   @param  Controller             Handle of device to bind driver to.
    131   @param  RemainingDevicePath    Optional parameter use to pick a specific child
    132                                  device to start.
    133 
    134   @retval EFI_SUCCESS            The controller is controlled by the usb keyboard driver.
    135   @retval EFI_UNSUPPORTED        No interrupt endpoint can be found.
    136   @retval Other                  This controller cannot be started.
    137 
    138 **/
    139 EFI_STATUS
    140 EFIAPI
    141 USBKeyboardDriverBindingStart (
    142   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    143   IN EFI_HANDLE                     Controller,
    144   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    145   )
    146 {
    147   EFI_STATUS                    Status;
    148   EFI_USB_IO_PROTOCOL           *UsbIo;
    149   USB_KB_DEV                    *UsbKeyboardDevice;
    150   UINT8                         EndpointNumber;
    151   EFI_USB_ENDPOINT_DESCRIPTOR   EndpointDescriptor;
    152   UINT8                         Index;
    153   UINT8                         EndpointAddr;
    154   UINT8                         PollingInterval;
    155   UINT8                         PacketSize;
    156   BOOLEAN                       Found;
    157   EFI_TPL                       OldTpl;
    158 
    159   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    160   //
    161   // Open USB I/O Protocol
    162   //
    163   Status = gBS->OpenProtocol (
    164                   Controller,
    165                   &gEfiUsbIoProtocolGuid,
    166                   (VOID **) &UsbIo,
    167                   This->DriverBindingHandle,
    168                   Controller,
    169                   EFI_OPEN_PROTOCOL_BY_DRIVER
    170                   );
    171   if (EFI_ERROR (Status)) {
    172     goto ErrorExit1;
    173   }
    174 
    175   UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV));
    176   ASSERT (UsbKeyboardDevice != NULL);
    177 
    178   //
    179   // Get the Device Path Protocol on Controller's handle
    180   //
    181   Status = gBS->OpenProtocol (
    182                   Controller,
    183                   &gEfiDevicePathProtocolGuid,
    184                   (VOID **) &UsbKeyboardDevice->DevicePath,
    185                   This->DriverBindingHandle,
    186                   Controller,
    187                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    188                   );
    189 
    190   if (EFI_ERROR (Status)) {
    191     goto ErrorExit;
    192   }
    193   //
    194   // Report that the USB keyboard is being enabled
    195   //
    196   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    197     EFI_PROGRESS_CODE,
    198     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE),
    199     UsbKeyboardDevice->DevicePath
    200     );
    201 
    202   //
    203   // This is pretty close to keyboard detection, so log progress
    204   //
    205   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    206     EFI_PROGRESS_CODE,
    207     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT),
    208     UsbKeyboardDevice->DevicePath
    209     );
    210 
    211   UsbKeyboardDevice->UsbIo = UsbIo;
    212 
    213   //
    214   // Get interface & endpoint descriptor
    215   //
    216   UsbIo->UsbGetInterfaceDescriptor (
    217            UsbIo,
    218            &UsbKeyboardDevice->InterfaceDescriptor
    219            );
    220 
    221   EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints;
    222 
    223   //
    224   // Traverse endpoints to find interrupt endpoint
    225   //
    226   Found = FALSE;
    227   for (Index = 0; Index < EndpointNumber; Index++) {
    228 
    229     UsbIo->UsbGetEndpointDescriptor (
    230              UsbIo,
    231              Index,
    232              &EndpointDescriptor
    233              );
    234 
    235     if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) {
    236       //
    237       // We only care interrupt endpoint here
    238       //
    239       CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
    240       Found = TRUE;
    241       break;
    242     }
    243   }
    244 
    245   if (!Found) {
    246     //
    247     // Report Status Code to indicate that there is no USB keyboard
    248     //
    249     REPORT_STATUS_CODE (
    250       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    251       (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED)
    252       );
    253     //
    254     // No interrupt endpoint found, then return unsupported.
    255     //
    256     Status = EFI_UNSUPPORTED;
    257     goto ErrorExit;
    258   }
    259 
    260   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    261     EFI_PROGRESS_CODE,
    262     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED),
    263     UsbKeyboardDevice->DevicePath
    264     );
    265 
    266   UsbKeyboardDevice->Signature                  = USB_KB_DEV_SIGNATURE;
    267   UsbKeyboardDevice->SimpleInput.Reset          = USBKeyboardReset;
    268   UsbKeyboardDevice->SimpleInput.ReadKeyStroke  = USBKeyboardReadKeyStroke;
    269 
    270   UsbKeyboardDevice->SimpleInputEx.Reset               = USBKeyboardResetEx;
    271   UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx     = USBKeyboardReadKeyStrokeEx;
    272   UsbKeyboardDevice->SimpleInputEx.SetState            = USBKeyboardSetState;
    273   UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify   = USBKeyboardRegisterKeyNotify;
    274   UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify;
    275 
    276   InitializeListHead (&UsbKeyboardDevice->NotifyList);
    277 
    278   Status = gBS->CreateEvent (
    279                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    280                   TPL_NOTIFY,
    281                   USBKeyboardTimerHandler,
    282                   UsbKeyboardDevice,
    283                   &UsbKeyboardDevice->TimerEvent
    284                   );
    285   if (!EFI_ERROR (Status)) {
    286     Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL);
    287   }
    288   if (EFI_ERROR (Status)) {
    289     goto ErrorExit;
    290   }
    291 
    292   Status = gBS->CreateEvent (
    293                   EVT_NOTIFY_WAIT,
    294                   TPL_NOTIFY,
    295                   USBKeyboardWaitForKey,
    296                   UsbKeyboardDevice,
    297                   &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx)
    298                   );
    299 
    300   if (EFI_ERROR (Status)) {
    301     goto ErrorExit;
    302   }
    303 
    304   Status = gBS->CreateEvent (
    305                   EVT_NOTIFY_WAIT,
    306                   TPL_NOTIFY,
    307                   USBKeyboardWaitForKey,
    308                   UsbKeyboardDevice,
    309                   &(UsbKeyboardDevice->SimpleInput.WaitForKey)
    310                   );
    311   if (EFI_ERROR (Status)) {
    312     goto ErrorExit;
    313   }
    314 
    315   Status = gBS->CreateEvent (
    316                   EVT_NOTIFY_SIGNAL,
    317                   TPL_CALLBACK,
    318                   KeyNotifyProcessHandler,
    319                   UsbKeyboardDevice,
    320                   &UsbKeyboardDevice->KeyNotifyProcessEvent
    321                   );
    322   if (EFI_ERROR (Status)) {
    323     goto ErrorExit;
    324   }
    325 
    326   //
    327   // Install Simple Text Input Protocol and Simple Text Input Ex Protocol
    328   // for the USB keyboard device.
    329   // USB keyboard is a hot plug device, and expected to work immediately
    330   // when plugging into system, other conventional console devices could
    331   // distinguish it by its device path.
    332   //
    333   Status = gBS->InstallMultipleProtocolInterfaces (
    334                   &Controller,
    335                   &gEfiSimpleTextInProtocolGuid,
    336                   &UsbKeyboardDevice->SimpleInput,
    337                   &gEfiSimpleTextInputExProtocolGuid,
    338                   &UsbKeyboardDevice->SimpleInputEx,
    339                   NULL
    340                   );
    341   if (EFI_ERROR (Status)) {
    342     goto ErrorExit;
    343   }
    344 
    345   UsbKeyboardDevice->ControllerHandle = Controller;
    346   Status = InitKeyboardLayout (UsbKeyboardDevice);
    347   if (EFI_ERROR (Status)) {
    348     gBS->UninstallMultipleProtocolInterfaces (
    349       Controller,
    350       &gEfiSimpleTextInProtocolGuid,
    351       &UsbKeyboardDevice->SimpleInput,
    352       &gEfiSimpleTextInputExProtocolGuid,
    353       &UsbKeyboardDevice->SimpleInputEx,
    354       NULL
    355       );
    356     goto ErrorExit;
    357   }
    358 
    359 
    360   //
    361   // Reset USB Keyboard Device exhaustively.
    362   //
    363   Status = UsbKeyboardDevice->SimpleInputEx.Reset (
    364                                             &UsbKeyboardDevice->SimpleInputEx,
    365                                             TRUE
    366                                             );
    367   if (EFI_ERROR (Status)) {
    368     gBS->UninstallMultipleProtocolInterfaces (
    369            Controller,
    370            &gEfiSimpleTextInProtocolGuid,
    371            &UsbKeyboardDevice->SimpleInput,
    372            &gEfiSimpleTextInputExProtocolGuid,
    373            &UsbKeyboardDevice->SimpleInputEx,
    374            NULL
    375            );
    376     goto ErrorExit;
    377   }
    378 
    379   //
    380   // Submit Asynchronous Interrupt Transfer to manage this device.
    381   //
    382   EndpointAddr    = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
    383   PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
    384   PacketSize      = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
    385 
    386   Status = UsbIo->UsbAsyncInterruptTransfer (
    387                     UsbIo,
    388                     EndpointAddr,
    389                     TRUE,
    390                     PollingInterval,
    391                     PacketSize,
    392                     KeyboardHandler,
    393                     UsbKeyboardDevice
    394                     );
    395 
    396   if (EFI_ERROR (Status)) {
    397     gBS->UninstallMultipleProtocolInterfaces (
    398            Controller,
    399            &gEfiSimpleTextInProtocolGuid,
    400            &UsbKeyboardDevice->SimpleInput,
    401            &gEfiSimpleTextInputExProtocolGuid,
    402            &UsbKeyboardDevice->SimpleInputEx,
    403            NULL
    404            );
    405     goto ErrorExit;
    406   }
    407 
    408   UsbKeyboardDevice->ControllerNameTable = NULL;
    409   AddUnicodeString2 (
    410     "eng",
    411     gUsbKeyboardComponentName.SupportedLanguages,
    412     &UsbKeyboardDevice->ControllerNameTable,
    413     L"Generic Usb Keyboard",
    414     TRUE
    415     );
    416   AddUnicodeString2 (
    417     "en",
    418     gUsbKeyboardComponentName2.SupportedLanguages,
    419     &UsbKeyboardDevice->ControllerNameTable,
    420     L"Generic Usb Keyboard",
    421     FALSE
    422     );
    423 
    424   gBS->RestoreTPL (OldTpl);
    425   return EFI_SUCCESS;
    426 
    427 //
    428 // Error handler
    429 //
    430 ErrorExit:
    431   if (UsbKeyboardDevice != NULL) {
    432     if (UsbKeyboardDevice->TimerEvent != NULL) {
    433       gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
    434     }
    435     if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
    436       gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
    437     }
    438     if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
    439       gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
    440     }
    441     if (UsbKeyboardDevice->KeyNotifyProcessEvent != NULL) {
    442       gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
    443     }
    444     if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {
    445       ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
    446       gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
    447     }
    448     FreePool (UsbKeyboardDevice);
    449     UsbKeyboardDevice = NULL;
    450   }
    451   gBS->CloseProtocol (
    452          Controller,
    453          &gEfiUsbIoProtocolGuid,
    454          This->DriverBindingHandle,
    455          Controller
    456          );
    457 
    458 ErrorExit1:
    459   gBS->RestoreTPL (OldTpl);
    460 
    461   return Status;
    462 
    463 }
    464 
    465 
    466 /**
    467   Stop the USB keyboard device handled by this driver.
    468 
    469   @param  This                   The USB keyboard driver binding protocol.
    470   @param  Controller             The controller to release.
    471   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
    472   @param  ChildHandleBuffer      The array of child handle.
    473 
    474   @retval EFI_SUCCESS            The device was stopped.
    475   @retval EFI_UNSUPPORTED        Simple Text In Protocol or Simple Text In Ex Protocol
    476                                  is not installed on Controller.
    477   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
    478   @retval Others                 Fail to uninstall protocols attached on the device.
    479 
    480 **/
    481 EFI_STATUS
    482 EFIAPI
    483 USBKeyboardDriverBindingStop (
    484   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    485   IN  EFI_HANDLE                     Controller,
    486   IN  UINTN                          NumberOfChildren,
    487   IN  EFI_HANDLE                     *ChildHandleBuffer
    488   )
    489 {
    490   EFI_STATUS                     Status;
    491   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
    492   USB_KB_DEV                     *UsbKeyboardDevice;
    493 
    494   Status = gBS->OpenProtocol (
    495                   Controller,
    496                   &gEfiSimpleTextInProtocolGuid,
    497                   (VOID **) &SimpleInput,
    498                   This->DriverBindingHandle,
    499                   Controller,
    500                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    501                   );
    502   if (EFI_ERROR (Status)) {
    503     return EFI_UNSUPPORTED;
    504   }
    505 
    506   Status = gBS->OpenProtocol (
    507                   Controller,
    508                   &gEfiSimpleTextInputExProtocolGuid,
    509                   NULL,
    510                   This->DriverBindingHandle,
    511                   Controller,
    512                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    513                   );
    514   if (EFI_ERROR (Status)) {
    515     return EFI_UNSUPPORTED;
    516   }
    517 
    518   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
    519 
    520   //
    521   // The key data input from this device will be disabled.
    522   //
    523   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    524     EFI_PROGRESS_CODE,
    525     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),
    526     UsbKeyboardDevice->DevicePath
    527     );
    528 
    529   //
    530   // Delete the Asynchronous Interrupt Transfer from this device
    531   //
    532   UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
    533                               UsbKeyboardDevice->UsbIo,
    534                               UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
    535                               FALSE,
    536                               UsbKeyboardDevice->IntEndpointDescriptor.Interval,
    537                               0,
    538                               NULL,
    539                               NULL
    540                               );
    541 
    542   gBS->CloseProtocol (
    543          Controller,
    544          &gEfiUsbIoProtocolGuid,
    545          This->DriverBindingHandle,
    546          Controller
    547          );
    548 
    549   Status = gBS->UninstallMultipleProtocolInterfaces (
    550                   Controller,
    551                   &gEfiSimpleTextInProtocolGuid,
    552                   &UsbKeyboardDevice->SimpleInput,
    553                   &gEfiSimpleTextInputExProtocolGuid,
    554                   &UsbKeyboardDevice->SimpleInputEx,
    555                   NULL
    556                   );
    557   //
    558   // Free all resources.
    559   //
    560   gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
    561   gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
    562   gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
    563   gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
    564   gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
    565   gBS->CloseEvent (UsbKeyboardDevice->KeyNotifyProcessEvent);
    566   KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
    567 
    568   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
    569   gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
    570 
    571   if (UsbKeyboardDevice->ControllerNameTable != NULL) {
    572     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
    573   }
    574 
    575   DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);
    576   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);
    577   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify);
    578 
    579   FreePool (UsbKeyboardDevice);
    580 
    581   return Status;
    582 }
    583 
    584 /**
    585   Internal function to read the next keystroke from the keyboard buffer.
    586 
    587   @param  UsbKeyboardDevice       USB keyboard's private structure.
    588   @param  KeyData                 A pointer to buffer to hold the keystroke
    589                                   data for the key that was pressed.
    590 
    591   @retval EFI_SUCCESS             The keystroke information was returned.
    592   @retval EFI_NOT_READY           There was no keystroke data availiable.
    593   @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to
    594                                   hardware errors.
    595   @retval EFI_INVALID_PARAMETER   KeyData is NULL.
    596   @retval Others                  Fail to translate keycode into EFI_INPUT_KEY
    597 
    598 **/
    599 EFI_STATUS
    600 USBKeyboardReadKeyStrokeWorker (
    601   IN OUT USB_KB_DEV                 *UsbKeyboardDevice,
    602      OUT EFI_KEY_DATA               *KeyData
    603   )
    604 {
    605   if (KeyData == NULL) {
    606     return EFI_INVALID_PARAMETER;
    607   }
    608 
    609   if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
    610     return EFI_NOT_READY;
    611   }
    612 
    613   Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));
    614 
    615   return EFI_SUCCESS;
    616 }
    617 
    618 /**
    619   Reset the input device and optionally run diagnostics
    620 
    621   There are 2 types of reset for USB keyboard.
    622   For non-exhaustive reset, only keyboard buffer is cleared.
    623   For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
    624   is also re-initialized.
    625 
    626   @param  This                 Protocol instance pointer.
    627   @param  ExtendedVerification Driver may perform diagnostics on reset.
    628 
    629   @retval EFI_SUCCESS          The device was reset.
    630   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.
    631 
    632 **/
    633 EFI_STATUS
    634 EFIAPI
    635 USBKeyboardReset (
    636   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
    637   IN  BOOLEAN                          ExtendedVerification
    638   )
    639 {
    640   EFI_STATUS          Status;
    641   USB_KB_DEV          *UsbKeyboardDevice;
    642 
    643   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
    644 
    645   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    646     EFI_PROGRESS_CODE,
    647     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),
    648     UsbKeyboardDevice->DevicePath
    649     );
    650 
    651   //
    652   // Non-exhaustive reset:
    653   // only reset private data structures.
    654   //
    655   if (!ExtendedVerification) {
    656     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    657       EFI_PROGRESS_CODE,
    658       (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),
    659       UsbKeyboardDevice->DevicePath
    660       );
    661     //
    662     // Clear the key buffer of this USB keyboard
    663     //
    664     InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
    665     InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
    666     InitQueue (&UsbKeyboardDevice->EfiKeyQueueForNotify, sizeof (EFI_KEY_DATA));
    667 
    668     return EFI_SUCCESS;
    669   }
    670 
    671   //
    672   // Exhaustive reset
    673   //
    674   Status = InitUSBKeyboard (UsbKeyboardDevice);
    675   if (EFI_ERROR (Status)) {
    676     return EFI_DEVICE_ERROR;
    677   }
    678 
    679   return EFI_SUCCESS;
    680 }
    681 
    682 
    683 /**
    684   Reads the next keystroke from the input device.
    685 
    686   @param  This                 The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
    687   @param  Key                  A pointer to a buffer that is filled in with the keystroke
    688                                information for the key that was pressed.
    689 
    690   @retval EFI_SUCCESS          The keystroke information was returned.
    691   @retval EFI_NOT_READY        There was no keystroke data availiable.
    692   @retval EFI_DEVICE_ERROR     The keystroke information was not returned due to
    693                                hardware errors.
    694 
    695 **/
    696 EFI_STATUS
    697 EFIAPI
    698 USBKeyboardReadKeyStroke (
    699   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
    700   OUT EFI_INPUT_KEY                    *Key
    701   )
    702 {
    703   USB_KB_DEV   *UsbKeyboardDevice;
    704   EFI_STATUS   Status;
    705   EFI_KEY_DATA KeyData;
    706 
    707   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
    708 
    709   //
    710   // Considering if the partial keystroke is enabled, there maybe a partial
    711   // keystroke in the queue, so here skip the partial keystroke and get the
    712   // next key from the queue
    713   //
    714   while (1) {
    715     Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
    716     if (EFI_ERROR (Status)) {
    717       return Status;
    718     }
    719     //
    720     // SimpleTextIn Protocol doesn't support partial keystroke;
    721     //
    722     if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) {
    723       continue;
    724     }
    725     //
    726     // Translate the CTRL-Alpha characters to their corresponding control value
    727     // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
    728     //
    729     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
    730       if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
    731         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
    732       } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
    733         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
    734       }
    735     }
    736 
    737     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
    738     return EFI_SUCCESS;
    739   }
    740 }
    741 
    742 
    743 /**
    744   Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
    745   and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
    746 
    747   @param  Event        Event to be signaled when a key is pressed.
    748   @param  Context      Points to USB_KB_DEV instance.
    749 
    750 **/
    751 VOID
    752 EFIAPI
    753 USBKeyboardWaitForKey (
    754   IN  EFI_EVENT               Event,
    755   IN  VOID                    *Context
    756   )
    757 {
    758   USB_KB_DEV  *UsbKeyboardDevice;
    759   EFI_KEY_DATA KeyData;
    760   EFI_TPL      OldTpl;
    761 
    762   UsbKeyboardDevice = (USB_KB_DEV *) Context;
    763 
    764   //
    765   // Enter critical section
    766   //
    767   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    768 
    769   //
    770   // WaitforKey doesn't suppor the partial key.
    771   // Considering if the partial keystroke is enabled, there maybe a partial
    772   // keystroke in the queue, so here skip the partial keystroke and get the
    773   // next key from the queue
    774   //
    775   while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
    776     //
    777     // If there is pending key, signal the event.
    778     //
    779     CopyMem (
    780       &KeyData,
    781       UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],
    782       sizeof (EFI_KEY_DATA)
    783       );
    784     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
    785       Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));
    786       continue;
    787     }
    788     gBS->SignalEvent (Event);
    789     break;
    790   }
    791   //
    792   // Leave critical section and return
    793   //
    794   gBS->RestoreTPL (OldTpl);
    795 }
    796 
    797 /**
    798   Timer handler to convert the key from USB.
    799 
    800   @param  Event                    Indicates the event that invoke this function.
    801   @param  Context                  Indicates the calling context.
    802 **/
    803 VOID
    804 EFIAPI
    805 USBKeyboardTimerHandler (
    806   IN  EFI_EVENT                 Event,
    807   IN  VOID                      *Context
    808   )
    809 {
    810   EFI_STATUS                    Status;
    811   USB_KB_DEV                    *UsbKeyboardDevice;
    812   UINT8                         KeyCode;
    813   EFI_KEY_DATA                  KeyData;
    814 
    815   UsbKeyboardDevice = (USB_KB_DEV *) Context;
    816 
    817   //
    818   // Fetch raw data from the USB keyboard buffer,
    819   // and translate it into USB keycode.
    820   //
    821   Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
    822   if (EFI_ERROR (Status)) {
    823     return ;
    824   }
    825 
    826   //
    827   // Translate saved USB keycode into EFI_INPUT_KEY
    828   //
    829   Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);
    830   if (EFI_ERROR (Status)) {
    831     return ;
    832   }
    833 
    834   //
    835   // Insert to the EFI Key queue
    836   //
    837   Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));
    838 }
    839 
    840 /**
    841   Free keyboard notify list.
    842 
    843   @param  NotifyList              The keyboard notify list to free.
    844 
    845   @retval EFI_SUCCESS             Free the notify list successfully.
    846   @retval EFI_INVALID_PARAMETER   NotifyList is NULL.
    847 
    848 **/
    849 EFI_STATUS
    850 KbdFreeNotifyList (
    851   IN OUT LIST_ENTRY           *NotifyList
    852   )
    853 {
    854   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
    855   LIST_ENTRY                    *Link;
    856 
    857   if (NotifyList == NULL) {
    858     return EFI_INVALID_PARAMETER;
    859   }
    860   while (!IsListEmpty (NotifyList)) {
    861     Link = GetFirstNode (NotifyList);
    862     NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
    863     RemoveEntryList (Link);
    864     FreePool (NotifyNode);
    865   }
    866 
    867   return EFI_SUCCESS;
    868 }
    869 
    870 /**
    871   Check whether the pressed key matches a registered key or not.
    872 
    873   @param  RegsiteredData    A pointer to keystroke data for the key that was registered.
    874   @param  InputData         A pointer to keystroke data for the key that was pressed.
    875 
    876   @retval TRUE              Key pressed matches a registered key.
    877   @retval FLASE             Key pressed does not matches a registered key.
    878 
    879 **/
    880 BOOLEAN
    881 IsKeyRegistered (
    882   IN EFI_KEY_DATA  *RegsiteredData,
    883   IN EFI_KEY_DATA  *InputData
    884   )
    885 {
    886   ASSERT (RegsiteredData != NULL && InputData != NULL);
    887 
    888   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
    889       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
    890     return FALSE;
    891   }
    892 
    893   //
    894   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
    895   //
    896   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
    897       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
    898     return FALSE;
    899   }
    900   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
    901       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
    902     return FALSE;
    903   }
    904 
    905   return TRUE;
    906 }
    907 
    908 //
    909 // Simple Text Input Ex protocol functions
    910 //
    911 /**
    912   Resets the input device hardware.
    913 
    914   The Reset() function resets the input device hardware. As part
    915   of initialization process, the firmware/device will make a quick
    916   but reasonable attempt to verify that the device is functioning.
    917   If the ExtendedVerification flag is TRUE the firmware may take
    918   an extended amount of time to verify the device is operating on
    919   reset. Otherwise the reset operation is to occur as quickly as
    920   possible. The hardware verification process is not defined by
    921   this specification and is left up to the platform firmware or
    922   driver to implement.
    923 
    924   @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
    925 
    926   @param ExtendedVerification Indicates that the driver may perform a more exhaustive
    927                               verification operation of the device during reset.
    928 
    929   @retval EFI_SUCCESS         The device was reset.
    930   @retval EFI_DEVICE_ERROR    The device is not functioning correctly and could not be reset.
    931 
    932 **/
    933 EFI_STATUS
    934 EFIAPI
    935 USBKeyboardResetEx (
    936   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    937   IN BOOLEAN                            ExtendedVerification
    938   )
    939 {
    940   EFI_STATUS                Status;
    941   USB_KB_DEV                *UsbKeyboardDevice;
    942 
    943   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
    944 
    945   Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
    946   if (EFI_ERROR (Status)) {
    947     return EFI_DEVICE_ERROR;
    948   }
    949 
    950   UsbKeyboardDevice->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
    951   UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
    952 
    953   return EFI_SUCCESS;
    954 
    955 }
    956 
    957 /**
    958   Reads the next keystroke from the input device.
    959 
    960   @param  This                   Protocol instance pointer.
    961   @param  KeyData                A pointer to a buffer that is filled in with the keystroke
    962                                  state data for the key that was pressed.
    963 
    964   @retval EFI_SUCCESS            The keystroke information was returned.
    965   @retval EFI_NOT_READY          There was no keystroke data available.
    966   @retval EFI_DEVICE_ERROR       The keystroke information was not returned due to
    967                                  hardware errors.
    968   @retval EFI_INVALID_PARAMETER  KeyData is NULL.
    969 
    970 **/
    971 EFI_STATUS
    972 EFIAPI
    973 USBKeyboardReadKeyStrokeEx (
    974   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
    975   OUT EFI_KEY_DATA                      *KeyData
    976   )
    977 {
    978   USB_KB_DEV                        *UsbKeyboardDevice;
    979 
    980   if (KeyData == NULL) {
    981     return EFI_INVALID_PARAMETER;
    982   }
    983 
    984   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
    985 
    986   return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
    987 
    988 }
    989 
    990 /**
    991   Set certain state for the input device.
    992 
    993   @param  This                    Protocol instance pointer.
    994   @param  KeyToggleState          A pointer to the EFI_KEY_TOGGLE_STATE to set the
    995                                   state for the input device.
    996 
    997   @retval EFI_SUCCESS             The device state was set appropriately.
    998   @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could
    999                                   not have the setting adjusted.
   1000   @retval EFI_UNSUPPORTED         The device does not support the ability to have its state set.
   1001   @retval EFI_INVALID_PARAMETER   KeyToggleState is NULL.
   1002 
   1003 **/
   1004 EFI_STATUS
   1005 EFIAPI
   1006 USBKeyboardSetState (
   1007   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   1008   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
   1009   )
   1010 {
   1011   USB_KB_DEV                        *UsbKeyboardDevice;
   1012 
   1013   if (KeyToggleState == NULL) {
   1014     return EFI_INVALID_PARAMETER;
   1015   }
   1016 
   1017   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
   1018 
   1019   if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
   1020       ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
   1021     return EFI_UNSUPPORTED;
   1022   }
   1023 
   1024   //
   1025   // Update the status light
   1026   //
   1027 
   1028   UsbKeyboardDevice->ScrollOn   = FALSE;
   1029   UsbKeyboardDevice->NumLockOn  = FALSE;
   1030   UsbKeyboardDevice->CapsOn     = FALSE;
   1031   UsbKeyboardDevice->IsSupportPartialKey = FALSE;
   1032 
   1033   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
   1034     UsbKeyboardDevice->ScrollOn = TRUE;
   1035   }
   1036   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
   1037     UsbKeyboardDevice->NumLockOn = TRUE;
   1038   }
   1039   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
   1040     UsbKeyboardDevice->CapsOn = TRUE;
   1041   }
   1042   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
   1043     UsbKeyboardDevice->IsSupportPartialKey = TRUE;
   1044   }
   1045 
   1046   SetKeyLED (UsbKeyboardDevice);
   1047 
   1048   UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
   1049 
   1050   return EFI_SUCCESS;
   1051 
   1052 }
   1053 
   1054 /**
   1055   Register a notification function for a particular keystroke for the input device.
   1056 
   1057   @param  This                        Protocol instance pointer.
   1058   @param  KeyData                     A pointer to a buffer that is filled in with the keystroke
   1059                                       information data for the key that was pressed.
   1060   @param  KeyNotificationFunction     Points to the function to be called when the key
   1061                                       sequence is typed specified by KeyData.
   1062   @param  NotifyHandle                Points to the unique handle assigned to the registered notification.
   1063 
   1064   @retval EFI_SUCCESS                 The notification function was registered successfully.
   1065   @retval EFI_OUT_OF_RESOURCES        Unable to allocate resources for necessary data structures.
   1066   @retval EFI_INVALID_PARAMETER       KeyData or NotifyHandle or KeyNotificationFunction is NULL.
   1067 
   1068 **/
   1069 EFI_STATUS
   1070 EFIAPI
   1071 USBKeyboardRegisterKeyNotify (
   1072   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   1073   IN  EFI_KEY_DATA                       *KeyData,
   1074   IN  EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
   1075   OUT VOID                               **NotifyHandle
   1076   )
   1077 {
   1078   USB_KB_DEV                        *UsbKeyboardDevice;
   1079   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *NewNotify;
   1080   LIST_ENTRY                        *Link;
   1081   LIST_ENTRY                        *NotifyList;
   1082   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
   1083 
   1084   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
   1085     return EFI_INVALID_PARAMETER;
   1086   }
   1087 
   1088   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
   1089 
   1090   //
   1091   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
   1092   //
   1093   NotifyList = &UsbKeyboardDevice->NotifyList;
   1094 
   1095   for (Link = GetFirstNode (NotifyList);
   1096        !IsNull (NotifyList, Link);
   1097        Link = GetNextNode (NotifyList, Link)) {
   1098     CurrentNotify = CR (
   1099                       Link,
   1100                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1101                       NotifyEntry,
   1102                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1103                       );
   1104     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
   1105       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
   1106         *NotifyHandle = CurrentNotify;
   1107         return EFI_SUCCESS;
   1108       }
   1109     }
   1110   }
   1111 
   1112   //
   1113   // Allocate resource to save the notification function
   1114   //
   1115   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
   1116   if (NewNotify == NULL) {
   1117     return EFI_OUT_OF_RESOURCES;
   1118   }
   1119 
   1120   NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
   1121   NewNotify->KeyNotificationFn = KeyNotificationFunction;
   1122   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
   1123   InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
   1124 
   1125 
   1126   *NotifyHandle = NewNotify;
   1127 
   1128   return EFI_SUCCESS;
   1129 
   1130 }
   1131 
   1132 /**
   1133   Remove a registered notification function from a particular keystroke.
   1134 
   1135   @param  This                      Protocol instance pointer.
   1136   @param  NotificationHandle        The handle of the notification function being unregistered.
   1137 
   1138   @retval EFI_SUCCESS              The notification function was unregistered successfully.
   1139   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid
   1140 
   1141 **/
   1142 EFI_STATUS
   1143 EFIAPI
   1144 USBKeyboardUnregisterKeyNotify (
   1145   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   1146   IN VOID                               *NotificationHandle
   1147   )
   1148 {
   1149   USB_KB_DEV                        *UsbKeyboardDevice;
   1150   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
   1151   LIST_ENTRY                        *Link;
   1152   LIST_ENTRY                        *NotifyList;
   1153 
   1154   if (NotificationHandle == NULL) {
   1155     return EFI_INVALID_PARAMETER;
   1156   }
   1157 
   1158   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
   1159 
   1160   //
   1161   // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
   1162   //
   1163   NotifyList = &UsbKeyboardDevice->NotifyList;
   1164   for (Link = GetFirstNode (NotifyList);
   1165        !IsNull (NotifyList, Link);
   1166        Link = GetNextNode (NotifyList, Link)) {
   1167     CurrentNotify = CR (
   1168                       Link,
   1169                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1170                       NotifyEntry,
   1171                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1172                       );
   1173     if (CurrentNotify == NotificationHandle) {
   1174       //
   1175       // Remove the notification function from NotifyList and free resources
   1176       //
   1177       RemoveEntryList (&CurrentNotify->NotifyEntry);
   1178 
   1179       FreePool (CurrentNotify);
   1180       return EFI_SUCCESS;
   1181     }
   1182   }
   1183 
   1184   //
   1185   // Cannot find the matching entry in database.
   1186   //
   1187   return EFI_INVALID_PARAMETER;
   1188 }
   1189 
   1190 /**
   1191   Process key notify.
   1192 
   1193   @param  Event                 Indicates the event that invoke this function.
   1194   @param  Context               Indicates the calling context.
   1195 **/
   1196 VOID
   1197 EFIAPI
   1198 KeyNotifyProcessHandler (
   1199   IN  EFI_EVENT                 Event,
   1200   IN  VOID                      *Context
   1201   )
   1202 {
   1203   EFI_STATUS                    Status;
   1204   USB_KB_DEV                    *UsbKeyboardDevice;
   1205   EFI_KEY_DATA                  KeyData;
   1206   LIST_ENTRY                    *Link;
   1207   LIST_ENTRY                    *NotifyList;
   1208   KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
   1209   EFI_TPL                       OldTpl;
   1210 
   1211   UsbKeyboardDevice = (USB_KB_DEV *) Context;
   1212 
   1213   //
   1214   // Invoke notification functions.
   1215   //
   1216   NotifyList = &UsbKeyboardDevice->NotifyList;
   1217   while (TRUE) {
   1218     //
   1219     // Enter critical section
   1220     //
   1221     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   1222     Status = Dequeue (&UsbKeyboardDevice->EfiKeyQueueForNotify, &KeyData, sizeof (KeyData));
   1223     //
   1224     // Leave critical section
   1225     //
   1226     gBS->RestoreTPL (OldTpl);
   1227     if (EFI_ERROR (Status)) {
   1228       break;
   1229     }
   1230     for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
   1231       CurrentNotify = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
   1232       if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
   1233         CurrentNotify->KeyNotificationFn (&KeyData);
   1234       }
   1235     }
   1236   }
   1237 }
   1238 
   1239