3 Routines that support SIMPLE_TEXT_IN protocol
5 Copyright (c) 2006 - 2007, Intel Corporation
6 All rights reserved. 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 // function declarations
25 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
26 IN BOOLEAN ExtendedVerification
31 KeyboardReadKeyStroke (
32 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
33 OUT EFI_INPUT_KEY
*Key
45 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
49 @param RegsiteredData - A pointer to a buffer that is filled in with the keystroke
50 state data for the key that was registered.
51 @param InputData - A pointer to a buffer that is filled in with the keystroke
52 state data for the key that was pressed.
54 @retval TRUE - Key be pressed matches a registered key.
55 @retval FALSE - Match failed.
61 IN EFI_KEY_DATA
*RegsiteredData
,
62 IN EFI_KEY_DATA
*InputData
66 Reads the next keystroke from the input device. The WaitForKey Event can
67 be used to test for existance of a keystroke via WaitForEvent () call.
70 @param ConsoleInDev - Ps2 Keyboard private structure
71 @param KeyData - A pointer to a buffer that is filled in with the keystroke
72 state data for the key that was pressed.
75 @retval EFI_SUCCESS - The keystroke information was returned.
76 @retval EFI_NOT_READY - There was no keystroke data availiable.
77 @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
79 @retval EFI_INVALID_PARAMETER - KeyData is NULL.
84 KeyboardReadKeyStrokeWorker (
85 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
,
86 OUT EFI_KEY_DATA
*KeyData
93 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
94 EFI_KEY_DATA OriginalKeyData
;
95 if (KeyData
== NULL
) {
96 return EFI_INVALID_PARAMETER
;
100 // Enter critical section
102 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
104 if (ConsoleInDev
->KeyboardErr
) {
105 gBS
->RestoreTPL (OldTpl
);
106 return EFI_DEVICE_ERROR
;
109 // If there's no key, just return
111 Status
= KeyboardCheckForKey (&ConsoleInDev
->ConIn
);
112 if (EFI_ERROR (Status
)) {
113 gBS
->RestoreTPL (OldTpl
);
114 return EFI_NOT_READY
;
116 CopyMem (&KeyData
->Key
, &ConsoleInDev
->Key
, sizeof (EFI_INPUT_KEY
));
118 ConsoleInDev
->Key
.ScanCode
= SCAN_NULL
;
119 ConsoleInDev
->Key
.UnicodeChar
= 0x0000;
120 CopyMem (&KeyData
->KeyState
, &ConsoleInDev
->KeyState
, sizeof (EFI_KEY_STATE
));
122 ConsoleInDev
->KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
123 ConsoleInDev
->KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
124 gBS
->RestoreTPL (OldTpl
);
126 //Switch the control value to their original characters. In KeyGetchar() the CTRL-Alpha characters have been switched to
127 // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function.
129 CopyMem (&OriginalKeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
130 if (ConsoleInDev
->Ctrled
) {
131 if (OriginalKeyData
.Key
.UnicodeChar
>= 0x01 && OriginalKeyData
.Key
.UnicodeChar
<= 0x1A) {
132 if (ConsoleInDev
->CapsLock
) {
133 OriginalKeyData
.Key
.UnicodeChar
= (CHAR16
)(OriginalKeyData
.Key
.UnicodeChar
+ 'A' - 1);
135 OriginalKeyData
.Key
.UnicodeChar
= (CHAR16
)(OriginalKeyData
.Key
.UnicodeChar
+ 'a' - 1);
140 // Invoke notification functions if exist
142 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
145 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
147 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
149 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &OriginalKeyData
)) {
150 CurrentNotify
->KeyNotificationFn (&OriginalKeyData
);
159 Implement SIMPLE_TEXT_IN.Reset()
160 Perform 8042 controller and keyboard initialization
162 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
163 @param ExtendedVerification Indicate that the driver may perform a more
164 exhaustive verification operation of the device during
165 reset, now this par is ignored in this driver
171 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
172 IN BOOLEAN ExtendedVerification
176 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
179 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
180 if (ConsoleIn
->KeyboardErr
) {
181 return EFI_DEVICE_ERROR
;
184 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
186 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
187 ConsoleIn
->DevicePath
191 // Enter critical section
193 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
196 // Call InitKeyboard to initialize the keyboard
198 Status
= InitKeyboard (ConsoleIn
, ExtendedVerification
);
199 if (EFI_ERROR (Status
)) {
201 // Leave critical section and return
203 gBS
->RestoreTPL (OldTpl
);
204 return EFI_DEVICE_ERROR
;
207 // Clear the status of ConsoleIn.Key
209 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
210 ConsoleIn
->Key
.UnicodeChar
= 0x0000;
213 // Leave critical section and return
215 gBS
->RestoreTPL (OldTpl
);
218 // Report the status If a stuck key was detected
220 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
221 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
222 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
223 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_STUCK_KEY
,
224 ConsoleIn
->DevicePath
228 // Report the status If keyboard is locked
230 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x10)) {
231 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
232 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
233 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_LOCKED
,
234 ConsoleIn
->DevicePath
242 Implement SIMPLE_TEXT_IN.ReadKeyStroke().
243 Retrieve key values for driver user.
245 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
246 @param Key The output buffer for key value
248 @retval EFI_SUCCESS success to read key stroke
252 KeyboardReadKeyStroke (
253 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
254 OUT EFI_INPUT_KEY
*Key
258 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
259 EFI_KEY_DATA KeyData
;
261 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
262 Status
= KeyboardReadKeyStrokeWorker (ConsoleIn
, &KeyData
);
263 if (EFI_ERROR (Status
)) {
267 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
273 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
274 Signal the event if there is key available
276 @param Event the event object
277 @param Context waitting context
288 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
290 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context
);
293 // Enter critical section
295 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
297 if (ConsoleIn
->KeyboardErr
) {
299 // Leave critical section and return
301 gBS
->RestoreTPL (OldTpl
);
305 // Someone is waiting on the keyboard event, if there's
306 // a key pending, signal the event
308 if (!EFI_ERROR (KeyboardCheckForKey (Context
))) {
309 gBS
->SignalEvent (Event
);
312 // Leave critical section and return
314 gBS
->RestoreTPL (OldTpl
);
320 Check keyboard for given key value
322 @param This Point to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
324 @retval EFI_SUCCESS success check keyboard value
327 KeyboardCheckForKey (
328 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
331 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
333 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
336 // If ready to read next key, check it
338 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
339 return KeyGetchar (ConsoleIn
);
346 Judge whether is a registed key
348 @param RegsiteredData - A pointer to a buffer that is filled in with the keystroke
349 state data for the key that was registered.
350 @param InputData - A pointer to a buffer that is filled in with the keystroke
351 state data for the key that was pressed.
353 @retval TRUE - Key be pressed matches a registered key.
354 @retval FLASE - Match failed.
360 IN EFI_KEY_DATA
*RegsiteredData
,
361 IN EFI_KEY_DATA
*InputData
365 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
367 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
368 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
373 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
375 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
376 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
379 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
380 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
389 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
390 Signal the event if there is key available
392 @param Event event object
393 @param Context waiting context
398 KeyboardWaitForKeyEx (
404 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
406 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context
);
407 KeyboardWaitForKey (Event
, &ConsoleInDev
->ConIn
);
412 Reset the input device and optionaly run diagnostics
414 @param This - Protocol instance pointer.
415 @param ExtendedVerification - Driver may perform diagnostics on reset.
417 @retval EFI_SUCCESS - The device was reset.
418 @retval EFI_DEVICE_ERROR - The device is not functioning properly and could
425 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
426 IN BOOLEAN ExtendedVerification
431 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
434 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
435 if (ConsoleInDev
->KeyboardErr
) {
436 return EFI_DEVICE_ERROR
;
439 Status
= ConsoleInDev
->ConIn
.Reset (
440 &ConsoleInDev
->ConIn
,
443 if (EFI_ERROR (Status
)) {
444 return EFI_DEVICE_ERROR
;
447 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
449 ConsoleInDev
->KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
450 ConsoleInDev
->KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
452 gBS
->RestoreTPL (OldTpl
);
458 Reads the next keystroke from the input device. The WaitForKey Event can
459 be used to test for existance of a keystroke via WaitForEvent () call.
462 @param This - Protocol instance pointer.
463 @param KeyData - A pointer to a buffer that is filled in with the keystroke
464 state data for the key that was pressed.
466 @retval EFI_SUCCESS - The keystroke information was returned.
467 @retval EFI_NOT_READY - There was no keystroke data availiable.
468 @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
470 @retval EFI_INVALID_PARAMETER - KeyData is NULL.
475 KeyboardReadKeyStrokeEx (
476 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
477 OUT EFI_KEY_DATA
*KeyData
481 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
483 if (KeyData
== NULL
) {
484 return EFI_INVALID_PARAMETER
;
487 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
488 return KeyboardReadKeyStrokeWorker (ConsoleInDev
, KeyData
);
493 Set certain state for the input device.
495 @param This - Protocol instance pointer.
496 @param KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
497 state for the input device.
499 @retval EFI_SUCCESS - The device state was set successfully.
500 @retval EFI_DEVICE_ERROR - The device is not functioning correctly and could
501 not have the setting adjusted.
502 @retval EFI_UNSUPPORTED - The device does not have the ability to set its state.
503 @retval EFI_INVALID_PARAMETER - KeyToggleState is NULL.
509 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
510 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
515 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
518 if (KeyToggleState
== NULL
) {
519 return EFI_INVALID_PARAMETER
;
522 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
525 // Enter critical section
527 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
529 if (ConsoleInDev
->KeyboardErr
) {
530 Status
= EFI_DEVICE_ERROR
;
534 if (((ConsoleInDev
->KeyState
.KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) ||
535 ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
)) {
536 Status
= EFI_UNSUPPORTED
;
541 // Update the status light
543 ConsoleInDev
->ScrollLock
= FALSE
;
544 ConsoleInDev
->NumLock
= FALSE
;
545 ConsoleInDev
->CapsLock
= FALSE
;
547 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
548 ConsoleInDev
->ScrollLock
= TRUE
;
550 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
551 ConsoleInDev
->NumLock
= TRUE
;
553 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
554 ConsoleInDev
->CapsLock
= TRUE
;
557 Status
= UpdateStatusLights (ConsoleInDev
);
558 if (EFI_ERROR (Status
)) {
559 Status
= EFI_DEVICE_ERROR
;
562 ConsoleInDev
->KeyState
.KeyToggleState
= *KeyToggleState
;
566 // Leave critical section and return
568 gBS
->RestoreTPL (OldTpl
);
575 Register a notification function for a particular keystroke for the input device.
577 @param This - Protocol instance pointer.
578 @param KeyData - A pointer to a buffer that is filled in with the keystroke
579 information data for the key that was pressed.
580 @param KeyNotificationFunction - Points to the function to be called when the key
581 sequence is typed specified by KeyData.
582 @param NotifyHandle - Points to the unique handle assigned to the registered notification.
584 @retval EFI_SUCCESS - The notification function was registered successfully.
585 @retval EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
586 @retval EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
591 KeyboardRegisterKeyNotify (
592 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
593 IN EFI_KEY_DATA
*KeyData
,
594 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
595 OUT EFI_HANDLE
*NotifyHandle
599 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
602 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
603 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
605 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
606 return EFI_INVALID_PARAMETER
;
609 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
612 // Enter critical section
614 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
617 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
619 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
622 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
624 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
626 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
627 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
628 *NotifyHandle
= CurrentNotify
->NotifyHandle
;
629 Status
= EFI_SUCCESS
;
636 // Allocate resource to save the notification function
638 NewNotify
= (KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
639 if (NewNotify
== NULL
) {
640 Status
= EFI_OUT_OF_RESOURCES
;
644 NewNotify
->Signature
= KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
645 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
646 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
647 InsertTailList (&ConsoleInDev
->NotifyList
, &NewNotify
->NotifyEntry
);
650 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
652 Status
= gBS
->InstallMultipleProtocolInterfaces (
653 &NewNotify
->NotifyHandle
,
654 &gSimpleTextInExNotifyGuid
,
658 ASSERT_EFI_ERROR (Status
);
659 *NotifyHandle
= NewNotify
->NotifyHandle
;
660 Status
= EFI_SUCCESS
;
664 // Leave critical section and return
666 gBS
->RestoreTPL (OldTpl
);
672 Remove a registered notification function from a particular keystroke.
674 @param This - Protocol instance pointer.
675 @param NotificationHandle - The handle of the notification function being unregistered.
678 @retval EFI_SUCCESS - The notification function was unregistered successfully.
679 @retval EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
680 @retval EFI_NOT_FOUND - Can not find the matching entry in database.
685 KeyboardUnregisterKeyNotify (
686 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
687 IN EFI_HANDLE NotificationHandle
691 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
694 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
696 if (NotificationHandle
== NULL
) {
697 return EFI_INVALID_PARAMETER
;
700 Status
= gBS
->OpenProtocol (
702 &gSimpleTextInExNotifyGuid
,
706 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
708 if (EFI_ERROR (Status
)) {
709 return EFI_INVALID_PARAMETER
;
712 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
715 // Enter critical section
717 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
719 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
722 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
724 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
726 if (CurrentNotify
->NotifyHandle
== NotificationHandle
) {
728 // Remove the notification function from NotifyList and free resources
730 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
731 Status
= gBS
->UninstallMultipleProtocolInterfaces (
732 CurrentNotify
->NotifyHandle
,
733 &gSimpleTextInExNotifyGuid
,
737 ASSERT_EFI_ERROR (Status
);
738 gBS
->FreePool (CurrentNotify
);
739 Status
= EFI_SUCCESS
;
745 // Can not find the specified Notification Handle
747 Status
= EFI_NOT_FOUND
;
750 // Leave critical section and return
752 gBS
->RestoreTPL (OldTpl
);