-/** @file\r
- ConsoleOut Routines that speak VGA.\r
-\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "BiosKeyboard.h"\r
-\r
-//\r
-// EFI Driver Binding Protocol Instance\r
-//\r
-EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {\r
- BiosKeyboardDriverBindingSupported,\r
- BiosKeyboardDriverBindingStart,\r
- BiosKeyboardDriverBindingStop,\r
- 0x3,\r
- NULL,\r
- NULL\r
-};\r
-\r
-\r
-/**\r
- Enqueue the key.\r
-\r
- @param Queue The queue to be enqueued.\r
- @param KeyData The key data to be enqueued.\r
-\r
- @retval EFI_NOT_READY The queue is full.\r
- @retval EFI_SUCCESS Successfully enqueued the key data.\r
-\r
-**/\r
-EFI_STATUS\r
-Enqueue (\r
- IN SIMPLE_QUEUE *Queue,\r
- IN EFI_KEY_DATA *KeyData\r
- )\r
-{\r
- if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
- Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Dequeue the key.\r
-\r
- @param Queue The queue to be dequeued.\r
- @param KeyData The key data to be dequeued.\r
-\r
- @retval EFI_NOT_READY The queue is empty.\r
- @retval EFI_SUCCESS Successfully dequeued the key data.\r
-\r
-**/\r
-EFI_STATUS\r
-Dequeue (\r
- IN SIMPLE_QUEUE *Queue,\r
- IN EFI_KEY_DATA *KeyData\r
- )\r
-{\r
- if (Queue->Front == Queue->Rear) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));\r
- Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Check whether the queue is empty.\r
-\r
- @param Queue The queue to be checked.\r
-\r
- @retval EFI_NOT_READY The queue is empty.\r
- @retval EFI_SUCCESS The queue is not empty.\r
-\r
-**/\r
-EFI_STATUS\r
-CheckQueue (\r
- IN SIMPLE_QUEUE *Queue\r
- )\r
-{\r
- if (Queue->Front == Queue->Rear) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// EFI Driver Binding Protocol Functions\r
-//\r
-\r
-/**\r
- Check whether the driver supports this device.\r
-\r
- @param This The Udriver binding protocol.\r
- @param Controller The controller handle to check.\r
- @param RemainingDevicePath The remaining device path.\r
-\r
- @retval EFI_SUCCESS The driver supports this controller.\r
- @retval other This device isn't supported.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardDriverBindingSupported (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
- EFI_ISA_IO_PROTOCOL *IsaIo;\r
-\r
- //\r
- // See if the Legacy BIOS Protocol is available\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiLegacyBiosProtocolGuid,\r
- NULL,\r
- (VOID **) &LegacyBios\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Open the IO Abstraction(s) needed to perform the supported test\r
- //\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiIsaIoProtocolGuid,\r
- (VOID **) &IsaIo,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Use the ISA I/O Protocol to see if Controller is the Keyboard controller\r
- //\r
- if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {\r
- Status = EFI_UNSUPPORTED;\r
- }\r
-\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiIsaIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Starts the device with this driver.\r
-\r
- @param This The driver binding instance.\r
- @param Controller Handle of device to bind driver to.\r
- @param RemainingDevicePath Optional parameter use to pick a specific child\r
- device to start.\r
-\r
- @retval EFI_SUCCESS The controller is controlled by the driver.\r
- @retval Other This controller cannot be started.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardDriverBindingStart (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
- EFI_ISA_IO_PROTOCOL *IsaIo;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_IA32_REGISTER_SET Regs;\r
- BOOLEAN CarryFlag;\r
- EFI_PS2_POLICY_PROTOCOL *Ps2Policy;\r
- UINT8 Command;\r
- EFI_STATUS_CODE_VALUE StatusCode;\r
-\r
- BiosKeyboardPrivate = NULL;\r
- IsaIo = NULL;\r
- StatusCode = 0;\r
-\r
- //\r
- // Get Ps2 policy to set. Will be use if present.\r
- //\r
- gBS->LocateProtocol (\r
- &gEfiPs2PolicyProtocolGuid,\r
- NULL,\r
- (VOID **) &Ps2Policy\r
- );\r
-\r
- //\r
- // See if the Legacy BIOS Protocol is available\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiLegacyBiosProtocolGuid,\r
- NULL,\r
- (VOID **) &LegacyBios\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Open the IO Abstraction(s) needed\r
- //\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiIsaIoProtocolGuid,\r
- (VOID **) &IsaIo,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Allocate the private device structure\r
- //\r
- BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));\r
- if (NULL == BiosKeyboardPrivate) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
-\r
- //\r
- // Initialize the private device structure\r
- //\r
- BiosKeyboardPrivate->Signature = BIOS_KEYBOARD_DEV_SIGNATURE;\r
- BiosKeyboardPrivate->Handle = Controller;\r
- BiosKeyboardPrivate->LegacyBios = LegacyBios;\r
- BiosKeyboardPrivate->IsaIo = IsaIo;\r
-\r
- BiosKeyboardPrivate->SimpleTextIn.Reset = BiosKeyboardReset;\r
- BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;\r
-\r
- BiosKeyboardPrivate->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;\r
- BiosKeyboardPrivate->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;\r
- BiosKeyboardPrivate->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;\r
- BiosKeyboardPrivate->ExtendedKeyboard = TRUE;\r
-\r
- BiosKeyboardPrivate->KeyState.KeyShiftState = 0;\r
- BiosKeyboardPrivate->KeyState.KeyToggleState = 0;\r
- BiosKeyboardPrivate->Queue.Front = 0;\r
- BiosKeyboardPrivate->Queue.Rear = 0;\r
- BiosKeyboardPrivate->QueueForNotify.Front = 0;\r
- BiosKeyboardPrivate->QueueForNotify.Rear = 0;\r
- BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx;\r
- BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx;\r
- BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState;\r
- BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = BiosKeyboardRegisterKeyNotify;\r
- BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;\r
- InitializeListHead (&BiosKeyboardPrivate->NotifyList);\r
-\r
- //\r
- // Report that the keyboard is being enabled\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE\r
- );\r
-\r
- //\r
- // Setup the WaitForKey event\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_WAIT,\r
- TPL_NOTIFY,\r
- BiosKeyboardWaitForKey,\r
- &(BiosKeyboardPrivate->SimpleTextIn),\r
- &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)\r
- );\r
- if (EFI_ERROR (Status)) {\r
- (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;\r
- goto Done;\r
- }\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_WAIT,\r
- TPL_NOTIFY,\r
- BiosKeyboardWaitForKeyEx,\r
- &(BiosKeyboardPrivate->SimpleTextInputEx),\r
- &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)\r
- );\r
- if (EFI_ERROR (Status)) {\r
- BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;\r
- goto Done;\r
- }\r
-\r
- //\r
- // Setup a periodic timer, used for reading keystrokes at a fixed interval\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
- TPL_NOTIFY,\r
- BiosKeyboardTimerHandler,\r
- BiosKeyboardPrivate,\r
- &BiosKeyboardPrivate->TimerEvent\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
- goto Done;\r
- }\r
-\r
- Status = gBS->SetTimer (\r
- BiosKeyboardPrivate->TimerEvent,\r
- TimerPeriodic,\r
- KEYBOARD_TIMER_INTERVAL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
- goto Done;\r
- }\r
-\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- KeyNotifyProcessHandler,\r
- BiosKeyboardPrivate,\r
- &BiosKeyboardPrivate->KeyNotifyProcessEvent\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
- goto Done;\r
- }\r
-\r
- //\r
- // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT\r
- );\r
-\r
- //\r
- // Reset the keyboard device\r
- //\r
- Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (\r
- &BiosKeyboardPrivate->SimpleTextInputEx,\r
- FeaturePcdGet (PcdPs2KbdExtendedVerification)\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));\r
- StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;\r
- goto Done;\r
- }\r
- //\r
- // Do platform specific policy like port swapping and keyboard light default\r
- //\r
- if (Ps2Policy != NULL) {\r
-\r
- Ps2Policy->Ps2InitHardware (Controller);\r
-\r
- Command = 0;\r
- if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {\r
- Command |= 4;\r
- }\r
-\r
- if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {\r
- Command |= 2;\r
- }\r
-\r
- if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {\r
- Command |= 1;\r
- }\r
-\r
- KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
- KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
- KeyboardWrite (BiosKeyboardPrivate, Command);\r
- //\r
- // Call Legacy BIOS Protocol to set whatever is necessary\r
- //\r
- LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);\r
- }\r
- //\r
- // Get Configuration\r
- //\r
- Regs.H.AH = 0xc0;\r
- CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (\r
- BiosKeyboardPrivate->LegacyBios,\r
- 0x15,\r
- &Regs\r
- );\r
-\r
- if (!CarryFlag) {\r
- //\r
- // Check bit 6 of Feature Byte 2.\r
- // If it is set, then Int 16 Func 09 is supported\r
- //\r
- if (*(UINT8 *) (((UINTN) Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
- //\r
- // Get Keyboard Functionality\r
- //\r
- Regs.H.AH = 0x09;\r
- CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (\r
- BiosKeyboardPrivate->LegacyBios,\r
- 0x16,\r
- &Regs\r
- );\r
-\r
- if (!CarryFlag) {\r
- //\r
- // Check bit 5 of AH.\r
- // If it is set, then INT 16 Finc 10-12 are supported.\r
- //\r
- if ((Regs.H.AL & 0x40) != 0) {\r
- //\r
- // Set the flag to use INT 16 Func 10-12\r
- //\r
- BiosKeyboardPrivate->ExtendedKeyboard = TRUE;\r
- }\r
- }\r
- }\r
- }\r
- DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard));\r
- //\r
- // Install protocol interfaces for the keyboard device.\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &Controller,\r
- &gEfiSimpleTextInProtocolGuid,\r
- &BiosKeyboardPrivate->SimpleTextIn,\r
- &gEfiSimpleTextInputExProtocolGuid,\r
- &BiosKeyboardPrivate->SimpleTextInputEx,\r
- NULL\r
- );\r
-\r
-Done:\r
- if (StatusCode != 0) {\r
- //\r
- // Report an Error Code for failing to start the keyboard device\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- StatusCode\r
- );\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
-\r
- if (BiosKeyboardPrivate != NULL) {\r
- if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {\r
- gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
- }\r
-\r
- if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {\r
- gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);\r
- }\r
-\r
- if (BiosKeyboardPrivate->KeyNotifyProcessEvent != NULL) {\r
- gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
- }\r
-\r
- BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
-\r
- if (BiosKeyboardPrivate->TimerEvent != NULL) {\r
- gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
- }\r
-\r
- FreePool (BiosKeyboardPrivate);\r
- }\r
-\r
- if (IsaIo != NULL) {\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiIsaIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Stop the device handled by this driver.\r
-\r
- @param This The driver binding protocol.\r
- @param Controller The controller to release.\r
- @param NumberOfChildren The number of handles in ChildHandleBuffer.\r
- @param ChildHandleBuffer The array of child handle.\r
-\r
- @retval EFI_SUCCESS The device was stopped.\r
- @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
- @retval Others Fail to uninstall protocols attached on the device.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardDriverBindingStop (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE Controller,\r
- IN UINTN NumberOfChildren,\r
- IN EFI_HANDLE *ChildHandleBuffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
-\r
- //\r
- // Disable Keyboard\r
- //\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiSimpleTextInProtocolGuid,\r
- (VOID **) &SimpleTextIn,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = gBS->OpenProtocol (\r
- Controller,\r
- &gEfiSimpleTextInputExProtocolGuid,\r
- NULL,\r
- This->DriverBindingHandle,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);\r
-\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- Controller,\r
- &gEfiSimpleTextInProtocolGuid,\r
- &BiosKeyboardPrivate->SimpleTextIn,\r
- &gEfiSimpleTextInputExProtocolGuid,\r
- &BiosKeyboardPrivate->SimpleTextInputEx,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Release the IsaIo protocol on the controller handle\r
- //\r
- gBS->CloseProtocol (\r
- Controller,\r
- &gEfiIsaIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- Controller\r
- );\r
-\r
- //\r
- // Free other resources\r
- //\r
- gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
- gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
- gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);\r
- gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
- BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
-\r
- FreePool (BiosKeyboardPrivate);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
-\r
- @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.\r
-\r
-**/\r
-UINT8\r
-KeyReadDataRegister (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate\r
- )\r
-{\r
- UINT8 Data;\r
-\r
- //\r
- // Use IsaIo protocol to perform IO operations\r
- //\r
- BiosKeyboardPrivate->IsaIo->Io.Read (\r
- BiosKeyboardPrivate->IsaIo,\r
- EfiIsaIoWidthUint8,\r
- BiosKeyboardPrivate->DataRegisterAddress,\r
- 1,\r
- &Data\r
- );\r
-\r
- return Data;\r
-}\r
-\r
-/**\r
- Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
-\r
- @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.\r
-\r
-**/\r
-UINT8\r
-KeyReadStatusRegister (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate\r
- )\r
-{\r
- UINT8 Data;\r
-\r
- //\r
- // Use IsaIo protocol to perform IO operations\r
- //\r
- BiosKeyboardPrivate->IsaIo->Io.Read (\r
- BiosKeyboardPrivate->IsaIo,\r
- EfiIsaIoWidthUint8,\r
- BiosKeyboardPrivate->StatusRegisterAddress,\r
- 1,\r
- &Data\r
- );\r
-\r
- return Data;\r
-}\r
-\r
-/**\r
- Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
- @param Data Data byte to write.\r
-\r
-**/\r
-VOID\r
-KeyWriteCommandRegister (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- IN UINT8 Data\r
- )\r
-{\r
- //\r
- // Use IsaIo protocol to perform IO operations\r
- //\r
- BiosKeyboardPrivate->IsaIo->Io.Write (\r
- BiosKeyboardPrivate->IsaIo,\r
- EfiIsaIoWidthUint8,\r
- BiosKeyboardPrivate->CommandRegisterAddress,\r
- 1,\r
- &Data\r
- );\r
-}\r
-\r
-/**\r
- Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
- @param Data Data byte to write.\r
-\r
-**/\r
-VOID\r
-KeyWriteDataRegister (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- IN UINT8 Data\r
- )\r
-{\r
- //\r
- // Use IsaIo protocol to perform IO operations\r
- //\r
- BiosKeyboardPrivate->IsaIo->Io.Write (\r
- BiosKeyboardPrivate->IsaIo,\r
- EfiIsaIoWidthUint8,\r
- BiosKeyboardPrivate->DataRegisterAddress,\r
- 1,\r
- &Data\r
- );\r
-}\r
-\r
-/**\r
- Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
- @param Data The pointer for data that being read out.\r
-\r
- @retval EFI_SUCCESS The data byte read out successfully.\r
- @retval EFI_TIMEOUT Timeout occurred during reading out data byte.\r
-\r
-**/\r
-EFI_STATUS\r
-KeyboardRead (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- OUT UINT8 *Data\r
- )\r
-{\r
- UINT32 TimeOut;\r
- UINT32 RegFilled;\r
-\r
- TimeOut = 0;\r
- RegFilled = 0;\r
-\r
- //\r
- // wait till output buffer full then perform the read\r
- //\r
- for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {\r
- RegFilled = 1;\r
- *Data = KeyReadDataRegister (BiosKeyboardPrivate);\r
- break;\r
- }\r
-\r
- gBS->Stall (30);\r
- }\r
-\r
- if (RegFilled == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
- @param Data Data byte to write.\r
-\r
- @retval EFI_SUCCESS The data byte is written successfully.\r
- @retval EFI_TIMEOUT Timeout occurred during writing.\r
-\r
-**/\r
-EFI_STATUS\r
-KeyboardWrite (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- IN UINT8 Data\r
- )\r
-{\r
- UINT32 TimeOut;\r
- UINT32 RegEmptied;\r
-\r
- TimeOut = 0;\r
- RegEmptied = 0;\r
-\r
- //\r
- // wait for input buffer empty\r
- //\r
- for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
- RegEmptied = 1;\r
- break;\r
- }\r
-\r
- gBS->Stall (30);\r
- }\r
-\r
- if (RegEmptied == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
- //\r
- // Write it\r
- //\r
- KeyWriteDataRegister (BiosKeyboardPrivate, Data);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
- @param Data Command byte to write.\r
-\r
- @retval EFI_SUCCESS The command byte is written successfully.\r
- @retval EFI_TIMEOUT Timeout occurred during writing.\r
-\r
-**/\r
-EFI_STATUS\r
-KeyboardCommand (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- IN UINT8 Data\r
- )\r
-{\r
- UINT32 TimeOut;\r
- UINT32 RegEmptied;\r
-\r
- TimeOut = 0;\r
- RegEmptied = 0;\r
-\r
- //\r
- // Wait For Input Buffer Empty\r
- //\r
- for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
- RegEmptied = 1;\r
- break;\r
- }\r
-\r
- gBS->Stall (30);\r
- }\r
-\r
- if (RegEmptied == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
- //\r
- // issue the command\r
- //\r
- KeyWriteCommandRegister (BiosKeyboardPrivate, Data);\r
-\r
- //\r
- // Wait For Input Buffer Empty again\r
- //\r
- RegEmptied = 0;\r
- for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
- RegEmptied = 1;\r
- break;\r
- }\r
-\r
- gBS->Stall (30);\r
- }\r
-\r
- if (RegEmptied == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Wait for a specific value to be presented in\r
- Data register of Keyboard Controller by keyboard and then read it,\r
- used in keyboard commands ack\r
-\r
- @param BiosKeyboardPrivate Keyboard instance pointer.\r
- @param Value The value to be waited for\r
- @param WaitForValueTimeOut The limit of microseconds for timeout\r
-\r
- @retval EFI_SUCCESS The command byte is written successfully.\r
- @retval EFI_TIMEOUT Timeout occurred during writing.\r
-\r
-**/\r
-EFI_STATUS\r
-KeyboardWaitForValue (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- IN UINT8 Value,\r
- IN UINTN WaitForValueTimeOut\r
- )\r
-{\r
- UINT8 Data;\r
- UINT32 TimeOut;\r
- UINT32 SumTimeOut;\r
- UINT32 GotIt;\r
-\r
- GotIt = 0;\r
- TimeOut = 0;\r
- SumTimeOut = 0;\r
-\r
- //\r
- // Make sure the initial value of 'Data' is different from 'Value'\r
- //\r
- Data = 0;\r
- if (Data == Value) {\r
- Data = 1;\r
- }\r
- //\r
- // Read from 8042 (multiple times if needed)\r
- // until the expected value appears\r
- // use SumTimeOut to control the iteration\r
- //\r
- while (1) {\r
- //\r
- // Perform a read\r
- //\r
- for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {\r
- Data = KeyReadDataRegister (BiosKeyboardPrivate);\r
- break;\r
- }\r
-\r
- gBS->Stall (30);\r
- }\r
-\r
- SumTimeOut += TimeOut;\r
-\r
- if (Data == Value) {\r
- GotIt = 1;\r
- break;\r
- }\r
-\r
- if (SumTimeOut >= WaitForValueTimeOut) {\r
- break;\r
- }\r
- }\r
- //\r
- // Check results\r
- //\r
- if (GotIt != 0) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
-}\r
-\r
-/**\r
- Reads the next keystroke from the input device. The WaitForKey Event can\r
- be used to test for existance of a keystroke via WaitForEvent () call.\r
-\r
- @param BiosKeyboardPrivate Bioskeyboard driver private structure.\r
- @param KeyData A pointer to a buffer that is filled in with the keystroke\r
- state data for the key that was pressed.\r
-\r
- @retval EFI_SUCCESS The keystroke information was returned.\r
- @retval EFI_NOT_READY There was no keystroke data availiable.\r
- @retval EFI_DEVICE_ERROR The keystroke information was not returned due to\r
- hardware errors.\r
- @retval EFI_INVALID_PARAMETER KeyData is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-KeyboardReadKeyStrokeWorker (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
- OUT EFI_KEY_DATA *KeyData\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_TPL OldTpl;\r
- if (KeyData == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Use TimerEvent callback function to check whether there's any key pressed\r
- //\r
-\r
- //\r
- // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.\r
- // Csm will be used to check whether there is a key pending, but the csm will disable all\r
- // interrupt before switch to compatibility16, which mean all the efiCompatibility timer\r
- // event will stop work during the compatibility16. And If a caller recursivly invoke this function,\r
- // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,\r
- // e.g. usb keyboard driver.\r
- // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.\r
- // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.\r
- //\r
- gBS->Stall (1000);\r
-\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);\r
- //\r
- // If there's no key, just return\r
- //\r
- Status = CheckQueue (&BiosKeyboardPrivate->Queue);\r
- if (EFI_ERROR (Status)) {\r
- ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
- CopyMem (&KeyData->KeyState, &BiosKeyboardPrivate->KeyState, sizeof (EFI_KEY_STATE));\r
- gBS->RestoreTPL (OldTpl);\r
- return EFI_NOT_READY;\r
- }\r
-\r
- Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);\r
-\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// EFI Simple Text In Protocol Functions\r
-//\r
-/**\r
- Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.\r
-\r
- @param This Pointer of simple text Protocol.\r
- @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
-\r
- @retval EFI_SUCCESS The command byte is written successfully.\r
- @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardReset (\r
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
- IN BOOLEAN ExtendedVerification\r
- )\r
-{\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_STATUS Status;\r
- EFI_TPL OldTpl;\r
- UINT8 CommandByte;\r
- BOOLEAN MouseEnable;\r
- EFI_INPUT_KEY Key;\r
-\r
- MouseEnable = FALSE;\r
- BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- //\r
- // 1\r
- // Report reset progress code\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET\r
- );\r
-\r
- //\r
- // Report a Progress Code for clearing the keyboard buffer\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER\r
- );\r
-\r
- //\r
- // 2\r
- // Raise TPL to avoid mouse operation impact\r
- //\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- //\r
- //\r
- // Exhaust output buffer data\r
- //\r
- do {\r
- Status = BiosKeyboardReadKeyStroke (\r
- This,\r
- &Key\r
- );\r
- } while (!EFI_ERROR (Status));\r
- //\r
- // 3\r
- // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H\r
- // if not skip step 4&5 and jump to step 6 to selftest KBC and report this\r
- // else go step 4\r
- //\r
- if (!PcdGetBool (PcdFastPS2Detection)) {\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {\r
- //\r
- // 4\r
- // CheckMouseStatus to decide enable it later or not\r
- //\r
- //\r
- // Read the command byte of KBC\r
- //\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_CMDBYTE_R\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardRead (\r
- BiosKeyboardPrivate,\r
- &CommandByte\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- //\r
- // Check mouse enabled or not before\r
- //\r
- if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {\r
- MouseEnable = FALSE;\r
- } else {\r
- MouseEnable = TRUE;\r
- }\r
- //\r
- // 5\r
- // disable mouse (via KBC) and Keyborad device\r
- //\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_AUX_DISABLE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_KB_DISABLE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- } else {\r
- //\r
- // 6\r
- // KBC Self Test\r
- //\r
- //\r
- // Report a Progress Code for performing a self test on the keyboard controller\r
- //\r
- REPORT_STATUS_CODE (\r
- EFI_PROGRESS_CODE,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST\r
- );\r
-\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_KBC_SLFTEST\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_KBCSLFTEST_OK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- }\r
- }\r
- //\r
- // 7\r
- // Disable Mouse interface, enable Keyboard interface and declare selftest success\r
- //\r
- // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.\r
- //\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_CMDBYTE_W\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- //\r
- // Write 8042 Command Byte, set System Flag\r
- // While at the same time:\r
- // 1. disable mouse interface,\r
- // 2. enable kbd interface,\r
- // 3. enable PC/XT kbd translation mode\r
- // 4. enable mouse and kbd interrupts\r
- //\r
- //Command Byte bits:\r
- // 7: Reserved\r
- // 6: PC/XT translation mode\r
- // 5: Disable Auxiliary device interface\r
- // 4: Disable keyboard interface\r
- // 3: Reserved\r
- // 2: System Flag\r
- // 1: Enable Auxiliary device interrupt\r
- // 0: Enable Keyboard interrupt\r
- //\r
- CommandByte = 0;\r
- Status = KeyboardWrite (\r
- BiosKeyboardPrivate,\r
- (UINT8) ((CommandByte &\r
- (~KB_CMMBYTE_DISABLE_KB)) |\r
- KB_CMMBYTE_KSCAN2UNI_COV |\r
- KB_CMMBYTE_ENABLE_AUXINT |\r
- KB_CMMBYTE_ENABLE_KBINT |\r
- KB_CMMBYTE_SLFTEST_SUCC |\r
- KB_CMMBYTE_DISABLE_AUX)\r
- );\r
-\r
- //\r
- // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
- // so we only do the real resetting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
- // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,\r
- // Real reset will not do.\r
- //\r
- if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {\r
- //\r
- // 8\r
- // Send keyboard reset command then read ACK\r
- //\r
- Status = KeyboardWrite (\r
- BiosKeyboardPrivate,\r
- KBC_INPBUF_VIA60_KBRESET\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_ACK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- //\r
- // 9\r
- // Wait for keyboard return test OK.\r
- //\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_BATTEST_OK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- //\r
- // 10\r
- // set keyboard scan code set = 02 (standard configuration)\r
- //\r
- Status = KeyboardWrite (\r
- BiosKeyboardPrivate,\r
- KBC_INPBUF_VIA60_KBSCODE\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_ACK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWrite (\r
- BiosKeyboardPrivate,\r
- KBC_INPBUF_VIA60_SCODESET2\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_ACK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- //\r
- // 11\r
- // enable keyboard itself (not via KBC) by writing CMD F4 via 60H\r
- //\r
- Status = KeyboardWrite (\r
- BiosKeyboardPrivate,\r
- KBC_INPBUF_VIA60_KBEN\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_ACK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- //\r
- // 12\r
- // Additional validation, do it as follow:\r
- // 1). check for status register of PARE && TIM via 64H\r
- // 2). perform KB checking by writing ABh via 64H\r
- //\r
- if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_KB_CKECK\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_KBCHECK_OK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- }\r
- //\r
- // 13\r
- // Done for validating keyboard. Enable keyboard (via KBC)\r
- // and recover the command byte to proper value\r
- //\r
- if (!PcdGetBool (PcdFastPS2Detection)) {\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_KB_ENABLE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- }\r
-\r
- //\r
- // 14\r
- // conditionally enable mouse (via KBC)\r
- //\r
- if (MouseEnable) {\r
- Status = KeyboardCommand (\r
- BiosKeyboardPrivate,\r
- KBC_CMDREG_VIA64_AUX_ENABLE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
-\r
- }\r
- }\r
-\r
-Exit:\r
- //\r
- // 15\r
- // resume priority of task level\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return Status;\r
-\r
-}\r
-\r
-/**\r
- Read out the scan code of the key that has just been stroked.\r
-\r
- @param This Pointer of simple text Protocol.\r
- @param Key Pointer for store the key that read out.\r
-\r
- @retval EFI_SUCCESS The key is read out successfully.\r
- @retval other The key reading failed.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardReadKeyStroke (\r
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
- OUT EFI_INPUT_KEY *Key\r
- )\r
-{\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_STATUS Status;\r
- EFI_KEY_DATA KeyData;\r
-\r
- BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Convert the Ctrl+[a-z] to Ctrl+[1-26]\r
- //\r
- if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
- if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
- KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
- } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
- KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
- }\r
- }\r
-\r
- CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
-\r
- @param Event The event that be siganlled when any key has been stroked.\r
- @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-BiosKeyboardWaitForKey (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- //\r
- // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.\r
- // Csm will be used to check whether there is a key pending, but the csm will disable all\r
- // interrupt before switch to compatibility16, which mean all the efiCompatibility timer\r
- // event will stop work during the compatibility16. And If a caller recursivly invoke this function,\r
- // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,\r
- // e.g. usb keyboard driver.\r
- // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.\r
- // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.\r
- //\r
- gBS->Stall (1000);\r
- //\r
- // Use TimerEvent callback function to check whether there's any key pressed\r
- //\r
- BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));\r
-\r
- if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {\r
- gBS->SignalEvent (Event);\r
- }\r
-}\r
-\r
-/**\r
- Check key buffer to get the key stroke status.\r
-\r
- @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.\r
-\r
- @retval EFI_SUCCESS A key is being pressed now.\r
- @retval Other No key is now pressed.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardCheckForKey (\r
- IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This\r
- )\r
-{\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
-\r
- BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- return CheckQueue (&BiosKeyboardPrivate->Queue);\r
-}\r
-//\r
-// Private worker functions\r
-//\r
-#define TABLE_END 0x0\r
-\r
-typedef struct _CONVERT_TABLE_ENTRY {\r
- UINT16 ScanCode;\r
- UINT16 EfiScanCode;\r
-} CONVERT_TABLE_ENTRY;\r
-\r
-CONVERT_TABLE_ENTRY mConvertTable[] = {\r
- {\r
- 0x47,\r
- SCAN_HOME\r
- },\r
- {\r
- 0x48,\r
- SCAN_UP\r
- },\r
- {\r
- 0x49,\r
- SCAN_PAGE_UP\r
- },\r
- {\r
- 0x4b,\r
- SCAN_LEFT\r
- },\r
- {\r
- 0x4d,\r
- SCAN_RIGHT\r
- },\r
- {\r
- 0x4f,\r
- SCAN_END\r
- },\r
- {\r
- 0x50,\r
- SCAN_DOWN\r
- },\r
- {\r
- 0x51,\r
- SCAN_PAGE_DOWN\r
- },\r
- {\r
- 0x52,\r
- SCAN_INSERT\r
- },\r
- {\r
- 0x53,\r
- SCAN_DELETE\r
- },\r
- //\r
- // Function Keys are only valid if KeyChar == 0x00\r
- // This function does not require KeyChar to be 0x00\r
- //\r
- {\r
- 0x3b,\r
- SCAN_F1\r
- },\r
- {\r
- 0x3c,\r
- SCAN_F2\r
- },\r
- {\r
- 0x3d,\r
- SCAN_F3\r
- },\r
- {\r
- 0x3e,\r
- SCAN_F4\r
- },\r
- {\r
- 0x3f,\r
- SCAN_F5\r
- },\r
- {\r
- 0x40,\r
- SCAN_F6\r
- },\r
- {\r
- 0x41,\r
- SCAN_F7\r
- },\r
- {\r
- 0x42,\r
- SCAN_F8\r
- },\r
- {\r
- 0x43,\r
- SCAN_F9\r
- },\r
- {\r
- 0x44,\r
- SCAN_F10\r
- },\r
- {\r
- 0x85,\r
- SCAN_F11\r
- },\r
- {\r
- 0x86,\r
- SCAN_F12\r
- },\r
- //\r
- // Convert ALT + Fn keys\r
- //\r
- {\r
- 0x68,\r
- SCAN_F1\r
- },\r
- {\r
- 0x69,\r
- SCAN_F2\r
- },\r
- {\r
- 0x6a,\r
- SCAN_F3\r
- },\r
- {\r
- 0x6b,\r
- SCAN_F4\r
- },\r
- {\r
- 0x6c,\r
- SCAN_F5\r
- },\r
- {\r
- 0x6d,\r
- SCAN_F6\r
- },\r
- {\r
- 0x6e,\r
- SCAN_F7\r
- },\r
- {\r
- 0x6f,\r
- SCAN_F8\r
- },\r
- {\r
- 0x70,\r
- SCAN_F9\r
- },\r
- {\r
- 0x71,\r
- SCAN_F10\r
- },\r
- {\r
- TABLE_END,\r
- SCAN_NULL\r
- },\r
-};\r
-\r
-/**\r
- Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.\r
-\r
- @param KeyChar Unicode of key.\r
- @param ScanCode Scan code of key.\r
-\r
- @return The value of EFI Scancode for the key.\r
- @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.\r
-\r
-**/\r
-UINT16\r
-ConvertToEFIScanCode (\r
- IN CHAR16 KeyChar,\r
- IN UINT16 ScanCode\r
- )\r
-{\r
- UINT16 EfiScanCode;\r
- UINT16 Index;\r
-\r
- if (KeyChar == CHAR_ESC) {\r
- EfiScanCode = SCAN_ESC;\r
- } else if (KeyChar == 0x00 || KeyChar == 0xe0) {\r
- //\r
- // Movement & Function Keys\r
- //\r
- for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {\r
- if (ScanCode == mConvertTable[Index].ScanCode) {\r
- return mConvertTable[Index].EfiScanCode;\r
- }\r
- }\r
- //\r
- // Reach Table end, return default value\r
- //\r
- return SCAN_NULL;\r
- } else {\r
- return SCAN_NULL;\r
- }\r
-\r
- return EfiScanCode;\r
-}\r
-\r
-/**\r
- Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command\r
- If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device\r
- should not be in system.\r
-\r
- @param BiosKeyboardPrivate Keyboard Private Data Struture\r
-\r
- @retval TRUE Keyboard in System.\r
- @retval FALSE Keyboard not in System.\r
-\r
-**/\r
-BOOLEAN\r
-CheckKeyboardConnect (\r
- IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- Status = EFI_SUCCESS;\r
- //\r
- // enable keyboard itself and wait for its ack\r
- // If can't receive ack, Keyboard should not be connected.\r
- //\r
- if (!PcdGetBool (PcdFastPS2Detection)) {\r
- Status = KeyboardWrite (\r
- BiosKeyboardPrivate,\r
- KBC_INPBUF_VIA60_KBEN\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR\r
- );\r
- return FALSE;\r
- }\r
-\r
- Status = KeyboardWaitForValue (\r
- BiosKeyboardPrivate,\r
- KBC_CMDECHO_ACK,\r
- KEYBOARD_WAITFORVALUE_TIMEOUT\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));\r
- REPORT_STATUS_CODE (\r
- EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
- EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR\r
- );\r
- return FALSE;\r
- }\r
- return TRUE;\r
- } else {\r
- return TRUE;\r
- }\r
-}\r
-\r
-/**\r
- Timer event handler: read a series of key stroke from 8042\r
- and put them into memory key buffer.\r
- It is registered as running under TPL_NOTIFY\r
-\r
- @param Event The timer event\r
- @param Context A BIOS_KEYBOARD_DEV pointer\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-BiosKeyboardTimerHandler (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_TPL OldTpl;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_IA32_REGISTER_SET Regs;\r
- UINT8 KbFlag1; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
- UINT8 KbFlag2; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2\r
- EFI_KEY_DATA KeyData;\r
- LIST_ENTRY *Link;\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
-\r
- BiosKeyboardPrivate = Context;\r
-\r
- //\r
- // Enter critical section\r
- //\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- //\r
- // if there is no key present, just return\r
- //\r
- if (BiosKeyboardPrivate->ExtendedKeyboard) {\r
- Regs.H.AH = 0x11;\r
- } else {\r
- Regs.H.AH = 0x01;\r
- }\r
-\r
- BiosKeyboardPrivate->LegacyBios->Int86 (\r
- BiosKeyboardPrivate->LegacyBios,\r
- 0x16,\r
- &Regs\r
- );\r
- if (Regs.X.Flags.ZF != 0) {\r
- gBS->RestoreTPL (OldTpl);\r
- return;\r
- }\r
-\r
- //\r
- // Read the key\r
- //\r
- if (BiosKeyboardPrivate->ExtendedKeyboard) {\r
- Regs.H.AH = 0x10;\r
- } else {\r
- Regs.H.AH = 0x00;\r
- }\r
-\r
- BiosKeyboardPrivate->LegacyBios->Int86 (\r
- BiosKeyboardPrivate->LegacyBios,\r
- 0x16,\r
- &Regs\r
- );\r
-\r
- KeyData.Key.ScanCode = (UINT16) Regs.H.AH;\r
- KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL;\r
- DEBUG ((\r
- EFI_D_INFO,\r
- "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",\r
- KeyData.Key.ScanCode,\r
- KeyData.Key.UnicodeChar\r
- ));\r
-\r
- KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;\r
- KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
- //\r
- // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then\r
- // 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\r
- // 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\r
- // 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\r
- // 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\r
- // 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\r
- // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other drivers\r
- // performance, like USB.\r
- //\r
- // 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\r
- // 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\r
- // 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\r
- // CTRL and ALT.\r
- //\r
- // 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\r
- // 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,\r
- // which will let persist to press SHIFT has same effection as only press one time.\r
- //\r
- //0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
- // 7 INSert active\r
- // 6 Caps Lock active\r
- // 5 Num Lock active\r
- // 4 Scroll Lock active\r
- // 3 either Alt pressed\r
- // 2 either Ctrl pressed\r
- // 1 Left Shift pressed\r
- // 0 Right Shift pressed\r
-\r
-\r
- //\r
- // Clear the CTRL and ALT BDA flag\r
- //\r
- ACCESS_PAGE0_CODE (\r
- KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1\r
- KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
- );\r
-\r
- DEBUG_CODE (\r
- {\r
- if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n"));\r
- }\r
- if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n"));\r
- }\r
- if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n"));\r
- }\r
- if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {\r
- if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n"));\r
- } else {\r
- DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n"));\r
- }\r
- }\r
- if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {\r
- if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n"));\r
- } else {\r
- DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n"));\r
- }\r
- }\r
- if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n"));\r
- }\r
- if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n"));\r
- }\r
- }\r
- );\r
-\r
- //\r
- // Record toggle state\r
- //\r
- if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {\r
- KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
- }\r
- if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {\r
- KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
- }\r
- if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {\r
- KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
- }\r
- //\r
- // Record shift state\r
- // BUGBUG: Need add Menu key and Left/Right Logo key state in the future\r
- //\r
- if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {\r
- KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;\r
- }\r
- if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {\r
- KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;\r
- }\r
- if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {\r
- KeyData.KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;\r
- }\r
- if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {\r
- KeyData.KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;\r
- }\r
-\r
- //\r
- // Clear left alt and left ctrl BDA flag\r
- //\r
- ACCESS_PAGE0_CODE (\r
- KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
- *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
- KbFlag1 &= ~0x0C;\r
- *((UINT8 *) (UINTN) 0x417) = KbFlag1;\r
- );\r
-\r
- //\r
- // Output EFI input key and shift/toggle state\r
- //\r
- if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {\r
- KeyData.Key.ScanCode = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);\r
- KeyData.Key.UnicodeChar = CHAR_NULL;\r
- } else {\r
- KeyData.Key.ScanCode = SCAN_NULL;\r
- }\r
-\r
- //\r
- // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.\r
- //\r
- if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
- if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {\r
- if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==\r
- ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)\r
- ) {\r
- KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);\r
- } else {\r
- KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);\r
- }\r
- }\r
- }\r
-\r
- DEBUG ((\r
- EFI_D_INFO,\r
- "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",\r
- KeyData.Key.ScanCode,\r
- KeyData.Key.UnicodeChar\r
- ));\r
-\r
- //\r
- // Need not return associated shift state if a class of printable characters that\r
- // are normally adjusted by shift modifiers.\r
- // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.\r
- //\r
- if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||\r
- (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')\r
- ) {\r
- DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));\r
- KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
- }\r
-\r
- //\r
- // Signal KeyNotify process event if this key pressed matches any key registered.\r
- //\r
- for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
- CurrentNotify = CR (\r
- Link,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
- NotifyEntry,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
- );\r
- if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
- //\r
- // The key notification function needs to run at TPL_CALLBACK\r
- // while current TPL is TPL_NOTIFY. It will be invoked in\r
- // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.\r
- //\r
- Enqueue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);\r
- gBS->SignalEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);\r
- break;\r
- }\r
- }\r
-\r
- Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);\r
-\r
- //\r
- // Save the current key state\r
- //\r
- CopyMem (&BiosKeyboardPrivate->KeyState, &KeyData.KeyState, sizeof (EFI_KEY_STATE));\r
-\r
- //\r
- // Leave critical section and return\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- Process key notify.\r
-\r
- @param Event Indicates the event that invoke this function.\r
- @param Context Indicates the calling context.\r
-**/\r
-VOID\r
-EFIAPI\r
-KeyNotifyProcessHandler (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_KEY_DATA KeyData;\r
- LIST_ENTRY *Link;\r
- LIST_ENTRY *NotifyList;\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
- EFI_TPL OldTpl;\r
-\r
- BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) Context;\r
-\r
- //\r
- // Invoke notification functions.\r
- //\r
- NotifyList = &BiosKeyboardPrivate->NotifyList;\r
- while (TRUE) {\r
- //\r
- // Enter critical section\r
- //\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
- Status = Dequeue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);\r
- //\r
- // Leave critical section\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
- for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {\r
- CurrentNotify = CR (Link, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);\r
- if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {\r
- CurrentNotify->KeyNotificationFn (&KeyData);\r
- }\r
- }\r
- }\r
-}\r
-\r
-/**\r
- Free keyboard notify list.\r
-\r
- @param ListHead The list head\r
-\r
- @retval EFI_SUCCESS Free the notify list successfully\r
- @retval EFI_INVALID_PARAMETER ListHead is invalid.\r
-\r
-**/\r
-EFI_STATUS\r
-BiosKeyboardFreeNotifyList (\r
- IN OUT LIST_ENTRY *ListHead\r
- )\r
-{\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
-\r
- if (ListHead == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- while (!IsListEmpty (ListHead)) {\r
- NotifyNode = CR (\r
- ListHead->ForwardLink,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
- NotifyEntry,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
- );\r
- RemoveEntryList (ListHead->ForwardLink);\r
- gBS->FreePool (NotifyNode);\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Check if key is registered.\r
-\r
- @param RegsiteredData A pointer to a buffer that is filled in with the keystroke\r
- state data for the key that was registered.\r
- @param InputData A pointer to a buffer that is filled in with the keystroke\r
- state data for the key that was pressed.\r
-\r
- @retval TRUE Key be pressed matches a registered key.\r
- @retval FLASE Match failed.\r
-\r
-**/\r
-BOOLEAN\r
-IsKeyRegistered (\r
- IN EFI_KEY_DATA *RegsiteredData,\r
- IN EFI_KEY_DATA *InputData\r
- )\r
-{\r
- ASSERT (RegsiteredData != NULL && InputData != NULL);\r
-\r
- if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||\r
- (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
- //\r
- if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
- RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
- return FALSE;\r
- }\r
- if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
- RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-\r
-}\r
-\r
-/**\r
- Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
-\r
- @param Event The event that be siganlled when any key has been stroked.\r
- @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-BiosKeyboardWaitForKeyEx (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
-\r
- BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context);\r
- BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);\r
-\r
-}\r
-\r
-/**\r
- Reset the input device and optionaly run diagnostics\r
-\r
- @param This Protocol instance pointer.\r
- @param ExtendedVerification Driver may perform diagnostics on reset.\r
-\r
- @retval EFI_SUCCESS The device was reset.\r
- @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
- not be reset.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardResetEx (\r
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
- IN BOOLEAN ExtendedVerification\r
- )\r
-{\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_STATUS Status;\r
- EFI_TPL OldTpl;\r
-\r
- BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- Status = BiosKeyboardPrivate->SimpleTextIn.Reset (\r
- &BiosKeyboardPrivate->SimpleTextIn,\r
- ExtendedVerification\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return EFI_SUCCESS;\r
-\r
-}\r
-\r
-/**\r
- Reads the next keystroke from the input device. The WaitForKey Event can\r
- be used to test for existance of a keystroke via WaitForEvent () call.\r
-\r
- @param This Protocol instance pointer.\r
- @param KeyData A pointer to a buffer that is filled in with the keystroke\r
- state data for the key that was pressed.\r
-\r
- @retval EFI_SUCCESS The keystroke information was returned.\r
- @retval EFI_NOT_READY There was no keystroke data availiable.\r
- @retval EFI_DEVICE_ERROR The keystroke information was not returned due to\r
- hardware errors.\r
- @retval EFI_INVALID_PARAMETER KeyData is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardReadKeyStrokeEx (\r
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
- OUT EFI_KEY_DATA *KeyData\r
- )\r
-{\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
-\r
- if (KeyData == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);\r
-\r
-}\r
-\r
-/**\r
- Set certain state for the input device.\r
-\r
- @param This Protocol instance pointer.\r
- @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the\r
- state for the input device.\r
-\r
- @retval EFI_SUCCESS The device state was set successfully.\r
- @retval EFI_DEVICE_ERROR The device is not functioning correctly and could\r
- not have the setting adjusted.\r
- @retval EFI_UNSUPPORTED The device does not have the ability to set its state.\r
- @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardSetState (\r
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
- IN EFI_KEY_TOGGLE_STATE *KeyToggleState\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_TPL OldTpl;\r
- EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
- UINT8 Command;\r
-\r
- if (KeyToggleState == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Thunk keyboard driver doesn't support partial keystroke.\r
- //\r
- if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||\r
- (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED\r
- ) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
- //\r
- // See if the Legacy BIOS Protocol is available\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiLegacyBiosProtocolGuid,\r
- NULL,\r
- (VOID **) &LegacyBios\r
- );\r
-\r
- ASSERT_EFI_ERROR (Status);\r
- //\r
- // Enter critical section\r
- //\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- Command = 0;\r
- if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
- Command |= 4;\r
- }\r
- if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
- Command |= 2;\r
- }\r
- if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
- Command |= 1;\r
- }\r
-\r
- Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- Status = KeyboardWrite (BiosKeyboardPrivate, Command);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
- //\r
- // Call Legacy BIOS Protocol to set whatever is necessary\r
- //\r
- LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);\r
-\r
- Status = EFI_SUCCESS;\r
-\r
-Exit:\r
- //\r
- // Leave critical section and return\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
-\r
- return Status;\r
-\r
-}\r
-\r
-/**\r
- Register a notification function for a particular keystroke for the input device.\r
-\r
- @param This Protocol instance pointer.\r
- @param KeyData A pointer to a buffer that is filled in with the keystroke\r
- information data for the key that was pressed. If KeyData.Key,\r
- KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState\r
- are 0, then any incomplete keystroke will trigger a notification of\r
- the KeyNotificationFunction.\r
- @param KeyNotificationFunction Points to the function to be called when the key\r
- sequence is typed specified by KeyData. This notification function\r
- should be called at <=TPL_CALLBACK.\r
- @param NotifyHandle Points to the unique handle assigned to the registered notification.\r
-\r
- @retval EFI_SUCCESS The notification function was registered successfully.\r
- @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.\r
- @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardRegisterKeyNotify (\r
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
- IN EFI_KEY_DATA *KeyData,\r
- IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,\r
- OUT VOID **NotifyHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_TPL OldTpl;\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;\r
- LIST_ENTRY *Link;\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
-\r
- if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- //\r
- // Enter critical section\r
- //\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- //\r
- // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
- //\r
- for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
- CurrentNotify = CR (\r
- Link,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
- NotifyEntry,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
- );\r
- if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {\r
- if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
- *NotifyHandle = CurrentNotify;\r
- Status = EFI_SUCCESS;\r
- goto Exit;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Allocate resource to save the notification function\r
- //\r
-\r
- NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));\r
- if (NewNotify == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Exit;\r
- }\r
-\r
- NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
- NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
- CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
- InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);\r
-\r
- *NotifyHandle = NewNotify;\r
- Status = EFI_SUCCESS;\r
-\r
-Exit:\r
- //\r
- // Leave critical section and return\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
- return Status;\r
-}\r
-\r
-/**\r
- Remove a registered notification function from a particular keystroke.\r
-\r
- @param This Protocol instance pointer.\r
- @param NotificationHandle The handle of the notification function being unregistered.\r
-\r
- @retval EFI_SUCCESS The notification function was unregistered successfully.\r
- @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BiosKeyboardUnregisterKeyNotify (\r
- IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
- IN VOID *NotificationHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
- EFI_TPL OldTpl;\r
- LIST_ENTRY *Link;\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
-\r
- //\r
- // Check incoming notification handle\r
- //\r
- if (NotificationHandle == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
-\r
- //\r
- // Enter critical section\r
- //\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-\r
- for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
- CurrentNotify = CR (\r
- Link,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,\r
- NotifyEntry,\r
- BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
- );\r
- if (CurrentNotify == NotificationHandle) {\r
- //\r
- // Remove the notification function from NotifyList and free resources\r
- //\r
- RemoveEntryList (&CurrentNotify->NotifyEntry);\r
-\r
- Status = EFI_SUCCESS;\r
- goto Exit;\r
- }\r
- }\r
-\r
- //\r
- // Can not find the specified Notification Handle\r
- //\r
- Status = EFI_INVALID_PARAMETER;\r
-\r
-Exit:\r
- //\r
- // Leave critical section and return\r
- //\r
- gBS->RestoreTPL (OldTpl);\r
- return Status;\r
-}\r
-\r
-/**\r
- The user Entry Point for module BiosKeyboard. The user code starts with this function.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
- @param[in] SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The entry point is executed successfully.\r
- @retval other Some error occurs when executing this entry point.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeBiosKeyboard(\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Install driver model protocol(s).\r
- //\r
- Status = EfiLibInstallDriverBindingComponentName2 (\r
- ImageHandle,\r
- SystemTable,\r
- &gBiosKeyboardDriverBinding,\r
- ImageHandle,\r
- &gBiosKeyboardComponentName,\r
- &gBiosKeyboardComponentName2\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r