Home | History | Annotate | Download | only in KeyboardDxe
      1 /** @file
      2   ConsoleOut Routines that speak VGA.
      3 
      4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions
      8 of the BSD License which accompanies this distribution.  The
      9 full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "BiosKeyboard.h"
     18 
     19 //
     20 // EFI Driver Binding Protocol Instance
     21 //
     22 EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {
     23   BiosKeyboardDriverBindingSupported,
     24   BiosKeyboardDriverBindingStart,
     25   BiosKeyboardDriverBindingStop,
     26   0x3,
     27   NULL,
     28   NULL
     29 };
     30 
     31 
     32 /**
     33   Enqueue the key.
     34 
     35   @param  Queue                 The queue to be enqueued.
     36   @param  KeyData               The key data to be enqueued.
     37 
     38   @retval EFI_NOT_READY         The queue is full.
     39   @retval EFI_SUCCESS           Successfully enqueued the key data.
     40 
     41 **/
     42 EFI_STATUS
     43 Enqueue (
     44   IN SIMPLE_QUEUE         *Queue,
     45   IN EFI_KEY_DATA         *KeyData
     46   )
     47 {
     48   if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
     49     return EFI_NOT_READY;
     50   }
     51 
     52   CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
     53   Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
     54 
     55   return EFI_SUCCESS;
     56 }
     57 
     58 
     59 /**
     60   Dequeue the key.
     61 
     62   @param  Queue                 The queue to be dequeued.
     63   @param  KeyData               The key data to be dequeued.
     64 
     65   @retval EFI_NOT_READY         The queue is empty.
     66   @retval EFI_SUCCESS           Successfully dequeued the key data.
     67 
     68 **/
     69 EFI_STATUS
     70 Dequeue (
     71   IN SIMPLE_QUEUE         *Queue,
     72   IN EFI_KEY_DATA         *KeyData
     73   )
     74 {
     75   if (Queue->Front == Queue->Rear) {
     76     return EFI_NOT_READY;
     77   }
     78 
     79   CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
     80   Queue->Front  = (Queue->Front + 1) % QUEUE_MAX_COUNT;
     81 
     82   return EFI_SUCCESS;
     83 }
     84 
     85 
     86 /**
     87   Check whether the queue is empty.
     88 
     89   @param  Queue                 The queue to be checked.
     90 
     91   @retval EFI_NOT_READY         The queue is empty.
     92   @retval EFI_SUCCESS           The queue is not empty.
     93 
     94 **/
     95 EFI_STATUS
     96 CheckQueue (
     97   IN SIMPLE_QUEUE         *Queue
     98   )
     99 {
    100   if (Queue->Front == Queue->Rear) {
    101     return EFI_NOT_READY;
    102   }
    103 
    104   return EFI_SUCCESS;
    105 }
    106 
    107 //
    108 // EFI Driver Binding Protocol Functions
    109 //
    110 
    111 /**
    112   Check whether the driver supports this device.
    113 
    114   @param  This                   The Udriver binding protocol.
    115   @param  Controller             The controller handle to check.
    116   @param  RemainingDevicePath    The remaining device path.
    117 
    118   @retval EFI_SUCCESS            The driver supports this controller.
    119   @retval other                  This device isn't supported.
    120 
    121 **/
    122 EFI_STATUS
    123 EFIAPI
    124 BiosKeyboardDriverBindingSupported (
    125   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    126   IN EFI_HANDLE                   Controller,
    127   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    128   )
    129 {
    130   EFI_STATUS                                Status;
    131   EFI_LEGACY_BIOS_PROTOCOL                  *LegacyBios;
    132   EFI_ISA_IO_PROTOCOL                       *IsaIo;
    133 
    134   //
    135   // See if the Legacy BIOS Protocol is available
    136   //
    137   Status = gBS->LocateProtocol (
    138                   &gEfiLegacyBiosProtocolGuid,
    139                   NULL,
    140                   (VOID **) &LegacyBios
    141                   );
    142 
    143   if (EFI_ERROR (Status)) {
    144     return Status;
    145   }
    146   //
    147   // Open the IO Abstraction(s) needed to perform the supported test
    148   //
    149   Status = gBS->OpenProtocol (
    150                   Controller,
    151                   &gEfiIsaIoProtocolGuid,
    152                   (VOID **) &IsaIo,
    153                   This->DriverBindingHandle,
    154                   Controller,
    155                   EFI_OPEN_PROTOCOL_BY_DRIVER
    156                   );
    157 
    158   if (EFI_ERROR (Status)) {
    159     return Status;
    160   }
    161   //
    162   // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
    163   //
    164   if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
    165     Status = EFI_UNSUPPORTED;
    166   }
    167 
    168   gBS->CloseProtocol (
    169          Controller,
    170          &gEfiIsaIoProtocolGuid,
    171          This->DriverBindingHandle,
    172          Controller
    173          );
    174 
    175   return Status;
    176 }
    177 
    178 /**
    179   Starts the device with this driver.
    180 
    181   @param  This                   The driver binding instance.
    182   @param  Controller             Handle of device to bind driver to.
    183   @param  RemainingDevicePath    Optional parameter use to pick a specific child
    184                                  device to start.
    185 
    186   @retval EFI_SUCCESS            The controller is controlled by the driver.
    187   @retval Other                  This controller cannot be started.
    188 
    189 **/
    190 EFI_STATUS
    191 EFIAPI
    192 BiosKeyboardDriverBindingStart (
    193   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    194   IN EFI_HANDLE                   Controller,
    195   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    196   )
    197 {
    198   EFI_STATUS                                Status;
    199   EFI_LEGACY_BIOS_PROTOCOL                  *LegacyBios;
    200   EFI_ISA_IO_PROTOCOL                       *IsaIo;
    201   BIOS_KEYBOARD_DEV                         *BiosKeyboardPrivate;
    202   EFI_IA32_REGISTER_SET                     Regs;
    203   BOOLEAN                                   CarryFlag;
    204   EFI_PS2_POLICY_PROTOCOL                   *Ps2Policy;
    205   UINT8                                     Command;
    206   EFI_STATUS_CODE_VALUE                     StatusCode;
    207 
    208   BiosKeyboardPrivate = NULL;
    209   IsaIo = NULL;
    210   StatusCode          = 0;
    211 
    212   //
    213   // Get Ps2 policy to set. Will be use if present.
    214   //
    215   gBS->LocateProtocol (
    216         &gEfiPs2PolicyProtocolGuid,
    217         NULL,
    218         (VOID **) &Ps2Policy
    219         );
    220 
    221   //
    222   // See if the Legacy BIOS Protocol is available
    223   //
    224   Status = gBS->LocateProtocol (
    225                   &gEfiLegacyBiosProtocolGuid,
    226                   NULL,
    227                   (VOID **) &LegacyBios
    228                   );
    229 
    230   if (EFI_ERROR (Status)) {
    231     return Status;
    232   }
    233   //
    234   // Open the IO Abstraction(s) needed
    235   //
    236   Status = gBS->OpenProtocol (
    237                   Controller,
    238                   &gEfiIsaIoProtocolGuid,
    239                   (VOID **) &IsaIo,
    240                   This->DriverBindingHandle,
    241                   Controller,
    242                   EFI_OPEN_PROTOCOL_BY_DRIVER
    243                   );
    244   if (EFI_ERROR (Status)) {
    245     return Status;
    246   }
    247 
    248   //
    249   // Allocate the private device structure
    250   //
    251     BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));
    252   if (NULL == BiosKeyboardPrivate) {
    253     Status = EFI_OUT_OF_RESOURCES;
    254     goto Done;
    255   }
    256 
    257   //
    258   // Initialize the private device structure
    259   //
    260   BiosKeyboardPrivate->Signature                  = BIOS_KEYBOARD_DEV_SIGNATURE;
    261   BiosKeyboardPrivate->Handle                     = Controller;
    262   BiosKeyboardPrivate->LegacyBios                 = LegacyBios;
    263   BiosKeyboardPrivate->IsaIo                      = IsaIo;
    264 
    265   BiosKeyboardPrivate->SimpleTextIn.Reset         = BiosKeyboardReset;
    266   BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;
    267 
    268   BiosKeyboardPrivate->DataRegisterAddress        = KEYBOARD_8042_DATA_REGISTER;
    269   BiosKeyboardPrivate->StatusRegisterAddress      = KEYBOARD_8042_STATUS_REGISTER;
    270   BiosKeyboardPrivate->CommandRegisterAddress     = KEYBOARD_8042_COMMAND_REGISTER;
    271   BiosKeyboardPrivate->ExtendedKeyboard           = TRUE;
    272 
    273   BiosKeyboardPrivate->Queue.Front                = 0;
    274   BiosKeyboardPrivate->Queue.Rear                 = 0;
    275   BiosKeyboardPrivate->SimpleTextInputEx.Reset               = BiosKeyboardResetEx;
    276   BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = BiosKeyboardReadKeyStrokeEx;
    277   BiosKeyboardPrivate->SimpleTextInputEx.SetState            = BiosKeyboardSetState;
    278   BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify   = BiosKeyboardRegisterKeyNotify;
    279   BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;
    280   InitializeListHead (&BiosKeyboardPrivate->NotifyList);
    281 
    282   //
    283   // Report that the keyboard is being enabled
    284   //
    285   REPORT_STATUS_CODE (
    286     EFI_PROGRESS_CODE,
    287     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
    288     );
    289 
    290   //
    291   // Setup the WaitForKey event
    292   //
    293   Status = gBS->CreateEvent (
    294                   EVT_NOTIFY_WAIT,
    295                   TPL_NOTIFY,
    296                   BiosKeyboardWaitForKey,
    297                   &(BiosKeyboardPrivate->SimpleTextIn),
    298                   &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)
    299                   );
    300   if (EFI_ERROR (Status)) {
    301     (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
    302     goto Done;
    303   }
    304   Status = gBS->CreateEvent (
    305                   EVT_NOTIFY_WAIT,
    306                   TPL_NOTIFY,
    307                   BiosKeyboardWaitForKeyEx,
    308                   &(BiosKeyboardPrivate->SimpleTextInputEx),
    309                   &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
    310                   );
    311   if (EFI_ERROR (Status)) {
    312     BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
    313     goto Done;
    314   }
    315 
    316   //
    317   // Setup a periodic timer, used for reading keystrokes at a fixed interval
    318   //
    319   Status = gBS->CreateEvent (
    320                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    321                   TPL_NOTIFY,
    322                   BiosKeyboardTimerHandler,
    323                   BiosKeyboardPrivate,
    324                   &BiosKeyboardPrivate->TimerEvent
    325                   );
    326   if (EFI_ERROR (Status)) {
    327     Status      = EFI_OUT_OF_RESOURCES;
    328     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    329     goto Done;
    330   }
    331 
    332   Status = gBS->SetTimer (
    333                   BiosKeyboardPrivate->TimerEvent,
    334                   TimerPeriodic,
    335                   KEYBOARD_TIMER_INTERVAL
    336                   );
    337   if (EFI_ERROR (Status)) {
    338     Status      = EFI_OUT_OF_RESOURCES;
    339     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    340     goto Done;
    341   }
    342 
    343   //
    344   // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
    345   //
    346   REPORT_STATUS_CODE (
    347     EFI_PROGRESS_CODE,
    348     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT
    349     );
    350 
    351   //
    352   // Reset the keyboard device
    353   //
    354   Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (
    355                                                     &BiosKeyboardPrivate->SimpleTextInputEx,
    356                                                     FeaturePcdGet (PcdPs2KbdExtendedVerification)
    357                                                     );
    358   if (EFI_ERROR (Status)) {
    359     DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
    360     StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
    361     goto Done;
    362   }
    363   //
    364   // Do platform specific policy like port swapping and keyboard light default
    365   //
    366   if (Ps2Policy != NULL) {
    367 
    368     Ps2Policy->Ps2InitHardware (Controller);
    369 
    370     Command = 0;
    371     if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
    372       Command |= 4;
    373     }
    374 
    375     if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
    376       Command |= 2;
    377     }
    378 
    379     if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
    380       Command |= 1;
    381     }
    382 
    383     KeyboardWrite (BiosKeyboardPrivate, 0xed);
    384     KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
    385     KeyboardWrite (BiosKeyboardPrivate, Command);
    386     //
    387     // Call Legacy BIOS Protocol to set whatever is necessary
    388     //
    389     LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
    390   }
    391   //
    392   // Get Configuration
    393   //
    394   Regs.H.AH = 0xc0;
    395   CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
    396                                                  BiosKeyboardPrivate->LegacyBios,
    397                                                  0x15,
    398                                                  &Regs
    399                                                  );
    400 
    401   if (!CarryFlag) {
    402     //
    403     // Check bit 6 of Feature Byte 2.
    404     // If it is set, then Int 16 Func 09 is supported
    405     //
    406     if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {
    407       //
    408       // Get Keyboard Functionality
    409       //
    410       Regs.H.AH = 0x09;
    411       CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
    412                                                      BiosKeyboardPrivate->LegacyBios,
    413                                                      0x16,
    414                                                      &Regs
    415                                                      );
    416 
    417       if (!CarryFlag) {
    418         //
    419         // Check bit 5 of AH.
    420         // If it is set, then INT 16 Finc 10-12 are supported.
    421         //
    422         if ((Regs.H.AL & 0x40) != 0) {
    423           //
    424           // Set the flag to use INT 16 Func 10-12
    425           //
    426           BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
    427         }
    428       }
    429     }
    430   }
    431   DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard));
    432   //
    433   // Install protocol interfaces for the keyboard device.
    434   //
    435   Status = gBS->InstallMultipleProtocolInterfaces (
    436                   &Controller,
    437                   &gEfiSimpleTextInProtocolGuid,
    438                   &BiosKeyboardPrivate->SimpleTextIn,
    439                   &gEfiSimpleTextInputExProtocolGuid,
    440                   &BiosKeyboardPrivate->SimpleTextInputEx,
    441                   NULL
    442                   );
    443 
    444 Done:
    445   if (StatusCode != 0) {
    446     //
    447     // Report an Error Code for failing to start the keyboard device
    448     //
    449     REPORT_STATUS_CODE (
    450       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    451       StatusCode
    452       );
    453   }
    454 
    455   if (EFI_ERROR (Status)) {
    456 
    457     if (BiosKeyboardPrivate != NULL) {
    458       if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
    459         gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
    460       }
    461 
    462       if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
    463         gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);
    464       }
    465       BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
    466 
    467       if (BiosKeyboardPrivate->TimerEvent != NULL) {
    468         gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
    469       }
    470 
    471       FreePool (BiosKeyboardPrivate);
    472     }
    473 
    474     if (IsaIo != NULL) {
    475       gBS->CloseProtocol (
    476              Controller,
    477              &gEfiIsaIoProtocolGuid,
    478              This->DriverBindingHandle,
    479              Controller
    480              );
    481     }
    482   }
    483 
    484   return Status;
    485 }
    486 
    487 /**
    488   Stop the device handled by this driver.
    489 
    490   @param  This                   The driver binding protocol.
    491   @param  Controller             The controller to release.
    492   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
    493   @param  ChildHandleBuffer      The array of child handle.
    494 
    495   @retval EFI_SUCCESS            The device was stopped.
    496   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
    497   @retval Others                 Fail to uninstall protocols attached on the device.
    498 
    499 **/
    500 EFI_STATUS
    501 EFIAPI
    502 BiosKeyboardDriverBindingStop (
    503   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    504   IN  EFI_HANDLE                      Controller,
    505   IN  UINTN                           NumberOfChildren,
    506   IN  EFI_HANDLE                      *ChildHandleBuffer
    507   )
    508 {
    509   EFI_STATUS                     Status;
    510   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;
    511   BIOS_KEYBOARD_DEV              *BiosKeyboardPrivate;
    512 
    513   //
    514   // Disable Keyboard
    515   //
    516   Status = gBS->OpenProtocol (
    517                   Controller,
    518                   &gEfiSimpleTextInProtocolGuid,
    519                   (VOID **) &SimpleTextIn,
    520                   This->DriverBindingHandle,
    521                   Controller,
    522                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    523                   );
    524   if (EFI_ERROR (Status)) {
    525     return Status;
    526   }
    527 
    528   Status = gBS->OpenProtocol (
    529                   Controller,
    530                   &gEfiSimpleTextInputExProtocolGuid,
    531                   NULL,
    532                   This->DriverBindingHandle,
    533                   Controller,
    534                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    535                   );
    536   if (EFI_ERROR (Status)) {
    537     return Status;
    538   }
    539 
    540   BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);
    541 
    542   Status = gBS->UninstallMultipleProtocolInterfaces (
    543                   Controller,
    544                   &gEfiSimpleTextInProtocolGuid,
    545                   &BiosKeyboardPrivate->SimpleTextIn,
    546                   &gEfiSimpleTextInputExProtocolGuid,
    547                   &BiosKeyboardPrivate->SimpleTextInputEx,
    548                   NULL
    549                   );
    550   if (EFI_ERROR (Status)) {
    551     return Status;
    552   }
    553   //
    554   // Release the IsaIo protocol on the controller handle
    555   //
    556   gBS->CloseProtocol (
    557          Controller,
    558          &gEfiIsaIoProtocolGuid,
    559          This->DriverBindingHandle,
    560          Controller
    561          );
    562 
    563   //
    564   // Free other resources
    565   //
    566   gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
    567   gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
    568   gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);
    569   BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
    570 
    571   FreePool (BiosKeyboardPrivate);
    572 
    573   return EFI_SUCCESS;
    574 }
    575 
    576 /**
    577   Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
    578 
    579   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    580 
    581   @return  The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
    582 
    583 **/
    584 UINT8
    585 KeyReadDataRegister (
    586   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate
    587   )
    588 {
    589   UINT8 Data;
    590 
    591   //
    592   // Use IsaIo protocol to perform IO operations
    593   //
    594   BiosKeyboardPrivate->IsaIo->Io.Read (
    595                                    BiosKeyboardPrivate->IsaIo,
    596                                    EfiIsaIoWidthUint8,
    597                                    BiosKeyboardPrivate->DataRegisterAddress,
    598                                    1,
    599                                    &Data
    600                                    );
    601 
    602   return Data;
    603 }
    604 
    605 /**
    606   Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
    607 
    608   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    609 
    610   @return  The status byte read from status register of Keyboard Controller from command port which often is port 64H.
    611 
    612 **/
    613 UINT8
    614 KeyReadStatusRegister (
    615   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate
    616   )
    617 {
    618   UINT8 Data;
    619 
    620   //
    621   // Use IsaIo protocol to perform IO operations
    622   //
    623   BiosKeyboardPrivate->IsaIo->Io.Read (
    624                                    BiosKeyboardPrivate->IsaIo,
    625                                    EfiIsaIoWidthUint8,
    626                                    BiosKeyboardPrivate->StatusRegisterAddress,
    627                                    1,
    628                                    &Data
    629                                    );
    630 
    631   return Data;
    632 }
    633 
    634 /**
    635   Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
    636 
    637   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    638   @param   Data                 Data byte to write.
    639 
    640 **/
    641 VOID
    642 KeyWriteCommandRegister (
    643   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    644   IN UINT8              Data
    645   )
    646 {
    647   //
    648   // Use IsaIo protocol to perform IO operations
    649   //
    650   BiosKeyboardPrivate->IsaIo->Io.Write (
    651                                    BiosKeyboardPrivate->IsaIo,
    652                                    EfiIsaIoWidthUint8,
    653                                    BiosKeyboardPrivate->CommandRegisterAddress,
    654                                    1,
    655                                    &Data
    656                                    );
    657 }
    658 
    659 /**
    660   Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
    661 
    662   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    663   @param   Data                 Data byte to write.
    664 
    665 **/
    666 VOID
    667 KeyWriteDataRegister (
    668   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    669   IN UINT8              Data
    670   )
    671 {
    672   //
    673   // Use IsaIo protocol to perform IO operations
    674   //
    675   BiosKeyboardPrivate->IsaIo->Io.Write (
    676                                    BiosKeyboardPrivate->IsaIo,
    677                                    EfiIsaIoWidthUint8,
    678                                    BiosKeyboardPrivate->DataRegisterAddress,
    679                                    1,
    680                                    &Data
    681                                    );
    682 }
    683 
    684 /**
    685   Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
    686 
    687   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    688   @param   Data                 The pointer for data that being read out.
    689 
    690   @retval  EFI_SUCCESS          The data byte read out successfully.
    691   @retval  EFI_TIMEOUT          Timeout occurred during reading out data byte.
    692 
    693 **/
    694 EFI_STATUS
    695 KeyboardRead (
    696   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    697   OUT UINT8             *Data
    698   )
    699 {
    700   UINT32  TimeOut;
    701   UINT32  RegFilled;
    702 
    703   TimeOut   = 0;
    704   RegFilled = 0;
    705 
    706   //
    707   // wait till output buffer full then perform the read
    708   //
    709   for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
    710     if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
    711       RegFilled = 1;
    712       *Data     = KeyReadDataRegister (BiosKeyboardPrivate);
    713       break;
    714     }
    715 
    716     gBS->Stall (30);
    717   }
    718 
    719   if (RegFilled == 0) {
    720     return EFI_TIMEOUT;
    721   }
    722 
    723   return EFI_SUCCESS;
    724 }
    725 
    726 /**
    727   Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
    728 
    729   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    730   @param   Data                 Data byte to write.
    731 
    732   @retval  EFI_SUCCESS          The data byte is written successfully.
    733   @retval  EFI_TIMEOUT          Timeout occurred during writing.
    734 
    735 **/
    736 EFI_STATUS
    737 KeyboardWrite (
    738   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    739   IN UINT8              Data
    740   )
    741 {
    742   UINT32  TimeOut;
    743   UINT32  RegEmptied;
    744 
    745   TimeOut     = 0;
    746   RegEmptied  = 0;
    747 
    748   //
    749   // wait for input buffer empty
    750   //
    751   for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
    752     if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
    753       RegEmptied = 1;
    754       break;
    755     }
    756 
    757     gBS->Stall (30);
    758   }
    759 
    760   if (RegEmptied == 0) {
    761     return EFI_TIMEOUT;
    762   }
    763   //
    764   // Write it
    765   //
    766   KeyWriteDataRegister (BiosKeyboardPrivate, Data);
    767 
    768   return EFI_SUCCESS;
    769 }
    770 
    771 /**
    772   Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
    773 
    774   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    775   @param   Data                 Command byte to write.
    776 
    777   @retval  EFI_SUCCESS          The command byte is written successfully.
    778   @retval  EFI_TIMEOUT          Timeout occurred during writing.
    779 
    780 **/
    781 EFI_STATUS
    782 KeyboardCommand (
    783   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    784   IN UINT8              Data
    785   )
    786 {
    787   UINT32  TimeOut;
    788   UINT32  RegEmptied;
    789 
    790   TimeOut     = 0;
    791   RegEmptied  = 0;
    792 
    793   //
    794   // Wait For Input Buffer Empty
    795   //
    796   for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
    797     if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
    798       RegEmptied = 1;
    799       break;
    800     }
    801 
    802     gBS->Stall (30);
    803   }
    804 
    805   if (RegEmptied == 0) {
    806     return EFI_TIMEOUT;
    807   }
    808   //
    809   // issue the command
    810   //
    811   KeyWriteCommandRegister (BiosKeyboardPrivate, Data);
    812 
    813   //
    814   // Wait For Input Buffer Empty again
    815   //
    816   RegEmptied = 0;
    817   for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
    818     if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
    819       RegEmptied = 1;
    820       break;
    821     }
    822 
    823     gBS->Stall (30);
    824   }
    825 
    826   if (RegEmptied == 0) {
    827     return EFI_TIMEOUT;
    828   }
    829 
    830   return EFI_SUCCESS;
    831 }
    832 
    833 /**
    834   Wait for a specific value to be presented in
    835   Data register of Keyboard Controller by keyboard and then read it,
    836   used in keyboard commands ack
    837 
    838   @param   BiosKeyboardPrivate  Keyboard instance pointer.
    839   @param   Value                The value to be waited for
    840   @param   WaitForValueTimeOut  The limit of microseconds for timeout
    841 
    842   @retval  EFI_SUCCESS          The command byte is written successfully.
    843   @retval  EFI_TIMEOUT          Timeout occurred during writing.
    844 
    845 **/
    846 EFI_STATUS
    847 KeyboardWaitForValue (
    848   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    849   IN UINT8              Value,
    850   IN UINTN              WaitForValueTimeOut
    851   )
    852 {
    853   UINT8   Data;
    854   UINT32  TimeOut;
    855   UINT32  SumTimeOut;
    856   UINT32  GotIt;
    857 
    858   GotIt       = 0;
    859   TimeOut     = 0;
    860   SumTimeOut  = 0;
    861 
    862   //
    863   // Make sure the initial value of 'Data' is different from 'Value'
    864   //
    865   Data = 0;
    866   if (Data == Value) {
    867     Data = 1;
    868   }
    869   //
    870   // Read from 8042 (multiple times if needed)
    871   // until the expected value appears
    872   // use SumTimeOut to control the iteration
    873   //
    874   while (1) {
    875     //
    876     // Perform a read
    877     //
    878     for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
    879       if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
    880         Data = KeyReadDataRegister (BiosKeyboardPrivate);
    881         break;
    882       }
    883 
    884       gBS->Stall (30);
    885     }
    886 
    887     SumTimeOut += TimeOut;
    888 
    889     if (Data == Value) {
    890       GotIt = 1;
    891       break;
    892     }
    893 
    894     if (SumTimeOut >= WaitForValueTimeOut) {
    895       break;
    896     }
    897   }
    898   //
    899   // Check results
    900   //
    901   if (GotIt != 0) {
    902     return EFI_SUCCESS;
    903   } else {
    904     return EFI_TIMEOUT;
    905   }
    906 
    907 }
    908 
    909 /**
    910   Reads the next keystroke from the input device. The WaitForKey Event can
    911   be used to test for existance of a keystroke via WaitForEvent () call.
    912 
    913   @param  BiosKeyboardPrivate   Bioskeyboard driver private structure.
    914   @param  KeyData               A pointer to a buffer that is filled in with the keystroke
    915                                 state data for the key that was pressed.
    916 
    917   @retval EFI_SUCCESS           The keystroke information was returned.
    918   @retval EFI_NOT_READY         There was no keystroke data availiable.
    919   @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to
    920                                 hardware errors.
    921   @retval EFI_INVALID_PARAMETER KeyData is NULL.
    922 
    923 **/
    924 EFI_STATUS
    925 KeyboardReadKeyStrokeWorker (
    926   IN BIOS_KEYBOARD_DEV  *BiosKeyboardPrivate,
    927   OUT EFI_KEY_DATA      *KeyData
    928   )
    929 {
    930   EFI_STATUS                            Status;
    931   EFI_TPL                               OldTpl;
    932   if (KeyData == NULL) {
    933     return EFI_INVALID_PARAMETER;
    934   }
    935 
    936   //
    937   // Use TimerEvent callback funciton to check whether there's any key pressed
    938   //
    939 
    940   //
    941   // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
    942   // Csm will be used to check whether there is a key pending, but the csm will disable all
    943   // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
    944   // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
    945   // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
    946   // e.g. usb keyboard driver.
    947   // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
    948   // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
    949   //
    950   gBS->Stall (1000);
    951 
    952   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    953 
    954   BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);
    955   //
    956   // If there's no key, just return
    957   //
    958   Status = CheckQueue (&BiosKeyboardPrivate->Queue);
    959   if (EFI_ERROR (Status)) {
    960     gBS->RestoreTPL (OldTpl);
    961     return EFI_NOT_READY;
    962   }
    963 
    964   Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);
    965 
    966   gBS->RestoreTPL (OldTpl);
    967 
    968   return EFI_SUCCESS;
    969 }
    970 
    971 //
    972 // EFI Simple Text In Protocol Functions
    973 //
    974 /**
    975   Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
    976 
    977   @param  This                  Pointer of simple text Protocol.
    978   @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
    979 
    980   @retval EFI_SUCCESS           The command byte is written successfully.
    981   @retval EFI_DEVICE_ERROR      Errors occurred during reseting keyboard.
    982 
    983 **/
    984 EFI_STATUS
    985 EFIAPI
    986 BiosKeyboardReset (
    987   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
    988   IN  BOOLEAN                         ExtendedVerification
    989   )
    990 {
    991   BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
    992   EFI_STATUS        Status;
    993   EFI_TPL           OldTpl;
    994   UINT8             CommandByte;
    995   BOOLEAN           MouseEnable;
    996   EFI_INPUT_KEY     Key;
    997 
    998   MouseEnable         = FALSE;
    999   BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
   1000 
   1001   //
   1002   // 1
   1003   // Report reset progress code
   1004   //
   1005   REPORT_STATUS_CODE (
   1006     EFI_PROGRESS_CODE,
   1007     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET
   1008     );
   1009 
   1010   //
   1011   // Report a Progress Code for clearing the keyboard buffer
   1012   //
   1013   REPORT_STATUS_CODE (
   1014     EFI_PROGRESS_CODE,
   1015     EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER
   1016     );
   1017 
   1018   //
   1019   // 2
   1020   // Raise TPL to avoid mouse operation impact
   1021   //
   1022   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   1023 
   1024   //
   1025   //
   1026   // Exhaust output buffer data
   1027   //
   1028   do {
   1029     Status = BiosKeyboardReadKeyStroke (
   1030                This,
   1031                &Key
   1032                );
   1033   } while (!EFI_ERROR (Status));
   1034   //
   1035   // 3
   1036   // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
   1037   // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
   1038   // else   go step 4
   1039   //
   1040   if (!PcdGetBool (PcdFastPS2Detection)) {
   1041     if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {
   1042       //
   1043       // 4
   1044       // CheckMouseStatus to decide enable it later or not
   1045       //
   1046       //
   1047       // Read the command byte of KBC
   1048       //
   1049       Status = KeyboardCommand (
   1050                  BiosKeyboardPrivate,
   1051                  KBC_CMDREG_VIA64_CMDBYTE_R
   1052                  );
   1053 
   1054       if (EFI_ERROR (Status)) {
   1055         Status    = EFI_DEVICE_ERROR;
   1056         goto Exit;
   1057       }
   1058 
   1059       Status = KeyboardRead (
   1060                  BiosKeyboardPrivate,
   1061                  &CommandByte
   1062                  );
   1063 
   1064       if (EFI_ERROR (Status)) {
   1065         Status    = EFI_DEVICE_ERROR;
   1066         goto Exit;
   1067       }
   1068       //
   1069       // Check mouse enabled or not before
   1070       //
   1071       if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {
   1072         MouseEnable = FALSE;
   1073       } else {
   1074         MouseEnable = TRUE;
   1075       }
   1076       //
   1077       // 5
   1078       // disable mouse (via KBC) and Keyborad device
   1079       //
   1080       Status = KeyboardCommand (
   1081                  BiosKeyboardPrivate,
   1082                  KBC_CMDREG_VIA64_AUX_DISABLE
   1083                  );
   1084 
   1085       if (EFI_ERROR (Status)) {
   1086         Status    = EFI_DEVICE_ERROR;
   1087         goto Exit;
   1088       }
   1089 
   1090       Status = KeyboardCommand (
   1091                  BiosKeyboardPrivate,
   1092                  KBC_CMDREG_VIA64_KB_DISABLE
   1093                  );
   1094 
   1095       if (EFI_ERROR (Status)) {
   1096         Status    = EFI_DEVICE_ERROR;
   1097         goto Exit;
   1098       }
   1099     } else {
   1100       //
   1101       // 6
   1102       // KBC Self Test
   1103       //
   1104       //
   1105       // Report a Progress Code for performing a self test on the keyboard controller
   1106       //
   1107       REPORT_STATUS_CODE (
   1108         EFI_PROGRESS_CODE,
   1109         EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST
   1110         );
   1111 
   1112       Status = KeyboardCommand (
   1113                  BiosKeyboardPrivate,
   1114                  KBC_CMDREG_VIA64_KBC_SLFTEST
   1115                  );
   1116       if (EFI_ERROR (Status)) {
   1117         Status    = EFI_DEVICE_ERROR;
   1118         goto Exit;
   1119       }
   1120 
   1121       Status = KeyboardWaitForValue (
   1122                  BiosKeyboardPrivate,
   1123                  KBC_CMDECHO_KBCSLFTEST_OK,
   1124                  KEYBOARD_WAITFORVALUE_TIMEOUT
   1125                  );
   1126       if (EFI_ERROR (Status)) {
   1127         Status    = EFI_DEVICE_ERROR;
   1128         goto Exit;
   1129       }
   1130     }
   1131   }
   1132   //
   1133   // 7
   1134   // Disable  Mouse interface, enable  Keyboard interface and declare selftest success
   1135   //
   1136   // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
   1137   //
   1138   Status = KeyboardCommand (
   1139              BiosKeyboardPrivate,
   1140              KBC_CMDREG_VIA64_CMDBYTE_W
   1141              );
   1142 
   1143   if (EFI_ERROR (Status)) {
   1144     Status    = EFI_DEVICE_ERROR;
   1145     goto Exit;
   1146   }
   1147 
   1148   //
   1149   // Write 8042 Command Byte, set System Flag
   1150   // While at the same time:
   1151   //  1. disable mouse interface,
   1152   //  2. enable kbd interface,
   1153   //  3. enable PC/XT kbd translation mode
   1154   //  4. enable mouse and kbd interrupts
   1155   //
   1156   //Command Byte bits:
   1157   //  7: Reserved
   1158   //  6: PC/XT translation mode
   1159   //  5: Disable Auxiliary device interface
   1160   //  4: Disable keyboard interface
   1161   //  3: Reserved
   1162   //  2: System Flag
   1163   //  1: Enable Auxiliary device interrupt
   1164   //  0: Enable Keyboard interrupt
   1165   //
   1166   CommandByte = 0;
   1167   Status = KeyboardWrite (
   1168              BiosKeyboardPrivate,
   1169              (UINT8) ((CommandByte &
   1170               (~KB_CMMBYTE_DISABLE_KB)) |
   1171               KB_CMMBYTE_KSCAN2UNI_COV |
   1172               KB_CMMBYTE_ENABLE_AUXINT |
   1173               KB_CMMBYTE_ENABLE_KBINT  |
   1174               KB_CMMBYTE_SLFTEST_SUCC  |
   1175               KB_CMMBYTE_DISABLE_AUX)
   1176              );
   1177 
   1178   //
   1179   // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
   1180   // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.
   1181   // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
   1182   // Real reset will not do.
   1183   //
   1184   if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {
   1185     //
   1186     // 8
   1187     // Send keyboard reset command then read ACK
   1188     //
   1189     Status = KeyboardWrite (
   1190                BiosKeyboardPrivate,
   1191                KBC_INPBUF_VIA60_KBRESET
   1192                );
   1193 
   1194     if (EFI_ERROR (Status)) {
   1195       Status    = EFI_DEVICE_ERROR;
   1196       goto Exit;
   1197     }
   1198 
   1199     Status = KeyboardWaitForValue (
   1200                BiosKeyboardPrivate,
   1201                KBC_CMDECHO_ACK,
   1202                KEYBOARD_WAITFORVALUE_TIMEOUT
   1203                );
   1204 
   1205     if (EFI_ERROR (Status)) {
   1206       Status    = EFI_DEVICE_ERROR;
   1207       goto Exit;
   1208     }
   1209     //
   1210     // 9
   1211     // Wait for keyboard return test OK.
   1212     //
   1213     Status = KeyboardWaitForValue (
   1214                BiosKeyboardPrivate,
   1215                KBC_CMDECHO_BATTEST_OK,
   1216                KEYBOARD_WAITFORVALUE_TIMEOUT
   1217                );
   1218 
   1219     if (EFI_ERROR (Status)) {
   1220       Status    = EFI_DEVICE_ERROR;
   1221       goto Exit;
   1222     }
   1223     //
   1224     // 10
   1225     // set keyboard scan code set = 02 (standard configuration)
   1226     //
   1227     Status = KeyboardWrite (
   1228                BiosKeyboardPrivate,
   1229                KBC_INPBUF_VIA60_KBSCODE
   1230                );
   1231     if (EFI_ERROR (Status)) {
   1232       Status    = EFI_DEVICE_ERROR;
   1233       goto Exit;
   1234     }
   1235 
   1236     Status = KeyboardWaitForValue (
   1237                BiosKeyboardPrivate,
   1238                KBC_CMDECHO_ACK,
   1239                KEYBOARD_WAITFORVALUE_TIMEOUT
   1240                );
   1241 
   1242     if (EFI_ERROR (Status)) {
   1243       Status    = EFI_DEVICE_ERROR;
   1244       goto Exit;
   1245     }
   1246 
   1247     Status = KeyboardWrite (
   1248                BiosKeyboardPrivate,
   1249                KBC_INPBUF_VIA60_SCODESET2
   1250                );
   1251     if (EFI_ERROR (Status)) {
   1252       Status    = EFI_DEVICE_ERROR;
   1253       goto Exit;
   1254     }
   1255 
   1256     Status = KeyboardWaitForValue (
   1257                BiosKeyboardPrivate,
   1258                KBC_CMDECHO_ACK,
   1259                KEYBOARD_WAITFORVALUE_TIMEOUT
   1260                );
   1261 
   1262     if (EFI_ERROR (Status)) {
   1263       Status    = EFI_DEVICE_ERROR;
   1264       goto Exit;
   1265     }
   1266     //
   1267     // 11
   1268     // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
   1269     //
   1270     Status = KeyboardWrite (
   1271                BiosKeyboardPrivate,
   1272                KBC_INPBUF_VIA60_KBEN
   1273                );
   1274     if (EFI_ERROR (Status)) {
   1275       Status    = EFI_DEVICE_ERROR;
   1276       goto Exit;
   1277     }
   1278 
   1279     Status = KeyboardWaitForValue (
   1280                BiosKeyboardPrivate,
   1281                KBC_CMDECHO_ACK,
   1282                KEYBOARD_WAITFORVALUE_TIMEOUT
   1283                );
   1284 
   1285     if (EFI_ERROR (Status)) {
   1286       Status    = EFI_DEVICE_ERROR;
   1287       goto Exit;
   1288     }
   1289     //
   1290     // 12
   1291     // Additional validation, do it as follow:
   1292     // 1). check for status register of PARE && TIM via 64H
   1293     // 2). perform KB checking by writing ABh via 64H
   1294     //
   1295     if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {
   1296       Status    = EFI_DEVICE_ERROR;
   1297       goto Exit;
   1298     }
   1299 
   1300     Status = KeyboardCommand (
   1301                BiosKeyboardPrivate,
   1302                KBC_CMDREG_VIA64_KB_CKECK
   1303                );
   1304     if (EFI_ERROR (Status)) {
   1305       Status    = EFI_DEVICE_ERROR;
   1306       goto Exit;
   1307     }
   1308 
   1309     Status = KeyboardWaitForValue (
   1310                BiosKeyboardPrivate,
   1311                KBC_CMDECHO_KBCHECK_OK,
   1312                KEYBOARD_WAITFORVALUE_TIMEOUT
   1313                );
   1314 
   1315     if (EFI_ERROR (Status)) {
   1316       Status    = EFI_DEVICE_ERROR;
   1317       goto Exit;
   1318     }
   1319   }
   1320   //
   1321   // 13
   1322   // Done for validating keyboard. Enable keyboard (via KBC)
   1323   // and recover the command byte to proper value
   1324   //
   1325   if (!PcdGetBool (PcdFastPS2Detection)) {
   1326     Status = KeyboardCommand (
   1327                BiosKeyboardPrivate,
   1328                KBC_CMDREG_VIA64_KB_ENABLE
   1329                );
   1330 
   1331     if (EFI_ERROR (Status)) {
   1332       Status    = EFI_DEVICE_ERROR;
   1333       goto Exit;
   1334     }
   1335   }
   1336 
   1337   //
   1338   // 14
   1339   // conditionally enable mouse (via KBC)
   1340   //
   1341   if (MouseEnable) {
   1342     Status = KeyboardCommand (
   1343                BiosKeyboardPrivate,
   1344                KBC_CMDREG_VIA64_AUX_ENABLE
   1345                );
   1346 
   1347     if (EFI_ERROR (Status)) {
   1348       Status    = EFI_DEVICE_ERROR;
   1349 
   1350     }
   1351   }
   1352 
   1353 Exit:
   1354   //
   1355   // 15
   1356   // resume priority of task level
   1357   //
   1358   gBS->RestoreTPL (OldTpl);
   1359 
   1360   return Status;
   1361 
   1362 }
   1363 
   1364 /**
   1365   Read out the scan code of the key that has just been stroked.
   1366 
   1367   @param  This        Pointer of simple text Protocol.
   1368   @param  Key         Pointer for store the key that read out.
   1369 
   1370   @retval EFI_SUCCESS The key is read out successfully.
   1371   @retval other       The key reading failed.
   1372 
   1373 **/
   1374 EFI_STATUS
   1375 EFIAPI
   1376 BiosKeyboardReadKeyStroke (
   1377   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
   1378   OUT EFI_INPUT_KEY                   *Key
   1379   )
   1380 {
   1381   BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate;
   1382   EFI_STATUS            Status;
   1383   EFI_KEY_DATA          KeyData;
   1384 
   1385   BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
   1386 
   1387   Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);
   1388   if (EFI_ERROR (Status)) {
   1389     return Status;
   1390   }
   1391 
   1392   //
   1393   // Convert the Ctrl+[a-z] to Ctrl+[1-26]
   1394   //
   1395   if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
   1396     if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
   1397       KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
   1398     } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
   1399       KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
   1400     }
   1401   }
   1402 
   1403   CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
   1404 
   1405   return EFI_SUCCESS;
   1406 }
   1407 
   1408 /**
   1409   Waiting on the keyboard event, if there's any key pressed by the user, signal the event
   1410 
   1411   @param  Event       The event that be siganlled when any key has been stroked.
   1412   @param  Context     Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
   1413 
   1414 **/
   1415 VOID
   1416 EFIAPI
   1417 BiosKeyboardWaitForKey (
   1418   IN  EFI_EVENT  Event,
   1419   IN  VOID       *Context
   1420   )
   1421 {
   1422   //
   1423   // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
   1424   // Csm will be used to check whether there is a key pending, but the csm will disable all
   1425   // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
   1426   // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
   1427   // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
   1428   // e.g. usb keyboard driver.
   1429   // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
   1430   // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
   1431   //
   1432   gBS->Stall (1000);
   1433   //
   1434   // Use TimerEvent callback funciton to check whether there's any key pressed
   1435   //
   1436   BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));
   1437 
   1438   if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {
   1439     gBS->SignalEvent (Event);
   1440   }
   1441 }
   1442 
   1443 /**
   1444   Check key buffer to get the key stroke status.
   1445 
   1446   @param  This         Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
   1447 
   1448   @retval EFI_SUCCESS  A key is being pressed now.
   1449   @retval Other        No key is now pressed.
   1450 
   1451 **/
   1452 EFI_STATUS
   1453 EFIAPI
   1454 BiosKeyboardCheckForKey (
   1455   IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This
   1456   )
   1457 {
   1458   BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate;
   1459 
   1460   BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
   1461 
   1462   return CheckQueue (&BiosKeyboardPrivate->Queue);
   1463 }
   1464 //
   1465 // Private worker functions
   1466 //
   1467 #define TABLE_END 0x0
   1468 
   1469 typedef struct _CONVERT_TABLE_ENTRY {
   1470   UINT16  ScanCode;
   1471   UINT16  EfiScanCode;
   1472 } CONVERT_TABLE_ENTRY;
   1473 
   1474 CONVERT_TABLE_ENTRY mConvertTable[] = {
   1475   {
   1476     0x47,
   1477     SCAN_HOME
   1478   },
   1479   {
   1480     0x48,
   1481     SCAN_UP
   1482   },
   1483   {
   1484     0x49,
   1485     SCAN_PAGE_UP
   1486   },
   1487   {
   1488     0x4b,
   1489     SCAN_LEFT
   1490   },
   1491   {
   1492     0x4d,
   1493     SCAN_RIGHT
   1494   },
   1495   {
   1496     0x4f,
   1497     SCAN_END
   1498   },
   1499   {
   1500     0x50,
   1501     SCAN_DOWN
   1502   },
   1503   {
   1504     0x51,
   1505     SCAN_PAGE_DOWN
   1506   },
   1507   {
   1508     0x52,
   1509     SCAN_INSERT
   1510   },
   1511   {
   1512     0x53,
   1513     SCAN_DELETE
   1514   },
   1515   //
   1516   // Function Keys are only valid if KeyChar == 0x00
   1517   //  This function does not require KeyChar to be 0x00
   1518   //
   1519   {
   1520     0x3b,
   1521     SCAN_F1
   1522   },
   1523   {
   1524     0x3c,
   1525     SCAN_F2
   1526   },
   1527   {
   1528     0x3d,
   1529     SCAN_F3
   1530   },
   1531   {
   1532     0x3e,
   1533     SCAN_F4
   1534   },
   1535   {
   1536     0x3f,
   1537     SCAN_F5
   1538   },
   1539   {
   1540     0x40,
   1541     SCAN_F6
   1542   },
   1543   {
   1544     0x41,
   1545     SCAN_F7
   1546   },
   1547   {
   1548     0x42,
   1549     SCAN_F8
   1550   },
   1551   {
   1552     0x43,
   1553     SCAN_F9
   1554   },
   1555   {
   1556     0x44,
   1557     SCAN_F10
   1558   },
   1559   {
   1560     0x85,
   1561     SCAN_F11
   1562   },
   1563   {
   1564     0x86,
   1565     SCAN_F12
   1566   },
   1567   //
   1568   // Convert ALT + Fn keys
   1569   //
   1570   {
   1571     0x68,
   1572     SCAN_F1
   1573   },
   1574   {
   1575     0x69,
   1576     SCAN_F2
   1577   },
   1578   {
   1579     0x6a,
   1580     SCAN_F3
   1581   },
   1582   {
   1583     0x6b,
   1584     SCAN_F4
   1585   },
   1586   {
   1587     0x6c,
   1588     SCAN_F5
   1589   },
   1590   {
   1591     0x6d,
   1592     SCAN_F6
   1593   },
   1594   {
   1595     0x6e,
   1596     SCAN_F7
   1597   },
   1598   {
   1599     0x6f,
   1600     SCAN_F8
   1601   },
   1602   {
   1603     0x70,
   1604     SCAN_F9
   1605   },
   1606   {
   1607     0x71,
   1608     SCAN_F10
   1609   },
   1610   {
   1611     TABLE_END,
   1612     SCAN_NULL
   1613   },
   1614 };
   1615 
   1616 /**
   1617   Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
   1618 
   1619   @param  KeyChar      Unicode of key.
   1620   @param  ScanCode     Scan code of key.
   1621 
   1622   @return The value of EFI Scancode for the key.
   1623   @retval SCAN_NULL   No corresponding value in the EFI convert table is found for the key.
   1624 
   1625 **/
   1626 UINT16
   1627 ConvertToEFIScanCode (
   1628   IN  CHAR16  KeyChar,
   1629   IN  UINT16  ScanCode
   1630   )
   1631 {
   1632   UINT16  EfiScanCode;
   1633   UINT16  Index;
   1634 
   1635   if (KeyChar == CHAR_ESC) {
   1636     EfiScanCode = SCAN_ESC;
   1637   } else if (KeyChar == 0x00 || KeyChar == 0xe0) {
   1638     //
   1639     // Movement & Function Keys
   1640     //
   1641     for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {
   1642       if (ScanCode == mConvertTable[Index].ScanCode) {
   1643         return mConvertTable[Index].EfiScanCode;
   1644       }
   1645     }
   1646     //
   1647     // Reach Table end, return default value
   1648     //
   1649     return SCAN_NULL;
   1650   } else {
   1651     return SCAN_NULL;
   1652   }
   1653 
   1654   return EfiScanCode;
   1655 }
   1656 
   1657 /**
   1658   Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
   1659   If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
   1660   should not be in system.
   1661 
   1662   @param  BiosKeyboardPrivate  Keyboard Private Data Struture
   1663 
   1664   @retval TRUE  Keyboard in System.
   1665   @retval FALSE Keyboard not in System.
   1666 
   1667 **/
   1668 BOOLEAN
   1669 CheckKeyboardConnect (
   1670   IN  BIOS_KEYBOARD_DEV     *BiosKeyboardPrivate
   1671   )
   1672 {
   1673   EFI_STATUS     Status;
   1674 
   1675   Status         = EFI_SUCCESS;
   1676   //
   1677   // enable keyboard itself and wait for its ack
   1678   // If can't receive ack, Keyboard should not be connected.
   1679   //
   1680   if (!PcdGetBool (PcdFastPS2Detection)) {
   1681     Status = KeyboardWrite (
   1682                BiosKeyboardPrivate,
   1683                KBC_INPBUF_VIA60_KBEN
   1684                );
   1685     if (EFI_ERROR (Status)) {
   1686       DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));
   1687       REPORT_STATUS_CODE (
   1688         EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1689         EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR
   1690         );
   1691       return FALSE;
   1692     }
   1693 
   1694     Status = KeyboardWaitForValue (
   1695                BiosKeyboardPrivate,
   1696                KBC_CMDECHO_ACK,
   1697                KEYBOARD_WAITFORVALUE_TIMEOUT
   1698                );
   1699 
   1700     if (EFI_ERROR (Status)) {
   1701       DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));
   1702       REPORT_STATUS_CODE (
   1703         EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1704         EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR
   1705         );
   1706       return FALSE;
   1707     }
   1708     return TRUE;
   1709   } else {
   1710     return TRUE;
   1711   }
   1712 }
   1713 
   1714 /**
   1715   Timer event handler: read a series of key stroke from 8042
   1716   and put them into memory key buffer.
   1717   It is registered as running under TPL_NOTIFY
   1718 
   1719   @param  Event   The timer event
   1720   @param  Context A BIOS_KEYBOARD_DEV pointer
   1721 
   1722 **/
   1723 VOID
   1724 EFIAPI
   1725 BiosKeyboardTimerHandler (
   1726   IN EFI_EVENT    Event,
   1727   IN VOID         *Context
   1728   )
   1729 {
   1730   EFI_TPL                            OldTpl;
   1731   BIOS_KEYBOARD_DEV                  *BiosKeyboardPrivate;
   1732   EFI_IA32_REGISTER_SET              Regs;
   1733   UINT8                              KbFlag1;  // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
   1734   UINT8                              KbFlag2;  // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
   1735   EFI_KEY_DATA                       KeyData;
   1736   LIST_ENTRY                         *Link;
   1737   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
   1738 
   1739   BiosKeyboardPrivate = Context;
   1740 
   1741   //
   1742   // Enter critical section
   1743   //
   1744   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   1745 
   1746   //
   1747   // if there is no key present, just return
   1748   //
   1749   if (BiosKeyboardPrivate->ExtendedKeyboard) {
   1750     Regs.H.AH = 0x11;
   1751   } else {
   1752     Regs.H.AH = 0x01;
   1753   }
   1754 
   1755   BiosKeyboardPrivate->LegacyBios->Int86 (
   1756                                      BiosKeyboardPrivate->LegacyBios,
   1757                                      0x16,
   1758                                      &Regs
   1759                                      );
   1760   if (Regs.X.Flags.ZF != 0) {
   1761     gBS->RestoreTPL (OldTpl);
   1762     return;
   1763   }
   1764 
   1765   //
   1766   // Read the key
   1767   //
   1768   if (BiosKeyboardPrivate->ExtendedKeyboard) {
   1769     Regs.H.AH = 0x10;
   1770   } else {
   1771     Regs.H.AH = 0x00;
   1772   }
   1773 
   1774   BiosKeyboardPrivate->LegacyBios->Int86 (
   1775                                      BiosKeyboardPrivate->LegacyBios,
   1776                                      0x16,
   1777                                      &Regs
   1778                                      );
   1779 
   1780   KeyData.Key.ScanCode            = (UINT16) Regs.H.AH;
   1781   KeyData.Key.UnicodeChar         = (UINT16) Regs.H.AL;
   1782   DEBUG ((
   1783     EFI_D_INFO,
   1784     "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
   1785     KeyData.Key.ScanCode,
   1786     KeyData.Key.UnicodeChar
   1787     ));
   1788 
   1789   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
   1790   KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
   1791   //
   1792   // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB  buffer in BDA (BIOS DATE AREA),  then
   1793   // Int 16 depend  KB buffer and some key bits in BDA to translate the scancode to ASCII code, and  return both the scancode and ASCII
   1794   // code to Int 16 caller. This translation process works well if the Int 9  could response user input in time. But in Tiano enviorment,  the Int 9
   1795   // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when
   1796   // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit
   1797   // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode
   1798   // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers
   1799   // performance, like USB.
   1800   //
   1801   // 1. If CTRL or ALT release code is missed,  all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In
   1802   //     this case, the KB input seems fail to work, and user input is blocked. To solve the problem, we can help to clear the CTRL or ALT flag in BDA
   1803   //    after every Int 16 finish. Thus persist to press CTRL or ALT has same effection as only press one time. It is Ok, since user not often use the
   1804   //    CTRL and ALT.
   1805   //
   1806   // 2. If SHIFT release code is missed, all later lowercase input will become capital. This is ugly, but not block user input. If user press the lost
   1807   //     SHIFT again,  the lowercase will come back to normal. Since user often use the SHIFT, it is not reasonable to help to clear the SHIFT flag in BDA,
   1808   //     which will let persist to press SHIFT has same effection as only press one time.
   1809   //
   1810   //0040h:0017h - KEYBOARD - STATUS FLAGS 1
   1811   //   7 INSert active
   1812   //   6 Caps Lock active
   1813   //   5 Num Lock active
   1814   //   4 Scroll Lock active
   1815   //   3 either Alt pressed
   1816   //   2 either Ctrl pressed
   1817   //   1 Left Shift pressed
   1818   //   0 Right Shift pressed
   1819 
   1820 
   1821   //
   1822   // Clear the CTRL and ALT BDA flag
   1823   //
   1824   KbFlag1 = *((UINT8 *) (UINTN) 0x417);  // read the STATUS FLAGS 1
   1825   KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2
   1826 
   1827   DEBUG_CODE (
   1828     {
   1829       if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
   1830         DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n"));
   1831       }
   1832       if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
   1833         DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n"));
   1834       }
   1835       if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
   1836         DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n"));
   1837       }
   1838       if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
   1839         if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) {
   1840           DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n"));
   1841         } else {
   1842           DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n"));
   1843         }
   1844       }
   1845       if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
   1846         if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) {
   1847           DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n"));
   1848         } else {
   1849           DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n"));
   1850         }
   1851       }
   1852       if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
   1853         DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n"));
   1854       }
   1855       if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
   1856         DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n"));
   1857       }
   1858     }
   1859   );
   1860 
   1861   //
   1862   // Record toggle state
   1863   //
   1864   if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
   1865     KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
   1866   }
   1867   if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
   1868     KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
   1869   }
   1870   if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
   1871     KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
   1872   }
   1873   //
   1874   // Record shift state
   1875   // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
   1876   //
   1877   if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
   1878     KeyData.KeyState.KeyShiftState  |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;
   1879   }
   1880   if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
   1881     KeyData.KeyState.KeyShiftState  |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;
   1882   }
   1883   if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
   1884     KeyData.KeyState.KeyShiftState  |= EFI_LEFT_SHIFT_PRESSED;
   1885   }
   1886   if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
   1887     KeyData.KeyState.KeyShiftState  |= EFI_RIGHT_SHIFT_PRESSED;
   1888   }
   1889 
   1890   //
   1891   // Clear left alt and left ctrl BDA flag
   1892   //
   1893   KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);
   1894   *((UINT8 *) (UINTN) 0x418) = KbFlag2;
   1895   KbFlag1 &= ~0x0C;
   1896   *((UINT8 *) (UINTN) 0x417) = KbFlag1;
   1897 
   1898 
   1899   //
   1900   // Output EFI input key and shift/toggle state
   1901   //
   1902   if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {
   1903     KeyData.Key.ScanCode     = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);
   1904     KeyData.Key.UnicodeChar  = CHAR_NULL;
   1905   } else {
   1906     KeyData.Key.ScanCode     = SCAN_NULL;
   1907   }
   1908 
   1909   //
   1910   // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
   1911   //
   1912   if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
   1913     if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {
   1914       if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==
   1915           ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)
   1916           ) {
   1917         KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);
   1918       } else {
   1919         KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);
   1920       }
   1921     }
   1922   }
   1923 
   1924   DEBUG ((
   1925     EFI_D_INFO,
   1926     "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
   1927     KeyData.Key.ScanCode,
   1928     KeyData.Key.UnicodeChar
   1929     ));
   1930 
   1931   //
   1932   // Need not return associated shift state if a class of printable characters that
   1933   // are normally adjusted by shift modifiers.
   1934   // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
   1935   //
   1936   if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||
   1937       (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')
   1938      ) {
   1939     DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));
   1940     KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
   1941   }
   1942 
   1943   //
   1944   // Invoke notification functions if exist
   1945   //
   1946   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
   1947     CurrentNotify = CR (
   1948                       Link,
   1949                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1950                       NotifyEntry,
   1951                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1952                       );
   1953     if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
   1954       CurrentNotify->KeyNotificationFn (&KeyData);
   1955     }
   1956   }
   1957 
   1958   Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);
   1959   //
   1960   // Leave critical section and return
   1961   //
   1962   gBS->RestoreTPL (OldTpl);
   1963 
   1964   return ;
   1965 }
   1966 
   1967 /**
   1968   Free keyboard notify list.
   1969 
   1970   @param  ListHead   The list head
   1971 
   1972   @retval EFI_SUCCESS           Free the notify list successfully
   1973   @retval EFI_INVALID_PARAMETER ListHead is invalid.
   1974 
   1975 **/
   1976 EFI_STATUS
   1977 BiosKeyboardFreeNotifyList (
   1978   IN OUT LIST_ENTRY           *ListHead
   1979   )
   1980 {
   1981   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
   1982 
   1983   if (ListHead == NULL) {
   1984     return EFI_INVALID_PARAMETER;
   1985   }
   1986   while (!IsListEmpty (ListHead)) {
   1987     NotifyNode = CR (
   1988                    ListHead->ForwardLink,
   1989                    BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   1990                    NotifyEntry,
   1991                    BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   1992                    );
   1993     RemoveEntryList (ListHead->ForwardLink);
   1994     gBS->FreePool (NotifyNode);
   1995   }
   1996 
   1997   return EFI_SUCCESS;
   1998 }
   1999 
   2000 /**
   2001   Check if key is registered.
   2002 
   2003   @param  RegsiteredData    A pointer to a buffer that is filled in with the keystroke
   2004                             state data for the key that was registered.
   2005   @param  InputData         A pointer to a buffer that is filled in with the keystroke
   2006                             state data for the key that was pressed.
   2007 
   2008   @retval TRUE              Key be pressed matches a registered key.
   2009   @retval FLASE             Match failed.
   2010 
   2011 **/
   2012 BOOLEAN
   2013 IsKeyRegistered (
   2014   IN EFI_KEY_DATA  *RegsiteredData,
   2015   IN EFI_KEY_DATA  *InputData
   2016   )
   2017 {
   2018   ASSERT (RegsiteredData != NULL && InputData != NULL);
   2019 
   2020   if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
   2021       (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
   2022     return FALSE;
   2023   }
   2024 
   2025   //
   2026   // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
   2027   //
   2028   if (RegsiteredData->KeyState.KeyShiftState != 0 &&
   2029       RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
   2030     return FALSE;
   2031   }
   2032   if (RegsiteredData->KeyState.KeyToggleState != 0 &&
   2033       RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
   2034     return FALSE;
   2035   }
   2036 
   2037   return TRUE;
   2038 
   2039 }
   2040 
   2041 /**
   2042   Waiting on the keyboard event, if there's any key pressed by the user, signal the event
   2043 
   2044   @param  Event    The event that be siganlled when any key has been stroked.
   2045   @param  Context  Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
   2046 
   2047 **/
   2048 VOID
   2049 EFIAPI
   2050 BiosKeyboardWaitForKeyEx (
   2051   IN  EFI_EVENT  Event,
   2052   IN  VOID       *Context
   2053   )
   2054 {
   2055   BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;
   2056 
   2057   BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context);
   2058   BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);
   2059 
   2060 }
   2061 
   2062 /**
   2063   Reset the input device and optionaly run diagnostics
   2064 
   2065   @param  This                  Protocol instance pointer.
   2066   @param  ExtendedVerification  Driver may perform diagnostics on reset.
   2067 
   2068   @retval EFI_SUCCESS           The device was reset.
   2069   @retval EFI_DEVICE_ERROR      The device is not functioning properly and could
   2070                                 not be reset.
   2071 
   2072 **/
   2073 EFI_STATUS
   2074 EFIAPI
   2075 BiosKeyboardResetEx (
   2076   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   2077   IN BOOLEAN                            ExtendedVerification
   2078   )
   2079 {
   2080   BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;
   2081   EFI_STATUS                            Status;
   2082   EFI_TPL                               OldTpl;
   2083 
   2084   BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
   2085 
   2086   Status = BiosKeyboardPrivate->SimpleTextIn.Reset (
   2087                                                &BiosKeyboardPrivate->SimpleTextIn,
   2088                                                ExtendedVerification
   2089                                                );
   2090   if (EFI_ERROR (Status)) {
   2091     return EFI_DEVICE_ERROR;
   2092   }
   2093 
   2094   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2095 
   2096   gBS->RestoreTPL (OldTpl);
   2097 
   2098   return EFI_SUCCESS;
   2099 
   2100 }
   2101 
   2102 /**
   2103   Reads the next keystroke from the input device. The WaitForKey Event can
   2104   be used to test for existance of a keystroke via WaitForEvent () call.
   2105 
   2106   @param  This         Protocol instance pointer.
   2107   @param  KeyData      A pointer to a buffer that is filled in with the keystroke
   2108                        state data for the key that was pressed.
   2109 
   2110   @retval  EFI_SUCCESS           The keystroke information was returned.
   2111   @retval  EFI_NOT_READY         There was no keystroke data availiable.
   2112   @retval  EFI_DEVICE_ERROR      The keystroke information was not returned due to
   2113                                  hardware errors.
   2114   @retval  EFI_INVALID_PARAMETER KeyData is NULL.
   2115 
   2116 **/
   2117 EFI_STATUS
   2118 EFIAPI
   2119 BiosKeyboardReadKeyStrokeEx (
   2120   IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
   2121   OUT EFI_KEY_DATA                      *KeyData
   2122   )
   2123 {
   2124   BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;
   2125 
   2126   if (KeyData == NULL) {
   2127     return EFI_INVALID_PARAMETER;
   2128   }
   2129 
   2130   BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
   2131 
   2132   return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);
   2133 
   2134 }
   2135 
   2136 /**
   2137   Set certain state for the input device.
   2138 
   2139   @param  This              Protocol instance pointer.
   2140   @param  KeyToggleState    A pointer to the EFI_KEY_TOGGLE_STATE to set the
   2141                             state for the input device.
   2142 
   2143   @retval EFI_SUCCESS           The device state was set successfully.
   2144   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could
   2145                                 not have the setting adjusted.
   2146   @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.
   2147   @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
   2148 
   2149 **/
   2150 EFI_STATUS
   2151 EFIAPI
   2152 BiosKeyboardSetState (
   2153   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   2154   IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
   2155   )
   2156 {
   2157   EFI_STATUS                            Status;
   2158   BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;
   2159   EFI_TPL                               OldTpl;
   2160   EFI_LEGACY_BIOS_PROTOCOL              *LegacyBios;
   2161   UINT8                                 Command;
   2162 
   2163   if (KeyToggleState == NULL) {
   2164     return EFI_INVALID_PARAMETER;
   2165   }
   2166 
   2167   //
   2168   // Thunk keyboard driver doesn't support partial keystroke.
   2169   //
   2170   if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||
   2171       (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED
   2172       ) {
   2173     return EFI_UNSUPPORTED;
   2174   }
   2175 
   2176   BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
   2177   //
   2178   // See if the Legacy BIOS Protocol is available
   2179   //
   2180   Status = gBS->LocateProtocol (
   2181                   &gEfiLegacyBiosProtocolGuid,
   2182                   NULL,
   2183                   (VOID **) &LegacyBios
   2184                   );
   2185 
   2186   ASSERT_EFI_ERROR (Status);
   2187   //
   2188   // Enter critical section
   2189   //
   2190   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2191 
   2192   Command = 0;
   2193   if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
   2194     Command |= 4;
   2195   }
   2196   if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
   2197     Command |= 2;
   2198   }
   2199   if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
   2200     Command |= 1;
   2201   }
   2202 
   2203   Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);
   2204   if (EFI_ERROR (Status)) {
   2205     Status = EFI_DEVICE_ERROR;
   2206     goto Exit;
   2207   }
   2208   Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
   2209   if (EFI_ERROR (Status)) {
   2210     Status = EFI_DEVICE_ERROR;
   2211     goto Exit;
   2212   }
   2213   Status = KeyboardWrite (BiosKeyboardPrivate, Command);
   2214   if (EFI_ERROR (Status)) {
   2215     Status = EFI_DEVICE_ERROR;
   2216     goto Exit;
   2217   }
   2218   //
   2219   // Call Legacy BIOS Protocol to set whatever is necessary
   2220   //
   2221   LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
   2222 
   2223   Status = EFI_SUCCESS;
   2224 
   2225 Exit:
   2226   //
   2227   // Leave critical section and return
   2228   //
   2229   gBS->RestoreTPL (OldTpl);
   2230 
   2231   return Status;
   2232 
   2233 }
   2234 
   2235 /**
   2236   Register a notification function for a particular keystroke for the input device.
   2237 
   2238   @param  This                    Protocol instance pointer.
   2239   @param  KeyData                 A pointer to a buffer that is filled in with the keystroke
   2240                                   information data for the key that was pressed.
   2241   @param  KeyNotificationFunction Points to the function to be called when the key
   2242                                   sequence is typed specified by KeyData.
   2243   @param  NotifyHandle            Points to the unique handle assigned to the registered notification.
   2244 
   2245 
   2246   @retval EFI_SUCCESS             The notification function was registered successfully.
   2247   @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.
   2248   @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.
   2249 
   2250 **/
   2251 EFI_STATUS
   2252 EFIAPI
   2253 BiosKeyboardRegisterKeyNotify (
   2254   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   2255   IN EFI_KEY_DATA                       *KeyData,
   2256   IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
   2257   OUT VOID                              **NotifyHandle
   2258   )
   2259 {
   2260   EFI_STATUS                            Status;
   2261   BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;
   2262   EFI_TPL                               OldTpl;
   2263   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *NewNotify;
   2264   LIST_ENTRY                            *Link;
   2265   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
   2266 
   2267   if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
   2268     return EFI_INVALID_PARAMETER;
   2269   }
   2270 
   2271   BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
   2272 
   2273   //
   2274   // Enter critical section
   2275   //
   2276   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2277 
   2278   //
   2279   // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
   2280   //
   2281   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
   2282     CurrentNotify = CR (
   2283                       Link,
   2284                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   2285                       NotifyEntry,
   2286                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   2287                       );
   2288     if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
   2289       if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
   2290         *NotifyHandle = CurrentNotify;
   2291         Status = EFI_SUCCESS;
   2292         goto Exit;
   2293       }
   2294     }
   2295   }
   2296 
   2297   //
   2298   // Allocate resource to save the notification function
   2299   //
   2300 
   2301   NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
   2302   if (NewNotify == NULL) {
   2303     Status = EFI_OUT_OF_RESOURCES;
   2304     goto Exit;
   2305   }
   2306 
   2307   NewNotify->Signature         = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
   2308   NewNotify->KeyNotificationFn = KeyNotificationFunction;
   2309   CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
   2310   InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
   2311 
   2312   *NotifyHandle                = NewNotify;
   2313   Status                       = EFI_SUCCESS;
   2314 
   2315 Exit:
   2316   //
   2317   // Leave critical section and return
   2318   //
   2319   gBS->RestoreTPL (OldTpl);
   2320   return Status;
   2321 }
   2322 
   2323 /**
   2324   Remove a registered notification function from a particular keystroke.
   2325 
   2326   @param  This                 Protocol instance pointer.
   2327   @param  NotificationHandle   The handle of the notification function being unregistered.
   2328 
   2329   @retval EFI_SUCCESS             The notification function was unregistered successfully.
   2330   @retval EFI_INVALID_PARAMETER   The NotificationHandle is invalid.
   2331 
   2332 **/
   2333 EFI_STATUS
   2334 EFIAPI
   2335 BiosKeyboardUnregisterKeyNotify (
   2336   IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
   2337   IN VOID                               *NotificationHandle
   2338   )
   2339 {
   2340   EFI_STATUS                            Status;
   2341   BIOS_KEYBOARD_DEV                     *BiosKeyboardPrivate;
   2342   EFI_TPL                               OldTpl;
   2343   LIST_ENTRY                            *Link;
   2344   BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
   2345 
   2346   //
   2347   // Check incoming notification handle
   2348   //
   2349   if (NotificationHandle == NULL) {
   2350     return EFI_INVALID_PARAMETER;
   2351   }
   2352 
   2353   if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
   2354     return EFI_INVALID_PARAMETER;
   2355   }
   2356 
   2357   BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
   2358 
   2359   //
   2360   // Enter critical section
   2361   //
   2362   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2363 
   2364   for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
   2365     CurrentNotify = CR (
   2366                       Link,
   2367                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
   2368                       NotifyEntry,
   2369                       BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
   2370                       );
   2371     if (CurrentNotify == NotificationHandle) {
   2372       //
   2373       // Remove the notification function from NotifyList and free resources
   2374       //
   2375       RemoveEntryList (&CurrentNotify->NotifyEntry);
   2376 
   2377       Status = EFI_SUCCESS;
   2378       goto Exit;
   2379     }
   2380   }
   2381 
   2382   //
   2383   // Can not find the specified Notification Handle
   2384   //
   2385   Status = EFI_INVALID_PARAMETER;
   2386 
   2387 Exit:
   2388   //
   2389   // Leave critical section and return
   2390   //
   2391   gBS->RestoreTPL (OldTpl);
   2392   return Status;
   2393 }
   2394 
   2395 /**
   2396   The user Entry Point for module BiosKeyboard. The user code starts with this function.
   2397 
   2398   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
   2399   @param[in] SystemTable    A pointer to the EFI System Table.
   2400 
   2401   @retval EFI_SUCCESS       The entry point is executed successfully.
   2402   @retval other             Some error occurs when executing this entry point.
   2403 
   2404 **/
   2405 EFI_STATUS
   2406 EFIAPI
   2407 InitializeBiosKeyboard(
   2408   IN EFI_HANDLE           ImageHandle,
   2409   IN EFI_SYSTEM_TABLE     *SystemTable
   2410   )
   2411 {
   2412   EFI_STATUS              Status;
   2413 
   2414   //
   2415   // Install driver model protocol(s).
   2416   //
   2417   Status = EfiLibInstallDriverBindingComponentName2 (
   2418              ImageHandle,
   2419              SystemTable,
   2420              &gBiosKeyboardDriverBinding,
   2421              ImageHandle,
   2422              &gBiosKeyboardComponentName,
   2423              &gBiosKeyboardComponentName2
   2424              );
   2425   ASSERT_EFI_ERROR (Status);
   2426 
   2427   return Status;
   2428 }
   2429