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 - 2012, 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   //
    316   // Install Simple Text Input Protocol and Simple Text Input Ex Protocol
    317   // for the USB keyboard device.
    318   // USB keyboard is a hot plug device, and expected to work immediately
    319   // when plugging into system, other conventional console devices could
    320   // distinguish it by its device path.
    321   //
    322   Status = gBS->InstallMultipleProtocolInterfaces (
    323                   &Controller,
    324                   &gEfiSimpleTextInProtocolGuid,
    325                   &UsbKeyboardDevice->SimpleInput,
    326                   &gEfiSimpleTextInputExProtocolGuid,
    327                   &UsbKeyboardDevice->SimpleInputEx,
    328                   NULL
    329                   );
    330   if (EFI_ERROR (Status)) {
    331     goto ErrorExit;
    332   }
    333 
    334   UsbKeyboardDevice->ControllerHandle = Controller;
    335   Status = InitKeyboardLayout (UsbKeyboardDevice);
    336   if (EFI_ERROR (Status)) {
    337     gBS->UninstallMultipleProtocolInterfaces (
    338       Controller,
    339       &gEfiSimpleTextInProtocolGuid,
    340       &UsbKeyboardDevice->SimpleInput,
    341       &gEfiSimpleTextInputExProtocolGuid,
    342       &UsbKeyboardDevice->SimpleInputEx,
    343       NULL
    344       );
    345     goto ErrorExit;
    346   }
    347 
    348 
    349   //
    350   // Reset USB Keyboard Device exhaustively.
    351   //
    352   Status = UsbKeyboardDevice->SimpleInputEx.Reset (
    353                                             &UsbKeyboardDevice->SimpleInputEx,
    354                                             TRUE
    355                                             );
    356   if (EFI_ERROR (Status)) {
    357     gBS->UninstallMultipleProtocolInterfaces (
    358            Controller,
    359            &gEfiSimpleTextInProtocolGuid,
    360            &UsbKeyboardDevice->SimpleInput,
    361            &gEfiSimpleTextInputExProtocolGuid,
    362            &UsbKeyboardDevice->SimpleInputEx,
    363            NULL
    364            );
    365     goto ErrorExit;
    366   }
    367 
    368   //
    369   // Submit Asynchronous Interrupt Transfer to manage this device.
    370   //
    371   EndpointAddr    = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress;
    372   PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval;
    373   PacketSize      = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize);
    374 
    375   Status = UsbIo->UsbAsyncInterruptTransfer (
    376                     UsbIo,
    377                     EndpointAddr,
    378                     TRUE,
    379                     PollingInterval,
    380                     PacketSize,
    381                     KeyboardHandler,
    382                     UsbKeyboardDevice
    383                     );
    384 
    385   if (EFI_ERROR (Status)) {
    386     gBS->UninstallMultipleProtocolInterfaces (
    387            Controller,
    388            &gEfiSimpleTextInProtocolGuid,
    389            &UsbKeyboardDevice->SimpleInput,
    390            &gEfiSimpleTextInputExProtocolGuid,
    391            &UsbKeyboardDevice->SimpleInputEx,
    392            NULL
    393            );
    394     goto ErrorExit;
    395   }
    396 
    397   UsbKeyboardDevice->ControllerNameTable = NULL;
    398   AddUnicodeString2 (
    399     "eng",
    400     gUsbKeyboardComponentName.SupportedLanguages,
    401     &UsbKeyboardDevice->ControllerNameTable,
    402     L"Generic Usb Keyboard",
    403     TRUE
    404     );
    405   AddUnicodeString2 (
    406     "en",
    407     gUsbKeyboardComponentName2.SupportedLanguages,
    408     &UsbKeyboardDevice->ControllerNameTable,
    409     L"Generic Usb Keyboard",
    410     FALSE
    411     );
    412 
    413   gBS->RestoreTPL (OldTpl);
    414   return EFI_SUCCESS;
    415 
    416 //
    417 // Error handler
    418 //
    419 ErrorExit:
    420   if (UsbKeyboardDevice != NULL) {
    421     if (UsbKeyboardDevice->TimerEvent != NULL) {
    422       gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
    423     }
    424     if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) {
    425       gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
    426     }
    427     if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) {
    428       gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
    429     }
    430     if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) {
    431       ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
    432       gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
    433     }
    434     FreePool (UsbKeyboardDevice);
    435     UsbKeyboardDevice = NULL;
    436   }
    437   gBS->CloseProtocol (
    438          Controller,
    439          &gEfiUsbIoProtocolGuid,
    440          This->DriverBindingHandle,
    441          Controller
    442          );
    443 
    444 ErrorExit1:
    445   gBS->RestoreTPL (OldTpl);
    446 
    447   return Status;
    448 
    449 }
    450 
    451 
    452 /**
    453   Stop the USB keyboard device handled by this driver.
    454 
    455   @param  This                   The USB keyboard driver binding protocol.
    456   @param  Controller             The controller to release.
    457   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
    458   @param  ChildHandleBuffer      The array of child handle.
    459 
    460   @retval EFI_SUCCESS            The device was stopped.
    461   @retval EFI_UNSUPPORTED        Simple Text In Protocol or Simple Text In Ex Protocol
    462                                  is not installed on Controller.
    463   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
    464   @retval Others                 Fail to uninstall protocols attached on the device.
    465 
    466 **/
    467 EFI_STATUS
    468 EFIAPI
    469 USBKeyboardDriverBindingStop (
    470   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    471   IN  EFI_HANDLE                     Controller,
    472   IN  UINTN                          NumberOfChildren,
    473   IN  EFI_HANDLE                     *ChildHandleBuffer
    474   )
    475 {
    476   EFI_STATUS                     Status;
    477   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleInput;
    478   USB_KB_DEV                     *UsbKeyboardDevice;
    479 
    480   Status = gBS->OpenProtocol (
    481                   Controller,
    482                   &gEfiSimpleTextInProtocolGuid,
    483                   (VOID **) &SimpleInput,
    484                   This->DriverBindingHandle,
    485                   Controller,
    486                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    487                   );
    488   if (EFI_ERROR (Status)) {
    489     return EFI_UNSUPPORTED;
    490   }
    491 
    492   Status = gBS->OpenProtocol (
    493                   Controller,
    494                   &gEfiSimpleTextInputExProtocolGuid,
    495                   NULL,
    496                   This->DriverBindingHandle,
    497                   Controller,
    498                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    499                   );
    500   if (EFI_ERROR (Status)) {
    501     return EFI_UNSUPPORTED;
    502   }
    503 
    504   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput);
    505 
    506   //
    507   // The key data input from this device will be disabled.
    508   //
    509   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    510     EFI_PROGRESS_CODE,
    511     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE),
    512     UsbKeyboardDevice->DevicePath
    513     );
    514 
    515   //
    516   // Delete the Asynchronous Interrupt Transfer from this device
    517   //
    518   UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer (
    519                               UsbKeyboardDevice->UsbIo,
    520                               UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress,
    521                               FALSE,
    522                               UsbKeyboardDevice->IntEndpointDescriptor.Interval,
    523                               0,
    524                               NULL,
    525                               NULL
    526                               );
    527 
    528   gBS->CloseProtocol (
    529          Controller,
    530          &gEfiUsbIoProtocolGuid,
    531          This->DriverBindingHandle,
    532          Controller
    533          );
    534 
    535   Status = gBS->UninstallMultipleProtocolInterfaces (
    536                   Controller,
    537                   &gEfiSimpleTextInProtocolGuid,
    538                   &UsbKeyboardDevice->SimpleInput,
    539                   &gEfiSimpleTextInputExProtocolGuid,
    540                   &UsbKeyboardDevice->SimpleInputEx,
    541                   NULL
    542                   );
    543   //
    544   // Free all resources.
    545   //
    546   gBS->CloseEvent (UsbKeyboardDevice->TimerEvent);
    547   gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer);
    548   gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent);
    549   gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey);
    550   gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx);
    551   KbdFreeNotifyList (&UsbKeyboardDevice->NotifyList);
    552 
    553   ReleaseKeyboardLayoutResources (UsbKeyboardDevice);
    554   gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent);
    555 
    556   if (UsbKeyboardDevice->ControllerNameTable != NULL) {
    557     FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable);
    558   }
    559 
    560   DestroyQueue (&UsbKeyboardDevice->UsbKeyQueue);
    561   DestroyQueue (&UsbKeyboardDevice->EfiKeyQueue);
    562 
    563   FreePool (UsbKeyboardDevice);
    564 
    565   return Status;
    566 }
    567 
    568 /**
    569   Internal function to read the next keystroke from the keyboard buffer.
    570 
    571   @param  UsbKeyboardDevice       USB keyboard's private structure.
    572   @param  KeyData                 A pointer to buffer to hold the keystroke
    573                                   data for the key that was pressed.
    574 
    575   @retval EFI_SUCCESS             The keystroke information was returned.
    576   @retval EFI_NOT_READY           There was no keystroke data availiable.
    577   @retval EFI_DEVICE_ERROR        The keystroke information was not returned due to
    578                                   hardware errors.
    579   @retval EFI_INVALID_PARAMETER   KeyData is NULL.
    580   @retval Others                  Fail to translate keycode into EFI_INPUT_KEY
    581 
    582 **/
    583 EFI_STATUS
    584 USBKeyboardReadKeyStrokeWorker (
    585   IN OUT USB_KB_DEV                 *UsbKeyboardDevice,
    586      OUT EFI_KEY_DATA               *KeyData
    587   )
    588 {
    589   if (KeyData == NULL) {
    590     return EFI_INVALID_PARAMETER;
    591   }
    592 
    593   if (IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
    594     return EFI_NOT_READY;
    595   }
    596 
    597   Dequeue (&UsbKeyboardDevice->EfiKeyQueue, KeyData, sizeof (*KeyData));
    598 
    599   return EFI_SUCCESS;
    600 }
    601 
    602 /**
    603   Reset the input device and optionally run diagnostics
    604 
    605   There are 2 types of reset for USB keyboard.
    606   For non-exhaustive reset, only keyboard buffer is cleared.
    607   For exhaustive reset, in addition to clearance of keyboard buffer, the hardware status
    608   is also re-initialized.
    609 
    610   @param  This                 Protocol instance pointer.
    611   @param  ExtendedVerification Driver may perform diagnostics on reset.
    612 
    613   @retval EFI_SUCCESS          The device was reset.
    614   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could not be reset.
    615 
    616 **/
    617 EFI_STATUS
    618 EFIAPI
    619 USBKeyboardReset (
    620   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
    621   IN  BOOLEAN                          ExtendedVerification
    622   )
    623 {
    624   EFI_STATUS          Status;
    625   USB_KB_DEV          *UsbKeyboardDevice;
    626 
    627   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
    628 
    629   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    630     EFI_PROGRESS_CODE,
    631     (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET),
    632     UsbKeyboardDevice->DevicePath
    633     );
    634 
    635   //
    636   // Non-exhaustive reset:
    637   // only reset private data structures.
    638   //
    639   if (!ExtendedVerification) {
    640     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    641       EFI_PROGRESS_CODE,
    642       (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER),
    643       UsbKeyboardDevice->DevicePath
    644       );
    645     //
    646     // Clear the key buffer of this USB keyboard
    647     //
    648     InitQueue (&UsbKeyboardDevice->UsbKeyQueue, sizeof (USB_KEY));
    649     InitQueue (&UsbKeyboardDevice->EfiKeyQueue, sizeof (EFI_KEY_DATA));
    650 
    651     return EFI_SUCCESS;
    652   }
    653 
    654   //
    655   // Exhaustive reset
    656   //
    657   Status = InitUSBKeyboard (UsbKeyboardDevice);
    658   if (EFI_ERROR (Status)) {
    659     return EFI_DEVICE_ERROR;
    660   }
    661 
    662   return EFI_SUCCESS;
    663 }
    664 
    665 
    666 /**
    667   Reads the next keystroke from the input device.
    668 
    669   @param  This                 The EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
    670   @param  Key                  A pointer to a buffer that is filled in with the keystroke
    671                                information for the key that was pressed.
    672 
    673   @retval EFI_SUCCESS          The keystroke information was returned.
    674   @retval EFI_NOT_READY        There was no keystroke data availiable.
    675   @retval EFI_DEVICE_ERROR     The keystroke information was not returned due to
    676                                hardware errors.
    677 
    678 **/
    679 EFI_STATUS
    680 EFIAPI
    681 USBKeyboardReadKeyStroke (
    682   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL   *This,
    683   OUT EFI_INPUT_KEY                    *Key
    684   )
    685 {
    686   USB_KB_DEV   *UsbKeyboardDevice;
    687   EFI_STATUS   Status;
    688   EFI_KEY_DATA KeyData;
    689 
    690   UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This);
    691 
    692   //
    693   // Considering if the partial keystroke is enabled, there maybe a partial
    694   // keystroke in the queue, so here skip the partial keystroke and get the
    695   // next key from the queue
    696   //
    697   while (1) {
    698     Status = USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, &KeyData);
    699     if (EFI_ERROR (Status)) {
    700       return Status;
    701     }
    702     //
    703     // SimpleTextIn Protocol doesn't support partial keystroke;
    704     //
    705     if (KeyData.Key.ScanCode == CHAR_NULL && KeyData.Key.UnicodeChar == SCAN_NULL) {
    706       continue;
    707     }
    708     //
    709     // Translate the CTRL-Alpha characters to their corresponding control value
    710     // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
    711     //
    712     if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
    713       if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
    714         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
    715       } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
    716         KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
    717       }
    718     }
    719 
    720     CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
    721     return EFI_SUCCESS;
    722   }
    723 }
    724 
    725 
    726 /**
    727   Event notification function registered for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
    728   and EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey.
    729 
    730   @param  Event        Event to be signaled when a key is pressed.
    731   @param  Context      Points to USB_KB_DEV instance.
    732 
    733 **/
    734 VOID
    735 EFIAPI
    736 USBKeyboardWaitForKey (
    737   IN  EFI_EVENT               Event,
    738   IN  VOID                    *Context
    739   )
    740 {
    741   USB_KB_DEV  *UsbKeyboardDevice;
    742   EFI_KEY_DATA KeyData;
    743   EFI_TPL      OldTpl;
    744 
    745   UsbKeyboardDevice = (USB_KB_DEV *) Context;
    746 
    747   //
    748   // Enter critical section
    749   //
    750   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    751 
    752   //
    753   // WaitforKey doesn't suppor the partial key.
    754   // Considering if the partial keystroke is enabled, there maybe a partial
    755   // keystroke in the queue, so here skip the partial keystroke and get the
    756   // next key from the queue
    757   //
    758   while (!IsQueueEmpty (&UsbKeyboardDevice->EfiKeyQueue)) {
    759     //
    760     // If there is pending key, signal the event.
    761     //
    762     CopyMem (
    763       &KeyData,
    764       UsbKeyboardDevice->EfiKeyQueue.Buffer[UsbKeyboardDevice->EfiKeyQueue.Head],
    765       sizeof (EFI_KEY_DATA)
    766       );
    767     if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
    768       Dequeue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (EFI_KEY_DATA));
    769       continue;
    770     }
    771     gBS->SignalEvent (Event);
    772     break;
    773   }
    774   //
    775   // Leave critical section and return
    776   //
    777   gBS->RestoreTPL (OldTpl);
    778 }
    779 
    780 /**
    781   Timer handler to convert the key from USB.
    782 
    783   @param  Event                    Indicates the event that invoke this function.
    784   @param  Context                  Indicates the calling context.
    785 **/
    786 VOID
    787 EFIAPI
    788 USBKeyboardTimerHandler (
    789   IN  EFI_EVENT                 Event,
    790   IN  VOID                      *Context
    791   )
    792 {
    793   EFI_STATUS                    Status;
    794   USB_KB_DEV                    *UsbKeyboardDevice;
    795   UINT8                         KeyCode;
    796   EFI_KEY_DATA                  KeyData;
    797 
    798   UsbKeyboardDevice = (USB_KB_DEV *) Context;
    799 
    800   //
    801   // Fetch raw data from the USB keyboard buffer,
    802   // and translate it into USB keycode.
    803   //
    804   Status = USBParseKey (UsbKeyboardDevice, &KeyCode);
    805   if (EFI_ERROR (Status)) {
    806     return ;
    807   }
    808 
    809   //
    810   // Translate saved USB keycode into EFI_INPUT_KEY
    811   //
    812   Status = UsbKeyCodeToEfiInputKey (UsbKeyboardDevice, KeyCode, &KeyData);
    813   if (EFI_ERROR (Status)) {
    814     return ;
    815   }
    816 
    817   //
    818   // Insert to the EFI Key queue
    819   //
    820   Enqueue (&UsbKeyboardDevice->EfiKeyQueue, &KeyData, sizeof (KeyData));
    821 }
    822 
    823 /**
    824   Free keyboard notify list.
    825 
    826   @param  NotifyList              The keyboard notify list to free.
    827 
    828   @retval EFI_SUCCESS             Free the notify list successfully.
    829   @retval EFI_INVALID_PARAMETER   NotifyList is NULL.
    830 
    831 **/
    832 EFI_STATUS
    833 KbdFreeNotifyList (
    834   IN OUT LIST_ENTRY           *NotifyList
    835   )
    836 {
    837   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
    838   LIST_ENTRY                    *Link;
    839 
    840   if (NotifyList == NULL) {
    841     return EFI_INVALID_PARAMETER;
    842   }
    843   while (!IsListEmpty (NotifyList)) {
    844     Link = GetFirstNode (NotifyList);
    845     NotifyNode = CR (Link, KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
    846     RemoveEntryList (Link);
    847     FreePool (NotifyNode);
    848   }
    849 
    850   return EFI_SUCCESS;
    851 }
    852 
    853 /**
    854   Check whether the pressed key matches a registered key or not.
    855 
    856   @param  RegsiteredData    A pointer to keystroke data for the key that was registered.
    857   @param  InputData         A pointer to keystroke data for the key that was pressed.
    858 
    859   @retval TRUE              Key pressed matches a registered key.
    860   @retval FLASE             Key pressed does not matches a registered key.
    861 
    862 **/
    863 BOOLEAN
    864 IsKeyRegistered (
    865   IN EFI_KEY_DATA  *RegsiteredData,
    866   IN EFI_KEY_DATA  *InputData
    867   )
    868 {
    869   ASSERT (RegsiteredData != NULL && InputData != NULL);
    870 
    871   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
    872       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
    873     return FALSE;
    874   }
    875 
    876   //
    877   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
    878   //
    879   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
    880       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
    881     return FALSE;
    882   }
    883   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
    884       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
    885     return FALSE;
    886   }
    887 
    888   return TRUE;
    889 }
    890 
    891 //
    892 // Simple Text Input Ex protocol functions
    893 //
    894 /**
    895   Resets the input device hardware.
    896 
    897   The Reset() function resets the input device hardware. As part
    898   of initialization process, the firmware/device will make a quick
    899   but reasonable attempt to verify that the device is functioning.
    900   If the ExtendedVerification flag is TRUE the firmware may take
    901   an extended amount of time to verify the device is operating on
    902   reset. Otherwise the reset operation is to occur as quickly as
    903   possible. The hardware verification process is not defined by
    904   this specification and is left up to the platform firmware or
    905   driver to implement.
    906 
    907   @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
    908 
    909   @param ExtendedVerification Indicates that the driver may perform a more exhaustive
    910                               verification operation of the device during reset.
    911 
    912   @retval EFI_SUCCESS         The device was reset.
    913   @retval EFI_DEVICE_ERROR    The device is not functioning correctly and could not be reset.
    914 
    915 **/
    916 EFI_STATUS
    917 EFIAPI
    918 USBKeyboardResetEx (
    919   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    920   IN BOOLEAN                            ExtendedVerification
    921   )
    922 {
    923   EFI_STATUS                Status;
    924   USB_KB_DEV                *UsbKeyboardDevice;
    925 
    926   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
    927 
    928   Status = UsbKeyboardDevice->SimpleInput.Reset (&UsbKeyboardDevice->SimpleInput, ExtendedVerification);
    929   if (EFI_ERROR (Status)) {
    930     return EFI_DEVICE_ERROR;
    931   }
    932 
    933   UsbKeyboardDevice->KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
    934   UsbKeyboardDevice->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
    935 
    936   return EFI_SUCCESS;
    937 
    938 }
    939 
    940 /**
    941   Reads the next keystroke from the input device.
    942 
    943   @param  This                   Protocol instance pointer.
    944   @param  KeyData                A pointer to a buffer that is filled in with the keystroke
    945                                  state data for the key that was pressed.
    946 
    947   @retval EFI_SUCCESS            The keystroke information was returned.
    948   @retval EFI_NOT_READY          There was no keystroke data available.
    949   @retval EFI_DEVICE_ERROR       The keystroke information was not returned due to
    950                                  hardware errors.
    951   @retval EFI_INVALID_PARAMETER  KeyData is NULL.
    952 
    953 **/
    954 EFI_STATUS
    955 EFIAPI
    956 USBKeyboardReadKeyStrokeEx (
    957   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
    958   OUT EFI_KEY_DATA                      *KeyData
    959   )
    960 {
    961   USB_KB_DEV                        *UsbKeyboardDevice;
    962 
    963   if (KeyData == NULL) {
    964     return EFI_INVALID_PARAMETER;
    965   }
    966 
    967   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
    968 
    969   return USBKeyboardReadKeyStrokeWorker (UsbKeyboardDevice, KeyData);
    970 
    971 }
    972 
    973 /**
    974   Set certain state for the input device.
    975 
    976   @param  This                    Protocol instance pointer.
    977   @param  KeyToggleState          A pointer to the EFI_KEY_TOGGLE_STATE to set the
    978                                   state for the input device.
    979 
    980   @retval EFI_SUCCESS             The device state was set appropriately.
    981   @retval EFI_DEVICE_ERROR        The device is not functioning correctly and could
    982                                   not have the setting adjusted.
    983   @retval EFI_UNSUPPORTED         The device does not support the ability to have its state set.
    984   @retval EFI_INVALID_PARAMETER   KeyToggleState is NULL.
    985 
    986 **/
    987 EFI_STATUS
    988 EFIAPI
    989 USBKeyboardSetState (
    990   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    991   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
    992   )
    993 {
    994   USB_KB_DEV                        *UsbKeyboardDevice;
    995 
    996   if (KeyToggleState == NULL) {
    997     return EFI_INVALID_PARAMETER;
    998   }
    999 
   1000   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
   1001 
   1002   if (((UsbKeyboardDevice->KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) ||
   1003       ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID)) {
   1004     return EFI_UNSUPPORTED;
   1005   }
   1006 
   1007   //
   1008   // Update the status light
   1009   //
   1010 
   1011   UsbKeyboardDevice->ScrollOn   = FALSE;
   1012   UsbKeyboardDevice->NumLockOn  = FALSE;
   1013   UsbKeyboardDevice->CapsOn     = FALSE;
   1014   UsbKeyboardDevice->IsSupportPartialKey = FALSE;
   1015 
   1016   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
   1017     UsbKeyboardDevice->ScrollOn = TRUE;
   1018   }
   1019   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
   1020     UsbKeyboardDevice->NumLockOn = TRUE;
   1021   }
   1022   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
   1023     UsbKeyboardDevice->CapsOn = TRUE;
   1024   }
   1025   if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
   1026     UsbKeyboardDevice->IsSupportPartialKey = TRUE;
   1027   }
   1028 
   1029   SetKeyLED (UsbKeyboardDevice);
   1030 
   1031   UsbKeyboardDevice->KeyState.KeyToggleState = *KeyToggleState;
   1032 
   1033   return EFI_SUCCESS;
   1034 
   1035 }
   1036 
   1037 /**
   1038   Register a notification function for a particular keystroke for the input device.
   1039 
   1040   @param  This                        Protocol instance pointer.
   1041   @param  KeyData                     A pointer to a buffer that is filled in with the keystroke
   1042                                       information data for the key that was pressed.
   1043   @param  KeyNotificationFunction     Points to the function to be called when the key
   1044                                       sequence is typed specified by KeyData.
   1045   @param  NotifyHandle                Points to the unique handle assigned to the registered notification.
   1046 
   1047   @retval EFI_SUCCESS                 The notification function was registered successfully.
   1048   @retval EFI_OUT_OF_RESOURCES        Unable to allocate resources for necessary data structures.
   1049   @retval EFI_INVALID_PARAMETER       KeyData or NotifyHandle or KeyNotificationFunction is NULL.
   1050 
   1051 **/
   1052 EFI_STATUS
   1053 EFIAPI
   1054 USBKeyboardRegisterKeyNotify (
   1055   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   1056   IN  EFI_KEY_DATA                       *KeyData,
   1057   IN  EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
   1058   OUT VOID                               **NotifyHandle
   1059   )
   1060 {
   1061   USB_KB_DEV                        *UsbKeyboardDevice;
   1062   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *NewNotify;
   1063   LIST_ENTRY                        *Link;
   1064   LIST_ENTRY                        *NotifyList;
   1065   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
   1066 
   1067   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
   1068     return EFI_INVALID_PARAMETER;
   1069   }
   1070 
   1071   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
   1072 
   1073   //
   1074   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
   1075   //
   1076   NotifyList = &UsbKeyboardDevice->NotifyList;
   1077 
   1078   for (Link = GetFirstNode (NotifyList);
   1079        !IsNull (NotifyList, Link);
   1080        Link = GetNextNode (NotifyList, Link)) {
   1081     CurrentNotify = CR (
   1082                       Link,
   1083                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1084                       NotifyEntry,
   1085                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1086                       );
   1087     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
   1088       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
   1089         *NotifyHandle = CurrentNotify;
   1090         return EFI_SUCCESS;
   1091       }
   1092     }
   1093   }
   1094 
   1095   //
   1096   // Allocate resource to save the notification function
   1097   //
   1098   NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
   1099   if (NewNotify == NULL) {
   1100     return EFI_OUT_OF_RESOURCES;
   1101   }
   1102 
   1103   NewNotify->Signature         = USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
   1104   NewNotify->KeyNotificationFn = KeyNotificationFunction;
   1105   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
   1106   InsertTailList (&UsbKeyboardDevice->NotifyList, &NewNotify->NotifyEntry);
   1107 
   1108 
   1109   *NotifyHandle = NewNotify;
   1110 
   1111   return EFI_SUCCESS;
   1112 
   1113 }
   1114 
   1115 /**
   1116   Remove a registered notification function from a particular keystroke.
   1117 
   1118   @param  This                      Protocol instance pointer.
   1119   @param  NotificationHandle        The handle of the notification function being unregistered.
   1120 
   1121   @retval EFI_SUCCESS              The notification function was unregistered successfully.
   1122   @retval EFI_INVALID_PARAMETER    The NotificationHandle is invalid
   1123 
   1124 **/
   1125 EFI_STATUS
   1126 EFIAPI
   1127 USBKeyboardUnregisterKeyNotify (
   1128   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   1129   IN VOID                               *NotificationHandle
   1130   )
   1131 {
   1132   USB_KB_DEV                        *UsbKeyboardDevice;
   1133   KEYBOARD_CONSOLE_IN_EX_NOTIFY     *CurrentNotify;
   1134   LIST_ENTRY                        *Link;
   1135   LIST_ENTRY                        *NotifyList;
   1136 
   1137   if (NotificationHandle == NULL) {
   1138     return EFI_INVALID_PARAMETER;
   1139   }
   1140 
   1141   UsbKeyboardDevice = TEXT_INPUT_EX_USB_KB_DEV_FROM_THIS (This);
   1142 
   1143   //
   1144   // Traverse notify list of USB keyboard and remove the entry of NotificationHandle.
   1145   //
   1146   NotifyList = &UsbKeyboardDevice->NotifyList;
   1147   for (Link = GetFirstNode (NotifyList);
   1148        !IsNull (NotifyList, Link);
   1149        Link = GetNextNode (NotifyList, Link)) {
   1150     CurrentNotify = CR (
   1151                       Link,
   1152                       KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1153                       NotifyEntry,
   1154                       USB_KB_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1155                       );
   1156     if (CurrentNotify == NotificationHandle) {
   1157       //
   1158       // Remove the notification function from NotifyList and free resources
   1159       //
   1160       RemoveEntryList (&CurrentNotify->NotifyEntry);
   1161 
   1162       FreePool (CurrentNotify);
   1163       return EFI_SUCCESS;
   1164     }
   1165   }
   1166 
   1167   //
   1168   // Cannot find the matching entry in database.
   1169   //
   1170   return EFI_INVALID_PARAMETER;
   1171 }
   1172 
   1173