2 ConsoleOut Routines that speak VGA.
4 Copyright (c) 2006 - 2012, 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
);
283 // Report that the keyboard is being enabled
287 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_ENABLE
291 // Setup the WaitForKey event
293 Status
= gBS
->CreateEvent (
296 BiosKeyboardWaitForKey
,
297 &(BiosKeyboardPrivate
->SimpleTextIn
),
298 &((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
)
300 if (EFI_ERROR (Status
)) {
301 (BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
= NULL
;
304 Status
= gBS
->CreateEvent (
307 BiosKeyboardWaitForKeyEx
,
308 &(BiosKeyboardPrivate
->SimpleTextInputEx
),
309 &(BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
)
311 if (EFI_ERROR (Status
)) {
312 BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
= NULL
;
317 // Setup a periodic timer, used for reading keystrokes at a fixed interval
319 Status
= gBS
->CreateEvent (
320 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
322 BiosKeyboardTimerHandler
,
324 &BiosKeyboardPrivate
->TimerEvent
326 if (EFI_ERROR (Status
)) {
327 Status
= EFI_OUT_OF_RESOURCES
;
328 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
332 Status
= gBS
->SetTimer (
333 BiosKeyboardPrivate
->TimerEvent
,
335 KEYBOARD_TIMER_INTERVAL
337 if (EFI_ERROR (Status
)) {
338 Status
= EFI_OUT_OF_RESOURCES
;
339 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
;
344 // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
348 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_PRESENCE_DETECT
352 // Reset the keyboard device
354 Status
= BiosKeyboardPrivate
->SimpleTextInputEx
.Reset (
355 &BiosKeyboardPrivate
->SimpleTextInputEx
,
356 FeaturePcdGet (PcdPs2KbdExtendedVerification
)
358 if (EFI_ERROR (Status
)) {
359 DEBUG ((EFI_D_ERROR
, "[KBD]Reset Failed. Status - %r\n", Status
));
360 StatusCode
= EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_NOT_DETECTED
;
364 // Do platform specific policy like port swapping and keyboard light default
366 if (Ps2Policy
!= NULL
) {
368 Ps2Policy
->Ps2InitHardware (Controller
);
371 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_CAPSLOCK
) == EFI_KEYBOARD_CAPSLOCK
) {
375 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_NUMLOCK
) == EFI_KEYBOARD_NUMLOCK
) {
379 if ((Ps2Policy
->KeyboardLight
& EFI_KEYBOARD_SCROLLLOCK
) == EFI_KEYBOARD_SCROLLLOCK
) {
383 KeyboardWrite (BiosKeyboardPrivate
, 0xed);
384 KeyboardWaitForValue (BiosKeyboardPrivate
, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT
);
385 KeyboardWrite (BiosKeyboardPrivate
, Command
);
387 // Call Legacy BIOS Protocol to set whatever is necessary
389 LegacyBios
->UpdateKeyboardLedStatus (LegacyBios
, Command
);
395 CarryFlag
= BiosKeyboardPrivate
->LegacyBios
->Int86 (
396 BiosKeyboardPrivate
->LegacyBios
,
403 // Check bit 6 of Feature Byte 2.
404 // If it is set, then Int 16 Func 09 is supported
406 if (*(UINT8
*)(UINTN
) ((Regs
.X
.ES
<< 4) + Regs
.X
.BX
+ 0x06) & 0x40) {
408 // Get Keyboard Functionality
411 CarryFlag
= BiosKeyboardPrivate
->LegacyBios
->Int86 (
412 BiosKeyboardPrivate
->LegacyBios
,
419 // Check bit 5 of AH.
420 // If it is set, then INT 16 Finc 10-12 are supported.
422 if ((Regs
.H
.AL
& 0x40) != 0) {
424 // Set the flag to use INT 16 Func 10-12
426 BiosKeyboardPrivate
->ExtendedKeyboard
= TRUE
;
431 DEBUG ((EFI_D_INFO
, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN
)BiosKeyboardPrivate
->ExtendedKeyboard
));
433 // Install protocol interfaces for the keyboard device.
435 Status
= gBS
->InstallMultipleProtocolInterfaces (
437 &gEfiSimpleTextInProtocolGuid
,
438 &BiosKeyboardPrivate
->SimpleTextIn
,
439 &gEfiSimpleTextInputExProtocolGuid
,
440 &BiosKeyboardPrivate
->SimpleTextInputEx
,
445 if (StatusCode
!= 0) {
447 // Report an Error Code for failing to start the keyboard device
450 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
455 if (EFI_ERROR (Status
)) {
457 if (BiosKeyboardPrivate
!= NULL
) {
458 if ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
!= NULL
) {
459 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
462 if ((BiosKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
!= NULL
) {
463 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
);
465 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate
->NotifyList
);
467 if (BiosKeyboardPrivate
->TimerEvent
!= NULL
) {
468 gBS
->CloseEvent (BiosKeyboardPrivate
->TimerEvent
);
471 FreePool (BiosKeyboardPrivate
);
477 &gEfiIsaIoProtocolGuid
,
478 This
->DriverBindingHandle
,
488 Stop the device handled by this driver.
490 @param This The driver binding protocol.
491 @param Controller The controller to release.
492 @param NumberOfChildren The number of handles in ChildHandleBuffer.
493 @param ChildHandleBuffer The array of child handle.
495 @retval EFI_SUCCESS The device was stopped.
496 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
497 @retval Others Fail to uninstall protocols attached on the device.
502 BiosKeyboardDriverBindingStop (
503 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
504 IN EFI_HANDLE Controller
,
505 IN UINTN NumberOfChildren
,
506 IN EFI_HANDLE
*ChildHandleBuffer
510 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextIn
;
511 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
516 Status
= gBS
->OpenProtocol (
518 &gEfiSimpleTextInProtocolGuid
,
519 (VOID
**) &SimpleTextIn
,
520 This
->DriverBindingHandle
,
522 EFI_OPEN_PROTOCOL_GET_PROTOCOL
524 if (EFI_ERROR (Status
)) {
528 Status
= gBS
->OpenProtocol (
530 &gEfiSimpleTextInputExProtocolGuid
,
532 This
->DriverBindingHandle
,
534 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
536 if (EFI_ERROR (Status
)) {
540 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn
);
542 Status
= gBS
->UninstallMultipleProtocolInterfaces (
544 &gEfiSimpleTextInProtocolGuid
,
545 &BiosKeyboardPrivate
->SimpleTextIn
,
546 &gEfiSimpleTextInputExProtocolGuid
,
547 &BiosKeyboardPrivate
->SimpleTextInputEx
,
550 if (EFI_ERROR (Status
)) {
554 // Release the IsaIo protocol on the controller handle
558 &gEfiIsaIoProtocolGuid
,
559 This
->DriverBindingHandle
,
564 // Free other resources
566 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
567 gBS
->CloseEvent (BiosKeyboardPrivate
->TimerEvent
);
568 gBS
->CloseEvent (BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
);
569 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate
->NotifyList
);
571 FreePool (BiosKeyboardPrivate
);
577 Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
579 @param BiosKeyboardPrivate Keyboard instance pointer.
581 @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
585 KeyReadDataRegister (
586 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
592 // Use IsaIo protocol to perform IO operations
594 BiosKeyboardPrivate
->IsaIo
->Io
.Read (
595 BiosKeyboardPrivate
->IsaIo
,
597 BiosKeyboardPrivate
->DataRegisterAddress
,
606 Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
608 @param BiosKeyboardPrivate Keyboard instance pointer.
610 @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.
614 KeyReadStatusRegister (
615 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
621 // Use IsaIo protocol to perform IO operations
623 BiosKeyboardPrivate
->IsaIo
->Io
.Read (
624 BiosKeyboardPrivate
->IsaIo
,
626 BiosKeyboardPrivate
->StatusRegisterAddress
,
635 Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
637 @param BiosKeyboardPrivate Keyboard instance pointer.
638 @param Data Data byte to write.
642 KeyWriteCommandRegister (
643 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
648 // Use IsaIo protocol to perform IO operations
650 BiosKeyboardPrivate
->IsaIo
->Io
.Write (
651 BiosKeyboardPrivate
->IsaIo
,
653 BiosKeyboardPrivate
->CommandRegisterAddress
,
660 Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
662 @param BiosKeyboardPrivate Keyboard instance pointer.
663 @param Data Data byte to write.
667 KeyWriteDataRegister (
668 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
673 // Use IsaIo protocol to perform IO operations
675 BiosKeyboardPrivate
->IsaIo
->Io
.Write (
676 BiosKeyboardPrivate
->IsaIo
,
678 BiosKeyboardPrivate
->DataRegisterAddress
,
685 Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
687 @param BiosKeyboardPrivate Keyboard instance pointer.
688 @param Data The pointer for data that being read out.
690 @retval EFI_SUCCESS The data byte read out successfully.
691 @retval EFI_TIMEOUT Timeout occurred during reading out data byte.
696 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
707 // wait till output buffer full then perform the read
709 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
710 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_OUTB
) != 0) {
712 *Data
= KeyReadDataRegister (BiosKeyboardPrivate
);
719 if (RegFilled
== 0) {
727 Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
729 @param BiosKeyboardPrivate Keyboard instance pointer.
730 @param Data Data byte to write.
732 @retval EFI_SUCCESS The data byte is written successfully.
733 @retval EFI_TIMEOUT Timeout occurred during writing.
738 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
749 // wait for input buffer empty
751 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
752 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
760 if (RegEmptied
== 0) {
766 KeyWriteDataRegister (BiosKeyboardPrivate
, Data
);
772 Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
774 @param BiosKeyboardPrivate Keyboard instance pointer.
775 @param Data Command byte to write.
777 @retval EFI_SUCCESS The command byte is written successfully.
778 @retval EFI_TIMEOUT Timeout occurred during writing.
783 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
794 // Wait For Input Buffer Empty
796 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
797 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
805 if (RegEmptied
== 0) {
811 KeyWriteCommandRegister (BiosKeyboardPrivate
, Data
);
814 // Wait For Input Buffer Empty again
817 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
818 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
826 if (RegEmptied
== 0) {
834 Wait for a specific value to be presented in
835 Data register of Keyboard Controller by keyboard and then read it,
836 used in keyboard commands ack
838 @param BiosKeyboardPrivate Keyboard instance pointer.
839 @param Value The value to be waited for
840 @param WaitForValueTimeOut The limit of microseconds for timeout
842 @retval EFI_SUCCESS The command byte is written successfully.
843 @retval EFI_TIMEOUT Timeout occurred during writing.
847 KeyboardWaitForValue (
848 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
850 IN UINTN WaitForValueTimeOut
863 // Make sure the initial value of 'Data' is different from 'Value'
870 // Read from 8042 (multiple times if needed)
871 // until the expected value appears
872 // use SumTimeOut to control the iteration
878 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
879 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_OUTB
) != 0) {
880 Data
= KeyReadDataRegister (BiosKeyboardPrivate
);
887 SumTimeOut
+= TimeOut
;
894 if (SumTimeOut
>= WaitForValueTimeOut
) {
910 Reads the next keystroke from the input device. The WaitForKey Event can
911 be used to test for existance of a keystroke via WaitForEvent () call.
913 @param BiosKeyboardPrivate Bioskeyboard driver private structure.
914 @param KeyData A pointer to a buffer that is filled in with the keystroke
915 state data for the key that was pressed.
917 @retval EFI_SUCCESS The keystroke information was returned.
918 @retval EFI_NOT_READY There was no keystroke data availiable.
919 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
921 @retval EFI_INVALID_PARAMETER KeyData is NULL.
925 KeyboardReadKeyStrokeWorker (
926 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
927 OUT EFI_KEY_DATA
*KeyData
932 if (KeyData
== NULL
) {
933 return EFI_INVALID_PARAMETER
;
937 // Use TimerEvent callback funciton to check whether there's any key pressed
941 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
942 // Csm will be used to check whether there is a key pending, but the csm will disable all
943 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
944 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
945 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
946 // e.g. usb keyboard driver.
947 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
948 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
952 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
954 BiosKeyboardTimerHandler (NULL
, BiosKeyboardPrivate
);
956 // If there's no key, just return
958 Status
= CheckQueue (&BiosKeyboardPrivate
->Queue
);
959 if (EFI_ERROR (Status
)) {
960 gBS
->RestoreTPL (OldTpl
);
961 return EFI_NOT_READY
;
964 Status
= Dequeue (&BiosKeyboardPrivate
->Queue
, KeyData
);
966 gBS
->RestoreTPL (OldTpl
);
972 // EFI Simple Text In Protocol Functions
975 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
977 @param This Pointer of simple text Protocol.
978 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
980 @retval EFI_SUCCESS The command byte is written successfully.
981 @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
987 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
988 IN BOOLEAN ExtendedVerification
991 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
999 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1003 // Report reset progress code
1005 REPORT_STATUS_CODE (
1007 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
1011 // Report a Progress Code for clearing the keyboard buffer
1013 REPORT_STATUS_CODE (
1015 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
1020 // Raise TPL to avoid mouse operation impact
1022 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1026 // Exhaust output buffer data
1029 Status
= BiosKeyboardReadKeyStroke (
1033 } while (!EFI_ERROR (Status
));
1036 // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
1037 // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
1040 if (!PcdGetBool (PcdFastPS2Detection
)) {
1041 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_SYSF
) != 0) {
1044 // CheckMouseStatus to decide enable it later or not
1047 // Read the command byte of KBC
1049 Status
= KeyboardCommand (
1050 BiosKeyboardPrivate
,
1051 KBC_CMDREG_VIA64_CMDBYTE_R
1054 if (EFI_ERROR (Status
)) {
1055 Status
= EFI_DEVICE_ERROR
;
1059 Status
= KeyboardRead (
1060 BiosKeyboardPrivate
,
1064 if (EFI_ERROR (Status
)) {
1065 Status
= EFI_DEVICE_ERROR
;
1069 // Check mouse enabled or not before
1071 if ((CommandByte
& KB_CMMBYTE_DISABLE_AUX
) != 0) {
1072 MouseEnable
= FALSE
;
1078 // disable mouse (via KBC) and Keyborad device
1080 Status
= KeyboardCommand (
1081 BiosKeyboardPrivate
,
1082 KBC_CMDREG_VIA64_AUX_DISABLE
1085 if (EFI_ERROR (Status
)) {
1086 Status
= EFI_DEVICE_ERROR
;
1090 Status
= KeyboardCommand (
1091 BiosKeyboardPrivate
,
1092 KBC_CMDREG_VIA64_KB_DISABLE
1095 if (EFI_ERROR (Status
)) {
1096 Status
= EFI_DEVICE_ERROR
;
1105 // Report a Progress Code for performing a self test on the keyboard controller
1107 REPORT_STATUS_CODE (
1109 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
1112 Status
= KeyboardCommand (
1113 BiosKeyboardPrivate
,
1114 KBC_CMDREG_VIA64_KBC_SLFTEST
1116 if (EFI_ERROR (Status
)) {
1117 Status
= EFI_DEVICE_ERROR
;
1121 Status
= KeyboardWaitForValue (
1122 BiosKeyboardPrivate
,
1123 KBC_CMDECHO_KBCSLFTEST_OK
,
1124 KEYBOARD_WAITFORVALUE_TIMEOUT
1126 if (EFI_ERROR (Status
)) {
1127 Status
= EFI_DEVICE_ERROR
;
1134 // Disable Mouse interface, enable Keyboard interface and declare selftest success
1136 // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
1138 Status
= KeyboardCommand (
1139 BiosKeyboardPrivate
,
1140 KBC_CMDREG_VIA64_CMDBYTE_W
1143 if (EFI_ERROR (Status
)) {
1144 Status
= EFI_DEVICE_ERROR
;
1149 // Write 8042 Command Byte, set System Flag
1150 // While at the same time:
1151 // 1. disable mouse interface,
1152 // 2. enable kbd interface,
1153 // 3. enable PC/XT kbd translation mode
1154 // 4. enable mouse and kbd interrupts
1156 //Command Byte bits:
1158 // 6: PC/XT translation mode
1159 // 5: Disable Auxiliary device interface
1160 // 4: Disable keyboard interface
1163 // 1: Enable Auxiliary device interrupt
1164 // 0: Enable Keyboard interrupt
1167 Status
= KeyboardWrite (
1168 BiosKeyboardPrivate
,
1169 (UINT8
) ((CommandByte
&
1170 (~KB_CMMBYTE_DISABLE_KB
)) |
1171 KB_CMMBYTE_KSCAN2UNI_COV
|
1172 KB_CMMBYTE_ENABLE_AUXINT
|
1173 KB_CMMBYTE_ENABLE_KBINT
|
1174 KB_CMMBYTE_SLFTEST_SUCC
|
1175 KB_CMMBYTE_DISABLE_AUX
)
1179 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1180 // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.
1181 // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
1182 // Real reset will not do.
1184 if (ExtendedVerification
&& CheckKeyboardConnect (BiosKeyboardPrivate
)) {
1187 // Send keyboard reset command then read ACK
1189 Status
= KeyboardWrite (
1190 BiosKeyboardPrivate
,
1191 KBC_INPBUF_VIA60_KBRESET
1194 if (EFI_ERROR (Status
)) {
1195 Status
= EFI_DEVICE_ERROR
;
1199 Status
= KeyboardWaitForValue (
1200 BiosKeyboardPrivate
,
1202 KEYBOARD_WAITFORVALUE_TIMEOUT
1205 if (EFI_ERROR (Status
)) {
1206 Status
= EFI_DEVICE_ERROR
;
1211 // Wait for keyboard return test OK.
1213 Status
= KeyboardWaitForValue (
1214 BiosKeyboardPrivate
,
1215 KBC_CMDECHO_BATTEST_OK
,
1216 KEYBOARD_WAITFORVALUE_TIMEOUT
1219 if (EFI_ERROR (Status
)) {
1220 Status
= EFI_DEVICE_ERROR
;
1225 // set keyboard scan code set = 02 (standard configuration)
1227 Status
= KeyboardWrite (
1228 BiosKeyboardPrivate
,
1229 KBC_INPBUF_VIA60_KBSCODE
1231 if (EFI_ERROR (Status
)) {
1232 Status
= EFI_DEVICE_ERROR
;
1236 Status
= KeyboardWaitForValue (
1237 BiosKeyboardPrivate
,
1239 KEYBOARD_WAITFORVALUE_TIMEOUT
1242 if (EFI_ERROR (Status
)) {
1243 Status
= EFI_DEVICE_ERROR
;
1247 Status
= KeyboardWrite (
1248 BiosKeyboardPrivate
,
1249 KBC_INPBUF_VIA60_SCODESET2
1251 if (EFI_ERROR (Status
)) {
1252 Status
= EFI_DEVICE_ERROR
;
1256 Status
= KeyboardWaitForValue (
1257 BiosKeyboardPrivate
,
1259 KEYBOARD_WAITFORVALUE_TIMEOUT
1262 if (EFI_ERROR (Status
)) {
1263 Status
= EFI_DEVICE_ERROR
;
1268 // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
1270 Status
= KeyboardWrite (
1271 BiosKeyboardPrivate
,
1272 KBC_INPBUF_VIA60_KBEN
1274 if (EFI_ERROR (Status
)) {
1275 Status
= EFI_DEVICE_ERROR
;
1279 Status
= KeyboardWaitForValue (
1280 BiosKeyboardPrivate
,
1282 KEYBOARD_WAITFORVALUE_TIMEOUT
1285 if (EFI_ERROR (Status
)) {
1286 Status
= EFI_DEVICE_ERROR
;
1291 // Additional validation, do it as follow:
1292 // 1). check for status register of PARE && TIM via 64H
1293 // 2). perform KB checking by writing ABh via 64H
1295 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & (KBC_STSREG_VIA64_PARE
| KBC_STSREG_VIA64_TIM
)) != 0) {
1296 Status
= EFI_DEVICE_ERROR
;
1300 Status
= KeyboardCommand (
1301 BiosKeyboardPrivate
,
1302 KBC_CMDREG_VIA64_KB_CKECK
1304 if (EFI_ERROR (Status
)) {
1305 Status
= EFI_DEVICE_ERROR
;
1309 Status
= KeyboardWaitForValue (
1310 BiosKeyboardPrivate
,
1311 KBC_CMDECHO_KBCHECK_OK
,
1312 KEYBOARD_WAITFORVALUE_TIMEOUT
1315 if (EFI_ERROR (Status
)) {
1316 Status
= EFI_DEVICE_ERROR
;
1322 // Done for validating keyboard. Enable keyboard (via KBC)
1323 // and recover the command byte to proper value
1325 if (!PcdGetBool (PcdFastPS2Detection
)) {
1326 Status
= KeyboardCommand (
1327 BiosKeyboardPrivate
,
1328 KBC_CMDREG_VIA64_KB_ENABLE
1331 if (EFI_ERROR (Status
)) {
1332 Status
= EFI_DEVICE_ERROR
;
1339 // conditionally enable mouse (via KBC)
1342 Status
= KeyboardCommand (
1343 BiosKeyboardPrivate
,
1344 KBC_CMDREG_VIA64_AUX_ENABLE
1347 if (EFI_ERROR (Status
)) {
1348 Status
= EFI_DEVICE_ERROR
;
1356 // resume priority of task level
1358 gBS
->RestoreTPL (OldTpl
);
1365 Read out the scan code of the key that has just been stroked.
1367 @param This Pointer of simple text Protocol.
1368 @param Key Pointer for store the key that read out.
1370 @retval EFI_SUCCESS The key is read out successfully.
1371 @retval other The key reading failed.
1376 BiosKeyboardReadKeyStroke (
1377 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
1378 OUT EFI_INPUT_KEY
*Key
1381 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1383 EFI_KEY_DATA KeyData
;
1385 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1387 Status
= KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate
, &KeyData
);
1388 if (EFI_ERROR (Status
)) {
1393 // Convert the Ctrl+[a-z] to Ctrl+[1-26]
1395 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
1396 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1397 KeyData
.Key
.UnicodeChar
= (CHAR16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
1398 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1399 KeyData
.Key
.UnicodeChar
= (CHAR16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
1403 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
1409 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
1411 @param Event The event that be siganlled when any key has been stroked.
1412 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1417 BiosKeyboardWaitForKey (
1423 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
1424 // Csm will be used to check whether there is a key pending, but the csm will disable all
1425 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
1426 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
1427 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
1428 // e.g. usb keyboard driver.
1429 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
1430 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
1434 // Use TimerEvent callback funciton to check whether there's any key pressed
1436 BiosKeyboardTimerHandler (NULL
, BIOS_KEYBOARD_DEV_FROM_THIS (Context
));
1438 if (!EFI_ERROR (BiosKeyboardCheckForKey (Context
))) {
1439 gBS
->SignalEvent (Event
);
1444 Check key buffer to get the key stroke status.
1446 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
1448 @retval EFI_SUCCESS A key is being pressed now.
1449 @retval Other No key is now pressed.
1454 BiosKeyboardCheckForKey (
1455 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
1458 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1460 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1462 return CheckQueue (&BiosKeyboardPrivate
->Queue
);
1465 // Private worker functions
1467 #define TABLE_END 0x0
1469 typedef struct _CONVERT_TABLE_ENTRY
{
1472 } CONVERT_TABLE_ENTRY
;
1474 CONVERT_TABLE_ENTRY mConvertTable
[] = {
1516 // Function Keys are only valid if KeyChar == 0x00
1517 // This function does not require KeyChar to be 0x00
1568 // Convert ALT + Fn keys
1617 Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
1619 @param KeyChar Unicode of key.
1620 @param ScanCode Scan code of key.
1622 @return The value of EFI Scancode for the key.
1623 @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
1627 ConvertToEFIScanCode (
1635 if (KeyChar
== CHAR_ESC
) {
1636 EfiScanCode
= SCAN_ESC
;
1637 } else if (KeyChar
== 0x00 || KeyChar
== 0xe0) {
1639 // Movement & Function Keys
1641 for (Index
= 0; (Index
< sizeof (mConvertTable
) / sizeof (CONVERT_TABLE_ENTRY
)) && (mConvertTable
[Index
].ScanCode
!= TABLE_END
); Index
+= 1) {
1642 if (ScanCode
== mConvertTable
[Index
].ScanCode
) {
1643 return mConvertTable
[Index
].EfiScanCode
;
1647 // Reach Table end, return default value
1658 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1659 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1660 should not be in system.
1662 @param BiosKeyboardPrivate Keyboard Private Data Struture
1664 @retval TRUE Keyboard in System.
1665 @retval FALSE Keyboard not in System.
1669 CheckKeyboardConnect (
1670 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
1675 Status
= EFI_SUCCESS
;
1677 // enable keyboard itself and wait for its ack
1678 // If can't receive ack, Keyboard should not be connected.
1680 if (!PcdGetBool (PcdFastPS2Detection
)) {
1681 Status
= KeyboardWrite (
1682 BiosKeyboardPrivate
,
1683 KBC_INPBUF_VIA60_KBEN
1685 if (EFI_ERROR (Status
)) {
1686 DEBUG ((EFI_D_ERROR
, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));
1687 REPORT_STATUS_CODE (
1688 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1689 EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
1694 Status
= KeyboardWaitForValue (
1695 BiosKeyboardPrivate
,
1697 KEYBOARD_WAITFORVALUE_TIMEOUT
1700 if (EFI_ERROR (Status
)) {
1701 DEBUG ((EFI_D_ERROR
, "[KBD]CheckKeyboardConnect - Timeout!\n"));
1702 REPORT_STATUS_CODE (
1703 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1704 EFI_PERIPHERAL_KEYBOARD
| EFI_P_EC_CONTROLLER_ERROR
1715 Timer event handler: read a series of key stroke from 8042
1716 and put them into memory key buffer.
1717 It is registered as running under TPL_NOTIFY
1719 @param Event The timer event
1720 @param Context A BIOS_KEYBOARD_DEV pointer
1725 BiosKeyboardTimerHandler (
1731 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1732 EFI_IA32_REGISTER_SET Regs
;
1733 UINT8 KbFlag1
; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
1734 UINT8 KbFlag2
; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
1735 EFI_KEY_DATA KeyData
;
1737 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1739 BiosKeyboardPrivate
= Context
;
1742 // Enter critical section
1744 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1747 // if there is no key present, just return
1749 if (BiosKeyboardPrivate
->ExtendedKeyboard
) {
1755 BiosKeyboardPrivate
->LegacyBios
->Int86 (
1756 BiosKeyboardPrivate
->LegacyBios
,
1760 if (Regs
.X
.Flags
.ZF
!= 0) {
1761 gBS
->RestoreTPL (OldTpl
);
1768 if (BiosKeyboardPrivate
->ExtendedKeyboard
) {
1774 BiosKeyboardPrivate
->LegacyBios
->Int86 (
1775 BiosKeyboardPrivate
->LegacyBios
,
1780 KeyData
.Key
.ScanCode
= (UINT16
) Regs
.H
.AH
;
1781 KeyData
.Key
.UnicodeChar
= (UINT16
) Regs
.H
.AL
;
1784 "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
1785 KeyData
.Key
.ScanCode
,
1786 KeyData
.Key
.UnicodeChar
1789 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
1790 KeyData
.KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
1792 // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then
1793 // 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
1794 // 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
1795 // 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
1796 // 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
1797 // 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
1798 // 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
1799 // performance, like USB.
1801 // 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
1802 // 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
1803 // 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
1806 // 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
1807 // 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,
1808 // which will let persist to press SHIFT has same effection as only press one time.
1810 //0040h:0017h - KEYBOARD - STATUS FLAGS 1
1812 // 6 Caps Lock active
1813 // 5 Num Lock active
1814 // 4 Scroll Lock active
1815 // 3 either Alt pressed
1816 // 2 either Ctrl pressed
1817 // 1 Left Shift pressed
1818 // 0 Right Shift pressed
1822 // Clear the CTRL and ALT BDA flag
1824 KbFlag1
= *((UINT8
*) (UINTN
) 0x417); // read the STATUS FLAGS 1
1825 KbFlag2
= *((UINT8
*) (UINTN
) 0x418); // read STATUS FLAGS 2
1829 if ((KbFlag1
& KB_CAPS_LOCK_BIT
) == KB_CAPS_LOCK_BIT
) {
1830 DEBUG ((EFI_D_INFO
, "[KBD]Caps Lock Key is pressed.\n"));
1832 if ((KbFlag1
& KB_NUM_LOCK_BIT
) == KB_NUM_LOCK_BIT
) {
1833 DEBUG ((EFI_D_INFO
, "[KBD]Num Lock Key is pressed.\n"));
1835 if ((KbFlag1
& KB_SCROLL_LOCK_BIT
) == KB_SCROLL_LOCK_BIT
) {
1836 DEBUG ((EFI_D_INFO
, "[KBD]Scroll Lock Key is pressed.\n"));
1838 if ((KbFlag1
& KB_ALT_PRESSED
) == KB_ALT_PRESSED
) {
1839 if ((KbFlag2
& KB_LEFT_ALT_PRESSED
) == KB_LEFT_ALT_PRESSED
) {
1840 DEBUG ((EFI_D_INFO
, "[KBD]Left Alt Key is pressed.\n"));
1842 DEBUG ((EFI_D_INFO
, "[KBD]Right Alt Key is pressed.\n"));
1845 if ((KbFlag1
& KB_CTRL_PRESSED
) == KB_CTRL_PRESSED
) {
1846 if ((KbFlag2
& KB_LEFT_CTRL_PRESSED
) == KB_LEFT_CTRL_PRESSED
) {
1847 DEBUG ((EFI_D_INFO
, "[KBD]Left Ctrl Key is pressed.\n"));
1849 DEBUG ((EFI_D_INFO
, "[KBD]Right Ctrl Key is pressed.\n"));
1852 if ((KbFlag1
& KB_LEFT_SHIFT_PRESSED
) == KB_LEFT_SHIFT_PRESSED
) {
1853 DEBUG ((EFI_D_INFO
, "[KBD]Left Shift Key is pressed.\n"));
1855 if ((KbFlag1
& KB_RIGHT_SHIFT_PRESSED
) == KB_RIGHT_SHIFT_PRESSED
) {
1856 DEBUG ((EFI_D_INFO
, "[KBD]Right Shift Key is pressed.\n"));
1862 // Record toggle state
1864 if ((KbFlag1
& KB_CAPS_LOCK_BIT
) == KB_CAPS_LOCK_BIT
) {
1865 KeyData
.KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1867 if ((KbFlag1
& KB_NUM_LOCK_BIT
) == KB_NUM_LOCK_BIT
) {
1868 KeyData
.KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1870 if ((KbFlag1
& KB_SCROLL_LOCK_BIT
) == KB_SCROLL_LOCK_BIT
) {
1871 KeyData
.KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1874 // Record shift state
1875 // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
1877 if ((KbFlag1
& KB_ALT_PRESSED
) == KB_ALT_PRESSED
) {
1878 KeyData
.KeyState
.KeyShiftState
|= ((KbFlag2
& KB_LEFT_ALT_PRESSED
) == KB_LEFT_ALT_PRESSED
) ? EFI_LEFT_ALT_PRESSED
: EFI_RIGHT_ALT_PRESSED
;
1880 if ((KbFlag1
& KB_CTRL_PRESSED
) == KB_CTRL_PRESSED
) {
1881 KeyData
.KeyState
.KeyShiftState
|= ((KbFlag2
& KB_LEFT_CTRL_PRESSED
) == KB_LEFT_CTRL_PRESSED
) ? EFI_LEFT_CONTROL_PRESSED
: EFI_RIGHT_CONTROL_PRESSED
;
1883 if ((KbFlag1
& KB_LEFT_SHIFT_PRESSED
) == KB_LEFT_SHIFT_PRESSED
) {
1884 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1886 if ((KbFlag1
& KB_RIGHT_SHIFT_PRESSED
) == KB_RIGHT_SHIFT_PRESSED
) {
1887 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1891 // Clear left alt and left ctrl BDA flag
1893 KbFlag2
&= ~(KB_LEFT_ALT_PRESSED
| KB_LEFT_CTRL_PRESSED
);
1894 *((UINT8
*) (UINTN
) 0x418) = KbFlag2
;
1896 *((UINT8
*) (UINTN
) 0x417) = KbFlag1
;
1900 // Output EFI input key and shift/toggle state
1902 if (KeyData
.Key
.UnicodeChar
== CHAR_NULL
|| KeyData
.Key
.UnicodeChar
== CHAR_SCANCODE
|| KeyData
.Key
.UnicodeChar
== CHAR_ESC
) {
1903 KeyData
.Key
.ScanCode
= ConvertToEFIScanCode (KeyData
.Key
.UnicodeChar
, KeyData
.Key
.ScanCode
);
1904 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1906 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1910 // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
1912 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
1913 if (KeyData
.Key
.UnicodeChar
>= 1 && KeyData
.Key
.UnicodeChar
<= 26) {
1914 if (((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
)) != 0) ==
1915 ((KeyData
.KeyState
.KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) != 0)
1917 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
+ L
'a' - 1);
1919 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
+ L
'A' - 1);
1926 "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
1927 KeyData
.Key
.ScanCode
,
1928 KeyData
.Key
.UnicodeChar
1932 // Need not return associated shift state if a class of printable characters that
1933 // are normally adjusted by shift modifiers.
1934 // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
1936 if ((KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') ||
1937 (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z')
1939 DEBUG ((EFI_D_INFO
, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));
1940 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1944 // Invoke notification functions if exist
1946 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
1947 CurrentNotify
= CR (
1949 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1951 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1953 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1954 CurrentNotify
->KeyNotificationFn (&KeyData
);
1958 Enqueue (&BiosKeyboardPrivate
->Queue
, &KeyData
);
1960 // Leave critical section and return
1962 gBS
->RestoreTPL (OldTpl
);
1968 Free keyboard notify list.
1970 @param ListHead The list head
1972 @retval EFI_SUCCESS Free the notify list successfully
1973 @retval EFI_INVALID_PARAMETER ListHead is invalid.
1977 BiosKeyboardFreeNotifyList (
1978 IN OUT LIST_ENTRY
*ListHead
1981 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
1983 if (ListHead
== NULL
) {
1984 return EFI_INVALID_PARAMETER
;
1986 while (!IsListEmpty (ListHead
)) {
1988 ListHead
->ForwardLink
,
1989 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1991 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1993 RemoveEntryList (ListHead
->ForwardLink
);
1994 gBS
->FreePool (NotifyNode
);
2001 Check if key is registered.
2003 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
2004 state data for the key that was registered.
2005 @param InputData A pointer to a buffer that is filled in with the keystroke
2006 state data for the key that was pressed.
2008 @retval TRUE Key be pressed matches a registered key.
2009 @retval FLASE Match failed.
2014 IN EFI_KEY_DATA
*RegsiteredData
,
2015 IN EFI_KEY_DATA
*InputData
2018 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
2020 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
2021 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
2026 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
2028 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
2029 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
2032 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
2033 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
2042 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
2044 @param Event The event that be siganlled when any key has been stroked.
2045 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
2050 BiosKeyboardWaitForKeyEx (
2055 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2057 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context
);
2058 BiosKeyboardWaitForKey (Event
, &BiosKeyboardPrivate
->SimpleTextIn
);
2063 Reset the input device and optionaly run diagnostics
2065 @param This Protocol instance pointer.
2066 @param ExtendedVerification Driver may perform diagnostics on reset.
2068 @retval EFI_SUCCESS The device was reset.
2069 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
2075 BiosKeyboardResetEx (
2076 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2077 IN BOOLEAN ExtendedVerification
2080 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2084 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2086 Status
= BiosKeyboardPrivate
->SimpleTextIn
.Reset (
2087 &BiosKeyboardPrivate
->SimpleTextIn
,
2088 ExtendedVerification
2090 if (EFI_ERROR (Status
)) {
2091 return EFI_DEVICE_ERROR
;
2094 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2096 gBS
->RestoreTPL (OldTpl
);
2103 Reads the next keystroke from the input device. The WaitForKey Event can
2104 be used to test for existance of a keystroke via WaitForEvent () call.
2106 @param This Protocol instance pointer.
2107 @param KeyData A pointer to a buffer that is filled in with the keystroke
2108 state data for the key that was pressed.
2110 @retval EFI_SUCCESS The keystroke information was returned.
2111 @retval EFI_NOT_READY There was no keystroke data availiable.
2112 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
2114 @retval EFI_INVALID_PARAMETER KeyData is NULL.
2119 BiosKeyboardReadKeyStrokeEx (
2120 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2121 OUT EFI_KEY_DATA
*KeyData
2124 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2126 if (KeyData
== NULL
) {
2127 return EFI_INVALID_PARAMETER
;
2130 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2132 return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate
, KeyData
);
2137 Set certain state for the input device.
2139 @param This Protocol instance pointer.
2140 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
2141 state for the input device.
2143 @retval EFI_SUCCESS The device state was set successfully.
2144 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
2145 not have the setting adjusted.
2146 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
2147 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
2152 BiosKeyboardSetState (
2153 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2154 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
2158 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2160 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
2163 if (KeyToggleState
== NULL
) {
2164 return EFI_INVALID_PARAMETER
;
2168 // Thunk keyboard driver doesn't support partial keystroke.
2170 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
||
2171 (*KeyToggleState
& EFI_KEY_STATE_EXPOSED
) == EFI_KEY_STATE_EXPOSED
2173 return EFI_UNSUPPORTED
;
2176 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2178 // See if the Legacy BIOS Protocol is available
2180 Status
= gBS
->LocateProtocol (
2181 &gEfiLegacyBiosProtocolGuid
,
2183 (VOID
**) &LegacyBios
2186 ASSERT_EFI_ERROR (Status
);
2188 // Enter critical section
2190 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2193 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
2196 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
2199 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
2203 Status
= KeyboardWrite (BiosKeyboardPrivate
, 0xed);
2204 if (EFI_ERROR (Status
)) {
2205 return EFI_DEVICE_ERROR
;
2207 Status
= KeyboardWaitForValue (BiosKeyboardPrivate
, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT
);
2208 if (EFI_ERROR (Status
)) {
2209 return EFI_DEVICE_ERROR
;
2211 Status
= KeyboardWrite (BiosKeyboardPrivate
, Command
);
2212 if (EFI_ERROR (Status
)) {
2213 return EFI_DEVICE_ERROR
;
2216 // Call Legacy BIOS Protocol to set whatever is necessary
2218 LegacyBios
->UpdateKeyboardLedStatus (LegacyBios
, Command
);
2220 Status
= EFI_SUCCESS
;
2223 // Leave critical section and return
2225 gBS
->RestoreTPL (OldTpl
);
2232 Register a notification function for a particular keystroke for the input device.
2234 @param This Protocol instance pointer.
2235 @param KeyData A pointer to a buffer that is filled in with the keystroke
2236 information data for the key that was pressed.
2237 @param KeyNotificationFunction Points to the function to be called when the key
2238 sequence is typed specified by KeyData.
2239 @param NotifyHandle Points to the unique handle assigned to the registered notification.
2242 @retval EFI_SUCCESS The notification function was registered successfully.
2243 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
2244 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
2249 BiosKeyboardRegisterKeyNotify (
2250 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2251 IN EFI_KEY_DATA
*KeyData
,
2252 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
2253 OUT VOID
**NotifyHandle
2257 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2259 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
2261 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
2263 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
2264 return EFI_INVALID_PARAMETER
;
2267 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2270 // Enter critical section
2272 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2275 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
2277 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
2278 CurrentNotify
= CR (
2280 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
2282 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2284 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
2285 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
2286 *NotifyHandle
= CurrentNotify
;
2287 Status
= EFI_SUCCESS
;
2294 // Allocate resource to save the notification function
2297 NewNotify
= (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
2298 if (NewNotify
== NULL
) {
2299 Status
= EFI_OUT_OF_RESOURCES
;
2303 NewNotify
->Signature
= BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
2304 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
2305 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
2306 InsertTailList (&BiosKeyboardPrivate
->NotifyList
, &NewNotify
->NotifyEntry
);
2308 *NotifyHandle
= NewNotify
;
2309 Status
= EFI_SUCCESS
;
2313 // Leave critical section and return
2315 gBS
->RestoreTPL (OldTpl
);
2320 Remove a registered notification function from a particular keystroke.
2322 @param This Protocol instance pointer.
2323 @param NotificationHandle The handle of the notification function being unregistered.
2325 @retval EFI_SUCCESS The notification function was unregistered successfully.
2326 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
2331 BiosKeyboardUnregisterKeyNotify (
2332 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2333 IN VOID
*NotificationHandle
2337 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2340 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
2343 // Check incoming notification handle
2345 if (NotificationHandle
== NULL
) {
2346 return EFI_INVALID_PARAMETER
;
2349 if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) NotificationHandle
)->Signature
!= BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
) {
2350 return EFI_INVALID_PARAMETER
;
2353 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2356 // Enter critical section
2358 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2360 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
2361 CurrentNotify
= CR (
2363 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
2365 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2367 if (CurrentNotify
== NotificationHandle
) {
2369 // Remove the notification function from NotifyList and free resources
2371 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
2373 Status
= EFI_SUCCESS
;
2379 // Can not find the specified Notification Handle
2381 Status
= EFI_INVALID_PARAMETER
;
2385 // Leave critical section and return
2387 gBS
->RestoreTPL (OldTpl
);
2392 The user Entry Point for module BiosKeyboard. The user code starts with this function.
2394 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2395 @param[in] SystemTable A pointer to the EFI System Table.
2397 @retval EFI_SUCCESS The entry point is executed successfully.
2398 @retval other Some error occurs when executing this entry point.
2403 InitializeBiosKeyboard(
2404 IN EFI_HANDLE ImageHandle
,
2405 IN EFI_SYSTEM_TABLE
*SystemTable
2411 // Install driver model protocol(s).
2413 Status
= EfiLibInstallDriverBindingComponentName2 (
2416 &gBiosKeyboardDriverBinding
,
2418 &gBiosKeyboardComponentName
,
2419 &gBiosKeyboardComponentName2
2421 ASSERT_EFI_ERROR (Status
);