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
,
367 if (EFI_ERROR (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
;
440 // Install protocol interfaces for the keyboard device.
442 Status
= gBS
->InstallMultipleProtocolInterfaces (
444 &gEfiSimpleTextInProtocolGuid
,
445 &BiosKeyboardPrivate
->SimpleTextIn
,
446 &gEfiSimpleTextInputExProtocolGuid
,
447 &BiosKeyboardPrivate
->SimpleTextInputEx
,
452 if (StatusCode
!= 0) {
454 // Report an Error Code for failing to start the keyboard device
456 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
457 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
459 BiosKeyboardPrivate
->DevicePath
463 if (EFI_ERROR (Status
)) {
465 if (BiosKeyboardPrivate
!= NULL
) {
466 if ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
!= NULL
) {
467 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
470 if ((BiosKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
!= NULL
) {
471 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextInputEx
).WaitForKeyEx
);
473 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate
->NotifyList
);
475 if (BiosKeyboardPrivate
->TimerEvent
!= NULL
) {
476 gBS
->CloseEvent (BiosKeyboardPrivate
->TimerEvent
);
479 FreePool (BiosKeyboardPrivate
);
485 &gEfiIsaIoProtocolGuid
,
486 This
->DriverBindingHandle
,
496 Stop the device handled by this driver.
498 @param This The driver binding protocol.
499 @param Controller The controller to release.
500 @param NumberOfChildren The number of handles in ChildHandleBuffer.
501 @param ChildHandleBuffer The array of child handle.
503 @retval EFI_SUCCESS The device was stopped.
504 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
505 @retval Others Fail to uninstall protocols attached on the device.
510 BiosKeyboardDriverBindingStop (
511 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
512 IN EFI_HANDLE Controller
,
513 IN UINTN NumberOfChildren
,
514 IN EFI_HANDLE
*ChildHandleBuffer
518 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*SimpleTextIn
;
519 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
524 Status
= gBS
->OpenProtocol (
526 &gEfiSimpleTextInProtocolGuid
,
527 (VOID
**) &SimpleTextIn
,
528 This
->DriverBindingHandle
,
530 EFI_OPEN_PROTOCOL_GET_PROTOCOL
532 if (EFI_ERROR (Status
)) {
536 Status
= gBS
->OpenProtocol (
538 &gEfiSimpleTextInputExProtocolGuid
,
540 This
->DriverBindingHandle
,
542 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
544 if (EFI_ERROR (Status
)) {
548 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn
);
550 Status
= gBS
->UninstallMultipleProtocolInterfaces (
552 &gEfiSimpleTextInProtocolGuid
,
553 &BiosKeyboardPrivate
->SimpleTextIn
,
554 &gEfiSimpleTextInputExProtocolGuid
,
555 &BiosKeyboardPrivate
->SimpleTextInputEx
,
558 if (EFI_ERROR (Status
)) {
562 // Release the IsaIo protocol on the controller handle
566 &gEfiIsaIoProtocolGuid
,
567 This
->DriverBindingHandle
,
572 // Free other resources
574 gBS
->CloseEvent ((BiosKeyboardPrivate
->SimpleTextIn
).WaitForKey
);
575 gBS
->CloseEvent (BiosKeyboardPrivate
->TimerEvent
);
576 gBS
->CloseEvent (BiosKeyboardPrivate
->SimpleTextInputEx
.WaitForKeyEx
);
577 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate
->NotifyList
);
579 FreePool (BiosKeyboardPrivate
);
585 Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
587 @param BiosKeyboardPrivate Keyboard instance pointer.
589 @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
593 KeyReadDataRegister (
594 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
600 // Use IsaIo protocol to perform IO operations
602 BiosKeyboardPrivate
->IsaIo
->Io
.Read (
603 BiosKeyboardPrivate
->IsaIo
,
605 BiosKeyboardPrivate
->DataRegisterAddress
,
614 Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
616 @param BiosKeyboardPrivate Keyboard instance pointer.
618 @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.
622 KeyReadStatusRegister (
623 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
629 // Use IsaIo protocol to perform IO operations
631 BiosKeyboardPrivate
->IsaIo
->Io
.Read (
632 BiosKeyboardPrivate
->IsaIo
,
634 BiosKeyboardPrivate
->StatusRegisterAddress
,
643 Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
645 @param BiosKeyboardPrivate Keyboard instance pointer.
646 @param Data Data byte to write.
650 KeyWriteCommandRegister (
651 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
656 // Use IsaIo protocol to perform IO operations
658 BiosKeyboardPrivate
->IsaIo
->Io
.Write (
659 BiosKeyboardPrivate
->IsaIo
,
661 BiosKeyboardPrivate
->CommandRegisterAddress
,
668 Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
670 @param BiosKeyboardPrivate Keyboard instance pointer.
671 @param Data Data byte to write.
675 KeyWriteDataRegister (
676 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
681 // Use IsaIo protocol to perform IO operations
683 BiosKeyboardPrivate
->IsaIo
->Io
.Write (
684 BiosKeyboardPrivate
->IsaIo
,
686 BiosKeyboardPrivate
->DataRegisterAddress
,
693 Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
695 @param BiosKeyboardPrivate Keyboard instance pointer.
696 @param Data The pointer for data that being read out.
698 @retval EFI_SUCCESS The data byte read out successfully.
699 @retval EFI_TIMEOUT Timeout occurred during reading out data byte.
704 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
715 // wait till output buffer full then perform the read
717 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
718 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_OUTB
) != 0) {
720 *Data
= KeyReadDataRegister (BiosKeyboardPrivate
);
727 if (RegFilled
== 0) {
735 Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
737 @param BiosKeyboardPrivate Keyboard instance pointer.
738 @param Data Data byte to write.
740 @retval EFI_SUCCESS The data byte is written successfully.
741 @retval EFI_TIMEOUT Timeout occurred during writing.
746 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
757 // wait for input buffer empty
759 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
760 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
768 if (RegEmptied
== 0) {
774 KeyWriteDataRegister (BiosKeyboardPrivate
, Data
);
780 Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
782 @param BiosKeyboardPrivate Keyboard instance pointer.
783 @param Data Command byte to write.
785 @retval EFI_SUCCESS The command byte is written successfully.
786 @retval EFI_TIMEOUT Timeout occurred during writing.
791 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
802 // Wait For Input Buffer Empty
804 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
805 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
813 if (RegEmptied
== 0) {
819 KeyWriteCommandRegister (BiosKeyboardPrivate
, Data
);
822 // Wait For Input Buffer Empty again
825 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
826 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_INPB
) == 0) {
834 if (RegEmptied
== 0) {
842 Wait for a specific value to be presented in
843 Data register of Keyboard Controller by keyboard and then read it,
844 used in keyboard commands ack
846 @param BiosKeyboardPrivate Keyboard instance pointer.
847 @param Value The value to be waited for
848 @param WaitForValueTimeOut The limit of microseconds for timeout
850 @retval EFI_SUCCESS The command byte is written successfully.
851 @retval EFI_TIMEOUT Timeout occurred during writing.
855 KeyboardWaitForValue (
856 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
858 IN UINTN WaitForValueTimeOut
871 // Make sure the initial value of 'Data' is different from 'Value'
878 // Read from 8042 (multiple times if needed)
879 // until the expected value appears
880 // use SumTimeOut to control the iteration
886 for (TimeOut
= 0; TimeOut
< KEYBOARD_TIMEOUT
; TimeOut
+= 30) {
887 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_OUTB
) != 0) {
888 Data
= KeyReadDataRegister (BiosKeyboardPrivate
);
895 SumTimeOut
+= TimeOut
;
902 if (SumTimeOut
>= WaitForValueTimeOut
) {
918 Reads the next keystroke from the input device. The WaitForKey Event can
919 be used to test for existance of a keystroke via WaitForEvent () call.
921 @param BiosKeyboardPrivate Bioskeyboard driver private structure.
922 @param KeyData A pointer to a buffer that is filled in with the keystroke
923 state data for the key that was pressed.
925 @retval EFI_SUCCESS The keystroke information was returned.
926 @retval EFI_NOT_READY There was no keystroke data availiable.
927 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
929 @retval EFI_INVALID_PARAMETER KeyData is NULL.
933 KeyboardReadKeyStrokeWorker (
934 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
,
935 OUT EFI_KEY_DATA
*KeyData
940 if (KeyData
== NULL
) {
941 return EFI_INVALID_PARAMETER
;
945 // Use TimerEvent callback funciton to check whether there's any key pressed
949 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
950 // Csm will be used to check whether there is a key pending, but the csm will disable all
951 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
952 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
953 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
954 // e.g. usb keyboard driver.
955 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
956 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
960 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
962 BiosKeyboardTimerHandler (NULL
, BiosKeyboardPrivate
);
964 // If there's no key, just return
966 Status
= CheckQueue (&BiosKeyboardPrivate
->Queue
);
967 if (EFI_ERROR (Status
)) {
968 gBS
->RestoreTPL (OldTpl
);
969 return EFI_NOT_READY
;
972 Status
= Dequeue (&BiosKeyboardPrivate
->Queue
, KeyData
);
974 gBS
->RestoreTPL (OldTpl
);
980 // EFI Simple Text In Protocol Functions
983 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
985 @param This Pointer of simple text Protocol.
986 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
988 @retval EFI_SUCCESS The command byte is written successfully.
989 @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
995 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
996 IN BOOLEAN ExtendedVerification
999 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1003 BOOLEAN MouseEnable
;
1006 MouseEnable
= FALSE
;
1007 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1011 // Report reset progress code
1013 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1015 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
1016 BiosKeyboardPrivate
->DevicePath
1020 // Report a Progress Code for clearing the keyboard buffer
1022 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1024 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_CLEAR_BUFFER
,
1025 BiosKeyboardPrivate
->DevicePath
1030 // Raise TPL to avoid mouse operation impact
1032 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1036 // Exhaust output buffer data
1039 Status
= BiosKeyboardReadKeyStroke (
1043 } while (!EFI_ERROR (Status
));
1046 // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
1047 // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
1050 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & KBC_STSREG_VIA64_SYSF
) != 0) {
1053 // CheckMouseStatus to decide enable it later or not
1056 // Read the command byte of KBC
1058 Status
= KeyboardCommand (
1059 BiosKeyboardPrivate
,
1060 KBC_CMDREG_VIA64_CMDBYTE_R
1063 if (EFI_ERROR (Status
)) {
1064 Status
= EFI_DEVICE_ERROR
;
1068 Status
= KeyboardRead (
1069 BiosKeyboardPrivate
,
1073 if (EFI_ERROR (Status
)) {
1074 Status
= EFI_DEVICE_ERROR
;
1078 // Check mouse enabled or not before
1080 if ((CommandByte
& KB_CMMBYTE_DISABLE_AUX
) != 0) {
1081 MouseEnable
= FALSE
;
1087 // disable mouse (via KBC) and Keyborad device
1089 Status
= KeyboardCommand (
1090 BiosKeyboardPrivate
,
1091 KBC_CMDREG_VIA64_AUX_DISABLE
1094 if (EFI_ERROR (Status
)) {
1095 Status
= EFI_DEVICE_ERROR
;
1099 Status
= KeyboardCommand (
1100 BiosKeyboardPrivate
,
1101 KBC_CMDREG_VIA64_KB_DISABLE
1104 if (EFI_ERROR (Status
)) {
1105 Status
= EFI_DEVICE_ERROR
;
1115 // Report a Progress Code for performing a self test on the keyboard controller
1117 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1119 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_PC_SELF_TEST
,
1120 BiosKeyboardPrivate
->DevicePath
1123 Status
= KeyboardCommand (
1124 BiosKeyboardPrivate
,
1125 KBC_CMDREG_VIA64_KBC_SLFTEST
1127 if (EFI_ERROR (Status
)) {
1128 Status
= EFI_DEVICE_ERROR
;
1132 Status
= KeyboardWaitForValue (
1133 BiosKeyboardPrivate
,
1134 KBC_CMDECHO_KBCSLFTEST_OK
,
1135 KEYBOARD_WAITFORVALUE_TIMEOUT
1137 if (EFI_ERROR (Status
)) {
1138 Status
= EFI_DEVICE_ERROR
;
1144 // Disable Mouse interface, enable Keyboard interface and declare selftest success
1146 // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
1148 Status
= KeyboardCommand (
1149 BiosKeyboardPrivate
,
1150 KBC_CMDREG_VIA64_CMDBYTE_W
1153 if (EFI_ERROR (Status
)) {
1154 Status
= EFI_DEVICE_ERROR
;
1159 // Write 8042 Command Byte, set System Flag
1160 // While at the same time:
1161 // 1. disable mouse interface,
1162 // 2. enable kbd interface,
1163 // 3. enable PC/XT kbd translation mode
1164 // 4. enable mouse and kbd interrupts
1166 //Command Byte bits:
1168 // 6: PC/XT translation mode
1169 // 5: Disable Auxiliary device interface
1170 // 4: Disable keyboard interface
1173 // 1: Enable Auxiliary device interrupt
1174 // 0: Enable Keyboard interrupt
1177 Status
= KeyboardWrite (
1178 BiosKeyboardPrivate
,
1179 (UINT8
) ((CommandByte
&
1180 (~KB_CMMBYTE_DISABLE_KB
)) |
1181 KB_CMMBYTE_KSCAN2UNI_COV
|
1182 KB_CMMBYTE_ENABLE_AUXINT
|
1183 KB_CMMBYTE_ENABLE_KBINT
|
1184 KB_CMMBYTE_SLFTEST_SUCC
|
1185 KB_CMMBYTE_DISABLE_AUX
)
1189 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1190 // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.
1191 // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
1192 // Real reset will not do.
1194 if (ExtendedVerification
&& CheckKeyboardConnect (BiosKeyboardPrivate
)) {
1197 // Send keyboard reset command then read ACK
1199 Status
= KeyboardWrite (
1200 BiosKeyboardPrivate
,
1201 KBC_INPBUF_VIA60_KBRESET
1204 if (EFI_ERROR (Status
)) {
1205 Status
= EFI_DEVICE_ERROR
;
1209 Status
= KeyboardWaitForValue (
1210 BiosKeyboardPrivate
,
1212 KEYBOARD_WAITFORVALUE_TIMEOUT
1215 if (EFI_ERROR (Status
)) {
1216 Status
= EFI_DEVICE_ERROR
;
1221 // Wait for keyboard return test OK.
1223 Status
= KeyboardWaitForValue (
1224 BiosKeyboardPrivate
,
1225 KBC_CMDECHO_BATTEST_OK
,
1226 KEYBOARD_WAITFORVALUE_TIMEOUT
1229 if (EFI_ERROR (Status
)) {
1230 Status
= EFI_DEVICE_ERROR
;
1235 // set keyboard scan code set = 02 (standard configuration)
1237 Status
= KeyboardWrite (
1238 BiosKeyboardPrivate
,
1239 KBC_INPBUF_VIA60_KBSCODE
1241 if (EFI_ERROR (Status
)) {
1242 Status
= EFI_DEVICE_ERROR
;
1246 Status
= KeyboardWaitForValue (
1247 BiosKeyboardPrivate
,
1249 KEYBOARD_WAITFORVALUE_TIMEOUT
1252 if (EFI_ERROR (Status
)) {
1253 Status
= EFI_DEVICE_ERROR
;
1257 Status
= KeyboardWrite (
1258 BiosKeyboardPrivate
,
1259 KBC_INPBUF_VIA60_SCODESET2
1261 if (EFI_ERROR (Status
)) {
1262 Status
= EFI_DEVICE_ERROR
;
1266 Status
= KeyboardWaitForValue (
1267 BiosKeyboardPrivate
,
1269 KEYBOARD_WAITFORVALUE_TIMEOUT
1272 if (EFI_ERROR (Status
)) {
1273 Status
= EFI_DEVICE_ERROR
;
1278 // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
1280 Status
= KeyboardWrite (
1281 BiosKeyboardPrivate
,
1282 KBC_INPBUF_VIA60_KBEN
1284 if (EFI_ERROR (Status
)) {
1285 Status
= EFI_DEVICE_ERROR
;
1289 Status
= KeyboardWaitForValue (
1290 BiosKeyboardPrivate
,
1292 KEYBOARD_WAITFORVALUE_TIMEOUT
1295 if (EFI_ERROR (Status
)) {
1296 Status
= EFI_DEVICE_ERROR
;
1301 // Additional validation, do it as follow:
1302 // 1). check for status register of PARE && TIM via 64H
1303 // 2). perform KB checking by writing ABh via 64H
1305 if ((KeyReadStatusRegister (BiosKeyboardPrivate
) & (KBC_STSREG_VIA64_PARE
| KBC_STSREG_VIA64_TIM
)) != 0) {
1306 Status
= EFI_DEVICE_ERROR
;
1310 Status
= KeyboardCommand (
1311 BiosKeyboardPrivate
,
1312 KBC_CMDREG_VIA64_KB_CKECK
1314 if (EFI_ERROR (Status
)) {
1315 Status
= EFI_DEVICE_ERROR
;
1319 Status
= KeyboardWaitForValue (
1320 BiosKeyboardPrivate
,
1321 KBC_CMDECHO_KBCHECK_OK
,
1322 KEYBOARD_WAITFORVALUE_TIMEOUT
1325 if (EFI_ERROR (Status
)) {
1326 Status
= EFI_DEVICE_ERROR
;
1332 // Done for validating keyboard. Enable keyboard (via KBC)
1333 // and recover the command byte to proper value
1335 Status
= KeyboardCommand (
1336 BiosKeyboardPrivate
,
1337 KBC_CMDREG_VIA64_KB_ENABLE
1340 if (EFI_ERROR (Status
)) {
1341 Status
= EFI_DEVICE_ERROR
;
1347 // conditionally enable mouse (via KBC)
1350 Status
= KeyboardCommand (
1351 BiosKeyboardPrivate
,
1352 KBC_CMDREG_VIA64_AUX_ENABLE
1355 if (EFI_ERROR (Status
)) {
1356 Status
= EFI_DEVICE_ERROR
;
1364 // resume priority of task level
1366 gBS
->RestoreTPL (OldTpl
);
1373 Read out the scan code of the key that has just been stroked.
1375 @param This Pointer of simple text Protocol.
1376 @param Key Pointer for store the key that read out.
1378 @retval EFI_SUCCESS The key is read out successfully.
1379 @retval other The key reading failed.
1384 BiosKeyboardReadKeyStroke (
1385 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
1386 OUT EFI_INPUT_KEY
*Key
1389 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1391 EFI_KEY_DATA KeyData
;
1393 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1395 Status
= KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate
, &KeyData
);
1396 if (EFI_ERROR (Status
)) {
1400 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
1406 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
1408 @param Event The event that be siganlled when any key has been stroked.
1409 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1414 BiosKeyboardWaitForKey (
1420 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
1421 // Csm will be used to check whether there is a key pending, but the csm will disable all
1422 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
1423 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
1424 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
1425 // e.g. usb keyboard driver.
1426 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
1427 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
1431 // Use TimerEvent callback funciton to check whether there's any key pressed
1433 BiosKeyboardTimerHandler (NULL
, BIOS_KEYBOARD_DEV_FROM_THIS (Context
));
1435 if (!EFI_ERROR (BiosKeyboardCheckForKey (Context
))) {
1436 gBS
->SignalEvent (Event
);
1441 Check key buffer to get the key stroke status.
1443 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
1445 @retval EFI_SUCCESS A key is being pressed now.
1446 @retval Other No key is now pressed.
1451 BiosKeyboardCheckForKey (
1452 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
1455 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1457 BiosKeyboardPrivate
= BIOS_KEYBOARD_DEV_FROM_THIS (This
);
1459 return CheckQueue (&BiosKeyboardPrivate
->Queue
);
1462 // Private worker functions
1464 #define TABLE_END 0x0
1466 typedef struct _CONVERT_TABLE_ENTRY
{
1469 } CONVERT_TABLE_ENTRY
;
1471 CONVERT_TABLE_ENTRY mConvertTable
[] = {
1513 // Function Keys are only valid if KeyChar == 0x00
1514 // This function does not require KeyChar to be 0x00
1565 // Convert ALT + Fn keys
1614 Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
1616 @param KeyChar Unicode of key.
1617 @param ScanCode Scan code of key.
1619 @return The value of EFI Scancode for the key.
1620 @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
1624 ConvertToEFIScanCode (
1632 if (KeyChar
== CHAR_ESC
) {
1633 EfiScanCode
= SCAN_ESC
;
1634 } else if (KeyChar
== 0x00 || KeyChar
== 0xe0) {
1636 // Movement & Function Keys
1638 for (Index
= 0; (Index
< sizeof (mConvertTable
) / sizeof (CONVERT_TABLE_ENTRY
)) && (mConvertTable
[Index
].ScanCode
!= TABLE_END
); Index
+= 1) {
1639 if (ScanCode
== mConvertTable
[Index
].ScanCode
) {
1640 return mConvertTable
[Index
].EfiScanCode
;
1644 // Reach Table end, return default value
1655 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1656 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1657 should not be in system.
1659 @param BiosKeyboardPrivate Keyboard Private Data Struture
1661 @retval TRUE Keyboard in System.
1662 @retval FALSE Keyboard not in System.
1666 CheckKeyboardConnect (
1667 IN BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
1672 Status
= EFI_SUCCESS
;
1674 // enable keyboard itself and wait for its ack
1675 // If can't receive ack, Keyboard should not be connected.
1677 Status
= KeyboardWrite (
1678 BiosKeyboardPrivate
,
1679 KBC_INPBUF_VIA60_KBEN
1681 if (EFI_ERROR (Status
)) {
1685 Status
= KeyboardWaitForValue (
1686 BiosKeyboardPrivate
,
1688 KEYBOARD_WAITFORVALUE_TIMEOUT
1691 if (EFI_ERROR (Status
)) {
1699 Timer event handler: read a series of key stroke from 8042
1700 and put them into memory key buffer.
1701 It is registered as running under TPL_NOTIFY
1703 @param Event The timer event
1704 @param Context A BIOS_KEYBOARD_DEV pointer
1709 BiosKeyboardTimerHandler (
1715 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
1716 EFI_IA32_REGISTER_SET Regs
;
1717 UINT8 KbFlag1
; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
1718 UINT8 KbFlag2
; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
1719 EFI_KEY_DATA KeyData
;
1721 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
1723 BiosKeyboardPrivate
= Context
;
1726 // Enter critical section
1728 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1731 // if there is no key present, just return
1733 if (BiosKeyboardPrivate
->ExtendedKeyboard
) {
1739 BiosKeyboardPrivate
->LegacyBios
->Int86 (
1740 BiosKeyboardPrivate
->LegacyBios
,
1744 if (Regs
.X
.Flags
.ZF
!= 0) {
1745 gBS
->RestoreTPL (OldTpl
);
1752 if (BiosKeyboardPrivate
->ExtendedKeyboard
) {
1758 BiosKeyboardPrivate
->LegacyBios
->Int86 (
1759 BiosKeyboardPrivate
->LegacyBios
,
1764 KeyData
.Key
.ScanCode
= (UINT16
) Regs
.H
.AH
;
1765 KeyData
.Key
.UnicodeChar
= (UINT16
) Regs
.H
.AL
;
1766 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
1767 KeyData
.KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
1769 // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then
1770 // 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
1771 // 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
1772 // 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
1773 // 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
1774 // 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
1775 // 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
1776 // performance, like USB.
1778 // 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
1779 // 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
1780 // 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
1783 // 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
1784 // 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,
1785 // which will let persist to press SHIFT has same effection as only press one time.
1787 //0040h:0017h - KEYBOARD - STATUS FLAGS 1
1789 // 6 Caps Lock active
1790 // 5 Num Lock active
1791 // 4 Scroll Lock active
1792 // 3 either Alt pressed
1793 // 2 either Ctrl pressed
1794 // 1 Left Shift pressed
1795 // 0 Right Shift pressed
1799 // Clear the CTRL and ALT BDA flag
1801 KbFlag1
= *((UINT8
*) (UINTN
) 0x417); // read the STATUS FLAGS 1
1802 KbFlag2
= *((UINT8
*) (UINTN
) 0x418); // read STATUS FLAGS 2
1805 // Record toggle state
1807 if ((KbFlag1
& KB_CAPS_LOCK_BIT
) == KB_CAPS_LOCK_BIT
) {
1808 KeyData
.KeyState
.KeyToggleState
|= EFI_CAPS_LOCK_ACTIVE
;
1810 if ((KbFlag1
& KB_NUM_LOCK_BIT
) == KB_NUM_LOCK_BIT
) {
1811 KeyData
.KeyState
.KeyToggleState
|= EFI_NUM_LOCK_ACTIVE
;
1813 if ((KbFlag1
& KB_SCROLL_LOCK_BIT
) == KB_SCROLL_LOCK_BIT
) {
1814 KeyData
.KeyState
.KeyToggleState
|= EFI_SCROLL_LOCK_ACTIVE
;
1817 // Record shift state
1818 // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
1820 if ((KbFlag1
& KB_ALT_PRESSED
) == KB_ALT_PRESSED
) {
1821 KeyData
.KeyState
.KeyShiftState
|= ((KbFlag2
& KB_LEFT_ALT_PRESSED
) == KB_LEFT_ALT_PRESSED
) ? EFI_LEFT_ALT_PRESSED
: EFI_RIGHT_ALT_PRESSED
;
1823 if ((KbFlag1
& KB_CTRL_PRESSED
) == KB_CTRL_PRESSED
) {
1824 KeyData
.KeyState
.KeyShiftState
|= ((KbFlag2
& KB_LEFT_CTRL_PRESSED
) == KB_LEFT_CTRL_PRESSED
) ? EFI_LEFT_CONTROL_PRESSED
: EFI_RIGHT_CONTROL_PRESSED
;
1826 if ((KbFlag1
& KB_LEFT_SHIFT_PRESSED
) == KB_LEFT_SHIFT_PRESSED
) {
1827 KeyData
.KeyState
.KeyShiftState
|= EFI_LEFT_SHIFT_PRESSED
;
1829 if ((KbFlag1
& KB_RIGHT_SHIFT_PRESSED
) == KB_RIGHT_SHIFT_PRESSED
) {
1830 KeyData
.KeyState
.KeyShiftState
|= EFI_RIGHT_SHIFT_PRESSED
;
1834 // Clear left alt and left ctrl BDA flag
1836 KbFlag2
&= ~(KB_LEFT_ALT_PRESSED
| KB_LEFT_CTRL_PRESSED
);
1837 *((UINT8
*) (UINTN
) 0x418) = KbFlag2
;
1839 *((UINT8
*) (UINTN
) 0x417) = KbFlag1
;
1843 // Output EFI input key and shift/toggle state
1845 if (KeyData
.Key
.UnicodeChar
== CHAR_NULL
|| KeyData
.Key
.UnicodeChar
== CHAR_SCANCODE
|| KeyData
.Key
.UnicodeChar
== CHAR_ESC
) {
1846 KeyData
.Key
.ScanCode
= ConvertToEFIScanCode (KeyData
.Key
.UnicodeChar
, KeyData
.Key
.ScanCode
);
1847 KeyData
.Key
.UnicodeChar
= CHAR_NULL
;
1849 KeyData
.Key
.ScanCode
= SCAN_NULL
;
1853 // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
1855 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
1856 if (KeyData
.Key
.UnicodeChar
>= 1 && KeyData
.Key
.UnicodeChar
<= 26) {
1857 if (((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
)) != 0) ==
1858 ((KeyData
.KeyState
.KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) != 0)
1860 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
+ L
'a' - 1);
1862 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
+ L
'A' - 1);
1868 // Need not return associated shift state if a class of printable characters that
1869 // are normally adjusted by shift modifiers.
1870 // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
1872 if ((KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') ||
1873 (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z')
1875 KeyData
.KeyState
.KeyShiftState
&= ~(EFI_LEFT_SHIFT_PRESSED
| EFI_RIGHT_SHIFT_PRESSED
);
1879 // Invoke notification functions if exist
1881 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
1882 CurrentNotify
= CR (
1884 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1886 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1888 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
1889 CurrentNotify
->KeyNotificationFn (&KeyData
);
1894 // Convert the Ctrl+[a-z] to Ctrl+[1-26]
1896 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
1897 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
1898 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
1899 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
1900 KeyData
.Key
.UnicodeChar
= (UINT16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
1903 Enqueue (&BiosKeyboardPrivate
->Queue
, &KeyData
);
1905 // Leave critical section and return
1907 gBS
->RestoreTPL (OldTpl
);
1913 Free keyboard notify list.
1915 @param ListHead The list head
1917 @retval EFI_SUCCESS Free the notify list successfully
1918 @retval EFI_INVALID_PARAMETER ListHead is invalid.
1922 BiosKeyboardFreeNotifyList (
1923 IN OUT LIST_ENTRY
*ListHead
1926 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NotifyNode
;
1928 if (ListHead
== NULL
) {
1929 return EFI_INVALID_PARAMETER
;
1931 while (!IsListEmpty (ListHead
)) {
1933 ListHead
->ForwardLink
,
1934 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
1936 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
1938 RemoveEntryList (ListHead
->ForwardLink
);
1939 gBS
->FreePool (NotifyNode
);
1946 Check if key is registered.
1948 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
1949 state data for the key that was registered.
1950 @param InputData A pointer to a buffer that is filled in with the keystroke
1951 state data for the key that was pressed.
1953 @retval TRUE Key be pressed matches a registered key.
1954 @retval FLASE Match failed.
1959 IN EFI_KEY_DATA
*RegsiteredData
,
1960 IN EFI_KEY_DATA
*InputData
1963 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
1965 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
1966 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
1971 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
1973 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
1974 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
1977 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
1978 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
1987 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
1989 @param Event The event that be siganlled when any key has been stroked.
1990 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
1995 BiosKeyboardWaitForKeyEx (
2000 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2002 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context
);
2003 BiosKeyboardWaitForKey (Event
, &BiosKeyboardPrivate
->SimpleTextIn
);
2008 Reset the input device and optionaly run diagnostics
2010 @param This Protocol instance pointer.
2011 @param ExtendedVerification Driver may perform diagnostics on reset.
2013 @retval EFI_SUCCESS The device was reset.
2014 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
2020 BiosKeyboardResetEx (
2021 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2022 IN BOOLEAN ExtendedVerification
2025 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2029 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2031 Status
= BiosKeyboardPrivate
->SimpleTextIn
.Reset (
2032 &BiosKeyboardPrivate
->SimpleTextIn
,
2033 ExtendedVerification
2035 if (EFI_ERROR (Status
)) {
2036 return EFI_DEVICE_ERROR
;
2039 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2041 gBS
->RestoreTPL (OldTpl
);
2048 Reads the next keystroke from the input device. The WaitForKey Event can
2049 be used to test for existance of a keystroke via WaitForEvent () call.
2051 @param This Protocol instance pointer.
2052 @param KeyData A pointer to a buffer that is filled in with the keystroke
2053 state data for the key that was pressed.
2055 @retval EFI_SUCCESS The keystroke information was returned.
2056 @retval EFI_NOT_READY There was no keystroke data availiable.
2057 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
2059 @retval EFI_INVALID_PARAMETER KeyData is NULL.
2064 BiosKeyboardReadKeyStrokeEx (
2065 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2066 OUT EFI_KEY_DATA
*KeyData
2069 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2071 if (KeyData
== NULL
) {
2072 return EFI_INVALID_PARAMETER
;
2075 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2077 return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate
, KeyData
);
2082 Set certain state for the input device.
2084 @param This Protocol instance pointer.
2085 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
2086 state for the input device.
2088 @retval EFI_SUCCESS The device state was set successfully.
2089 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
2090 not have the setting adjusted.
2091 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
2092 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
2097 BiosKeyboardSetState (
2098 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2099 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
2103 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2105 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
2108 if (KeyToggleState
== NULL
) {
2109 return EFI_INVALID_PARAMETER
;
2112 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) {
2113 return EFI_UNSUPPORTED
;
2116 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2118 // See if the Legacy BIOS Protocol is available
2120 Status
= gBS
->LocateProtocol (
2121 &gEfiLegacyBiosProtocolGuid
,
2123 (VOID
**) &LegacyBios
2126 ASSERT_EFI_ERROR (Status
);
2128 // Enter critical section
2130 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2133 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
2136 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
2139 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
2143 Status
= KeyboardWrite (BiosKeyboardPrivate
, 0xed);
2144 if (EFI_ERROR (Status
)) {
2145 return EFI_DEVICE_ERROR
;
2147 Status
= KeyboardWaitForValue (BiosKeyboardPrivate
, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT
);
2148 if (EFI_ERROR (Status
)) {
2149 return EFI_DEVICE_ERROR
;
2151 Status
= KeyboardWrite (BiosKeyboardPrivate
, Command
);
2152 if (EFI_ERROR (Status
)) {
2153 return EFI_DEVICE_ERROR
;
2156 // Call Legacy BIOS Protocol to set whatever is necessary
2158 LegacyBios
->UpdateKeyboardLedStatus (LegacyBios
, Command
);
2160 Status
= EFI_SUCCESS
;
2163 // Leave critical section and return
2165 gBS
->RestoreTPL (OldTpl
);
2172 Register a notification function for a particular keystroke for the input device.
2174 @param This Protocol instance pointer.
2175 @param KeyData A pointer to a buffer that is filled in with the keystroke
2176 information data for the key that was pressed.
2177 @param KeyNotificationFunction Points to the function to be called when the key
2178 sequence is typed specified by KeyData.
2179 @param NotifyHandle Points to the unique handle assigned to the registered notification.
2182 @retval EFI_SUCCESS The notification function was registered successfully.
2183 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
2184 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
2189 BiosKeyboardRegisterKeyNotify (
2190 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2191 IN EFI_KEY_DATA
*KeyData
,
2192 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
2193 OUT EFI_HANDLE
*NotifyHandle
2197 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2199 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
2201 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
2203 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
2204 return EFI_INVALID_PARAMETER
;
2207 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2210 // Enter critical section
2212 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2215 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
2217 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
2218 CurrentNotify
= CR (
2220 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
2222 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2224 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
2225 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
2226 *NotifyHandle
= CurrentNotify
->NotifyHandle
;
2227 Status
= EFI_SUCCESS
;
2234 // Allocate resource to save the notification function
2237 NewNotify
= (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
2238 if (NewNotify
== NULL
) {
2239 Status
= EFI_OUT_OF_RESOURCES
;
2243 NewNotify
->Signature
= BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
2244 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
2245 NewNotify
->NotifyHandle
= (EFI_HANDLE
) NewNotify
;
2246 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
2247 InsertTailList (&BiosKeyboardPrivate
->NotifyList
, &NewNotify
->NotifyEntry
);
2249 *NotifyHandle
= NewNotify
->NotifyHandle
;
2250 Status
= EFI_SUCCESS
;
2254 // Leave critical section and return
2256 gBS
->RestoreTPL (OldTpl
);
2261 Remove a registered notification function from a particular keystroke.
2263 @param This Protocol instance pointer.
2264 @param NotificationHandle The handle of the notification function being unregistered.
2266 @retval EFI_SUCCESS The notification function was unregistered successfully.
2267 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
2272 BiosKeyboardUnregisterKeyNotify (
2273 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
2274 IN EFI_HANDLE NotificationHandle
2278 BIOS_KEYBOARD_DEV
*BiosKeyboardPrivate
;
2281 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
2284 // Check incoming notification handle
2286 if (NotificationHandle
== NULL
) {
2287 return EFI_INVALID_PARAMETER
;
2290 if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) NotificationHandle
)->Signature
!= BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
) {
2291 return EFI_INVALID_PARAMETER
;
2294 BiosKeyboardPrivate
= TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This
);
2297 // Enter critical section
2299 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2301 for (Link
= BiosKeyboardPrivate
->NotifyList
.ForwardLink
; Link
!= &BiosKeyboardPrivate
->NotifyList
; Link
= Link
->ForwardLink
) {
2302 CurrentNotify
= CR (
2304 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
2306 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2308 if (CurrentNotify
->NotifyHandle
== NotificationHandle
) {
2310 // Remove the notification function from NotifyList and free resources
2312 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
2314 Status
= EFI_SUCCESS
;
2320 // Can not find the specified Notification Handle
2322 Status
= EFI_INVALID_PARAMETER
;
2326 // Leave critical section and return
2328 gBS
->RestoreTPL (OldTpl
);
2333 The user Entry Point for module BiosKeyboard. The user code starts with this function.
2335 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2336 @param[in] SystemTable A pointer to the EFI System Table.
2338 @retval EFI_SUCCESS The entry point is executed successfully.
2339 @retval other Some error occurs when executing this entry point.
2344 InitializeBiosKeyboard(
2345 IN EFI_HANDLE ImageHandle
,
2346 IN EFI_SYSTEM_TABLE
*SystemTable
2352 // Install driver model protocol(s).
2354 Status
= EfiLibInstallDriverBindingComponentName2 (
2357 &gBiosKeyboardDriverBinding
,
2359 &gBiosKeyboardComponentName
,
2360 &gBiosKeyboardComponentName2
2362 ASSERT_EFI_ERROR (Status
);