123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /** @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>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #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 stopping 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;
- }
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- KeyNotifyProcessHandler,
- ConsoleIn,
- &ConsoleIn->KeyNotifyProcessEvent
- );
- 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);
- }
- if ((ConsoleIn != NULL) && (ConsoleIn->KeyNotifyProcessEvent != NULL)) {
- gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent);
- }
- 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 stopping 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;
- }
- if (ConsoleIn->KeyNotifyProcessEvent != NULL) {
- gBS->CloseEvent (ConsoleIn->KeyNotifyProcessEvent);
- ConsoleIn->KeyNotifyProcessEvent = 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;
- }
|