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
67 Reads the next keystroke from the input device. The WaitForKey Event can
68 be used to test for existance of a keystroke via WaitForEvent () call.
71 @param ConsoleInDev - Ps2 Keyboard private structure
72 @param KeyData - A pointer to a buffer that is filled in with the keystroke
73 state data for the key that was pressed.
76 @retval EFI_SUCCESS - The keystroke information was returned.
77 @retval EFI_NOT_READY - There was no keystroke data availiable.
78 @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
80 @retval EFI_INVALID_PARAMETER - KeyData is NULL.
85 KeyboardReadKeyStrokeWorker (
86 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
,
87 OUT EFI_KEY_DATA
*KeyData
94 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
95 EFI_KEY_DATA OriginalKeyData
;
96 if (KeyData
== NULL
) {
97 return EFI_INVALID_PARAMETER
;
101 // Enter critical section
103 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
105 if (ConsoleInDev
->KeyboardErr
) {
106 gBS
->RestoreTPL (OldTpl
);
107 return EFI_DEVICE_ERROR
;
110 // If there's no key, just return
112 Status
= KeyboardCheckForKey (&ConsoleInDev
->ConIn
);
113 if (EFI_ERROR (Status
)) {
114 gBS
->RestoreTPL (OldTpl
);
115 return EFI_NOT_READY
;
117 CopyMem (&KeyData
->Key
, &ConsoleInDev
->Key
, sizeof (EFI_INPUT_KEY
));
119 ConsoleInDev
->Key
.ScanCode
= SCAN_NULL
;
120 ConsoleInDev
->Key
.UnicodeChar
= 0x0000;
121 CopyMem (&KeyData
->KeyState
, &ConsoleInDev
->KeyState
, sizeof (EFI_KEY_STATE
));
123 ConsoleInDev
->KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
124 ConsoleInDev
->KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
125 gBS
->RestoreTPL (OldTpl
);
127 //Switch the control value to their original characters. In KeyGetchar() the CTRL-Alpha characters have been switched to
128 // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function.
130 CopyMem (&OriginalKeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
131 if (ConsoleInDev
->Ctrled
) {
132 if (OriginalKeyData
.Key
.UnicodeChar
>= 0x01 && OriginalKeyData
.Key
.UnicodeChar
<= 0x1A) {
133 if (ConsoleInDev
->CapsLock
) {
134 OriginalKeyData
.Key
.UnicodeChar
= (CHAR16
)(OriginalKeyData
.Key
.UnicodeChar
+ 'A' - 1);
136 OriginalKeyData
.Key
.UnicodeChar
= (CHAR16
)(OriginalKeyData
.Key
.UnicodeChar
+ 'a' - 1);
141 // Invoke notification functions if exist
143 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
146 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
148 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
150 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &OriginalKeyData
)) {
151 CurrentNotify
->KeyNotificationFn (&OriginalKeyData
);
160 Implement SIMPLE_TEXT_IN.Reset()
161 Perform 8042 controller and keyboard initialization
163 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
164 @param ExtendedVerification Indicate that the driver may perform a more
165 exhaustive verification operation of the device during
166 reset, now this par is ignored in this driver
172 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
173 IN BOOLEAN ExtendedVerification
177 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
180 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
181 if (ConsoleIn
->KeyboardErr
) {
182 return EFI_DEVICE_ERROR
;
185 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
187 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
188 ConsoleIn
->DevicePath
192 // Enter critical section
194 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
197 // Call InitKeyboard to initialize the keyboard
199 Status
= InitKeyboard (ConsoleIn
, ExtendedVerification
);
200 if (EFI_ERROR (Status
)) {
202 // Leave critical section and return
204 gBS
->RestoreTPL (OldTpl
);
205 return EFI_DEVICE_ERROR
;
208 // Clear the status of ConsoleIn.Key
210 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
211 ConsoleIn
->Key
.UnicodeChar
= 0x0000;
214 // Leave critical section and return
216 gBS
->RestoreTPL (OldTpl
);
219 // Report the status If a stuck key was detected
221 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
222 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
223 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
224 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_STUCK_KEY
,
225 ConsoleIn
->DevicePath
229 // Report the status If keyboard is locked
231 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x10)) {
232 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
233 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
234 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_LOCKED
,
235 ConsoleIn
->DevicePath
243 Implement SIMPLE_TEXT_IN.ReadKeyStroke().
244 Retrieve key values for driver user.
246 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
247 @param Key The output buffer for key value
249 @retval EFI_SUCCESS success to read key stroke
253 KeyboardReadKeyStroke (
254 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
255 OUT EFI_INPUT_KEY
*Key
259 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
260 EFI_KEY_DATA KeyData
;
262 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
263 Status
= KeyboardReadKeyStrokeWorker (ConsoleIn
, &KeyData
);
264 if (EFI_ERROR (Status
)) {
268 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
274 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
275 Signal the event if there is key available
277 @param Event the event object
278 @param Context waitting context
289 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
291 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context
);
294 // Enter critical section
296 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
298 if (ConsoleIn
->KeyboardErr
) {
300 // Leave critical section and return
302 gBS
->RestoreTPL (OldTpl
);
306 // Someone is waiting on the keyboard event, if there's
307 // a key pending, signal the event
309 if (!EFI_ERROR (KeyboardCheckForKey (Context
))) {
310 gBS
->SignalEvent (Event
);
313 // Leave critical section and return
315 gBS
->RestoreTPL (OldTpl
);
321 Check keyboard for given key value
323 @param This Point to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
325 @retval EFI_SUCCESS success check keyboard value
328 KeyboardCheckForKey (
329 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
332 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
334 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
337 // If ready to read next key, check it
339 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
340 return KeyGetchar (ConsoleIn
);
347 Judge whether is a registed key
349 @param RegsiteredData - A pointer to a buffer that is filled in with the keystroke
350 state data for the key that was registered.
351 @param InputData - A pointer to a buffer that is filled in with the keystroke
352 state data for the key that was pressed.
354 @retval TRUE - Key be pressed matches a registered key.
355 @retval FLASE - Match failed.
361 IN EFI_KEY_DATA
*RegsiteredData
,
362 IN EFI_KEY_DATA
*InputData
366 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
368 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
369 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
374 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
376 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
377 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
380 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
381 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
390 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
391 Signal the event if there is key available
393 @param Event event object
394 @param Context waiting context
399 KeyboardWaitForKeyEx (
405 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
407 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context
);
408 KeyboardWaitForKey (Event
, &ConsoleInDev
->ConIn
);
413 Reset the input device and optionaly run diagnostics
415 @param This - Protocol instance pointer.
416 @param ExtendedVerification - Driver may perform diagnostics on reset.
418 @retval EFI_SUCCESS - The device was reset.
419 @retval EFI_DEVICE_ERROR - The device is not functioning properly and could
426 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
427 IN BOOLEAN ExtendedVerification
432 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
435 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
436 if (ConsoleInDev
->KeyboardErr
) {
437 return EFI_DEVICE_ERROR
;
440 Status
= ConsoleInDev
->ConIn
.Reset (
441 &ConsoleInDev
->ConIn
,
444 if (EFI_ERROR (Status
)) {
445 return EFI_DEVICE_ERROR
;
448 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
450 ConsoleInDev
->KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
451 ConsoleInDev
->KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
453 gBS
->RestoreTPL (OldTpl
);
459 Reads the next keystroke from the input device. The WaitForKey Event can
460 be used to test for existance of a keystroke via WaitForEvent () call.
463 @param This - Protocol instance pointer.
464 @param KeyData - A pointer to a buffer that is filled in with the keystroke
465 state data for the key that was pressed.
467 @retval EFI_SUCCESS - The keystroke information was returned.
468 @retval EFI_NOT_READY - There was no keystroke data availiable.
469 @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
471 @retval EFI_INVALID_PARAMETER - KeyData is NULL.
476 KeyboardReadKeyStrokeEx (
477 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
478 OUT EFI_KEY_DATA
*KeyData
482 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
484 if (KeyData
== NULL
) {
485 return EFI_INVALID_PARAMETER
;
488 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
489 return KeyboardReadKeyStrokeWorker (ConsoleInDev
, KeyData
);
494 Set certain state for the input device.
496 @param This - Protocol instance pointer.
497 @param KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
498 state for the input device.
500 @retval EFI_SUCCESS - The device state was set successfully.
501 @retval EFI_DEVICE_ERROR - The device is not functioning correctly and could
502 not have the setting adjusted.
503 @retval EFI_UNSUPPORTED - The device does not have the ability to set its state.
504 @retval EFI_INVALID_PARAMETER - KeyToggleState is NULL.
510 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
511 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
516 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
519 if (KeyToggleState
== NULL
) {
520 return EFI_INVALID_PARAMETER
;
523 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
526 // Enter critical section
528 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
530 if (ConsoleInDev
->KeyboardErr
) {
531 Status
= EFI_DEVICE_ERROR
;
535 if (((ConsoleInDev
->KeyState
.KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) ||
536 ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
)) {
537 Status
= EFI_UNSUPPORTED
;
542 // Update the status light
544 ConsoleInDev
->ScrollLock
= FALSE
;
545 ConsoleInDev
->NumLock
= FALSE
;
546 ConsoleInDev
->CapsLock
= FALSE
;
548 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
549 ConsoleInDev
->ScrollLock
= TRUE
;
551 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
552 ConsoleInDev
->NumLock
= TRUE
;
554 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
555 ConsoleInDev
->CapsLock
= TRUE
;
558 Status
= UpdateStatusLights (ConsoleInDev
);
559 if (EFI_ERROR (Status
)) {
560 Status
= EFI_DEVICE_ERROR
;
563 ConsoleInDev
->KeyState
.KeyToggleState
= *KeyToggleState
;
567 // Leave critical section and return
569 gBS
->RestoreTPL (OldTpl
);
576 Register a notification function for a particular keystroke for the input device.
578 @param This - Protocol instance pointer.
579 @param KeyData - A pointer to a buffer that is filled in with the keystroke
580 information data for the key that was pressed.
581 @param KeyNotificationFunction - Points to the function to be called when the key
582 sequence is typed specified by KeyData.
583 @param NotifyHandle - Points to the unique handle assigned to the registered notification.
585 @retval EFI_SUCCESS - The notification function was registered successfully.
586 @retval EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
587 @retval EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
592 KeyboardRegisterKeyNotify (
593 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
594 IN EFI_KEY_DATA
*KeyData
,
595 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
596 OUT EFI_HANDLE
*NotifyHandle
600 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
603 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
604 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
606 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
607 return EFI_INVALID_PARAMETER
;
610 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
613 // Enter critical section
615 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
618 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
620 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
623 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
625 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
627 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
628 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
629 *NotifyHandle
= CurrentNotify
->NotifyHandle
;
630 Status
= EFI_SUCCESS
;
637 // Allocate resource to save the notification function
639 NewNotify
= (KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
640 if (NewNotify
== NULL
) {
641 Status
= EFI_OUT_OF_RESOURCES
;
645 NewNotify
->Signature
= KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
646 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
647 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
648 InsertTailList (&ConsoleInDev
->NotifyList
, &NewNotify
->NotifyEntry
);
651 // Use gSimpleTextInExNotifyGuid to get a valid EFI_HANDLE
653 Status
= gBS
->InstallMultipleProtocolInterfaces (
654 &NewNotify
->NotifyHandle
,
655 &gSimpleTextInExNotifyGuid
,
659 ASSERT_EFI_ERROR (Status
);
660 *NotifyHandle
= NewNotify
->NotifyHandle
;
661 Status
= EFI_SUCCESS
;
665 // Leave critical section and return
667 gBS
->RestoreTPL (OldTpl
);
673 Remove a registered notification function from a particular keystroke.
675 @param This - Protocol instance pointer.
676 @param NotificationHandle - The handle of the notification function being unregistered.
679 @retval EFI_SUCCESS - The notification function was unregistered successfully.
680 @retval EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
681 @retval EFI_NOT_FOUND - Can not find the matching entry in database.
686 KeyboardUnregisterKeyNotify (
687 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
688 IN EFI_HANDLE NotificationHandle
692 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
695 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
697 if (NotificationHandle
== NULL
) {
698 return EFI_INVALID_PARAMETER
;
701 Status
= gBS
->OpenProtocol (
703 &gSimpleTextInExNotifyGuid
,
707 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
709 if (EFI_ERROR (Status
)) {
710 return EFI_INVALID_PARAMETER
;
713 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
716 // Enter critical section
718 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
720 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
723 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
725 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
727 if (CurrentNotify
->NotifyHandle
== NotificationHandle
) {
729 // Remove the notification function from NotifyList and free resources
731 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
732 Status
= gBS
->UninstallMultipleProtocolInterfaces (
733 CurrentNotify
->NotifyHandle
,
734 &gSimpleTextInExNotifyGuid
,
738 ASSERT_EFI_ERROR (Status
);
739 gBS
->FreePool (CurrentNotify
);
740 Status
= EFI_SUCCESS
;
746 // Can not find the specified Notification Handle
748 Status
= EFI_NOT_FOUND
;
751 // Leave critical section and return
753 gBS
->RestoreTPL (OldTpl
);