2 Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces
3 provided by Ps2KbdCtrller.c.
5 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "Ps2Keyboard.h"
20 Check whether the EFI key buffer is empty.
22 @param Queue Pointer to instance of EFI_KEY_QUEUE.
24 @retval TRUE The EFI key buffer is empty.
25 @retval FALSE The EFI key buffer isn't empty.
29 IN EFI_KEY_QUEUE
*Queue
32 return (BOOLEAN
) (Queue
->Head
== Queue
->Tail
);
36 Read & remove one key data from the EFI key buffer.
38 @param Queue Pointer to instance of EFI_KEY_QUEUE.
39 @param KeyData Receive the key data.
41 @retval EFI_SUCCESS The key data is popped successfully.
42 @retval EFI_NOT_READY There is no key data available.
46 IN EFI_KEY_QUEUE
*Queue
,
47 OUT EFI_KEY_DATA
*KeyData OPTIONAL
50 if (IsEfikeyBufEmpty (Queue
)) {
54 // Retrieve and remove the values
56 if (KeyData
!= NULL
) {
57 CopyMem (KeyData
, &Queue
->Buffer
[Queue
->Head
], sizeof (EFI_KEY_DATA
));
59 Queue
->Head
= (Queue
->Head
+ 1) % KEYBOARD_EFI_KEY_MAX_COUNT
;
64 Push one key data to the EFI key buffer.
66 @param Queue Pointer to instance of EFI_KEY_QUEUE.
67 @param KeyData The key data to push.
71 IN EFI_KEY_QUEUE
*Queue
,
72 IN EFI_KEY_DATA
*KeyData
75 if ((Queue
->Tail
+ 1) % KEYBOARD_EFI_KEY_MAX_COUNT
== Queue
->Head
) {
77 // If Queue is full, pop the one from head.
79 PopEfikeyBufHead (Queue
, NULL
);
81 CopyMem (&Queue
->Buffer
[Queue
->Tail
], KeyData
, sizeof (EFI_KEY_DATA
));
82 Queue
->Tail
= (Queue
->Tail
+ 1) % KEYBOARD_EFI_KEY_MAX_COUNT
;
86 Judge whether is a registed key
88 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
89 state data for the key that was registered.
90 @param InputData A pointer to a buffer that is filled in with the keystroke
91 state data for the key that was pressed.
93 @retval TRUE Key be pressed matches a registered key.
94 @retval FLASE Match failed.
99 IN EFI_KEY_DATA
*RegsiteredData
,
100 IN EFI_KEY_DATA
*InputData
104 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
106 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
107 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
112 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
114 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
115 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
118 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
119 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
128 Reads the next keystroke from the input device. The WaitForKey Event can
129 be used to test for existance of a keystroke via WaitForEvent () call.
131 @param ConsoleInDev Ps2 Keyboard private structure
132 @param KeyData A pointer to a buffer that is filled in with the keystroke
133 state data for the key that was pressed.
136 @retval EFI_SUCCESS The keystroke information was returned.
137 @retval EFI_NOT_READY There was no keystroke data availiable.
138 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
140 @retval EFI_INVALID_PARAMETER KeyData is NULL.
144 KeyboardReadKeyStrokeWorker (
145 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
,
146 OUT EFI_KEY_DATA
*KeyData
153 if (KeyData
== NULL
) {
154 return EFI_INVALID_PARAMETER
;
158 // Enter critical section
160 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
162 KeyboardTimerHandler (NULL
, ConsoleInDev
);
164 if (ConsoleInDev
->KeyboardErr
) {
165 Status
= EFI_DEVICE_ERROR
;
167 Status
= PopEfikeyBufHead (&ConsoleInDev
->EfiKeyQueue
, KeyData
);
170 gBS
->RestoreTPL (OldTpl
);
175 Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()
177 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
178 @param ExtendedVerification Indicate that the driver may perform a more
179 exhaustive verification operation of the device during
180 reset, now this par is ignored in this driver
186 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
187 IN BOOLEAN ExtendedVerification
191 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
194 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
195 if (ConsoleIn
->KeyboardErr
) {
196 return EFI_DEVICE_ERROR
;
199 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
201 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
202 ConsoleIn
->DevicePath
206 // Enter critical section
208 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
211 // Call InitKeyboard to initialize the keyboard
213 Status
= InitKeyboard (ConsoleIn
, ExtendedVerification
);
214 if (EFI_ERROR (Status
)) {
216 // Leave critical section and return
218 gBS
->RestoreTPL (OldTpl
);
219 return EFI_DEVICE_ERROR
;
223 // Leave critical section and return
225 gBS
->RestoreTPL (OldTpl
);
228 // Report the status If a stuck key was detected
230 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
231 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
232 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
233 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_STUCK_KEY
,
234 ConsoleIn
->DevicePath
238 // Report the status If keyboard is locked
240 if ((KeyReadStatusRegister (ConsoleIn
) & 0x10) == 0) {
241 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
242 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
243 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_LOCKED
,
244 ConsoleIn
->DevicePath
252 Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().
254 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
255 @param Key The output buffer for key value
257 @retval EFI_SUCCESS success to read key stroke
261 KeyboardReadKeyStroke (
262 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
263 OUT EFI_INPUT_KEY
*Key
267 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
268 EFI_KEY_DATA KeyData
;
270 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
273 // Considering if the partial keystroke is enabled, there maybe a partial
274 // keystroke in the queue, so here skip the partial keystroke and get the
275 // next key from the queue
279 // If there is no pending key, then return.
281 Status
= KeyboardReadKeyStrokeWorker (ConsoleIn
, &KeyData
);
282 if (EFI_ERROR (Status
)) {
286 // If it is partial keystroke, skip it.
288 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
292 // Translate the CTRL-Alpha characters to their corresponding control value
293 // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
295 if ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) {
296 if (KeyData
.Key
.UnicodeChar
>= L
'a' && KeyData
.Key
.UnicodeChar
<= L
'z') {
297 KeyData
.Key
.UnicodeChar
= (CHAR16
) (KeyData
.Key
.UnicodeChar
- L
'a' + 1);
298 } else if (KeyData
.Key
.UnicodeChar
>= L
'A' && KeyData
.Key
.UnicodeChar
<= L
'Z') {
299 KeyData
.Key
.UnicodeChar
= (CHAR16
) (KeyData
.Key
.UnicodeChar
- L
'A' + 1);
303 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
309 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
310 Signal the event if there is key available
312 @param Event the event object
313 @param Context waitting context
324 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
325 EFI_KEY_DATA KeyData
;
327 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
330 // Enter critical section
332 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
334 KeyboardTimerHandler (NULL
, ConsoleIn
);
336 if (!ConsoleIn
->KeyboardErr
) {
338 // WaitforKey doesn't suppor the partial key.
339 // Considering if the partial keystroke is enabled, there maybe a partial
340 // keystroke in the queue, so here skip the partial keystroke and get the
341 // next key from the queue
343 while (!IsEfikeyBufEmpty (&ConsoleIn
->EfiKeyQueue
)) {
346 &(ConsoleIn
->EfiKeyQueue
.Buffer
[ConsoleIn
->EfiKeyQueue
.Head
]),
347 sizeof (EFI_KEY_DATA
)
349 if (KeyData
.Key
.ScanCode
== SCAN_NULL
&& KeyData
.Key
.UnicodeChar
== CHAR_NULL
) {
350 PopEfikeyBufHead (&ConsoleIn
->EfiKeyQueue
, &KeyData
);
354 // if there is pending value key, signal the event.
356 gBS
->SignalEvent (Event
);
361 // Leave critical section and return
363 gBS
->RestoreTPL (OldTpl
);
367 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
368 Signal the event if there is key available
370 @param Event event object
371 @param Context waiting context
376 KeyboardWaitForKeyEx (
382 KeyboardWaitForKey (Event
, Context
);
386 Reset the input device and optionaly run diagnostics
388 @param This Protocol instance pointer.
389 @param ExtendedVerification Driver may perform diagnostics on reset.
391 @retval EFI_SUCCESS The device was reset.
392 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
399 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
400 IN BOOLEAN ExtendedVerification
404 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
406 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
408 return ConsoleInDev
->ConIn
.Reset (
409 &ConsoleInDev
->ConIn
,
415 Reads the next keystroke from the input device. The WaitForKey Event can
416 be used to test for existance of a keystroke via WaitForEvent () call.
419 @param This Protocol instance pointer.
420 @param KeyData A pointer to a buffer that is filled in with the keystroke
421 state data for the key that was pressed.
423 @retval EFI_SUCCESS The keystroke information was returned.
424 @retval EFI_NOT_READY There was no keystroke data availiable.
425 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
427 @retval EFI_INVALID_PARAMETER KeyData is NULL.
432 KeyboardReadKeyStrokeEx (
433 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
434 OUT EFI_KEY_DATA
*KeyData
438 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
440 if (KeyData
== NULL
) {
441 return EFI_INVALID_PARAMETER
;
444 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
445 return KeyboardReadKeyStrokeWorker (ConsoleInDev
, KeyData
);
449 Set certain state for the input device.
451 @param This Protocol instance pointer.
452 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
453 state for the input device.
455 @retval EFI_SUCCESS The device state was set successfully.
456 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
457 not have the setting adjusted.
458 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
459 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
465 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
466 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
471 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
474 if (KeyToggleState
== NULL
) {
475 return EFI_INVALID_PARAMETER
;
478 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
481 // Enter critical section
483 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
485 if (ConsoleInDev
->KeyboardErr
) {
486 Status
= EFI_DEVICE_ERROR
;
490 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) {
491 Status
= EFI_UNSUPPORTED
;
496 // Update the status light
498 ConsoleInDev
->ScrollLock
= FALSE
;
499 ConsoleInDev
->NumLock
= FALSE
;
500 ConsoleInDev
->CapsLock
= FALSE
;
501 ConsoleInDev
->IsSupportPartialKey
= FALSE
;
503 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
504 ConsoleInDev
->ScrollLock
= TRUE
;
506 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
507 ConsoleInDev
->NumLock
= TRUE
;
509 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
510 ConsoleInDev
->CapsLock
= TRUE
;
512 if ((*KeyToggleState
& EFI_KEY_STATE_EXPOSED
) == EFI_KEY_STATE_EXPOSED
) {
513 ConsoleInDev
->IsSupportPartialKey
= TRUE
;
516 Status
= UpdateStatusLights (ConsoleInDev
);
517 if (EFI_ERROR (Status
)) {
518 Status
= EFI_DEVICE_ERROR
;
523 // Leave critical section and return
525 gBS
->RestoreTPL (OldTpl
);
532 Register a notification function for a particular keystroke for the input device.
534 @param This Protocol instance pointer.
535 @param KeyData A pointer to a buffer that is filled in with the keystroke
536 information data for the key that was pressed. If KeyData.Key,
537 KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState
538 are 0, then any incomplete keystroke will trigger a notification of
539 the KeyNotificationFunction.
540 @param KeyNotificationFunction Points to the function to be called when the key
541 sequence is typed specified by KeyData. This notification function
542 should be called at <=TPL_CALLBACK.
543 @param NotifyHandle Points to the unique handle assigned to the registered notification.
545 @retval EFI_SUCCESS The notification function was registered successfully.
546 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
547 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
552 KeyboardRegisterKeyNotify (
553 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
554 IN EFI_KEY_DATA
*KeyData
,
555 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
556 OUT VOID
**NotifyHandle
560 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
563 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
564 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
566 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
567 return EFI_INVALID_PARAMETER
;
570 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
573 // Enter critical section
575 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
578 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
580 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
583 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
585 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
587 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
588 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
589 *NotifyHandle
= CurrentNotify
;
590 Status
= EFI_SUCCESS
;
597 // Allocate resource to save the notification function
599 NewNotify
= (KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
600 if (NewNotify
== NULL
) {
601 Status
= EFI_OUT_OF_RESOURCES
;
605 NewNotify
->Signature
= KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
606 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
607 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
608 InsertTailList (&ConsoleInDev
->NotifyList
, &NewNotify
->NotifyEntry
);
610 *NotifyHandle
= NewNotify
;
611 Status
= EFI_SUCCESS
;
615 // Leave critical section and return
617 gBS
->RestoreTPL (OldTpl
);
623 Remove a registered notification function from a particular keystroke.
625 @param This Protocol instance pointer.
626 @param NotificationHandle The handle of the notification function being unregistered.
629 @retval EFI_SUCCESS The notification function was unregistered successfully.
630 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
635 KeyboardUnregisterKeyNotify (
636 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
637 IN VOID
*NotificationHandle
641 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
644 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
646 if (NotificationHandle
== NULL
) {
647 return EFI_INVALID_PARAMETER
;
650 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
653 // Enter critical section
655 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
657 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
660 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
662 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
664 if (CurrentNotify
== NotificationHandle
) {
666 // Remove the notification function from NotifyList and free resources
668 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
670 gBS
->FreePool (CurrentNotify
);
671 Status
= EFI_SUCCESS
;
677 // Can not find the specified Notification Handle
679 Status
= EFI_INVALID_PARAMETER
;
682 // Leave critical section and return
684 gBS
->RestoreTPL (OldTpl
);
691 @param Event Indicates the event that invoke this function.
692 @param Context Indicates the calling context.
696 KeyNotifyProcessHandler (
702 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
703 EFI_KEY_DATA KeyData
;
705 LIST_ENTRY
*NotifyList
;
706 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
709 ConsoleIn
= (KEYBOARD_CONSOLE_IN_DEV
*) Context
;
712 // Invoke notification functions.
714 NotifyList
= &ConsoleIn
->NotifyList
;
717 // Enter critical section
719 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
720 Status
= PopEfikeyBufHead (&ConsoleIn
->EfiKeyQueueForNotify
, &KeyData
);
722 // Leave critical section
724 gBS
->RestoreTPL (OldTpl
);
725 if (EFI_ERROR (Status
)) {
728 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
, Link
); Link
= GetNextNode (NotifyList
, Link
)) {
729 CurrentNotify
= CR (Link
, KEYBOARD_CONSOLE_IN_EX_NOTIFY
, NotifyEntry
, KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
);
730 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
731 CurrentNotify
->KeyNotificationFn (&KeyData
);