| /**@file | |
| PS/2 Keyboard driver. Routines that interacts with callers, | |
| conforming to EFI driver model | |
| Copyright (c) 2006 - 2007, Intel Corporation | |
| All rights reserved. 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 | |
| // | |
| EFI_STATUS | |
| EFIAPI | |
| KbdControllerDriverSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| KbdControllerDriverStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| KbdControllerDriverStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ); | |
| // | |
| // Global variables | |
| // | |
| // | |
| // DriverBinding Protocol Instance | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver = { | |
| KbdControllerDriverSupported, | |
| KbdControllerDriverStart, | |
| KbdControllerDriverStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| EFI_STATUS | |
| EFIAPI | |
| KbdControllerDriverSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| /*++ | |
| Routine Description: | |
| ControllerDriver Protocol Method | |
| Arguments: | |
| Returns: | |
| --*/ | |
| // GC_TODO: This - add argument and description to function comment | |
| // GC_TODO: Controller - add argument and description to function comment | |
| // GC_TODO: RemainingDevicePath - add argument and description to function comment | |
| { | |
| EFI_STATUS Status; | |
| EFI_ISA_IO_PROTOCOL *IsaIo; | |
| // | |
| // Open the IO Abstraction(s) needed to perform the supported test | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiIsaIoProtocolGuid, | |
| (VOID **) &IsaIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Use the ISA I/O Protocol to see if Controller is the Keyboard controller | |
| // | |
| if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) { | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Close the I/O Abstraction(s) used to perform the supported test | |
| // | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiIsaIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| KbdControllerDriverStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| --*/ | |
| // GC_TODO: This - add argument and description to function comment | |
| // GC_TODO: Controller - add argument and description to function comment | |
| // GC_TODO: RemainingDevicePath - add argument and description to function comment | |
| // GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS Status1; | |
| EFI_ISA_IO_PROTOCOL *IsaIo; | |
| KEYBOARD_CONSOLE_IN_DEV *ConsoleIn; | |
| UINT8 Data; | |
| EFI_STATUS_CODE_VALUE StatusCode; | |
| EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
| StatusCode = 0; | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &ParentDevicePath, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| 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, | |
| ParentDevicePath | |
| ); | |
| // | |
| // Get the ISA I/O Protocol on Controller's handle | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiIsaIoProtocolGuid, | |
| (VOID **) &IsaIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // 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->IsaIo = IsaIo; | |
| ConsoleIn->ScancodeBufStartPos = 0; | |
| ConsoleIn->ScancodeBufEndPos = KEYBOARD_BUFFER_MAX_COUNT - 1; | |
| ConsoleIn->ScancodeBufCount = 0; | |
| ConsoleIn->Ctrled = FALSE; | |
| ConsoleIn->Alted = FALSE; | |
| ConsoleIn->DevicePath = ParentDevicePath; | |
| // | |
| // Setup the WaitForKey event | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_WAIT, | |
| TPL_NOTIFY, | |
| KeyboardWaitForKey, | |
| &(ConsoleIn->ConIn), | |
| &((ConsoleIn->ConIn).WaitForKey) | |
| ); | |
| 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, | |
| ParentDevicePath | |
| ); | |
| // | |
| // Reset the keyboard device | |
| // | |
| Status = ConsoleIn->ConIn.Reset (&ConsoleIn->ConIn, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| Status = EFI_DEVICE_ERROR; | |
| StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED; | |
| goto ErrorExit; | |
| } | |
| ConsoleIn->ControllerNameTable = NULL; | |
| AddUnicodeString ( | |
| "eng", | |
| gPs2KeyboardComponentName.SupportedLanguages, | |
| &ConsoleIn->ControllerNameTable, | |
| L"PS/2 Keyboard Device" | |
| ); | |
| // | |
| // Install protocol interfaces for the keyboard device. | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &Controller, | |
| &gEfiSimpleTextInProtocolGuid, | |
| &ConsoleIn->ConIn, | |
| 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, | |
| ParentDevicePath | |
| ); | |
| } | |
| 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->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 | |
| // | |
| Status1 = EFI_SUCCESS; | |
| while (!EFI_ERROR (Status1)) { | |
| Status1 = KeyboardRead (ConsoleIn, &Data);; | |
| } | |
| if (ConsoleIn != NULL) { | |
| gBS->FreePool (ConsoleIn); | |
| } | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiIsaIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| KbdControllerDriverStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| --*/ | |
| // GC_TODO: This - add argument and description to function comment | |
| // GC_TODO: Controller - add argument and description to function comment | |
| // GC_TODO: NumberOfChildren - add argument and description to function comment | |
| // GC_TODO: ChildHandleBuffer - add argument and description to function comment | |
| // GC_TODO: EFI_SUCCESS - add return value to function comment | |
| { | |
| 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; | |
| } | |
| 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) { | |
| gBS->CloseEvent (ConsoleIn->TimerEvent); | |
| ConsoleIn->TimerEvent = NULL; | |
| } | |
| // | |
| // Disable the keyboard interface | |
| // | |
| Status = DisableKeyboard (ConsoleIn); | |
| // | |
| // 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 Simple TextIn Protocol | |
| // | |
| Status = gBS->UninstallProtocolInterface ( | |
| Controller, | |
| &gEfiSimpleTextInProtocolGuid, | |
| &ConsoleIn->ConIn | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiIsaIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| // | |
| // Free other resources | |
| // | |
| if ((ConsoleIn->ConIn).WaitForKey) { | |
| gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey); | |
| (ConsoleIn->ConIn).WaitForKey = NULL; | |
| } | |
| FreeUnicodeStringTable (ConsoleIn->ControllerNameTable); | |
| gBS->FreePool (ConsoleIn); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| The user Entry Point for module Ps2Keyboard. The user code starts with this function. | |
| @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 = EfiLibInstallAllDriverProtocols ( | |
| ImageHandle, | |
| SystemTable, | |
| &gKeyboardControllerDriver, | |
| ImageHandle, | |
| &gPs2KeyboardComponentName, | |
| NULL, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |