Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com>
		
			
				
	
	
		
			648 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			648 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
|   PS/2 Keyboard driver. Routines that interacts with callers,
 | |
|   conforming to EFI driver model
 | |
| 
 | |
| Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Ps2Keyboard.h"
 | |
| 
 | |
| //
 | |
| // Function prototypes
 | |
| //
 | |
| /**
 | |
|   Test controller is a keyboard Controller.
 | |
| 
 | |
|   @param This                 Pointer of EFI_DRIVER_BINDING_PROTOCOL
 | |
|   @param Controller           driver's controller
 | |
|   @param RemainingDevicePath  children device path
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED controller is not floppy disk
 | |
|   @retval EFI_SUCCESS     controller is floppy disk
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| KbdControllerDriverSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
 | |
| 
 | |
|   @param This         Pointer of EFI_DRIVER_BINDING_PROTOCOL
 | |
|   @param Controller   driver controller handle
 | |
|   @param RemainingDevicePath Children's device path
 | |
| 
 | |
|   @retval whether success to create floppy control instance.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| KbdControllerDriverStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Stop this driver on ControllerHandle. Support stoping any child handles
 | |
|   created by this driver.
 | |
| 
 | |
|   @param  This              Protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| KbdControllerDriverStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN  EFI_HANDLE                     Controller,
 | |
|   IN  UINTN                          NumberOfChildren,
 | |
|   IN  EFI_HANDLE                     *ChildHandleBuffer
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Free the waiting key notify list.
 | |
| 
 | |
|   @param ListHead  Pointer to list head
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  ListHead is NULL
 | |
|   @retval EFI_SUCCESS            Sucess to free NotifyList
 | |
| **/
 | |
| EFI_STATUS
 | |
| KbdFreeNotifyList (
 | |
|   IN OUT LIST_ENTRY           *ListHead
 | |
|   );
 | |
| 
 | |
| //
 | |
| // DriverBinding Protocol Instance
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver = {
 | |
|   KbdControllerDriverSupported,
 | |
|   KbdControllerDriverStart,
 | |
|   KbdControllerDriverStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Test controller is a keyboard Controller.
 | |
| 
 | |
|   @param This                 Pointer of EFI_DRIVER_BINDING_PROTOCOL
 | |
|   @param Controller           driver's controller
 | |
|   @param RemainingDevicePath  children device path
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED controller is not floppy disk
 | |
|   @retval EFI_SUCCESS     controller is floppy disk
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| KbdControllerDriverSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                 Status;
 | |
|   EFI_SIO_PROTOCOL                           *Sio;
 | |
|   EFI_DEVICE_PATH_PROTOCOL                   *DevicePath;
 | |
|   ACPI_HID_DEVICE_PATH                       *Acpi;
 | |
| 
 | |
|   //
 | |
|   // Check whether the controller is keyboard.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &DevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
 | |
|     DevicePath = NextDevicePathNode (DevicePath);
 | |
|   } while (!IsDevicePathEnd (DevicePath));
 | |
| 
 | |
|   if (DevicePathType (Acpi) != ACPI_DEVICE_PATH ||
 | |
|       (DevicePathSubType (Acpi) != ACPI_DP && DevicePathSubType (Acpi) != ACPI_EXTENDED_DP)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (Acpi->HID != EISA_PNP_ID (0x303) || Acpi->UID != 0) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the IO Abstraction(s) needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSioProtocolGuid,
 | |
|                   (VOID **) &Sio,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close the I/O Abstraction(s) used to perform the supported test
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiSioProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
 | |
| 
 | |
|   @param This         Pointer of EFI_DRIVER_BINDING_PROTOCOL
 | |
|   @param Controller   driver controller handle
 | |
|   @param RemainingDevicePath Children's device path
 | |
| 
 | |
|   @retval whether success to create floppy control instance.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| KbdControllerDriverStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                Status;
 | |
|   EFI_STATUS                                Status1;
 | |
|   EFI_SIO_PROTOCOL                          *Sio;
 | |
|   KEYBOARD_CONSOLE_IN_DEV                   *ConsoleIn;
 | |
|   UINT8                                     Data;
 | |
|   EFI_STATUS_CODE_VALUE                     StatusCode;
 | |
|   EFI_DEVICE_PATH_PROTOCOL                  *DevicePath;
 | |
| 
 | |
|   StatusCode = 0;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &DevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Report that the keyboard is being enabled
 | |
|   //
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,
 | |
|     DevicePath
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Get the ISA I/O Protocol on Controller's handle
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSioProtocolGuid,
 | |
|                   (VOID **) &Sio,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Allocate private data
 | |
|   //
 | |
|   ConsoleIn = AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV));
 | |
|   if (ConsoleIn == NULL) {
 | |
|     Status      = EFI_OUT_OF_RESOURCES;
 | |
|     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
|   //
 | |
|   // Setup the device instance
 | |
|   //
 | |
|   ConsoleIn->Signature              = KEYBOARD_CONSOLE_IN_DEV_SIGNATURE;
 | |
|   ConsoleIn->Handle                 = Controller;
 | |
|   (ConsoleIn->ConIn).Reset          = KeyboardEfiReset;
 | |
|   (ConsoleIn->ConIn).ReadKeyStroke  = KeyboardReadKeyStroke;
 | |
|   ConsoleIn->DataRegisterAddress    = KEYBOARD_8042_DATA_REGISTER;
 | |
|   ConsoleIn->StatusRegisterAddress  = KEYBOARD_8042_STATUS_REGISTER;
 | |
|   ConsoleIn->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
 | |
|   ConsoleIn->DevicePath             = DevicePath;
 | |
| 
 | |
|   ConsoleIn->ConInEx.Reset               = KeyboardEfiResetEx;
 | |
|   ConsoleIn->ConInEx.ReadKeyStrokeEx     = KeyboardReadKeyStrokeEx;
 | |
|   ConsoleIn->ConInEx.SetState            = KeyboardSetState;
 | |
|   ConsoleIn->ConInEx.RegisterKeyNotify   = KeyboardRegisterKeyNotify;
 | |
|   ConsoleIn->ConInEx.UnregisterKeyNotify = KeyboardUnregisterKeyNotify;
 | |
| 
 | |
|   InitializeListHead (&ConsoleIn->NotifyList);
 | |
| 
 | |
|   //
 | |
|   // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
 | |
|   // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
 | |
|   // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
 | |
|   // So instead we read status register to detect after read if KBC decode is enabled.
 | |
|   //
 | |
| 
 | |
|   //
 | |
|   // Return code is ignored on purpose.
 | |
|   //
 | |
|   if (!PcdGetBool (PcdFastPS2Detection)) {
 | |
|     KeyboardRead (ConsoleIn, &Data);
 | |
|     if ((KeyReadStatusRegister (ConsoleIn) & (KBC_PARE | KBC_TIM)) == (KBC_PARE | KBC_TIM)) {
 | |
|       //
 | |
|       // If nobody decodes KBC I/O port, it will read back as 0xFF.
 | |
|       // Check the Time-Out and Parity bit to see if it has an active KBC in system
 | |
|       //
 | |
|       Status      = EFI_DEVICE_ERROR;
 | |
|       StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
 | |
|       goto ErrorExit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Setup the WaitForKey event
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_WAIT,
 | |
|                   TPL_NOTIFY,
 | |
|                   KeyboardWaitForKey,
 | |
|                   ConsoleIn,
 | |
|                   &((ConsoleIn->ConIn).WaitForKey)
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status      = EFI_OUT_OF_RESOURCES;
 | |
|     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
|   //
 | |
|   // Setup the WaitForKeyEx event
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_WAIT,
 | |
|                   TPL_NOTIFY,
 | |
|                   KeyboardWaitForKeyEx,
 | |
|                   ConsoleIn,
 | |
|                   &(ConsoleIn->ConInEx.WaitForKeyEx)
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status      = EFI_OUT_OF_RESOURCES;
 | |
|     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
|   // Setup a periodic timer, used for reading keystrokes at a fixed interval
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   KeyboardTimerHandler,
 | |
|                   ConsoleIn,
 | |
|                   &ConsoleIn->TimerEvent
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status      = EFI_OUT_OF_RESOURCES;
 | |
|     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->SetTimer (
 | |
|                   ConsoleIn->TimerEvent,
 | |
|                   TimerPeriodic,
 | |
|                   KEYBOARD_TIMER_INTERVAL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status      = EFI_OUT_OF_RESOURCES;
 | |
|     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,
 | |
|     DevicePath
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Reset the keyboard device
 | |
|   //
 | |
|   Status = ConsoleIn->ConInEx.Reset (&ConsoleIn->ConInEx, FeaturePcdGet (PcdPs2KbdExtendedVerification));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status      = EFI_DEVICE_ERROR;
 | |
|     StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED,
 | |
|     DevicePath
 | |
|     );
 | |
| 
 | |
|   ConsoleIn->ControllerNameTable = NULL;
 | |
|   AddUnicodeString2 (
 | |
|     "eng",
 | |
|     gPs2KeyboardComponentName.SupportedLanguages,
 | |
|     &ConsoleIn->ControllerNameTable,
 | |
|     L"PS/2 Keyboard Device",
 | |
|     TRUE
 | |
|     );
 | |
|   AddUnicodeString2 (
 | |
|     "en",
 | |
|     gPs2KeyboardComponentName2.SupportedLanguages,
 | |
|     &ConsoleIn->ControllerNameTable,
 | |
|     L"PS/2 Keyboard Device",
 | |
|     FALSE
 | |
|     );
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Install protocol interfaces for the keyboard device.
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &Controller,
 | |
|                   &gEfiSimpleTextInProtocolGuid,
 | |
|                   &ConsoleIn->ConIn,
 | |
|                   &gEfiSimpleTextInputExProtocolGuid,
 | |
|                   &ConsoleIn->ConInEx,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| 
 | |
| ErrorExit:
 | |
|   //
 | |
|   // Report error code
 | |
|   //
 | |
|   if (StatusCode != 0) {
 | |
|     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|       EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|       StatusCode,
 | |
|       DevicePath
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   if ((ConsoleIn != NULL) && (ConsoleIn->ConIn.WaitForKey != NULL)) {
 | |
|     gBS->CloseEvent (ConsoleIn->ConIn.WaitForKey);
 | |
|   }
 | |
| 
 | |
|   if ((ConsoleIn != NULL) && (ConsoleIn->TimerEvent != NULL)) {
 | |
|     gBS->CloseEvent (ConsoleIn->TimerEvent);
 | |
|   }
 | |
|   if ((ConsoleIn != NULL) && (ConsoleIn->ConInEx.WaitForKeyEx != NULL)) {
 | |
|     gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
 | |
|   }
 | |
|   KbdFreeNotifyList (&ConsoleIn->NotifyList);
 | |
|   if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) {
 | |
|     FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
 | |
|   }
 | |
|   //
 | |
|   // Since there will be no timer handler for keyboard input any more,
 | |
|   // exhaust input data just in case there is still keyboard data left
 | |
|   //
 | |
|   if (ConsoleIn != NULL) {
 | |
|     Status1 = EFI_SUCCESS;
 | |
|     while (!EFI_ERROR (Status1) && (Status != EFI_DEVICE_ERROR)) {
 | |
|       Status1 = KeyboardRead (ConsoleIn, &Data);;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (ConsoleIn != NULL) {
 | |
|     gBS->FreePool (ConsoleIn);
 | |
|   }
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiSioProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Stop this driver on ControllerHandle. Support stoping any child handles
 | |
|   created by this driver.
 | |
| 
 | |
|   @param  This              Protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| KbdControllerDriverStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN  EFI_HANDLE                     Controller,
 | |
|   IN  UINTN                          NumberOfChildren,
 | |
|   IN  EFI_HANDLE                     *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                     Status;
 | |
|   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
 | |
|   KEYBOARD_CONSOLE_IN_DEV        *ConsoleIn;
 | |
|   UINT8                          Data;
 | |
| 
 | |
|   //
 | |
|   // Disable Keyboard
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSimpleTextInProtocolGuid,
 | |
|                   (VOID **) &ConIn,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSimpleTextInputExProtocolGuid,
 | |
|                   NULL,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn);
 | |
| 
 | |
|   //
 | |
|   // Report that the keyboard is being disabled
 | |
|   //
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE,
 | |
|     ConsoleIn->DevicePath
 | |
|     );
 | |
| 
 | |
|   if (ConsoleIn->TimerEvent != NULL) {
 | |
|     gBS->CloseEvent (ConsoleIn->TimerEvent);
 | |
|     ConsoleIn->TimerEvent = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Since there will be no timer handler for keyboard input any more,
 | |
|   // exhaust input data just in case there is still keyboard data left
 | |
|   //
 | |
|   Status = EFI_SUCCESS;
 | |
|   while (!EFI_ERROR (Status)) {
 | |
|     Status = KeyboardRead (ConsoleIn, &Data);;
 | |
|   }
 | |
|   //
 | |
|   // Uninstall the SimpleTextIn and SimpleTextInEx protocols
 | |
|   //
 | |
|   Status = gBS->UninstallMultipleProtocolInterfaces (
 | |
|                   Controller,
 | |
|                   &gEfiSimpleTextInProtocolGuid,
 | |
|                   &ConsoleIn->ConIn,
 | |
|                   &gEfiSimpleTextInputExProtocolGuid,
 | |
|                   &ConsoleIn->ConInEx,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiSioProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   //
 | |
|   // Free other resources
 | |
|   //
 | |
|   if ((ConsoleIn->ConIn).WaitForKey != NULL) {
 | |
|     gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey);
 | |
|     (ConsoleIn->ConIn).WaitForKey = NULL;
 | |
|   }
 | |
|   if (ConsoleIn->ConInEx.WaitForKeyEx != NULL) {
 | |
|     gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
 | |
|     ConsoleIn->ConInEx.WaitForKeyEx = NULL;
 | |
|   }
 | |
|   KbdFreeNotifyList (&ConsoleIn->NotifyList);
 | |
|   FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
 | |
|   gBS->FreePool (ConsoleIn);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free the waiting key notify list.
 | |
| 
 | |
|   @param ListHead  Pointer to list head
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  ListHead is NULL
 | |
|   @retval EFI_SUCCESS            Sucess to free NotifyList
 | |
| **/
 | |
| EFI_STATUS
 | |
| KbdFreeNotifyList (
 | |
|   IN OUT LIST_ENTRY           *ListHead
 | |
|   )
 | |
| {
 | |
|   KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
 | |
| 
 | |
|   if (ListHead == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   while (!IsListEmpty (ListHead)) {
 | |
|     NotifyNode = CR (
 | |
|                    ListHead->ForwardLink,
 | |
|                    KEYBOARD_CONSOLE_IN_EX_NOTIFY,
 | |
|                    NotifyEntry,
 | |
|                    KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
 | |
|                    );
 | |
|     RemoveEntryList (ListHead->ForwardLink);
 | |
|     gBS->FreePool (NotifyNode);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The module Entry Point for module Ps2Keyboard.
 | |
| 
 | |
|   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
 | |
|   @param[in] SystemTable    A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The entry point is executed successfully.
 | |
|   @retval other             Some error occurs when executing this entry point.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializePs2Keyboard(
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   //
 | |
|   // Install driver model protocol(s).
 | |
|   //
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gKeyboardControllerDriver,
 | |
|              ImageHandle,
 | |
|              &gPs2KeyboardComponentName,
 | |
|              &gPs2KeyboardComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |