2 ConsoleOut Routines that speak VGA.
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "BiosKeyboard.h"
20 // EFI Driver Binding Protocol Instance
22 EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding
= {
23 BiosKeyboardDriverBindingSupported
,
24 BiosKeyboardDriverBindingStart
,
25 BiosKeyboardDriverBindingStop
,
35 @param Queue The queue to be enqueued.
36 @param KeyData The key data to be enqueued.
38 @retval EFI_NOT_READY The queue is full.
39 @retval EFI_SUCCESS Successfully enqueued the key data.
44 IN SIMPLE_QUEUE
*Queue
,
45 IN EFI_KEY_DATA
*KeyData
48 if ((Queue
->Rear
+ 1) % QUEUE_MAX_COUNT
== Queue
->Front
) {
52 CopyMem (&Queue
->Buffer
[Queue
->Rear
], KeyData
, sizeof (EFI_KEY_DATA
));
53 Queue
->Rear
= (Queue
->Rear
+ 1) % QUEUE_MAX_COUNT
;
62 @param Queue The queue to be dequeued.
63 @param KeyData The key data to be dequeued.
65 @retval EFI_NOT_READY The queue is empty.
66 @retval EFI_SUCCESS Successfully dequeued the key data.
71 IN SIMPLE_QUEUE
*Queue
,
72 IN EFI_KEY_DATA
*KeyData
75 if (Queue
->Front
== Queue
->Rear
) {
79 CopyMem (KeyData
, &Queue
->Buffer
[Queue
->Front
], sizeof (EFI_KEY_DATA
));
80 Queue
->Front
= (Queue
->Front
+ 1) % QUEUE_MAX_COUNT
;
87 Check whether the queue is empty.
89 @param Queue The queue to be checked.
91 @retval EFI_NOT_READY The queue is empty.
92 @retval EFI_SUCCESS The queue is not empty.
97 IN SIMPLE_QUEUE
*Queue
100 if (Queue
->Front
== Queue
->Rear
) {
101 return EFI_NOT_READY
;
108 // EFI Driver Binding Protocol Functions
112 Check whether the driver supports this device.
114 @param This The Udriver binding protocol.
115 @param Controller The controller handle to check.
116 @param RemainingDevicePath The remaining device path.
118 @retval EFI_SUCCESS The driver supports this controller.
119 @retval other This device isn't supported.
124 BiosKeyboardDriverBindingSupported (
125 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
126 IN EFI_HANDLE Controller
,
127 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
131 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
132 EFI_ISA_IO_PROTOCOL
*IsaIo
;
135 // See if the Legacy BIOS Protocol is available
137 Status
= gBS
->LocateProtocol (
138 &gEfiLegacyBiosProtocolGuid
,
140 (VOID
**) &LegacyBios
143 if (EFI_ERROR (Status
)) {
147 // Open the IO Abstraction(s) needed to perform the supported test
149 Status
= gBS
->OpenProtocol (
151 &gEfiIsaIoProtocolGuid
,
153 This
->DriverBindingHandle
,
155 EFI_OPEN_PROTOCOL_BY_DRIVER
158 if (EFI_ERROR (Status
)) {
162 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
164 if (IsaIo
->ResourceList
->Device
.HID
!= EISA_PNP_ID (0x303) || IsaIo
->ResourceList
->Device
.UID
!= 0) {
165 Status
= EFI_UNSUPPORTED
;
170 &gEfiIsaIoProtocolGuid
,
171 This
->DriverBindingHandle
,
179 Starts the device with this driver.
181 @param This The driver binding instance.
182 @param Controller Handle of device to bind driver to.
183 @param RemainingDevicePath Optional parameter use to pick a specific child
186 @retval EFI_SUCCESS The controller is controlled by the driver.
187 @retval Other This controller cannot be started.
192 BiosKeyboardDriverBindingStart (
193 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
194 IN EFI_HANDLE Controller
,
195 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
199 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
200 EFI_ISA_IO_PROTOCOL
*IsaIo
;
201 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
202 EFI_IA32_REGISTER_SET Regs
;
204 EFI_PS2_POLICY_PROTOCOL
*Ps2Policy
;
206 EFI_STATUS_CODE_VALUE StatusCode
;
208 BiosKeyboardPrivate
= NULL
;
213 // Get Ps2 policy to set. Will be use if present.
215 gBS
->LocateProtocol (
216 &gEfiPs2PolicyProtocolGuid
,
222 // See if the Legacy BIOS Protocol is available
224 Status
= gBS
->LocateProtocol (
225 &gEfiLegacyBiosProtocolGuid
,
227 (VOID
**) &LegacyBios
230 if (EFI_ERROR (Status
)) {
234 // Open the IO Abstraction(s) needed
236 Status
= gBS
->OpenProtocol (
238 &gEfiIsaIoProtocolGuid
,
240 This
->DriverBindingHandle
,
242 EFI_OPEN_PROTOCOL_BY_DRIVER
244 if (EFI_ERROR (Status
)) {
249 // Allocate the private device structure
251 BiosKeyboardPrivate
= (BIOS_KEYBOARD_DEV
*) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV
));
252 if (NULL
== BiosKeyboardPrivate
) {
253 Status
= EFI_OUT_OF_RESOURCES
;
258 // Initialize the private device structure
260 BiosKeyboardPrivate
->Signature
= BIOS_KEYBOARD_DEV_SIGNATURE
;
261 BiosKeyboardPrivate
->Handle
= Controller
;
262 BiosKeyboardPrivate
->LegacyBios
= LegacyBios
;
263 BiosKeyboardPrivate
->IsaIo
= IsaIo
;
265 BiosKeyboardPrivate
->SimpleTextIn
.Reset
= BiosKeyboardReset
;
266 BiosKeyboardPrivate
->SimpleTextIn
.ReadKeyStroke
= BiosKeyboardReadKeyStroke
;
268 BiosKeyboardPrivate
->DataRegisterAddress
= KEYBOARD_8042_DATA_REGISTER
;
269 BiosKeyboardPrivate
->StatusRegisterAddress
= KEYBOARD_8042_STATUS_REGISTER
;
270 BiosKeyboardPrivate
->CommandRegisterAddress
= KEYBOARD_8042_COMMAND_REGISTER
;
271 BiosKeyboardPrivate
->ExtendedKeyboard
= TRUE
;
273 BiosKeyboardPrivate
->Queue
.Front
= 0;
274 BiosKeyboardPrivate
->Queue
.Rear
= 0;
275 BiosKeyboardPrivate
->SimpleTextInputEx
.Reset
= BiosKeyboardResetEx
;
276 BiosKeyboardPrivate
->SimpleTextInputEx
.ReadKeyStrokeEx
= BiosKeyboardReadKeyStrokeEx
;
277 BiosKeyboardPrivate
->SimpleTextInputEx
.SetState
= BiosKeyboardSetState
;
278 BiosKeyboardPrivate
->SimpleTextInputEx
.RegisterKeyNotify
= BiosKeyboardRegisterKeyNotify
;
279 BiosKeyboardPrivate
->SimpleTextInputEx
.UnregisterKeyNotify
= BiosKeyboardUnregisterKeyNotify
;
280 InitializeListHead (&BiosKeyboardPrivate
->NotifyList
);
282 Status
= gBS
->HandleProtocol (
284 &gEfiDevicePathProtocolGuid
,
285 (VOID
**) &BiosKeyboardPrivate
->DevicePath
289 // Report that the keyboard is being enabled
291 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
293 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
,
294 BiosKeyboardPrivate
->DevicePath
298 // Setup the WaitForKey event
300 Status
= gBS
->CreateEvent (
303 BiosKeyboardWaitForKey
,
304 &(BiosKeyboardPrivate
->SimpleTextIn
),
305 &((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
)
307 if (EFI_ERROR (Status
)) {
308 (BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
= NULL
;
311 Status
= gBS
->CreateEvent (
314 BiosKeyboardWaitForKeyEx
,
315 &(BiosKeyboardPrivate
->SimpleTextInputEx
),
316 &(BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
)
318 if (EFI_ERROR (Status
)) {
319 BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
= NULL
;
324 // Setup a periodic timer, used for reading keystrokes at a fixed interval
326 Status
= gBS
->CreateEvent (
327 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
329 BiosKeyboardTimerHandler
,
331 &BiosKeyboardPrivate
->TimerEvent
333 if (EFI_ERROR (Status
)) {
334 Status
= EFI_OUT_OF_RESOURCES
;
335 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
339 Status
= gBS
->SetTimer (
340 BiosKeyboardPrivate
->TimerEvent
,
342 KEYBOARD_TIMER_INTERVAL
344 if (EFI_ERROR (Status
)) {
345 Status
= EFI_OUT_OF_RESOURCES
;
346 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
351 // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
353 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
355 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
,
356 BiosKeyboardPrivate
->DevicePath
360 // Reset the keyboard device
362 Status
= BiosKeyboardPrivate
->SimpleTextInputEx
.Reset (
363 &BiosKeyboardPrivate
->SimpleTextInputEx
,
364 FeaturePcdGet (PcdPs2KbdExtendedVerification
)
366 if (EFI_ERROR (Status
)) {
367 DEBUG ((EFI_D_ERROR
, "[KBD]Reset Failed. Status - %r\n", Status
));
368 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
372 // Do platform specific policy like port swapping and keyboard light default
374 if (Ps2Policy
!= NULL
) {
376 Ps2Policy
->Ps2InitHardware (Controller
);
379 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
383 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
387 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
391 KeyboardWrite (BiosKeyboardPrivate
, 0xed);
392 KeyboardWaitForValue (BiosKeyboardPrivate
, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT
);
393 KeyboardWrite (BiosKeyboardPrivate
, Command
);
395 // Call Legacy BIOS Protocol to set whatever is necessary
397 LegacyBios
->UpdateKeyboardLedStatus (LegacyBios
, Command
);
403 CarryFlag
= BiosKeyboardPrivate
->LegacyBios
->Int86 (
404 BiosKeyboardPrivate
->LegacyBios
,
411 // Check bit 6 of Feature Byte 2.
412 // If it is set, then Int 16 Func 09 is supported
414 if (*(UINT8
*)(UINTN
) ((Regs
.X
.ES
<< 4) + Regs
.X
.BX
+ 0x06) & 0x40) {
416 // Get Keyboard Functionality
419 CarryFlag
= BiosKeyboardPrivate
->LegacyBios
->Int86 (
420 BiosKeyboardPrivate
->LegacyBios
,
427 // Check bit 5 of AH.
428 // If it is set, then INT 16 Finc 10-12 are supported.
430 if ((Regs
.H
.AL
& 0x40) != 0) {
432 // Set the flag to use INT 16 Func 10-12
434 BiosKeyboardPrivate
->ExtendedKeyboard
= TRUE
;
439 DEBUG ((EFI_D_INFO
, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN
)BiosKeyboardPrivate
->ExtendedKeyboard
));
441 // Install protocol interfaces for the keyboard device.
443 Status
= gBS
->InstallMultipleProtocolInterfaces (
445 &gEfiSimpleTextInProtocolGuid
,
446 &BiosKeyboardPrivate
->SimpleTextIn
,
447 &gEfiSimpleTextInputExProtocolGuid
,
448 &BiosKeyboardPrivate
->SimpleTextInputEx
,
453 if (StatusCode
!= 0) {
455 // Report an Error Code for failing to start the keyboard device
457 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
458 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
460 BiosKeyboardPrivate
->DevicePath
464 if (EFI_ERROR (Status
)) {
466 if (BiosKeyboardPrivate
!= NULL
) {
467 if ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
!= NULL
) {
468 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
471 if ((BiosKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
!= NULL
) {
472 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
);
474 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate
->NotifyList
);
476 if (BiosKeyboardPrivate
->TimerEvent
!= NULL
) {
477 gBS
->CloseEvent (BiosKeyboardPrivate
->TimerEvent
);
480 FreePool (BiosKeyboardPrivate
);
486 &gEfiIsaIoProtocolGuid
,
487 This
->DriverBindingHandle
,
497 Stop the device handled by this driver.
499 @param This The driver binding protocol.
500 @param Controller The controller to release.
501 @param NumberOfChildren The number of handles in ChildHandleBuffer.
502 @param ChildHandleBuffer The array of child handle.
504 @retval EFI_SUCCESS The device was stopped.
505 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
506 @retval Others Fail to uninstall protocols attached on the device.
511 BiosKeyboardDriverBindingStop (
512 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
513 IN EFI_HANDLE Controller
,
514 IN UINTN NumberOfChildren
,
515 IN EFI_HANDLE
*ChildHandleBuffer
519 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextIn
;
520 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
525 Status
= gBS
->OpenProtocol (
527 &gEfiSimpleTextInProtocolGuid
,
528 (VOID
**) &SimpleTextIn
,
529 This
->DriverBindingHandle
,
531 EFI_OPEN_PROTOCOL_GET_PROTOCOL
533 if (EFI_ERROR (Status
)) {
537 Status
= gBS
->OpenProtocol (
539 &gEfiSimpleTextInputExProtocolGuid
,
541 This
->DriverBindingHandle
,
543 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
545 if (EFI_ERROR (Status
)) {
549 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn
);
551 Status
= gBS
->UninstallMultipleProtocolInterfaces (
553 &gEfiSimpleTextInProtocolGuid
,
554 &BiosKeyboardPrivate
->SimpleTextIn
,
555 &gEfiSimpleTextInputExProtocolGuid
,
556 &BiosKeyboardPrivate
->SimpleTextInputEx
,
559 if (EFI_ERROR (Status
)) {
563 // Release the IsaIo protocol on the controller handle
567 &gEfiIsaIoProtocolGuid
,
568 This
->DriverBindingHandle
,
573 // Free other resources
575 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
576 gBS
->CloseEvent (BiosKeyboardPrivate
->TimerEvent
);
577 gBS
->CloseEvent (BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
);
578 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate
->NotifyList
);
580 FreePool (BiosKeyboardPrivate
);
586 Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
588 @param BiosKeyboardPrivate Keyboard instance pointer.
590 @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
594 KeyReadDataRegister (
595 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
601 // Use IsaIo protocol to perform IO operations
603 BiosKeyboardPrivate
->IsaIo
->Io
.Read (
604 BiosKeyboardPrivate
->IsaIo
,
606 BiosKeyboardPrivate
->DataRegisterAddress
,
615 Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
617 @param BiosKeyboardPrivate Keyboard instance pointer.
619 @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.
623 KeyReadStatusRegister (
624 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
630 // Use IsaIo protocol to perform IO operations
632 BiosKeyboardPrivate
->IsaIo
->Io
.Read (
633 BiosKeyboardPrivate
->IsaIo
,
635 BiosKeyboardPrivate
->StatusRegisterAddress
,
644 Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
646 @param BiosKeyboardPrivate Keyboard instance pointer.
647 @param Data Data byte to write.
651 KeyWriteCommandRegister (
652 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
657 // Use IsaIo protocol to perform IO operations
659 BiosKeyboardPrivate
->IsaIo
->Io
.Write (
660 BiosKeyboardPrivate
->IsaIo
,
662 BiosKeyboardPrivate
->CommandRegisterAddress
,
669 Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
671 @param BiosKeyboardPrivate Keyboard instance pointer.
672 @param Data Data byte to write.
676 KeyWriteDataRegister (
677 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
682 // Use IsaIo protocol to perform IO operations
684 BiosKeyboardPrivate
->IsaIo
->Io
.Write (
685 BiosKeyboardPrivate
->IsaIo
,
687 BiosKeyboardPrivate
->DataRegisterAddress
,
694 Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
696 @param BiosKeyboardPrivate Keyboard instance pointer.
697 @param Data The pointer for data that being read out.
699 @retval EFI_SUCCESS The data byte read out successfully.
700 @retval EFI_TIMEOUT Timeout occurred during reading out data byte.
705 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
716 // wait till output buffer full then perform the read
718 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
719 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_OUTB
) != 0) {
721 *Data
= KeyReadDataRegister (BiosKeyboardPrivate
);
728 if (RegFilled
== 0) {
736 Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
738 @param BiosKeyboardPrivate Keyboard instance pointer.
739 @param Data Data byte to write.
741 @retval EFI_SUCCESS The data byte is written successfully.
742 @retval EFI_TIMEOUT Timeout occurred during writing.
747 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
758 // wait for input buffer empty
760 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
761 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
769 if (RegEmptied
== 0) {
775 KeyWriteDataRegister (BiosKeyboardPrivate
, Data
);
781 Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
783 @param BiosKeyboardPrivate Keyboard instance pointer.
784 @param Data Command byte to write.
786 @retval EFI_SUCCESS The command byte is written successfully.
787 @retval EFI_TIMEOUT Timeout occurred during writing.
792 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
803 // Wait For Input Buffer Empty
805 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
806 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
814 if (RegEmptied
== 0) {
820 KeyWriteCommandRegister (BiosKeyboardPrivate
, Data
);
823 // Wait For Input Buffer Empty again
826 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
827 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
835 if (RegEmptied
== 0) {
843 Wait for a specific value to be presented in
844 Data register of Keyboard Controller by keyboard and then read it,
845 used in keyboard commands ack
847 @param BiosKeyboardPrivate Keyboard instance pointer.
848 @param Value The value to be waited for
849 @param WaitForValueTimeOut The limit of microseconds for timeout
851 @retval EFI_SUCCESS The command byte is written successfully.
852 @retval EFI_TIMEOUT Timeout occurred during writing.
856 KeyboardWaitForValue (
857 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
859 IN UINTN WaitForValueTimeOut
872 // Make sure the initial value of 'Data' is different from 'Value'
879 // Read from 8042 (multiple times if needed)
880 // until the expected value appears
881 // use SumTimeOut to control the iteration
887 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
888 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_OUTB
) != 0) {
889 Data
= KeyReadDataRegister (BiosKeyboardPrivate
);
896 SumTimeOut
+= TimeOut
;
903 if (SumTimeOut
>= WaitForValueTimeOut
) {
919 Reads the next keystroke from the input device. The WaitForKey Event can
920 be used to test for existance of a keystroke via WaitForEvent () call.
922 @param BiosKeyboardPrivate Bioskeyboard driver private structure.
923 @param KeyData A pointer to a buffer that is filled in with the keystroke
924 state data for the key that was pressed.
926 @retval EFI_SUCCESS The keystroke information was returned.
927 @retval EFI_NOT_READY There was no keystroke data availiable.
928 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
930 @retval EFI_INVALID_PARAMETER KeyData is NULL.
934 KeyboardReadKeyStrokeWorker (
935 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
936 OUT EFI_KEY_DATA
*KeyData
941 if (KeyData
== NULL
) {
942 return EFI_INVALID_PARAMETER
;
946 // Use TimerEvent callback funciton to check whether there's any key pressed
950 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
951 // Csm will be used to check whether there is a key pending, but the csm will disable all
952 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
953 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
954 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
955 // e.g. usb keyboard driver.
956 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
957 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
961 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
963 BiosKeyboardTimerHandler (NULL
, BiosKeyboardPrivate
);
965 // If there's no key, just return
967 Status
= CheckQueue (&BiosKeyboardPrivate
->Queue
);
968 if (EFI_ERROR (Status
)) {
969 gBS
->RestoreTPL (OldTpl
);
970 return EFI_NOT_READY
;
973 Status
= Dequeue (&BiosKeyboardPrivate
->Queue
, KeyData
);
975 gBS
->RestoreTPL (OldTpl
);
981 // EFI Simple Text In Protocol Functions
984 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
986 @param This Pointer of simple text Protocol.
987 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
989 @retval EFI_SUCCESS The command byte is written successfully.
990 @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
996 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
997 IN BOOLEAN ExtendedVerification
1000 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1004 BOOLEAN MouseEnable
;
1007 MouseEnable
= FALSE
;
1008 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1012 // Report reset progress code
1014 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1016 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
1017 BiosKeyboardPrivate
->DevicePath
1021 // Report a Progress Code for clearing the keyboard buffer
1023 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1025 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1026 BiosKeyboardPrivate
->DevicePath
1031 // Raise TPL to avoid mouse operation impact
1033 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1037 // Exhaust output buffer data
1040 Status
= BiosKeyboardReadKeyStroke (
1044 } while (!EFI_ERROR (Status
));
1047 // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
1048 // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
1051 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_SYSF
) != 0) {
1054 // CheckMouseStatus to decide enable it later or not
1057 // Read the command byte of KBC
1059 Status
= KeyboardCommand (
1060 BiosKeyboardPrivate
,
1061 KBC_CMDREG_VIA64_CMDBYTE_R
1064 if (EFI_ERROR (Status
)) {
1065 Status
= EFI_DEVICE_ERROR
;
1069 Status
= KeyboardRead (
1070 BiosKeyboardPrivate
,
1074 if (EFI_ERROR (Status
)) {
1075 Status
= EFI_DEVICE_ERROR
;
1079 // Check mouse enabled or not before
1081 if ((CommandByte
& KB_CMMBYTE_DISABLE_AUX
) != 0) {
1082 MouseEnable
= FALSE
;
1088 // disable mouse (via KBC) and Keyborad device
1090 Status
= KeyboardCommand (
1091 BiosKeyboardPrivate
,
1092 KBC_CMDREG_VIA64_AUX_DISABLE
1095 if (EFI_ERROR (Status
)) {
1096 Status
= EFI_DEVICE_ERROR
;
1100 Status
= KeyboardCommand (
1101 BiosKeyboardPrivate
,
1102 KBC_CMDREG_VIA64_KB_DISABLE
1105 if (EFI_ERROR (Status
)) {
1106 Status
= EFI_DEVICE_ERROR
;
1116 // Report a Progress Code for performing a self test on the keyboard controller
1118 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1120 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1121 BiosKeyboardPrivate
->DevicePath
1124 Status
= KeyboardCommand (
1125 BiosKeyboardPrivate
,
1126 KBC_CMDREG_VIA64_KBC_SLFTEST
1128 if (EFI_ERROR (Status
)) {
1129 Status
= EFI_DEVICE_ERROR
;
1133 Status
= KeyboardWaitForValue (
1134 BiosKeyboardPrivate
,
1135 KBC_CMDECHO_KBCSLFTEST_OK
,
1136 KEYBOARD_WAITFORVALUE_TIMEOUT
1138 if (EFI_ERROR (Status
)) {
1139 Status
= EFI_DEVICE_ERROR
;
1145 // Disable Mouse interface, enable Keyboard interface and declare selftest success
1147 // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
1149 Status
= KeyboardCommand (
1150 BiosKeyboardPrivate
,
1151 KBC_CMDREG_VIA64_CMDBYTE_W
1154 if (EFI_ERROR (Status
)) {
1155 Status
= EFI_DEVICE_ERROR
;
1160 // Write 8042 Command Byte, set System Flag
1161 // While at the same time:
1162 // 1. disable mouse interface,
1163 // 2. enable kbd interface,
1164 // 3. enable PC/XT kbd translation mode
1165 // 4. enable mouse and kbd interrupts
1167 //Command Byte bits:
1169 // 6: PC/XT translation mode
1170 // 5: Disable Auxiliary device interface
1171 // 4: Disable keyboard interface
1174 // 1: Enable Auxiliary device interrupt
1175 // 0: Enable Keyboard interrupt
1178 Status
= KeyboardWrite (
1179 BiosKeyboardPrivate
,
1180 (UINT8
) ((CommandByte
&
1181 (~KB_CMMBYTE_DISABLE_KB
)) |
1182 KB_CMMBYTE_KSCAN2UNI_COV
|
1183 KB_CMMBYTE_ENABLE_AUXINT
|
1184 KB_CMMBYTE_ENABLE_KBINT
|
1185 KB_CMMBYTE_SLFTEST_SUCC
|
1186 KB_CMMBYTE_DISABLE_AUX
)
1190 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1191 // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.
1192 // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
1193 // Real reset will not do.
1195 if (ExtendedVerification
&& CheckKeyboardConnect (BiosKeyboardPrivate
)) {
1198 // Send keyboard reset command then read ACK
1200 Status
= KeyboardWrite (
1201 BiosKeyboardPrivate
,
1202 KBC_INPBUF_VIA60_KBRESET
1205 if (EFI_ERROR (Status
)) {
1206 Status
= EFI_DEVICE_ERROR
;
1210 Status
= KeyboardWaitForValue (
1211 BiosKeyboardPrivate
,
1213 KEYBOARD_WAITFORVALUE_TIMEOUT
1216 if (EFI_ERROR (Status
)) {
1217 Status
= EFI_DEVICE_ERROR
;
1222 // Wait for keyboard return test OK.
1224 Status
= KeyboardWaitForValue (
1225 BiosKeyboardPrivate
,
1226 KBC_CMDECHO_BATTEST_OK
,
1227 KEYBOARD_WAITFORVALUE_TIMEOUT
1230 if (EFI_ERROR (Status
)) {
1231 Status
= EFI_DEVICE_ERROR
;
1236 // set keyboard scan code set = 02 (standard configuration)
1238 Status
= KeyboardWrite (
1239 BiosKeyboardPrivate
,
1240 KBC_INPBUF_VIA60_KBSCODE
1242 if (EFI_ERROR (Status
)) {
1243 Status
= EFI_DEVICE_ERROR
;
1247 Status
= KeyboardWaitForValue (
1248 BiosKeyboardPrivate
,
1250 KEYBOARD_WAITFORVALUE_TIMEOUT
1253 if (EFI_ERROR (Status
)) {
1254 Status
= EFI_DEVICE_ERROR
;
1258 Status
= KeyboardWrite (
1259 BiosKeyboardPrivate
,
1260 KBC_INPBUF_VIA60_SCODESET2
1262 if (EFI_ERROR (Status
)) {
1263 Status
= EFI_DEVICE_ERROR
;
1267 Status
= KeyboardWaitForValue (
1268 BiosKeyboardPrivate
,
1270 KEYBOARD_WAITFORVALUE_TIMEOUT
1273 if (EFI_ERROR (Status
)) {
1274 Status
= EFI_DEVICE_ERROR
;
1279 // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
1281 Status
= KeyboardWrite (
1282 BiosKeyboardPrivate
,
1283 KBC_INPBUF_VIA60_KBEN
1285 if (EFI_ERROR (Status
)) {
1286 Status
= EFI_DEVICE_ERROR
;
1290 Status
= KeyboardWaitForValue (
1291 BiosKeyboardPrivate
,
1293 KEYBOARD_WAITFORVALUE_TIMEOUT
1296 if (EFI_ERROR (Status
)) {
1297 Status
= EFI_DEVICE_ERROR
;
1302 // Additional validation, do it as follow:
1303 // 1). check for status register of PARE && TIM via 64H
1304 // 2). perform KB checking by writing ABh via 64H
1306 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & (KBC_STSREG_VIA64_PARE
| KBC_STSREG_VIA64_TIM
)) != 0) {
1307 Status
= EFI_DEVICE_ERROR
;
1311 Status
= KeyboardCommand (
1312 BiosKeyboardPrivate
,
1313 KBC_CMDREG_VIA64_KB_CKECK
1315 if (EFI_ERROR (Status
)) {
1316 Status
= EFI_DEVICE_ERROR
;
1320 Status
= KeyboardWaitForValue (
1321 BiosKeyboardPrivate
,
1322 KBC_CMDECHO_KBCHECK_OK
,
1323 KEYBOARD_WAITFORVALUE_TIMEOUT
1326 if (EFI_ERROR (Status
)) {
1327 Status
= EFI_DEVICE_ERROR
;
1333 // Done for validating keyboard. Enable keyboard (via KBC)
1334 // and recover the command byte to proper value
1336 Status
= KeyboardCommand (
1337 BiosKeyboardPrivate
,
1338 KBC_CMDREG_VIA64_KB_ENABLE
1341 if (EFI_ERROR (Status
)) {
1342 Status
= EFI_DEVICE_ERROR
;
1348 // conditionally enable mouse (via KBC)
1351 Status
= KeyboardCommand (
1352 BiosKeyboardPrivate
,
1353 KBC_CMDREG_VIA64_AUX_ENABLE
1356 if (EFI_ERROR (Status
)) {
1357 Status
= EFI_DEVICE_ERROR
;
1365 // resume priority of task level
1367 gBS
->RestoreTPL (OldTpl
);
1374 Read out the scan code of the key that has just been stroked.
1376 @param This Pointer of simple text Protocol.
1377 @param Key Pointer for store the key that read out.
1379 @retval EFI_SUCCESS The key is read out successfully.
1380 @retval other The key reading failed.
1385 BiosKeyboardReadKeyStroke (
1386 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
1387 OUT EFI_INPUT_KEY
*Key
1390 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1392 EFI_KEY_DATA KeyData
;
1394 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1396 Status
= KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate
, &KeyData
);
1397 if (EFI_ERROR (Status
)) {
1401 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
1407 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
1409 @param Event The event that be siganlled when any key has been stroked.
1410 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1415 BiosKeyboardWaitForKey (
1421 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
1422 // Csm will be used to check whether there is a key pending, but the csm will disable all
1423 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
1424 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
1425 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
1426 // e.g. usb keyboard driver.
1427 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
1428 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
1432 // Use TimerEvent callback funciton to check whether there's any key pressed
1434 BiosKeyboardTimerHandler (NULL
, BIOS_KEYBOARD_DEV_FROM_THIS (Context
));
1436 if (!EFI_ERROR (BiosKeyboardCheckForKey (Context
))) {
1437 gBS
->SignalEvent (Event
);
1442 Check key buffer to get the key stroke status.
1444 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
1446 @retval EFI_SUCCESS A key is being pressed now.
1447 @retval Other No key is now pressed.
1452 BiosKeyboardCheckForKey (
1453 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
1456 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1458 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1460 return CheckQueue (&BiosKeyboardPrivate
->Queue
);
1463 // Private worker functions
1465 #define TABLE_END 0x0
1467 typedef struct _CONVERT_TABLE_ENTRY
{
1470 } CONVERT_TABLE_ENTRY
;
1472 CONVERT_TABLE_ENTRY mConvertTable
[] = {
1514 // Function Keys are only valid if KeyChar == 0x00
1515 // This function does not require KeyChar to be 0x00
1566 // Convert ALT + Fn keys
1615 Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
1617 @param KeyChar Unicode of key.
1618 @param ScanCode Scan code of key.
1620 @return The value of EFI Scancode for the key.
1621 @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
1625 ConvertToEFIScanCode (
1633 if (KeyChar
== CHAR_ESC
) {
1634 EfiScanCode
= SCAN_ESC
;
1635 } else if (KeyChar
== 0x00 || KeyChar
== 0xe0) {
1637 // Movement & Function Keys
1639 for (Index
= 0; (Index
< sizeof (mConvertTable
) / sizeof (CONVERT_TABLE_ENTRY
)) && (mConvertTable
[Index
].ScanCode
!= TABLE_END
); Index
+= 1) {
1640 if (ScanCode
== mConvertTable
[Index
].ScanCode
) {
1641 return mConvertTable
[Index
].EfiScanCode
;
1645 // Reach Table end, return default value
1656 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1657 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1658 should not be in system.
1660 @param BiosKeyboardPrivate Keyboard Private Data Struture
1662 @retval TRUE Keyboard in System.
1663 @retval FALSE Keyboard not in System.
1667 CheckKeyboardConnect (
1668 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
1673 Status
= EFI_SUCCESS
;
1675 // enable keyboard itself and wait for its ack
1676 // If can't receive ack, Keyboard should not be connected.
1678 Status
= KeyboardWrite (
1679 BiosKeyboardPrivate
,
1680 KBC_INPBUF_VIA60_KBEN
1682 if (EFI_ERROR (Status
)) {
1683 DEBUG ((EFI_D_ERROR
, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));
1684 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1685 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1686 EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
,
1687 BiosKeyboardPrivate
->DevicePath
1692 Status
= KeyboardWaitForValue (
1693 BiosKeyboardPrivate
,
1695 KEYBOARD_WAITFORVALUE_TIMEOUT
1698 if (EFI_ERROR (Status
)) {
1699 DEBUG ((EFI_D_ERROR
, "[KBD]CheckKeyboardConnect - Timeout!\n"));
1700 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1701 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1702 EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
,
1703 BiosKeyboardPrivate
->DevicePath
1712 Timer event handler: read a series of key stroke from 8042
1713 and put them into memory key buffer.
1714 It is registered as running under TPL_NOTIFY
1716 @param Event The timer event
1717 @param Context A BIOS_KEYBOARD_DEV pointer
1722 BiosKeyboardTimerHandler (
1728 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1729 EFI_IA32_REGISTER_SET Regs
;
1730 UINT8 KbFlag1
; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
1731 UINT8 KbFlag2
; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
1732 EFI_KEY_DATA KeyData
;
1734 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1736 BiosKeyboardPrivate
= Context
;
1739 // Enter critical section
1741 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1744 // if there is no key present, just return
1746 if (BiosKeyboardPrivate
->ExtendedKeyboard
) {
1752 BiosKeyboardPrivate
->LegacyBios
->Int86 (
1753 BiosKeyboardPrivate
->LegacyBios
,
1757 if (Regs
.X
.Flags
.ZF
!= 0) {
1758 gBS
->RestoreTPL (OldTpl
);
1765 if (BiosKeyboardPrivate
->ExtendedKeyboard
) {
1771 BiosKeyboardPrivate
->LegacyBios
->Int86 (
1772 BiosKeyboardPrivate
->LegacyBios
,
1777 KeyData
.Key
.ScanCode
= (UINT16
) Regs
.H
.AH
;
1778 KeyData
.Key
.UnicodeChar
= (UINT16
) Regs
.H
.AL
;
1781 "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
1782 KeyData
.Key
.ScanCode
,
1783 KeyData
.Key
.UnicodeChar
1786 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
1787 KeyData
.KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
1789 // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then
1790 // 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
1791 // 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
1792 // 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
1793 // 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
1794 // 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
1795 // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers
1796 // performance, like USB.
1798 // 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
1799 // 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
1800 // 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
1803 // 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
1804 // 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,
1805 // which will let persist to press SHIFT has same effection as only press one time.
1807 //0040h:0017h - KEYBOARD - STATUS FLAGS 1
1809 // 6 Caps Lock active
1810 // 5 Num Lock active
1811 // 4 Scroll Lock active
1812 // 3 either Alt pressed
1813 // 2 either Ctrl pressed
1814 // 1 Left Shift pressed
1815 // 0 Right Shift pressed
1819 // Clear the CTRL and ALT BDA flag
1821 KbFlag1
= *((UINT8
*) (UINTN
) 0x417); // read the STATUS FLAGS 1
1822 KbFlag2
= *((UINT8
*) (UINTN
) 0x418); // read STATUS FLAGS 2
1826 if ((KbFlag1
& KB_CAPS_LOCK_BIT
) == KB_CAPS_LOCK_BIT
) {
1827 DEBUG ((EFI_D_INFO
, "[KBD]Caps Lock Key is pressed.\n"));
1829 if ((KbFlag1
& KB_NUM_LOCK_BIT
) == KB_NUM_LOCK_BIT
) {
1830 DEBUG ((EFI_D_INFO
, "[KBD]Num Lock Key is pressed.\n"));
1832 if ((KbFlag1
& KB_SCROLL_LOCK_BIT
) == KB_SCROLL_LOCK_BIT
) {
1833 DEBUG ((EFI_D_INFO
, "[KBD]Scroll Lock Key is pressed.\n"));
1835 if ((KbFlag1
& KB_ALT_PRESSED
) == KB_ALT_PRESSED
) {
1836 if ((KbFlag2
& KB_LEFT_ALT_PRESSED
) == KB_LEFT_ALT_PRESSED
) {
1837 DEBUG ((EFI_D_INFO
, "[KBD]Left Alt Key is pressed.\n"));
1839 DEBUG ((EFI_D_INFO
, "[KBD]Right Alt Key is pressed.\n"));
1842 if ((KbFlag1
& KB_CTRL_PRESSED
) == KB_CTRL_PRESSED
) {
1843 if ((KbFlag2
& KB_LEFT_CTRL_PRESSED
) == KB_LEFT_CTRL_PRESSED
) {
1844 DEBUG ((EFI_D_INFO
, "[KBD]Left Ctrl Key is pressed.\n"));
1846 DEBUG ((EFI_D_INFO
, "[KBD]Right Ctrl Key is pressed.\n"));
1849 if ((KbFlag1
& KB_LEFT_SHIFT_PRESSED
) == KB_LEFT_SHIFT_PRESSED
) {
1850 DEBUG ((EFI_D_INFO
, "[KBD]Left Shift Key is pressed.\n"));
1852 if ((KbFlag1
& KB_RIGHT_SHIFT_PRESSED
) == KB_RIGHT_SHIFT_PRESSED
) {
1853 DEBUG ((EFI_D_INFO
, "[KBD]Right Shift Key is pressed.\n"));
1859 // Record toggle state
1861 if ((KbFlag1
& KB_CAPS_LOCK_BIT
) == KB_CAPS_LOCK_BIT
) {
1862 KeyData
.KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1864 if ((KbFlag1
& KB_NUM_LOCK_BIT
) == KB_NUM_LOCK_BIT
) {
1865 KeyData
.KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1867 if ((KbFlag1
& KB_SCROLL_LOCK_BIT
) == KB_SCROLL_LOCK_BIT
) {
1868 KeyData
.KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1871 // Record shift state
1872 // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
1874 if ((KbFlag1
& KB_ALT_PRESSED
) == KB_ALT_PRESSED
) {
1875 KeyData
.KeyState
.KeyShiftState
|= ((KbFlag2
& KB_LEFT_ALT_PRESSED
) == KB_LEFT_ALT_PRESSED
) ? EFI_LEFT_ALT_PRESSED
: EFI_RIGHT_ALT_PRESSED
;
1877 if ((KbFlag1
& KB_CTRL_PRESSED
) == KB_CTRL_PRESSED
) {
1878 KeyData
.KeyState
.KeyShiftState
|= ((KbFlag2
& KB_LEFT_CTRL_PRESSED
) == KB_LEFT_CTRL_PRESSED
) ? EFI_LEFT_CONTROL_PRESSED
: EFI_RIGHT_CONTROL_PRESSED
;
1880 if ((KbFlag1
& KB_LEFT_SHIFT_PRESSED
) == KB_LEFT_SHIFT_PRESSED
) {
1881 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1883 if ((KbFlag1
& KB_RIGHT_SHIFT_PRESSED
) == KB_RIGHT_SHIFT_PRESSED
) {
1884 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1888 // Clear left alt and left ctrl BDA flag
1890 KbFlag2
&= ~(KB_LEFT_ALT_PRESSED
| KB_LEFT_CTRL_PRESSED
);
1891 *((UINT8
*) (UINTN
) 0x418) = KbFlag2
;
1893 *((UINT8
*) (UINTN
) 0x417) = KbFlag1
;
1897 // Output EFI input key and shift/toggle state
1899 if (KeyData
.Key
.UnicodeChar
== CHAR_NULL
|| KeyData
.Key
.UnicodeChar
== CHAR_SCANCODE
|| KeyData
.Key
.UnicodeChar
== CHAR_ESC
) {
1900 KeyData
.Key
.ScanCode
= ConvertToEFIScanCode (KeyData
.Key
.UnicodeChar
, KeyData
.Key
.ScanCode
);
1901 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1903 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1907 // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
1909 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
1910 if (KeyData
.Key
.UnicodeChar
>= 1 && KeyData
.Key
.UnicodeChar
<= 26) {
1911 if (((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
)) != 0) ==
1912 ((KeyData
.KeyState
.KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) != 0)
1914 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
+ L
'a' - 1);
1916 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
+ L
'A' - 1);
1923 "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
1924 KeyData
.Key
.ScanCode
,
1925 KeyData
.Key
.UnicodeChar
1929 // Need not return associated shift state if a class of printable characters that
1930 // are normally adjusted by shift modifiers.
1931 // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
1933 if ((KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') ||
1934 (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z')
1936 DEBUG ((EFI_D_INFO
, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));
1937 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1941 // Invoke notification functions if exist
1943 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
1944 CurrentNotify
= CR (
1946 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1948 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1950 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1951 CurrentNotify
->KeyNotificationFn (&KeyData
);
1956 // Convert the Ctrl+[a-z] to Ctrl+[1-26]
1958 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
1959 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1960 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
1961 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1962 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
1965 Enqueue (&BiosKeyboardPrivate
->Queue
, &KeyData
);
1967 // Leave critical section and return
1969 gBS
->RestoreTPL (OldTpl
);
1975 Free keyboard notify list.
1977 @param ListHead The list head
1979 @retval EFI_SUCCESS Free the notify list successfully
1980 @retval EFI_INVALID_PARAMETER ListHead is invalid.
1984 BiosKeyboardFreeNotifyList (
1985 IN OUT LIST_ENTRY
*ListHead
1988 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
1990 if (ListHead
== NULL
) {
1991 return EFI_INVALID_PARAMETER
;
1993 while (!IsListEmpty (ListHead
)) {
1995 ListHead
->ForwardLink
,
1996 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1998 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2000 RemoveEntryList (ListHead
->ForwardLink
);
2001 gBS
->FreePool (NotifyNode
);
2008 Check if key is registered.
2010 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
2011 state data for the key that was registered.
2012 @param InputData A pointer to a buffer that is filled in with the keystroke
2013 state data for the key that was pressed.
2015 @retval TRUE Key be pressed matches a registered key.
2016 @retval FLASE Match failed.
2021 IN EFI_KEY_DATA
*RegsiteredData
,
2022 IN EFI_KEY_DATA
*InputData
2025 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
2027 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
2028 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
2033 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
2035 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
2036 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
2039 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
2040 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
2049 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
2051 @param Event The event that be siganlled when any key has been stroked.
2052 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
2057 BiosKeyboardWaitForKeyEx (
2062 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2064 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context
);
2065 BiosKeyboardWaitForKey (Event
, &BiosKeyboardPrivate
->SimpleTextIn
);
2070 Reset the input device and optionaly run diagnostics
2072 @param This Protocol instance pointer.
2073 @param ExtendedVerification Driver may perform diagnostics on reset.
2075 @retval EFI_SUCCESS The device was reset.
2076 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
2082 BiosKeyboardResetEx (
2083 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2084 IN BOOLEAN ExtendedVerification
2087 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2091 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2093 Status
= BiosKeyboardPrivate
->SimpleTextIn
.Reset (
2094 &BiosKeyboardPrivate
->SimpleTextIn
,
2095 ExtendedVerification
2097 if (EFI_ERROR (Status
)) {
2098 return EFI_DEVICE_ERROR
;
2101 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2103 gBS
->RestoreTPL (OldTpl
);
2110 Reads the next keystroke from the input device. The WaitForKey Event can
2111 be used to test for existance of a keystroke via WaitForEvent () call.
2113 @param This Protocol instance pointer.
2114 @param KeyData A pointer to a buffer that is filled in with the keystroke
2115 state data for the key that was pressed.
2117 @retval EFI_SUCCESS The keystroke information was returned.
2118 @retval EFI_NOT_READY There was no keystroke data availiable.
2119 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
2121 @retval EFI_INVALID_PARAMETER KeyData is NULL.
2126 BiosKeyboardReadKeyStrokeEx (
2127 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2128 OUT EFI_KEY_DATA
*KeyData
2131 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2133 if (KeyData
== NULL
) {
2134 return EFI_INVALID_PARAMETER
;
2137 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2139 return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate
, KeyData
);
2144 Set certain state for the input device.
2146 @param This Protocol instance pointer.
2147 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
2148 state for the input device.
2150 @retval EFI_SUCCESS The device state was set successfully.
2151 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
2152 not have the setting adjusted.
2153 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
2154 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
2159 BiosKeyboardSetState (
2160 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2161 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
2165 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2167 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
2170 if (KeyToggleState
== NULL
) {
2171 return EFI_INVALID_PARAMETER
;
2175 // Thunk keyboard driver doesn't support partial keystroke.
2177 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
||
2178 (*KeyToggleState
& EFI_KEY_STATE_EXPOSED
) == EFI_KEY_STATE_EXPOSED
2180 return EFI_UNSUPPORTED
;
2183 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2185 // See if the Legacy BIOS Protocol is available
2187 Status
= gBS
->LocateProtocol (
2188 &gEfiLegacyBiosProtocolGuid
,
2190 (VOID
**) &LegacyBios
2193 ASSERT_EFI_ERROR (Status
);
2195 // Enter critical section
2197 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2200 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
2203 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
2206 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
2210 Status
= KeyboardWrite (BiosKeyboardPrivate
, 0xed);
2211 if (EFI_ERROR (Status
)) {
2212 return EFI_DEVICE_ERROR
;
2214 Status
= KeyboardWaitForValue (BiosKeyboardPrivate
, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT
);
2215 if (EFI_ERROR (Status
)) {
2216 return EFI_DEVICE_ERROR
;
2218 Status
= KeyboardWrite (BiosKeyboardPrivate
, Command
);
2219 if (EFI_ERROR (Status
)) {
2220 return EFI_DEVICE_ERROR
;
2223 // Call Legacy BIOS Protocol to set whatever is necessary
2225 LegacyBios
->UpdateKeyboardLedStatus (LegacyBios
, Command
);
2227 Status
= EFI_SUCCESS
;
2230 // Leave critical section and return
2232 gBS
->RestoreTPL (OldTpl
);
2239 Register a notification function for a particular keystroke for the input device.
2241 @param This Protocol instance pointer.
2242 @param KeyData A pointer to a buffer that is filled in with the keystroke
2243 information data for the key that was pressed.
2244 @param KeyNotificationFunction Points to the function to be called when the key
2245 sequence is typed specified by KeyData.
2246 @param NotifyHandle Points to the unique handle assigned to the registered notification.
2249 @retval EFI_SUCCESS The notification function was registered successfully.
2250 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
2251 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
2256 BiosKeyboardRegisterKeyNotify (
2257 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2258 IN EFI_KEY_DATA
*KeyData
,
2259 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
2260 OUT EFI_HANDLE
*NotifyHandle
2264 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2266 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
2268 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
2270 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
2271 return EFI_INVALID_PARAMETER
;
2274 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2277 // Enter critical section
2279 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2282 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
2284 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
2285 CurrentNotify
= CR (
2287 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
2289 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2291 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
2292 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
2293 *NotifyHandle
= CurrentNotify
->NotifyHandle
;
2294 Status
= EFI_SUCCESS
;
2301 // Allocate resource to save the notification function
2304 NewNotify
= (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
2305 if (NewNotify
== NULL
) {
2306 Status
= EFI_OUT_OF_RESOURCES
;
2310 NewNotify
->Signature
= BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
2311 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
2312 NewNotify
->NotifyHandle
= (EFI_HANDLE
) NewNotify
;
2313 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
2314 InsertTailList (&BiosKeyboardPrivate
->NotifyList
, &NewNotify
->NotifyEntry
);
2316 *NotifyHandle
= NewNotify
->NotifyHandle
;
2317 Status
= EFI_SUCCESS
;
2321 // Leave critical section and return
2323 gBS
->RestoreTPL (OldTpl
);
2328 Remove a registered notification function from a particular keystroke.
2330 @param This Protocol instance pointer.
2331 @param NotificationHandle The handle of the notification function being unregistered.
2333 @retval EFI_SUCCESS The notification function was unregistered successfully.
2334 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
2339 BiosKeyboardUnregisterKeyNotify (
2340 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2341 IN EFI_HANDLE NotificationHandle
2345 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2348 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
2351 // Check incoming notification handle
2353 if (NotificationHandle
== NULL
) {
2354 return EFI_INVALID_PARAMETER
;
2357 if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) NotificationHandle
)->Signature
!= BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
) {
2358 return EFI_INVALID_PARAMETER
;
2361 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2364 // Enter critical section
2366 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2368 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
2369 CurrentNotify
= CR (
2371 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
2373 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2375 if (CurrentNotify
->NotifyHandle
== NotificationHandle
) {
2377 // Remove the notification function from NotifyList and free resources
2379 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
2381 Status
= EFI_SUCCESS
;
2387 // Can not find the specified Notification Handle
2389 Status
= EFI_INVALID_PARAMETER
;
2393 // Leave critical section and return
2395 gBS
->RestoreTPL (OldTpl
);
2400 The user Entry Point for module BiosKeyboard. The user code starts with this function.
2402 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2403 @param[in] SystemTable A pointer to the EFI System Table.
2405 @retval EFI_SUCCESS The entry point is executed successfully.
2406 @retval other Some error occurs when executing this entry point.
2411 InitializeBiosKeyboard(
2412 IN EFI_HANDLE ImageHandle
,
2413 IN EFI_SYSTEM_TABLE
*SystemTable
2419 // Install driver model protocol(s).
2421 Status
= EfiLibInstallDriverBindingComponentName2 (
2424 &gBiosKeyboardDriverBinding
,
2426 &gBiosKeyboardComponentName
,
2427 &gBiosKeyboardComponentName2
2429 ASSERT_EFI_ERROR (Status
);