Home | History | Annotate | Download | only in VirtualKeyboardDxe
      1 /** @file
      2   VirtualKeyboard driver
      3 
      4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      5 Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions
      9 of the BSD License which accompanies this distribution.  The
     10 full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "VirtualKeyboard.h"
     19 
     20 //
     21 // RAM Keyboard Driver Binding Protocol Instance
     22 //
     23 EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
     24   VirtualKeyboardDriverBindingSupported,
     25   VirtualKeyboardDriverBindingStart,
     26   VirtualKeyboardDriverBindingStop,
     27   0x10,
     28   NULL,
     29   NULL
     30 };
     31 
     32 //
     33 // EFI Driver Binding Protocol Functions
     34 //
     35 
     36 /**
     37   Check whether the driver supports this device.
     38 
     39   @param  This                   The Udriver binding protocol.
     40   @param  Controller             The controller handle to check.
     41   @param  RemainingDevicePath    The remaining device path.
     42 
     43   @retval EFI_SUCCESS            The driver supports this controller.
     44   @retval other                  This device isn't supported.
     45 
     46 **/
     47 EFI_STATUS
     48 EFIAPI
     49 VirtualKeyboardDriverBindingSupported (
     50   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     51   IN EFI_HANDLE                   Controller,
     52   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
     53   )
     54 {
     55   EFI_STATUS                     Status;
     56   PLATFORM_VIRTUAL_KBD_PROTOCOL  *PlatformVirtual;
     57 
     58   Status = gBS->OpenProtocol (
     59                   Controller,
     60                   &gPlatformVirtualKeyboardProtocolGuid,
     61                   (VOID **) &PlatformVirtual,
     62                   This->DriverBindingHandle,
     63                   Controller,
     64                   EFI_OPEN_PROTOCOL_BY_DRIVER
     65                   );
     66   if (EFI_ERROR (Status)) {
     67     return Status;
     68   }
     69   gBS->CloseProtocol (
     70          Controller,
     71          &gPlatformVirtualKeyboardProtocolGuid,
     72          This->DriverBindingHandle,
     73          Controller
     74          );
     75   return Status;
     76 }
     77 
     78 /**
     79   Starts the device with this driver.
     80 
     81   @param  This                   The driver binding instance.
     82   @param  Controller             Handle of device to bind driver to.
     83   @param  RemainingDevicePath    Optional parameter use to pick a specific child
     84                                  device to start.
     85 
     86   @retval EFI_SUCCESS            The controller is controlled by the driver.
     87   @retval Other                  This controller cannot be started.
     88 
     89 **/
     90 EFI_STATUS
     91 EFIAPI
     92 VirtualKeyboardDriverBindingStart (
     93   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     94   IN EFI_HANDLE                   Controller,
     95   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
     96   )
     97 {
     98   EFI_STATUS                                Status;
     99   VIRTUAL_KEYBOARD_DEV                      *VirtualKeyboardPrivate;
    100   PLATFORM_VIRTUAL_KBD_PROTOCOL             *PlatformVirtual;
    101 
    102   Status = gBS->OpenProtocol (
    103                   Controller,
    104                   &gPlatformVirtualKeyboardProtocolGuid,
    105                   (VOID **) &PlatformVirtual,
    106                   This->DriverBindingHandle,
    107                   Controller,
    108                   EFI_OPEN_PROTOCOL_BY_DRIVER
    109                   );
    110   if (EFI_ERROR (Status)) {
    111     return Status;
    112   }
    113 
    114   //
    115   // Allocate the private device structure
    116   //
    117   VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV));
    118   if (NULL == VirtualKeyboardPrivate) {
    119     Status = EFI_OUT_OF_RESOURCES;
    120     goto Done;
    121   }
    122 
    123   //
    124   // Initialize the private device structure
    125   //
    126   VirtualKeyboardPrivate->Signature                  = VIRTUAL_KEYBOARD_DEV_SIGNATURE;
    127   VirtualKeyboardPrivate->Handle                     = Controller;
    128   VirtualKeyboardPrivate->PlatformVirtual            = PlatformVirtual;
    129   VirtualKeyboardPrivate->Queue.Front                = 0;
    130   VirtualKeyboardPrivate->Queue.Rear                 = 0;
    131   VirtualKeyboardPrivate->QueueForNotify.Front       = 0;
    132   VirtualKeyboardPrivate->QueueForNotify.Rear        = 0;
    133 
    134   VirtualKeyboardPrivate->SimpleTextIn.Reset         = VirtualKeyboardReset;
    135   VirtualKeyboardPrivate->SimpleTextIn.ReadKeyStroke = VirtualKeyboardReadKeyStroke;
    136 
    137   VirtualKeyboardPrivate->SimpleTextInputEx.Reset               = VirtualKeyboardResetEx;
    138   VirtualKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = VirtualKeyboardReadKeyStrokeEx;
    139   VirtualKeyboardPrivate->SimpleTextInputEx.SetState            = VirtualKeyboardSetState;
    140 
    141   VirtualKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify   = VirtualKeyboardRegisterKeyNotify;
    142   VirtualKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = VirtualKeyboardUnregisterKeyNotify;
    143   InitializeListHead (&VirtualKeyboardPrivate->NotifyList);
    144 
    145   Status = PlatformVirtual->Register ();
    146   if (EFI_ERROR (Status)) {
    147     goto Done;
    148   }
    149 
    150   //
    151   // Report that the keyboard is being enabled
    152   //
    153   REPORT_STATUS_CODE (
    154     EFI_PROGRESS_CODE,
    155     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
    156     );
    157 
    158   //
    159   // Setup the WaitForKey event
    160   //
    161   Status = gBS->CreateEvent (
    162                   EVT_NOTIFY_WAIT,
    163                   TPL_NOTIFY,
    164                   VirtualKeyboardWaitForKey,
    165                   &(VirtualKeyboardPrivate->SimpleTextIn),
    166                   &((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey)
    167                   );
    168   if (EFI_ERROR (Status)) {
    169     (VirtualKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
    170     goto Done;
    171   }
    172   Status = gBS->CreateEvent (
    173                   EVT_NOTIFY_WAIT,
    174                   TPL_NOTIFY,
    175                   VirtualKeyboardWaitForKeyEx,
    176                   &(VirtualKeyboardPrivate->SimpleTextInputEx),
    177                   &(VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
    178                   );
    179   if (EFI_ERROR (Status)) {
    180     VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
    181     goto Done;
    182   }
    183 
    184   //
    185   // Setup a periodic timer, used for reading keystrokes at a fixed interval
    186   //
    187   Status = gBS->CreateEvent (
    188                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    189                   TPL_NOTIFY,
    190                   VirtualKeyboardTimerHandler,
    191                   VirtualKeyboardPrivate,
    192                   &VirtualKeyboardPrivate->TimerEvent
    193                   );
    194   if (EFI_ERROR (Status)) {
    195     Status      = EFI_OUT_OF_RESOURCES;
    196     goto Done;
    197   }
    198 
    199   Status = gBS->SetTimer (
    200                   VirtualKeyboardPrivate->TimerEvent,
    201                   TimerPeriodic,
    202                   KEYBOARD_TIMER_INTERVAL
    203                   );
    204   if (EFI_ERROR (Status)) {
    205     Status      = EFI_OUT_OF_RESOURCES;
    206     goto Done;
    207   }
    208 
    209   Status = gBS->CreateEvent (
    210                   EVT_NOTIFY_SIGNAL,
    211                   TPL_CALLBACK,
    212                   KeyNotifyProcessHandler,
    213                   VirtualKeyboardPrivate,
    214                   &VirtualKeyboardPrivate->KeyNotifyProcessEvent
    215                   );
    216   if (EFI_ERROR (Status)) {
    217     Status      = EFI_OUT_OF_RESOURCES;
    218     goto Done;
    219   }
    220 
    221   //
    222   // Reset the keyboard device
    223   //
    224   Status = VirtualKeyboardPrivate->SimpleTextInputEx.Reset (
    225                                                     &VirtualKeyboardPrivate->SimpleTextInputEx,
    226                                                     FALSE
    227                                                     );
    228   if (EFI_ERROR (Status)) {
    229     DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
    230     goto Done;
    231   }
    232   //
    233   // Install protocol interfaces for the keyboard device.
    234   //
    235   Status = gBS->InstallMultipleProtocolInterfaces (
    236                   &Controller,
    237                   &gEfiSimpleTextInProtocolGuid,
    238                   &VirtualKeyboardPrivate->SimpleTextIn,
    239                   &gEfiSimpleTextInputExProtocolGuid,
    240                   &VirtualKeyboardPrivate->SimpleTextInputEx,
    241                   NULL
    242                   );
    243 
    244 Done:
    245   if (EFI_ERROR (Status)) {
    246     if (VirtualKeyboardPrivate != NULL) {
    247       if ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
    248         gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey);
    249       }
    250 
    251       if ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
    252         gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);
    253       }
    254 
    255       if (VirtualKeyboardPrivate->KeyNotifyProcessEvent != NULL) {
    256         gBS->CloseEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
    257       }
    258 
    259       VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList);
    260 
    261       if (VirtualKeyboardPrivate->TimerEvent != NULL) {
    262         gBS->CloseEvent (VirtualKeyboardPrivate->TimerEvent);
    263       }
    264       FreePool (VirtualKeyboardPrivate);
    265     }
    266   }
    267 
    268   gBS->CloseProtocol (
    269          Controller,
    270          &gPlatformVirtualKeyboardProtocolGuid,
    271          This->DriverBindingHandle,
    272          Controller
    273          );
    274 
    275   return Status;
    276 }
    277 
    278 /**
    279   Stop the device handled by this driver.
    280 
    281   @param  This                   The driver binding protocol.
    282   @param  Controller             The controller to release.
    283   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
    284   @param  ChildHandleBuffer      The array of child handle.
    285 
    286   @retval EFI_SUCCESS            The device was stopped.
    287   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
    288   @retval Others                 Fail to uninstall protocols attached on the device.
    289 
    290 **/
    291 EFI_STATUS
    292 EFIAPI
    293 VirtualKeyboardDriverBindingStop (
    294   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    295   IN  EFI_HANDLE                   Controller,
    296   IN  UINTN                        NumberOfChildren,
    297   IN  EFI_HANDLE                   *ChildHandleBuffer
    298   )
    299 {
    300   return EFI_SUCCESS;
    301 }
    302 
    303 
    304 /**
    305   Enqueue the key.
    306 
    307   @param  Queue                 The queue to be enqueued.
    308   @param  KeyData               The key data to be enqueued.
    309 
    310   @retval EFI_NOT_READY         The queue is full.
    311   @retval EFI_SUCCESS           Successfully enqueued the key data.
    312 
    313 **/
    314 EFI_STATUS
    315 Enqueue (
    316   IN SIMPLE_QUEUE         *Queue,
    317   IN EFI_KEY_DATA         *KeyData
    318   )
    319 {
    320   if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
    321     return EFI_NOT_READY;
    322   }
    323 
    324   CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
    325   Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
    326 
    327   return EFI_SUCCESS;
    328 }
    329 
    330 /**
    331   Dequeue the key.
    332 
    333   @param  Queue                 The queue to be dequeued.
    334   @param  KeyData               The key data to be dequeued.
    335 
    336   @retval EFI_NOT_READY         The queue is empty.
    337   @retval EFI_SUCCESS           Successfully dequeued the key data.
    338 
    339 **/
    340 EFI_STATUS
    341 Dequeue (
    342   IN SIMPLE_QUEUE         *Queue,
    343   IN EFI_KEY_DATA         *KeyData
    344   )
    345 {
    346   if (Queue->Front == Queue->Rear) {
    347     return EFI_NOT_READY;
    348   }
    349 
    350   CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
    351   Queue->Front  = (Queue->Front + 1) % QUEUE_MAX_COUNT;
    352 
    353   return EFI_SUCCESS;
    354 }
    355 
    356 /**
    357   Check whether the queue is empty.
    358 
    359   @param  Queue                 The queue to be checked.
    360 
    361   @retval EFI_NOT_READY         The queue is empty.
    362   @retval EFI_SUCCESS           The queue is not empty.
    363 
    364 **/
    365 EFI_STATUS
    366 CheckQueue (
    367   IN SIMPLE_QUEUE         *Queue
    368   )
    369 {
    370   if (Queue->Front == Queue->Rear) {
    371     return EFI_NOT_READY;
    372   }
    373 
    374   return EFI_SUCCESS;
    375 }
    376 
    377 /**
    378   Check key buffer to get the key stroke status.
    379 
    380   @param  This         Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
    381 
    382   @retval EFI_SUCCESS  A key is being pressed now.
    383   @retval Other        No key is now pressed.
    384 
    385 **/
    386 EFI_STATUS
    387 EFIAPI
    388 VirtualKeyboardCheckForKey (
    389   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This
    390   )
    391 {
    392   VIRTUAL_KEYBOARD_DEV     *VirtualKeyboardPrivate;
    393 
    394   VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    395 
    396   return CheckQueue (&VirtualKeyboardPrivate->Queue);
    397 }
    398 
    399 /**
    400   Free keyboard notify list.
    401 
    402   @param  ListHead   The list head
    403 
    404   @retval EFI_SUCCESS           Free the notify list successfully
    405   @retval EFI_INVALID_PARAMETER ListHead is invalid.
    406 
    407 **/
    408 EFI_STATUS
    409 VirtualKeyboardFreeNotifyList (
    410   IN OUT LIST_ENTRY           *ListHead
    411   )
    412 {
    413   VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
    414 
    415   if (ListHead == NULL) {
    416     return EFI_INVALID_PARAMETER;
    417   }
    418   while (!IsListEmpty (ListHead)) {
    419     NotifyNode = CR (
    420                    ListHead->ForwardLink,
    421                    VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
    422                    NotifyEntry,
    423                    VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    424                    );
    425     RemoveEntryList (ListHead->ForwardLink);
    426     gBS->FreePool (NotifyNode);
    427   }
    428 
    429   return EFI_SUCCESS;
    430 }
    431 
    432 /**
    433   Judge whether is a registed key
    434 
    435   @param RegsiteredData       A pointer to a buffer that is filled in with the keystroke
    436                               state data for the key that was registered.
    437   @param InputData            A pointer to a buffer that is filled in with the keystroke
    438                               state data for the key that was pressed.
    439 
    440   @retval TRUE                Key be pressed matches a registered key.
    441   @retval FLASE               Match failed.
    442 
    443 **/
    444 BOOLEAN
    445 IsKeyRegistered (
    446   IN EFI_KEY_DATA  *RegsiteredData,
    447   IN EFI_KEY_DATA  *InputData
    448   )
    449 
    450 {
    451   ASSERT (RegsiteredData != NULL && InputData != NULL);
    452 
    453   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
    454       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
    455     return FALSE;
    456   }
    457 
    458   //
    459   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
    460   //
    461   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
    462       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
    463     return FALSE;
    464   }
    465   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
    466       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
    467     return FALSE;
    468   }
    469 
    470   return TRUE;
    471 
    472 }
    473 
    474 /**
    475   Event notification function for SIMPLE_TEXT_IN.WaitForKey event
    476   Signal the event if there is key available
    477 
    478   @param Event    the event object
    479   @param Context  waitting context
    480 
    481 **/
    482 VOID
    483 EFIAPI
    484 VirtualKeyboardWaitForKey (
    485   IN  EFI_EVENT               Event,
    486   IN  VOID                    *Context
    487   )
    488 {
    489   //
    490   // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
    491   // Csm will be used to check whether there is a key pending, but the csm will disable all
    492   // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
    493   // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
    494   // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
    495   // e.g. usb keyboard driver.
    496   // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
    497   // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
    498   //
    499   gBS->Stall (1000);
    500   //
    501   // Use TimerEvent callback function to check whether there's any key pressed
    502   //
    503   VirtualKeyboardTimerHandler (NULL, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context));
    504 
    505   if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context))) {
    506     gBS->SignalEvent (Event);
    507   }
    508 }
    509 
    510 /**
    511   Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
    512   Signal the event if there is key available
    513 
    514   @param Event    event object
    515   @param Context  waiting context
    516 
    517 **/
    518 VOID
    519 EFIAPI
    520 VirtualKeyboardWaitForKeyEx (
    521   IN  EFI_EVENT               Event,
    522   IN  VOID                    *Context
    523   )
    524 
    525 {
    526   VIRTUAL_KEYBOARD_DEV                     *VirtualKeyboardPrivate;
    527 
    528   VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context);
    529   VirtualKeyboardWaitForKey (Event, &VirtualKeyboardPrivate->SimpleTextIn);
    530 
    531 }
    532 
    533 //
    534 // EFI Simple Text In Protocol Functions
    535 //
    536 /**
    537   Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
    538 
    539   @param  This                  Pointer of simple text Protocol.
    540   @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
    541 
    542   @retval EFI_SUCCESS           The command byte is written successfully.
    543   @retval EFI_DEVICE_ERROR      Errors occurred during resetting keyboard.
    544 
    545 **/
    546 EFI_STATUS
    547 EFIAPI
    548 VirtualKeyboardReset (
    549   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
    550   IN  BOOLEAN                         ExtendedVerification
    551   )
    552 {
    553   VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
    554   EFI_STATUS           Status;
    555   EFI_TPL              OldTpl;
    556 
    557   VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    558 
    559   //
    560   // Raise TPL to avoid mouse operation impact
    561   //
    562   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    563 
    564   if (VirtualKeyboardPrivate->PlatformVirtual && VirtualKeyboardPrivate->PlatformVirtual->Reset) {
    565     Status = VirtualKeyboardPrivate->PlatformVirtual->Reset ();
    566   } else {
    567     Status = EFI_INVALID_PARAMETER;
    568   }
    569 
    570   //
    571   // resume priority of task level
    572   //
    573   gBS->RestoreTPL (OldTpl);
    574 
    575   return Status;
    576 }
    577 
    578 /**
    579   Reset the input device and optionaly run diagnostics
    580 
    581   @param  This                  Protocol instance pointer.
    582   @param  ExtendedVerification  Driver may perform diagnostics on reset.
    583 
    584   @retval EFI_SUCCESS           The device was reset.
    585   @retval EFI_DEVICE_ERROR      The device is not functioning properly and could-
    586                                 not be reset.
    587 
    588 **/
    589 EFI_STATUS
    590 EFIAPI
    591 VirtualKeyboardResetEx (
    592   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    593   IN BOOLEAN                            ExtendedVerification
    594   )
    595 {
    596   VIRTUAL_KEYBOARD_DEV                     *VirtualKeyboardPrivate;
    597   EFI_STATUS                            Status;
    598   EFI_TPL                               OldTpl;
    599 
    600   VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    601 
    602   Status = VirtualKeyboardPrivate->SimpleTextIn.Reset (
    603                                                &VirtualKeyboardPrivate->SimpleTextIn,
    604                                                ExtendedVerification
    605                                                );
    606   if (EFI_ERROR (Status)) {
    607     return EFI_DEVICE_ERROR;
    608   }
    609 
    610   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    611 
    612   gBS->RestoreTPL (OldTpl);
    613 
    614   return EFI_SUCCESS;
    615 
    616 }
    617 
    618 /**
    619   Reads the next keystroke from the input device. The WaitForKey Event can
    620   be used to test for existance of a keystroke via WaitForEvent () call.
    621 
    622   @param  VirtualKeyboardPrivate   Virtualkeyboard driver private structure.
    623   @param  KeyData               A pointer to a buffer that is filled in with the keystroke
    624                                 state data for the key that was pressed.
    625 
    626   @retval EFI_SUCCESS           The keystroke information was returned.
    627   @retval EFI_NOT_READY         There was no keystroke data availiable.
    628   @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to
    629                                 hardware errors.
    630   @retval EFI_INVALID_PARAMETER KeyData is NULL.
    631 
    632 **/
    633 EFI_STATUS
    634 KeyboardReadKeyStrokeWorker (
    635   IN VIRTUAL_KEYBOARD_DEV  *VirtualKeyboardPrivate,
    636   OUT EFI_KEY_DATA      *KeyData
    637   )
    638 {
    639   EFI_STATUS                            Status;
    640   EFI_TPL                               OldTpl;
    641   if (KeyData == NULL) {
    642     return EFI_INVALID_PARAMETER;
    643   }
    644 
    645   //
    646   // Use TimerEvent callback function to check whether there's any key pressed
    647   //
    648 
    649   //
    650   // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
    651   // Csm will be used to check whether there is a key pending, but the csm will disable all
    652   // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
    653   // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
    654   // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
    655   // e.g. usb keyboard driver.
    656   // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
    657   // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
    658   //
    659   gBS->Stall (1000);
    660 
    661   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    662 
    663   VirtualKeyboardTimerHandler (NULL, VirtualKeyboardPrivate);
    664   //
    665   // If there's no key, just return
    666   //
    667   Status = CheckQueue (&VirtualKeyboardPrivate->Queue);
    668   if (EFI_ERROR (Status)) {
    669     gBS->RestoreTPL (OldTpl);
    670     return EFI_NOT_READY;
    671   }
    672 
    673   Status = Dequeue (&VirtualKeyboardPrivate->Queue, KeyData);
    674 
    675   gBS->RestoreTPL (OldTpl);
    676 
    677   return EFI_SUCCESS;
    678 }
    679 
    680 /**
    681   Read out the scan code of the key that has just been stroked.
    682 
    683   @param  This        Pointer of simple text Protocol.
    684   @param  Key         Pointer for store the key that read out.
    685 
    686   @retval EFI_SUCCESS The key is read out successfully.
    687   @retval other       The key reading failed.
    688 
    689 **/
    690 EFI_STATUS
    691 EFIAPI
    692 VirtualKeyboardReadKeyStroke (
    693   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
    694   OUT EFI_INPUT_KEY                   *Key
    695   )
    696 {
    697   VIRTUAL_KEYBOARD_DEV     *VirtualKeyboardPrivate;
    698   EFI_STATUS            Status;
    699   EFI_KEY_DATA          KeyData;
    700 
    701   VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    702 
    703   Status = KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, &KeyData);
    704   if (EFI_ERROR (Status)) {
    705     return Status;
    706   }
    707 
    708   //
    709   // Convert the Ctrl+[a-z] to Ctrl+[1-26]
    710   //
    711   if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
    712     if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
    713       KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
    714     } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
    715       KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
    716     }
    717   }
    718 
    719   CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
    720 
    721   return EFI_SUCCESS;
    722 }
    723 
    724 /**
    725   Reads the next keystroke from the input device. The WaitForKey Event can
    726   be used to test for existance of a keystroke via WaitForEvent () call.
    727 
    728   @param  This         Protocol instance pointer.
    729   @param  KeyData      A pointer to a buffer that is filled in with the keystroke
    730                        state data for the key that was pressed.
    731 
    732   @retval  EFI_SUCCESS           The keystroke information was returned.
    733   @retval  EFI_NOT_READY         There was no keystroke data availiable.
    734   @retval  EFI_DEVICE_ERROR      The keystroke information was not returned due to
    735                                  hardware errors.
    736   @retval  EFI_INVALID_PARAMETER KeyData is NULL.
    737 
    738 **/
    739 EFI_STATUS
    740 EFIAPI
    741 VirtualKeyboardReadKeyStrokeEx (
    742   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
    743   OUT EFI_KEY_DATA                      *KeyData
    744   )
    745 {
    746   VIRTUAL_KEYBOARD_DEV                     *VirtualKeyboardPrivate;
    747 
    748   if (KeyData == NULL) {
    749     return EFI_INVALID_PARAMETER;
    750   }
    751 
    752   VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    753 
    754   return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, KeyData);
    755 
    756 }
    757 
    758 /**
    759   Set certain state for the input device.
    760 
    761   @param  This              Protocol instance pointer.
    762   @param  KeyToggleState    A pointer to the EFI_KEY_TOGGLE_STATE to set the-
    763                             state for the input device.
    764 
    765   @retval EFI_SUCCESS           The device state was set successfully.
    766   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could-
    767                                 not have the setting adjusted.
    768   @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.
    769   @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
    770 
    771 **/
    772 EFI_STATUS
    773 EFIAPI
    774 VirtualKeyboardSetState (
    775   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    776   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
    777   )
    778 {
    779   if (KeyToggleState == NULL) {
    780     return EFI_INVALID_PARAMETER;
    781   }
    782 
    783   //
    784   // Thunk keyboard driver doesn't support partial keystroke.
    785   //
    786   if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||
    787       (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED
    788       ) {
    789     return EFI_UNSUPPORTED;
    790   }
    791 
    792   return EFI_SUCCESS;
    793 }
    794 
    795 /**
    796   Register a notification function for a particular keystroke for the input device.
    797 
    798   @param  This                    Protocol instance pointer.
    799   @param  KeyData                 A pointer to a buffer that is filled in with the keystroke
    800                                   information data for the key that was pressed.
    801   @param  KeyNotificationFunction Points to the function to be called when the key
    802                                   sequence is typed specified by KeyData.
    803   @param  NotifyHandle            Points to the unique handle assigned to the registered notification.
    804 
    805 
    806   @retval EFI_SUCCESS             The notification function was registered successfully.
    807   @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.
    808   @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.
    809 
    810 **/
    811 EFI_STATUS
    812 EFIAPI
    813 VirtualKeyboardRegisterKeyNotify (
    814   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    815   IN EFI_KEY_DATA                       *KeyData,
    816   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
    817   OUT VOID                              **NotifyHandle
    818   )
    819 {
    820   EFI_STATUS                            Status;
    821   VIRTUAL_KEYBOARD_DEV                     *VirtualKeyboardPrivate;
    822   EFI_TPL                               OldTpl;
    823   VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *NewNotify;
    824   LIST_ENTRY                            *Link;
    825   VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
    826 
    827   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
    828     return EFI_INVALID_PARAMETER;
    829   }
    830 
    831   VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    832 
    833   //
    834   // Enter critical section
    835   //
    836   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    837 
    838   //
    839   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
    840   //
    841   for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
    842     CurrentNotify = CR (
    843                       Link,
    844                       VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
    845                       NotifyEntry,
    846                       VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    847                       );
    848     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
    849       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
    850         *NotifyHandle = CurrentNotify;
    851         Status = EFI_SUCCESS;
    852         goto Exit;
    853       }
    854     }
    855   }
    856 
    857   //
    858   // Allocate resource to save the notification function
    859   //
    860 
    861   NewNotify = (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
    862   if (NewNotify == NULL) {
    863     Status = EFI_OUT_OF_RESOURCES;
    864     goto Exit;
    865   }
    866 
    867   NewNotify->Signature         = VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
    868   NewNotify->KeyNotificationFn = KeyNotificationFunction;
    869   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
    870   InsertTailList (&VirtualKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
    871 
    872   *NotifyHandle                = NewNotify;
    873   Status                       = EFI_SUCCESS;
    874 
    875 Exit:
    876   //
    877   // Leave critical section and return
    878   //
    879   gBS->RestoreTPL (OldTpl);
    880   return Status;
    881 
    882 }
    883 
    884 /**
    885   Remove a registered notification function from a particular keystroke.
    886 
    887   @param  This                 Protocol instance pointer.
    888   @param  NotificationHandle   The handle of the notification function being unregistered.
    889 
    890   @retval EFI_SUCCESS             The notification function was unregistered successfully.
    891   @retval EFI_INVALID_PARAMETER   The NotificationHandle is invalid.
    892 
    893 **/
    894 EFI_STATUS
    895 EFIAPI
    896 VirtualKeyboardUnregisterKeyNotify (
    897   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
    898   IN VOID                               *NotificationHandle
    899   )
    900 {
    901   EFI_STATUS                            Status;
    902   VIRTUAL_KEYBOARD_DEV                     *VirtualKeyboardPrivate;
    903   EFI_TPL                               OldTpl;
    904   LIST_ENTRY                            *Link;
    905   VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
    906 
    907   //
    908   // Check incoming notification handle
    909   //
    910   if (NotificationHandle == NULL) {
    911     return EFI_INVALID_PARAMETER;
    912   }
    913 
    914   if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
    915     return EFI_INVALID_PARAMETER;
    916   }
    917 
    918   VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
    919 
    920   //
    921   // Enter critical section
    922   //
    923   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    924 
    925   for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
    926     CurrentNotify = CR (
    927                       Link,
    928                       VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
    929                       NotifyEntry,
    930                       VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    931                       );
    932     if (CurrentNotify == NotificationHandle) {
    933       //
    934       // Remove the notification function from NotifyList and free resources
    935       //
    936       RemoveEntryList (&CurrentNotify->NotifyEntry);
    937 
    938       Status = EFI_SUCCESS;
    939       goto Exit;
    940     }
    941   }
    942 
    943   //
    944   // Can not find the specified Notification Handle
    945   //
    946   Status = EFI_INVALID_PARAMETER;
    947 
    948 Exit:
    949   //
    950   // Leave critical section and return
    951   //
    952   gBS->RestoreTPL (OldTpl);
    953   return Status;
    954 }
    955 
    956 /**
    957   Timer event handler: read a series of scancodes from 8042
    958   and put them into memory scancode buffer.
    959   it read as much scancodes to either fill
    960   the memory buffer or empty the keyboard buffer.
    961   It is registered as running under TPL_NOTIFY
    962 
    963   @param Event       The timer event
    964   @param Context     A KEYBOARD_CONSOLE_IN_DEV pointer
    965 
    966 **/
    967 VOID
    968 EFIAPI
    969 VirtualKeyboardTimerHandler (
    970   IN EFI_EVENT    Event,
    971   IN VOID         *Context
    972   )
    973 {
    974   EFI_TPL                            OldTpl;
    975   LIST_ENTRY                         *Link;
    976   EFI_KEY_DATA                       KeyData;
    977   VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY  *CurrentNotify;
    978   VIRTUAL_KEYBOARD_DEV                   *VirtualKeyboardPrivate;
    979   VIRTUAL_KBD_KEY                        VirtualKey;
    980 
    981   VirtualKeyboardPrivate = Context;
    982 
    983   //
    984   // Enter critical section
    985   //
    986   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    987 
    988   if (VirtualKeyboardPrivate->PlatformVirtual &&
    989       VirtualKeyboardPrivate->PlatformVirtual->Query) {
    990     if (VirtualKeyboardPrivate->PlatformVirtual->Query (&VirtualKey) == FALSE) {
    991       goto Exit;
    992     }
    993     // Found key
    994     KeyData.Key.ScanCode = VirtualKey.Key.ScanCode;
    995     KeyData.Key.UnicodeChar = VirtualKey.Key.UnicodeChar;
    996     KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
    997     KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
    998     if (VirtualKeyboardPrivate->PlatformVirtual->Clear) {
    999       VirtualKeyboardPrivate->PlatformVirtual->Clear (&VirtualKey);
   1000     }
   1001   } else {
   1002     goto Exit;
   1003   }
   1004 
   1005   //
   1006   // Signal KeyNotify process event if this key pressed matches any key registered.
   1007   //
   1008   for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; Link != &VirtualKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
   1009     CurrentNotify = CR (
   1010                       Link,
   1011                       VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1012                       NotifyEntry,
   1013                       VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1014                       );
   1015     if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
   1016       //
   1017       // The key notification function needs to run at TPL_CALLBACK
   1018       // while current TPL is TPL_NOTIFY. It will be invoked in
   1019       // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
   1020       //
   1021       Enqueue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData);
   1022       gBS->SignalEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
   1023     }
   1024   }
   1025 
   1026   Enqueue (&VirtualKeyboardPrivate->Queue, &KeyData);
   1027 
   1028 Exit:
   1029   //
   1030   // Leave critical section and return
   1031   //
   1032   gBS->RestoreTPL (OldTpl);
   1033 }
   1034 
   1035 /**
   1036   Process key notify.
   1037 
   1038   @param  Event                 Indicates the event that invoke this function.
   1039   @param  Context               Indicates the calling context.
   1040 **/
   1041 VOID
   1042 EFIAPI
   1043 KeyNotifyProcessHandler (
   1044   IN  EFI_EVENT                 Event,
   1045   IN  VOID                      *Context
   1046   )
   1047 {
   1048   EFI_STATUS                            Status;
   1049   VIRTUAL_KEYBOARD_DEV                     *VirtualKeyboardPrivate;
   1050   EFI_KEY_DATA                          KeyData;
   1051   LIST_ENTRY                            *Link;
   1052   LIST_ENTRY                            *NotifyList;
   1053   VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
   1054   EFI_TPL                               OldTpl;
   1055 
   1056   VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) Context;
   1057 
   1058   //
   1059   // Invoke notification functions.
   1060   //
   1061   NotifyList = &VirtualKeyboardPrivate->NotifyList;
   1062   while (TRUE) {
   1063     //
   1064     // Enter critical section
   1065     //
   1066     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   1067     Status = Dequeue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData);
   1068     //
   1069     // Leave critical section
   1070     //
   1071     gBS->RestoreTPL (OldTpl);
   1072     if (EFI_ERROR (Status)) {
   1073       break;
   1074     }
   1075     for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
   1076       CurrentNotify = CR (Link, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
   1077       if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
   1078         CurrentNotify->KeyNotificationFn (&KeyData);
   1079       }
   1080     }
   1081   }
   1082 }
   1083 
   1084 /**
   1085   The user Entry Point for module VirtualKeyboard. The user code starts with this function.
   1086 
   1087   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
   1088   @param[in] SystemTable    A pointer to the EFI System Table.
   1089 
   1090   @retval EFI_SUCCESS       The entry point is executed successfully.
   1091   @retval other             Some error occurs when executing this entry point.
   1092 
   1093 **/
   1094 EFI_STATUS
   1095 EFIAPI
   1096 InitializeVirtualKeyboard(
   1097   IN EFI_HANDLE           ImageHandle,
   1098   IN EFI_SYSTEM_TABLE     *SystemTable
   1099   )
   1100 {
   1101   EFI_STATUS              Status;
   1102 
   1103   //
   1104   // Install driver model protocol(s).
   1105   //
   1106   Status = EfiLibInstallDriverBindingComponentName2 (
   1107              ImageHandle,
   1108              SystemTable,
   1109              &gVirtualKeyboardDriverBinding,
   1110              ImageHandle,
   1111              &gVirtualKeyboardComponentName,
   1112              &gVirtualKeyboardComponentName2
   1113              );
   1114   ASSERT_EFI_ERROR (Status);
   1115 
   1116   return Status;
   1117 }
   1118