Home | History | Annotate | Download | only in Ps2KeyboardDxe
      1 /** @file
      2 
      3   PS/2 Keyboard driver. Routines that interacts with callers,
      4   conforming to EFI driver model
      5 
      6 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The 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 "Ps2Keyboard.h"
     18 
     19 //
     20 // Function prototypes
     21 //
     22 /**
     23   Test controller is a keyboard Controller.
     24 
     25   @param This                 Pointer of EFI_DRIVER_BINDING_PROTOCOL
     26   @param Controller           driver's controller
     27   @param RemainingDevicePath  children device path
     28 
     29   @retval EFI_UNSUPPORTED controller is not floppy disk
     30   @retval EFI_SUCCESS     controller is floppy disk
     31 **/
     32 EFI_STATUS
     33 EFIAPI
     34 KbdControllerDriverSupported (
     35   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
     36   IN EFI_HANDLE                     Controller,
     37   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
     38   );
     39 
     40 /**
     41   Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
     42 
     43   @param This         Pointer of EFI_DRIVER_BINDING_PROTOCOL
     44   @param Controller   driver controller handle
     45   @param RemainingDevicePath Children's device path
     46 
     47   @retval whether success to create floppy control instance.
     48 **/
     49 EFI_STATUS
     50 EFIAPI
     51 KbdControllerDriverStart (
     52   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
     53   IN EFI_HANDLE                     Controller,
     54   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
     55   );
     56 
     57 /**
     58   Stop this driver on ControllerHandle. Support stopping any child handles
     59   created by this driver.
     60 
     61   @param  This              Protocol instance pointer.
     62   @param  ControllerHandle  Handle of device to stop driver on
     63   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
     64                             children is zero stop the entire bus driver.
     65   @param  ChildHandleBuffer List of Child Handles to Stop.
     66 
     67   @retval EFI_SUCCESS       This driver is removed ControllerHandle
     68   @retval other             This driver was not removed from this device
     69 
     70 **/
     71 EFI_STATUS
     72 EFIAPI
     73 KbdControllerDriverStop (
     74   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
     75   IN  EFI_HANDLE                     Controller,
     76   IN  UINTN                          NumberOfChildren,
     77   IN  EFI_HANDLE                     *ChildHandleBuffer
     78   );
     79 
     80 /**
     81   Free the waiting key notify list.
     82 
     83   @param ListHead  Pointer to list head
     84 
     85   @retval EFI_INVALID_PARAMETER  ListHead is NULL
     86   @retval EFI_SUCCESS            Sucess to free NotifyList
     87 **/
     88 EFI_STATUS
     89 KbdFreeNotifyList (
     90   IN OUT LIST_ENTRY           *ListHead
     91   );
     92 
     93 //
     94 // DriverBinding Protocol Instance
     95 //
     96 EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver = {
     97   KbdControllerDriverSupported,
     98   KbdControllerDriverStart,
     99   KbdControllerDriverStop,
    100   0xa,
    101   NULL,
    102   NULL
    103 };
    104 
    105 /**
    106   Test controller is a keyboard Controller.
    107 
    108   @param This                 Pointer of EFI_DRIVER_BINDING_PROTOCOL
    109   @param Controller           driver's controller
    110   @param RemainingDevicePath  children device path
    111 
    112   @retval EFI_UNSUPPORTED controller is not floppy disk
    113   @retval EFI_SUCCESS     controller is floppy disk
    114 **/
    115 EFI_STATUS
    116 EFIAPI
    117 KbdControllerDriverSupported (
    118   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    119   IN EFI_HANDLE                     Controller,
    120   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    121   )
    122 {
    123   EFI_STATUS                          Status;
    124   EFI_ISA_IO_PROTOCOL                 *IsaIo;
    125 
    126   //
    127   // Open the IO Abstraction(s) needed to perform the supported test
    128   //
    129   Status = gBS->OpenProtocol (
    130                   Controller,
    131                   &gEfiIsaIoProtocolGuid,
    132                   (VOID **) &IsaIo,
    133                   This->DriverBindingHandle,
    134                   Controller,
    135                   EFI_OPEN_PROTOCOL_BY_DRIVER
    136                   );
    137   if (EFI_ERROR (Status)) {
    138     return Status;
    139   }
    140   //
    141   // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
    142   //
    143   if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
    144     Status = EFI_UNSUPPORTED;
    145   }
    146   //
    147   // Close the I/O Abstraction(s) used to perform the supported test
    148   //
    149   gBS->CloseProtocol (
    150          Controller,
    151          &gEfiIsaIoProtocolGuid,
    152          This->DriverBindingHandle,
    153          Controller
    154          );
    155 
    156   return Status;
    157 }
    158 
    159 /**
    160   Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
    161 
    162   @param This         Pointer of EFI_DRIVER_BINDING_PROTOCOL
    163   @param Controller   driver controller handle
    164   @param RemainingDevicePath Children's device path
    165 
    166   @retval whether success to create floppy control instance.
    167 **/
    168 EFI_STATUS
    169 EFIAPI
    170 KbdControllerDriverStart (
    171   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    172   IN EFI_HANDLE                     Controller,
    173   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    174   )
    175 {
    176   EFI_STATUS                                Status;
    177   EFI_STATUS                                Status1;
    178   EFI_ISA_IO_PROTOCOL                       *IsaIo;
    179   KEYBOARD_CONSOLE_IN_DEV                   *ConsoleIn;
    180   UINT8                                     Data;
    181   EFI_STATUS_CODE_VALUE                     StatusCode;
    182   EFI_DEVICE_PATH_PROTOCOL                  *ParentDevicePath;
    183 
    184   StatusCode = 0;
    185 
    186   Status = gBS->OpenProtocol (
    187                   Controller,
    188                   &gEfiDevicePathProtocolGuid,
    189                   (VOID **) &ParentDevicePath,
    190                   This->DriverBindingHandle,
    191                   Controller,
    192                   EFI_OPEN_PROTOCOL_BY_DRIVER
    193                   );
    194   if (EFI_ERROR (Status)) {
    195     return Status;
    196   }
    197   //
    198   // Report that the keyboard is being enabled
    199   //
    200   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    201     EFI_PROGRESS_CODE,
    202     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,
    203     ParentDevicePath
    204     );
    205 
    206   //
    207   // Get the ISA I/O Protocol on Controller's handle
    208   //
    209   Status = gBS->OpenProtocol (
    210                   Controller,
    211                   &gEfiIsaIoProtocolGuid,
    212                   (VOID **) &IsaIo,
    213                   This->DriverBindingHandle,
    214                   Controller,
    215                   EFI_OPEN_PROTOCOL_BY_DRIVER
    216                   );
    217   if (EFI_ERROR (Status)) {
    218     gBS->CloseProtocol (
    219            Controller,
    220            &gEfiDevicePathProtocolGuid,
    221            This->DriverBindingHandle,
    222            Controller
    223            );
    224     return EFI_INVALID_PARAMETER;
    225   }
    226   //
    227   // Allocate private data
    228   //
    229   ConsoleIn = AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV));
    230   if (ConsoleIn == NULL) {
    231     Status      = EFI_OUT_OF_RESOURCES;
    232     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    233     goto ErrorExit;
    234   }
    235   //
    236   // Setup the device instance
    237   //
    238   ConsoleIn->Signature              = KEYBOARD_CONSOLE_IN_DEV_SIGNATURE;
    239   ConsoleIn->Handle                 = Controller;
    240   (ConsoleIn->ConIn).Reset          = KeyboardEfiReset;
    241   (ConsoleIn->ConIn).ReadKeyStroke  = KeyboardReadKeyStroke;
    242   ConsoleIn->DataRegisterAddress    = KEYBOARD_8042_DATA_REGISTER;
    243   ConsoleIn->StatusRegisterAddress  = KEYBOARD_8042_STATUS_REGISTER;
    244   ConsoleIn->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
    245   ConsoleIn->IsaIo                  = IsaIo;
    246   ConsoleIn->DevicePath             = ParentDevicePath;
    247 
    248   ConsoleIn->ConInEx.Reset               = KeyboardEfiResetEx;
    249   ConsoleIn->ConInEx.ReadKeyStrokeEx     = KeyboardReadKeyStrokeEx;
    250   ConsoleIn->ConInEx.SetState            = KeyboardSetState;
    251   ConsoleIn->ConInEx.RegisterKeyNotify   = KeyboardRegisterKeyNotify;
    252   ConsoleIn->ConInEx.UnregisterKeyNotify = KeyboardUnregisterKeyNotify;
    253 
    254   InitializeListHead (&ConsoleIn->NotifyList);
    255 
    256   //
    257   // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
    258   // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
    259   // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
    260   // So instead we read status register to detect after read if KBC decode is enabled.
    261   //
    262 
    263   //
    264   // Return code is ignored on purpose.
    265   //
    266   if (!PcdGetBool (PcdFastPS2Detection)) {
    267     KeyboardRead (ConsoleIn, &Data);
    268     if ((KeyReadStatusRegister (ConsoleIn) & (KBC_PARE | KBC_TIM)) == (KBC_PARE | KBC_TIM)) {
    269       //
    270       // If nobody decodes KBC I/O port, it will read back as 0xFF.
    271       // Check the Time-Out and Parity bit to see if it has an active KBC in system
    272       //
    273       Status      = EFI_DEVICE_ERROR;
    274       StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
    275       goto ErrorExit;
    276     }
    277   }
    278 
    279   //
    280   // Setup the WaitForKey event
    281   //
    282   Status = gBS->CreateEvent (
    283                   EVT_NOTIFY_WAIT,
    284                   TPL_NOTIFY,
    285                   KeyboardWaitForKey,
    286                   ConsoleIn,
    287                   &((ConsoleIn->ConIn).WaitForKey)
    288                   );
    289   if (EFI_ERROR (Status)) {
    290     Status      = EFI_OUT_OF_RESOURCES;
    291     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    292     goto ErrorExit;
    293   }
    294   //
    295   // Setup the WaitForKeyEx event
    296   //
    297   Status = gBS->CreateEvent (
    298                   EVT_NOTIFY_WAIT,
    299                   TPL_NOTIFY,
    300                   KeyboardWaitForKeyEx,
    301                   ConsoleIn,
    302                   &(ConsoleIn->ConInEx.WaitForKeyEx)
    303                   );
    304   if (EFI_ERROR (Status)) {
    305     Status      = EFI_OUT_OF_RESOURCES;
    306     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    307     goto ErrorExit;
    308   }
    309 
    310   // Setup a periodic timer, used for reading keystrokes at a fixed interval
    311   //
    312   Status = gBS->CreateEvent (
    313                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    314                   TPL_NOTIFY,
    315                   KeyboardTimerHandler,
    316                   ConsoleIn,
    317                   &ConsoleIn->TimerEvent
    318                   );
    319   if (EFI_ERROR (Status)) {
    320     Status      = EFI_OUT_OF_RESOURCES;
    321     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    322     goto ErrorExit;
    323   }
    324 
    325   Status = gBS->SetTimer (
    326                   ConsoleIn->TimerEvent,
    327                   TimerPeriodic,
    328                   KEYBOARD_TIMER_INTERVAL
    329                   );
    330   if (EFI_ERROR (Status)) {
    331     Status      = EFI_OUT_OF_RESOURCES;
    332     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    333     goto ErrorExit;
    334   }
    335 
    336   Status = gBS->CreateEvent (
    337                   EVT_NOTIFY_SIGNAL,
    338                   TPL_CALLBACK,
    339                   KeyNotifyProcessHandler,
    340                   ConsoleIn,
    341                   &ConsoleIn->KeyNotifyProcessEvent
    342                   );
    343   if (EFI_ERROR (Status)) {
    344     Status      = EFI_OUT_OF_RESOURCES;
    345     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    346     goto ErrorExit;
    347   }
    348 
    349   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    350     EFI_PROGRESS_CODE,
    351     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,
    352     ParentDevicePath
    353     );
    354 
    355   //
    356   // Reset the keyboard device
    357   //
    358   Status = ConsoleIn->ConInEx.Reset (&ConsoleIn->ConInEx, FeaturePcdGet (PcdPs2KbdExtendedVerification));
    359   if (EFI_ERROR (Status)) {
    360     Status      = EFI_DEVICE_ERROR;
    361     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
    362     goto ErrorExit;
    363   }
    364 
    365   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    366     EFI_PROGRESS_CODE,
    367     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED,
    368     ParentDevicePath
    369     );
    370 
    371   ConsoleIn->ControllerNameTable = NULL;
    372   AddUnicodeString2 (
    373     "eng",
    374     gPs2KeyboardComponentName.SupportedLanguages,
    375     &ConsoleIn->ControllerNameTable,
    376     L"PS/2 Keyboard Device",
    377     TRUE
    378     );
    379   AddUnicodeString2 (
    380     "en",
    381     gPs2KeyboardComponentName2.SupportedLanguages,
    382     &ConsoleIn->ControllerNameTable,
    383     L"PS/2 Keyboard Device",
    384     FALSE
    385     );
    386 
    387 
    388   //
    389   // Install protocol interfaces for the keyboard device.
    390   //
    391   Status = gBS->InstallMultipleProtocolInterfaces (
    392                   &Controller,
    393                   &gEfiSimpleTextInProtocolGuid,
    394                   &ConsoleIn->ConIn,
    395                   &gEfiSimpleTextInputExProtocolGuid,
    396                   &ConsoleIn->ConInEx,
    397                   NULL
    398                   );
    399   if (EFI_ERROR (Status)) {
    400     StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
    401     goto ErrorExit;
    402   }
    403 
    404   return Status;
    405 
    406 ErrorExit:
    407   //
    408   // Report error code
    409   //
    410   if (StatusCode != 0) {
    411     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    412       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    413       StatusCode,
    414       ParentDevicePath
    415       );
    416   }
    417 
    418   if ((ConsoleIn != NULL) && (ConsoleIn->ConIn.WaitForKey != NULL)) {
    419     gBS->CloseEvent (ConsoleIn->ConIn.WaitForKey);
    420   }
    421 
    422   if ((ConsoleIn != NULL) && (ConsoleIn->TimerEvent != NULL)) {
    423     gBS->CloseEvent (ConsoleIn->TimerEvent);
    424   }
    425   if ((ConsoleIn != NULL) && (ConsoleIn->ConInEx.WaitForKeyEx != NULL)) {
    426     gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
    427   }
    428   if ((ConsoleIn != NULL) && (ConsoleIn->KeyNotifyProcessEvent != NULL)) {
    429     gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent);
    430   }
    431   KbdFreeNotifyList (&ConsoleIn->NotifyList);
    432   if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) {
    433     FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
    434   }
    435   //
    436   // Since there will be no timer handler for keyboard input any more,
    437   // exhaust input data just in case there is still keyboard data left
    438   //
    439   if (ConsoleIn != NULL) {
    440     Status1 = EFI_SUCCESS;
    441     while (!EFI_ERROR (Status1) && (Status != EFI_DEVICE_ERROR)) {
    442       Status1 = KeyboardRead (ConsoleIn, &Data);;
    443     }
    444   }
    445 
    446   if (ConsoleIn != NULL) {
    447     gBS->FreePool (ConsoleIn);
    448   }
    449 
    450   gBS->CloseProtocol (
    451          Controller,
    452          &gEfiDevicePathProtocolGuid,
    453          This->DriverBindingHandle,
    454          Controller
    455          );
    456 
    457   gBS->CloseProtocol (
    458          Controller,
    459          &gEfiIsaIoProtocolGuid,
    460          This->DriverBindingHandle,
    461          Controller
    462          );
    463 
    464   return Status;
    465 }
    466 
    467 /**
    468   Stop this driver on ControllerHandle. Support stopping any child handles
    469   created by this driver.
    470 
    471   @param  This              Protocol instance pointer.
    472   @param  ControllerHandle  Handle of device to stop driver on
    473   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    474                             children is zero stop the entire bus driver.
    475   @param  ChildHandleBuffer List of Child Handles to Stop.
    476 
    477   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    478   @retval other             This driver was not removed from this device
    479 
    480 **/
    481 EFI_STATUS
    482 EFIAPI
    483 KbdControllerDriverStop (
    484   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
    485   IN  EFI_HANDLE                     Controller,
    486   IN  UINTN                          NumberOfChildren,
    487   IN  EFI_HANDLE                     *ChildHandleBuffer
    488   )
    489 {
    490   EFI_STATUS                     Status;
    491   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
    492   KEYBOARD_CONSOLE_IN_DEV        *ConsoleIn;
    493   UINT8                          Data;
    494 
    495   //
    496   // Disable Keyboard
    497   //
    498   Status = gBS->OpenProtocol (
    499                   Controller,
    500                   &gEfiSimpleTextInProtocolGuid,
    501                   (VOID **) &ConIn,
    502                   This->DriverBindingHandle,
    503                   Controller,
    504                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    505                   );
    506   if (EFI_ERROR (Status)) {
    507     return Status;
    508   }
    509   Status = gBS->OpenProtocol (
    510                   Controller,
    511                   &gEfiSimpleTextInputExProtocolGuid,
    512                   NULL,
    513                   This->DriverBindingHandle,
    514                   Controller,
    515                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    516                   );
    517   if (EFI_ERROR (Status)) {
    518     return Status;
    519   }
    520 
    521   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn);
    522 
    523   //
    524   // Report that the keyboard is being disabled
    525   //
    526   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    527     EFI_PROGRESS_CODE,
    528     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE,
    529     ConsoleIn->DevicePath
    530     );
    531 
    532   if (ConsoleIn->TimerEvent != NULL) {
    533     gBS->CloseEvent (ConsoleIn->TimerEvent);
    534     ConsoleIn->TimerEvent = NULL;
    535   }
    536 
    537   //
    538   // Since there will be no timer handler for keyboard input any more,
    539   // exhaust input data just in case there is still keyboard data left
    540   //
    541   Status = EFI_SUCCESS;
    542   while (!EFI_ERROR (Status)) {
    543     Status = KeyboardRead (ConsoleIn, &Data);;
    544   }
    545   //
    546   // Uninstall the SimpleTextIn and SimpleTextInEx protocols
    547   //
    548   Status = gBS->UninstallMultipleProtocolInterfaces (
    549                   Controller,
    550                   &gEfiSimpleTextInProtocolGuid,
    551                   &ConsoleIn->ConIn,
    552                   &gEfiSimpleTextInputExProtocolGuid,
    553                   &ConsoleIn->ConInEx,
    554                   NULL
    555                   );
    556   if (EFI_ERROR (Status)) {
    557     return Status;
    558   }
    559 
    560   gBS->CloseProtocol (
    561          Controller,
    562          &gEfiDevicePathProtocolGuid,
    563          This->DriverBindingHandle,
    564          Controller
    565          );
    566 
    567   gBS->CloseProtocol (
    568          Controller,
    569          &gEfiIsaIoProtocolGuid,
    570          This->DriverBindingHandle,
    571          Controller
    572          );
    573 
    574   //
    575   // Free other resources
    576   //
    577   if ((ConsoleIn->ConIn).WaitForKey != NULL) {
    578     gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey);
    579     (ConsoleIn->ConIn).WaitForKey = NULL;
    580   }
    581   if (ConsoleIn->ConInEx.WaitForKeyEx != NULL) {
    582     gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
    583     ConsoleIn->ConInEx.WaitForKeyEx = NULL;
    584   }
    585   if (ConsoleIn->KeyNotifyProcessEvent != NULL) {
    586     gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent);
    587     ConsoleIn->KeyNotifyProcessEvent = NULL;
    588   }
    589   KbdFreeNotifyList (&ConsoleIn->NotifyList);
    590   FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
    591   gBS->FreePool (ConsoleIn);
    592 
    593   return EFI_SUCCESS;
    594 }
    595 
    596 /**
    597   Free the waiting key notify list.
    598 
    599   @param ListHead  Pointer to list head
    600 
    601   @retval EFI_INVALID_PARAMETER  ListHead is NULL
    602   @retval EFI_SUCCESS            Sucess to free NotifyList
    603 **/
    604 EFI_STATUS
    605 KbdFreeNotifyList (
    606   IN OUT LIST_ENTRY           *ListHead
    607   )
    608 {
    609   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
    610 
    611   if (ListHead == NULL) {
    612     return EFI_INVALID_PARAMETER;
    613   }
    614   while (!IsListEmpty (ListHead)) {
    615     NotifyNode = CR (
    616                    ListHead->ForwardLink,
    617                    KEYBOARD_CONSOLE_IN_EX_NOTIFY,
    618                    NotifyEntry,
    619                    KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
    620                    );
    621     RemoveEntryList (ListHead->ForwardLink);
    622     gBS->FreePool (NotifyNode);
    623   }
    624 
    625   return EFI_SUCCESS;
    626 }
    627 
    628 /**
    629   The module Entry Point for module Ps2Keyboard.
    630 
    631   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
    632   @param[in] SystemTable    A pointer to the EFI System Table.
    633 
    634   @retval EFI_SUCCESS       The entry point is executed successfully.
    635   @retval other             Some error occurs when executing this entry point.
    636 
    637 **/
    638 EFI_STATUS
    639 EFIAPI
    640 InitializePs2Keyboard(
    641   IN EFI_HANDLE           ImageHandle,
    642   IN EFI_SYSTEM_TABLE     *SystemTable
    643   )
    644 {
    645   EFI_STATUS              Status;
    646 
    647   //
    648   // Install driver model protocol(s).
    649   //
    650   Status = EfiLibInstallDriverBindingComponentName2 (
    651              ImageHandle,
    652              SystemTable,
    653              &gKeyboardControllerDriver,
    654              ImageHandle,
    655              &gPs2KeyboardComponentName,
    656              &gPs2KeyboardComponentName2
    657              );
    658   ASSERT_EFI_ERROR (Status);
    659 
    660 
    661   return Status;
    662 }
    663 
    664