2 Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces
3 provided by Ps2KbdCtrller.c.
5 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "Ps2Keyboard.h"
13 Check whether the EFI key buffer is empty.
15 @param Queue Pointer to instance of EFI_KEY_QUEUE.
17 @retval TRUE The EFI key buffer is empty.
18 @retval FALSE The EFI key buffer isn't empty.
22 IN EFI_KEY_QUEUE
*Queue
25 return (BOOLEAN
)(Queue
->Head
== Queue
->Tail
);
29 Read & remove one key data from the EFI key buffer.
31 @param Queue Pointer to instance of EFI_KEY_QUEUE.
32 @param KeyData Receive the key data.
34 @retval EFI_SUCCESS The key data is popped successfully.
35 @retval EFI_NOT_READY There is no key data available.
39 IN EFI_KEY_QUEUE
*Queue
,
40 OUT EFI_KEY_DATA
*KeyData OPTIONAL
43 if (IsEfikeyBufEmpty (Queue
)) {
48 // Retrieve and remove the values
50 if (KeyData
!= NULL
) {
51 CopyMem (KeyData
, &Queue
->Buffer
[Queue
->Head
], sizeof (EFI_KEY_DATA
));
54 Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_EFI_KEY_MAX_COUNT
;
59 Push one key data to the EFI key buffer.
61 @param Queue Pointer to instance of EFI_KEY_QUEUE.
62 @param KeyData The key data to push.
66 IN EFI_KEY_QUEUE
*Queue
,
67 IN EFI_KEY_DATA
*KeyData
70 if ((Queue
->Tail
+ 1) % KEYBOARD_EFI_KEY_MAX_COUNT
== Queue
->Head
) {
72 // If Queue is full, pop the one from head.
74 PopEfikeyBufHead (Queue
, NULL
);
77 CopyMem (&Queue
->Buffer
[Queue
->Tail
], KeyData
, sizeof (EFI_KEY_DATA
));
78 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_EFI_KEY_MAX_COUNT
;
82 Judge whether is a registered key
84 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
85 state data for the key that was registered.
86 @param InputData A pointer to a buffer that is filled in with the keystroke
87 state data for the key that was pressed.
89 @retval TRUE Key be pressed matches a registered key.
90 @retval FALSE Match failed.
95 IN EFI_KEY_DATA
*RegsiteredData
,
96 IN EFI_KEY_DATA
*InputData
100 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
102 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
103 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
))
109 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
111 if ((RegsiteredData
->KeyState
.KeyShiftState
!= 0) &&
112 (RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
))
117 if ((RegsiteredData
->KeyState
.KeyToggleState
!= 0) &&
118 (RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
))
127 Reads the next keystroke from the input device. The WaitForKey Event can
128 be used to test for existence of a keystroke via WaitForEvent () call.
130 @param ConsoleInDev Ps2 Keyboard private structure
131 @param KeyData A pointer to a buffer that is filled in with the keystroke
132 state data for the key that was pressed.
135 @retval EFI_SUCCESS The keystroke information was returned.
136 @retval EFI_NOT_READY There was no keystroke data available.
137 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
139 @retval EFI_INVALID_PARAMETER KeyData is NULL.
143 KeyboardReadKeyStrokeWorker (
144 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
,
145 OUT EFI_KEY_DATA
*KeyData
152 if (KeyData
== NULL
) {
153 return EFI_INVALID_PARAMETER
;
157 // Enter critical section
159 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
161 KeyboardTimerHandler (NULL
, ConsoleInDev
);
163 if (ConsoleInDev
->KeyboardErr
) {
164 Status
= EFI_DEVICE_ERROR
;
166 Status
= PopEfikeyBufHead (&ConsoleInDev
->EfiKeyQueue
, KeyData
);
167 if (Status
== EFI_NOT_READY
) {
168 ZeroMem (&KeyData
->Key
, sizeof (KeyData
->Key
));
169 InitializeKeyState (ConsoleInDev
, &KeyData
->KeyState
);
173 gBS
->RestoreTPL (OldTpl
);
178 Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()
180 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
181 @param ExtendedVerification Indicate that the driver may perform a more
182 exhaustive verification operation of the device during
183 reset, now this par is ignored in this driver
189 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
190 IN BOOLEAN ExtendedVerification
194 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
197 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
198 if (ConsoleIn
->KeyboardErr
) {
199 return EFI_DEVICE_ERROR
;
202 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
204 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
205 ConsoleIn
->DevicePath
209 // Enter critical section
211 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
214 // Call InitKeyboard to initialize the keyboard
216 Status
= InitKeyboard (ConsoleIn
, ExtendedVerification
);
217 if (EFI_ERROR (Status
)) {
219 // Leave critical section and return
221 gBS
->RestoreTPL (OldTpl
);
222 return EFI_DEVICE_ERROR
;
226 // Leave critical section and return
228 gBS
->RestoreTPL (OldTpl
);
231 // Report the status If a stuck key was detected
233 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
234 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
235 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
236 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_STUCK_KEY
,
237 ConsoleIn
->DevicePath
242 // Report the status If keyboard is locked
244 if ((KeyReadStatusRegister (ConsoleIn
) & 0x10) == 0) {
245 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
246 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
247 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_LOCKED
,
248 ConsoleIn
->DevicePath
256 Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().
258 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
259 @param Key The output buffer for key value
261 @retval EFI_SUCCESS success to read key stroke
265 KeyboardReadKeyStroke (
266 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
267 OUT EFI_INPUT_KEY
*Key
271 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
272 EFI_KEY_DATA KeyData
;
274 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
277 // Considering if the partial keystroke is enabled, there maybe a partial
278 // keystroke in the queue, so here skip the partial keystroke and get the
279 // next key from the queue
283 // If there is no pending key, then return.
285 Status
= KeyboardReadKeyStrokeWorker (ConsoleIn
, &KeyData
);
286 if (EFI_ERROR (Status
)) {
291 // If it is partial keystroke, skip it.
293 if ((KeyData
.Key
.ScanCode
== SCAN_NULL
) && (KeyData
.Key
.UnicodeChar
== CHAR_NULL
)) {
298 // Translate the CTRL-Alpha characters to their corresponding control value
299 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
301 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
302 if ((KeyData
.Key
.UnicodeChar
>= L
'a') && (KeyData
.Key
.UnicodeChar
<= L
'z')) {
303 KeyData
.Key
.UnicodeChar
= (CHAR16
)(KeyData
.Key
.UnicodeChar
- L
'a' + 1);
304 } else if ((KeyData
.Key
.UnicodeChar
>= L
'A') && (KeyData
.Key
.UnicodeChar
<= L
'Z')) {
305 KeyData
.Key
.UnicodeChar
= (CHAR16
)(KeyData
.Key
.UnicodeChar
- L
'A' + 1);
309 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
315 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
316 Signal the event if there is key available
318 @param Event the event object
319 @param Context waiting context
330 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
331 EFI_KEY_DATA KeyData
;
333 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*)Context
;
336 // Enter critical section
338 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
340 KeyboardTimerHandler (NULL
, ConsoleIn
);
342 if (!ConsoleIn
->KeyboardErr
) {
344 // WaitforKey doesn't support the partial key.
345 // Considering if the partial keystroke is enabled, there maybe a partial
346 // keystroke in the queue, so here skip the partial keystroke and get the
347 // next key from the queue
349 while (!IsEfikeyBufEmpty (&ConsoleIn
->EfiKeyQueue
)) {
352 &(ConsoleIn
->EfiKeyQueue
.Buffer
[ConsoleIn
->EfiKeyQueue
.Head
]),
353 sizeof (EFI_KEY_DATA
)
355 if ((KeyData
.Key
.ScanCode
== SCAN_NULL
) && (KeyData
.Key
.UnicodeChar
== CHAR_NULL
)) {
356 PopEfikeyBufHead (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
361 // if there is pending value key, signal the event.
363 gBS
->SignalEvent (Event
);
369 // Leave critical section and return
371 gBS
->RestoreTPL (OldTpl
);
375 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
376 Signal the event if there is key available
378 @param Event event object
379 @param Context waiting context
384 KeyboardWaitForKeyEx (
390 KeyboardWaitForKey (Event
, Context
);
394 Reset the input device and optionally run diagnostics
396 @param This Protocol instance pointer.
397 @param ExtendedVerification Driver may perform diagnostics on reset.
399 @retval EFI_SUCCESS The device was reset.
400 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
407 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
408 IN BOOLEAN ExtendedVerification
412 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
414 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
416 return ConsoleInDev
->ConIn
.Reset (
417 &ConsoleInDev
->ConIn
,
423 Reads the next keystroke from the input device. The WaitForKey Event can
424 be used to test for existence of a keystroke via WaitForEvent () call.
427 @param This Protocol instance pointer.
428 @param KeyData A pointer to a buffer that is filled in with the keystroke
429 state data for the key that was pressed.
431 @retval EFI_SUCCESS The keystroke information was returned.
432 @retval EFI_NOT_READY There was no keystroke data available.
433 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
435 @retval EFI_INVALID_PARAMETER KeyData is NULL.
440 KeyboardReadKeyStrokeEx (
441 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
442 OUT EFI_KEY_DATA
*KeyData
446 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
448 if (KeyData
== NULL
) {
449 return EFI_INVALID_PARAMETER
;
452 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
453 return KeyboardReadKeyStrokeWorker (ConsoleInDev
, KeyData
);
457 Set certain state for the input device.
459 @param This Protocol instance pointer.
460 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
461 state for the input device.
463 @retval EFI_SUCCESS The device state was set successfully.
464 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
465 not have the setting adjusted.
466 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
467 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
473 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
474 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
479 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
482 if (KeyToggleState
== NULL
) {
483 return EFI_INVALID_PARAMETER
;
486 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
489 // Enter critical section
491 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
493 if (ConsoleInDev
->KeyboardErr
) {
494 Status
= EFI_DEVICE_ERROR
;
498 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) {
499 Status
= EFI_UNSUPPORTED
;
504 // Update the status light
506 ConsoleInDev
->ScrollLock
= FALSE
;
507 ConsoleInDev
->NumLock
= FALSE
;
508 ConsoleInDev
->CapsLock
= FALSE
;
509 ConsoleInDev
->IsSupportPartialKey
= FALSE
;
511 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
512 ConsoleInDev
->ScrollLock
= TRUE
;
515 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
516 ConsoleInDev
->NumLock
= TRUE
;
519 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
520 ConsoleInDev
->CapsLock
= TRUE
;
523 if ((*KeyToggleState
& EFI_KEY_STATE_EXPOSED
) == EFI_KEY_STATE_EXPOSED
) {
524 ConsoleInDev
->IsSupportPartialKey
= TRUE
;
527 Status
= UpdateStatusLights (ConsoleInDev
);
528 if (EFI_ERROR (Status
)) {
529 Status
= EFI_DEVICE_ERROR
;
534 // Leave critical section and return
536 gBS
->RestoreTPL (OldTpl
);
542 Register a notification function for a particular keystroke for the input device.
544 @param This Protocol instance pointer.
545 @param KeyData A pointer to a buffer that is filled in with the keystroke
546 information data for the key that was pressed. If KeyData.Key,
547 KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState are 0,
548 then any incomplete keystroke will trigger a notification of the KeyNotificationFunction.
549 @param KeyNotificationFunction Points to the function to be called when the key
550 sequence is typed specified by KeyData. This notification function
551 should be called at <=TPL_CALLBACK.
552 @param NotifyHandle Points to the unique handle assigned to the registered notification.
554 @retval EFI_SUCCESS The notification function was registered successfully.
555 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures.
556 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
561 KeyboardRegisterKeyNotify (
562 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
563 IN EFI_KEY_DATA
*KeyData
,
564 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
565 OUT VOID
**NotifyHandle
569 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
572 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
573 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
575 if ((KeyData
== NULL
) || (NotifyHandle
== NULL
) || (KeyNotificationFunction
== NULL
)) {
576 return EFI_INVALID_PARAMETER
;
579 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
582 // Enter critical section
584 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
587 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
589 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
592 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
594 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
596 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
597 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
598 *NotifyHandle
= CurrentNotify
;
599 Status
= EFI_SUCCESS
;
606 // Allocate resource to save the notification function
608 NewNotify
= (KEYBOARD_CONSOLE_IN_EX_NOTIFY
*)AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
609 if (NewNotify
== NULL
) {
610 Status
= EFI_OUT_OF_RESOURCES
;
614 NewNotify
->Signature
= KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
615 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
616 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
617 InsertTailList (&ConsoleInDev
->NotifyList
, &NewNotify
->NotifyEntry
);
619 *NotifyHandle
= NewNotify
;
620 Status
= EFI_SUCCESS
;
624 // Leave critical section and return
626 gBS
->RestoreTPL (OldTpl
);
631 Remove a registered notification function from a particular keystroke.
633 @param This Protocol instance pointer.
634 @param NotificationHandle The handle of the notification function being unregistered.
637 @retval EFI_SUCCESS The notification function was unregistered successfully.
638 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
643 KeyboardUnregisterKeyNotify (
644 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
645 IN VOID
*NotificationHandle
649 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
652 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
654 if (NotificationHandle
== NULL
) {
655 return EFI_INVALID_PARAMETER
;
658 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
661 // Enter critical section
663 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
665 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
668 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
670 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
672 if (CurrentNotify
== NotificationHandle
) {
674 // Remove the notification function from NotifyList and free resources
676 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
678 gBS
->FreePool (CurrentNotify
);
679 Status
= EFI_SUCCESS
;
685 // Can not find the specified Notification Handle
687 Status
= EFI_INVALID_PARAMETER
;
690 // Leave critical section and return
692 gBS
->RestoreTPL (OldTpl
);
699 @param Event Indicates the event that invoke this function.
700 @param Context Indicates the calling context.
704 KeyNotifyProcessHandler (
710 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
711 EFI_KEY_DATA KeyData
;
713 LIST_ENTRY
*NotifyList
;
714 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
717 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*)Context
;
720 // Invoke notification functions.
722 NotifyList
= &ConsoleIn
->NotifyList
;
725 // Enter critical section
727 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
728 Status
= PopEfikeyBufHead (&ConsoleIn
->EfiKeyQueueForNotify
, &KeyData
);
730 // Leave critical section
732 gBS
->RestoreTPL (OldTpl
);
733 if (EFI_ERROR (Status
)) {
737 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
, Link
); Link
= GetNextNode (NotifyList
, Link
)) {
738 CurrentNotify
= CR (Link
, KEYBOARD_CONSOLE_IN_EX_NOTIFY
, NotifyEntry
, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
);
739 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
740 CurrentNotify
->KeyNotificationFn (&KeyData
);