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.
60 IN EFI_KEY_DATA
*RegsiteredData
,
61 IN EFI_KEY_DATA
*InputData
65 Reads the next keystroke from the input device. The WaitForKey Event can
66 be used to test for existance of a keystroke via WaitForEvent () call.
69 @param ConsoleInDev - Ps2 Keyboard private structure
70 @param KeyData - A pointer to a buffer that is filled in with the keystroke
71 state data for the key that was pressed.
74 @retval EFI_SUCCESS - The keystroke information was returned.
75 @retval EFI_NOT_READY - There was no keystroke data availiable.
76 @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
78 @retval EFI_INVALID_PARAMETER - KeyData is NULL.
82 KeyboardReadKeyStrokeWorker (
83 IN KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
,
84 OUT EFI_KEY_DATA
*KeyData
91 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
92 EFI_KEY_DATA OriginalKeyData
;
93 if (KeyData
== NULL
) {
94 return EFI_INVALID_PARAMETER
;
98 // Enter critical section
100 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
102 if (ConsoleInDev
->KeyboardErr
) {
103 gBS
->RestoreTPL (OldTpl
);
104 return EFI_DEVICE_ERROR
;
107 // If there's no key, just return
109 Status
= KeyboardCheckForKey (&ConsoleInDev
->ConIn
);
110 if (EFI_ERROR (Status
)) {
111 gBS
->RestoreTPL (OldTpl
);
112 return EFI_NOT_READY
;
114 CopyMem (&KeyData
->Key
, &ConsoleInDev
->Key
, sizeof (EFI_INPUT_KEY
));
116 ConsoleInDev
->Key
.ScanCode
= SCAN_NULL
;
117 ConsoleInDev
->Key
.UnicodeChar
= 0x0000;
118 CopyMem (&KeyData
->KeyState
, &ConsoleInDev
->KeyState
, sizeof (EFI_KEY_STATE
));
120 ConsoleInDev
->KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
121 ConsoleInDev
->KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
122 gBS
->RestoreTPL (OldTpl
);
124 //Switch the control value to their original characters. In KeyGetchar() the CTRL-Alpha characters have been switched to
125 // their corresponding control value (ctrl-a = 0x0001 through ctrl-Z = 0x001A), here switch them back for notification function.
127 CopyMem (&OriginalKeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
128 if (ConsoleInDev
->Ctrled
) {
129 if (OriginalKeyData
.Key
.UnicodeChar
>= 0x01 && OriginalKeyData
.Key
.UnicodeChar
<= 0x1A) {
130 if (ConsoleInDev
->CapsLock
) {
131 OriginalKeyData
.Key
.UnicodeChar
= (CHAR16
)(OriginalKeyData
.Key
.UnicodeChar
+ 'A' - 1);
133 OriginalKeyData
.Key
.UnicodeChar
= (CHAR16
)(OriginalKeyData
.Key
.UnicodeChar
+ 'a' - 1);
138 // Invoke notification functions if exist
140 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
143 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
145 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
147 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &OriginalKeyData
)) {
148 CurrentNotify
->KeyNotificationFn (&OriginalKeyData
);
157 Implement SIMPLE_TEXT_IN.Reset()
158 Perform 8042 controller and keyboard initialization
160 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
161 @param ExtendedVerification Indicate that the driver may perform a more
162 exhaustive verification operation of the device during
163 reset, now this par is ignored in this driver
169 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
170 IN BOOLEAN ExtendedVerification
174 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
177 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
178 if (ConsoleIn
->KeyboardErr
) {
179 return EFI_DEVICE_ERROR
;
182 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
184 EFI_PERIPHERAL_KEYBOARD
| EFI_P_PC_RESET
,
185 ConsoleIn
->DevicePath
189 // Enter critical section
191 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
194 // Call InitKeyboard to initialize the keyboard
196 Status
= InitKeyboard (ConsoleIn
, ExtendedVerification
);
197 if (EFI_ERROR (Status
)) {
199 // Leave critical section and return
201 gBS
->RestoreTPL (OldTpl
);
202 return EFI_DEVICE_ERROR
;
205 // Clear the status of ConsoleIn.Key
207 ConsoleIn
->Key
.ScanCode
= SCAN_NULL
;
208 ConsoleIn
->Key
.UnicodeChar
= 0x0000;
211 // Leave critical section and return
213 gBS
->RestoreTPL (OldTpl
);
216 // Report the status If a stuck key was detected
218 if (KeyReadStatusRegister (ConsoleIn
) & 0x01) {
219 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
220 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
221 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_STUCK_KEY
,
222 ConsoleIn
->DevicePath
226 // Report the status If keyboard is locked
228 if (!(KeyReadStatusRegister (ConsoleIn
) & 0x10)) {
229 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
230 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
231 EFI_PERIPHERAL_KEYBOARD
| EFI_P_KEYBOARD_EC_LOCKED
,
232 ConsoleIn
->DevicePath
240 Implement SIMPLE_TEXT_IN.ReadKeyStroke().
241 Retrieve key values for driver user.
243 @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
244 @param Key The output buffer for key value
246 @retval EFI_SUCCESS success to read key stroke
250 KeyboardReadKeyStroke (
251 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
252 OUT EFI_INPUT_KEY
*Key
256 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
257 EFI_KEY_DATA KeyData
;
259 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
260 Status
= KeyboardReadKeyStrokeWorker (ConsoleIn
, &KeyData
);
261 if (EFI_ERROR (Status
)) {
265 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
271 Event notification function for SIMPLE_TEXT_IN.WaitForKey event
272 Signal the event if there is key available
274 @param Event the event object
275 @param Context waitting context
286 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
288 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context
);
291 // Enter critical section
293 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
295 if (ConsoleIn
->KeyboardErr
) {
297 // Leave critical section and return
299 gBS
->RestoreTPL (OldTpl
);
303 // Someone is waiting on the keyboard event, if there's
304 // a key pending, signal the event
306 if (!EFI_ERROR (KeyboardCheckForKey (Context
))) {
307 gBS
->SignalEvent (Event
);
310 // Leave critical section and return
312 gBS
->RestoreTPL (OldTpl
);
318 Check keyboard for given key value
320 @param This Point to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
322 @retval EFI_SUCCESS success check keyboard value
325 KeyboardCheckForKey (
326 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
329 KEYBOARD_CONSOLE_IN_DEV
*ConsoleIn
;
331 ConsoleIn
= KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
334 // If ready to read next key, check it
336 if (ConsoleIn
->Key
.ScanCode
== SCAN_NULL
&& ConsoleIn
->Key
.UnicodeChar
== 0x00) {
337 return KeyGetchar (ConsoleIn
);
344 Judge whether is a registed key
346 @param RegsiteredData - A pointer to a buffer that is filled in with the keystroke
347 state data for the key that was registered.
348 @param InputData - A pointer to a buffer that is filled in with the keystroke
349 state data for the key that was pressed.
351 @retval TRUE - Key be pressed matches a registered key.
352 @retval FLASE - Match failed.
357 IN EFI_KEY_DATA
*RegsiteredData
,
358 IN EFI_KEY_DATA
*InputData
362 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
364 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
365 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
370 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
372 if (RegsiteredData
->KeyState
.KeyShiftState
!= 0 &&
373 RegsiteredData
->KeyState
.KeyShiftState
!= InputData
->KeyState
.KeyShiftState
) {
376 if (RegsiteredData
->KeyState
.KeyToggleState
!= 0 &&
377 RegsiteredData
->KeyState
.KeyToggleState
!= InputData
->KeyState
.KeyToggleState
) {
386 Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
387 Signal the event if there is key available
389 @param Event event object
390 @param Context waiting context
395 KeyboardWaitForKeyEx (
401 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
403 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (Context
);
404 KeyboardWaitForKey (Event
, &ConsoleInDev
->ConIn
);
409 Reset the input device and optionaly run diagnostics
411 @param This - Protocol instance pointer.
412 @param ExtendedVerification - Driver may perform diagnostics on reset.
414 @retval EFI_SUCCESS - The device was reset.
415 @retval EFI_DEVICE_ERROR - The device is not functioning properly and could
422 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
423 IN BOOLEAN ExtendedVerification
428 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
431 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
432 if (ConsoleInDev
->KeyboardErr
) {
433 return EFI_DEVICE_ERROR
;
436 Status
= ConsoleInDev
->ConIn
.Reset (
437 &ConsoleInDev
->ConIn
,
440 if (EFI_ERROR (Status
)) {
441 return EFI_DEVICE_ERROR
;
444 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
446 ConsoleInDev
->KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
;
447 ConsoleInDev
->KeyState
.KeyToggleState
= EFI_TOGGLE_STATE_VALID
;
449 gBS
->RestoreTPL (OldTpl
);
455 Reads the next keystroke from the input device. The WaitForKey Event can
456 be used to test for existance of a keystroke via WaitForEvent () call.
459 @param This - Protocol instance pointer.
460 @param KeyData - A pointer to a buffer that is filled in with the keystroke
461 state data for the key that was pressed.
463 @retval EFI_SUCCESS - The keystroke information was returned.
464 @retval EFI_NOT_READY - There was no keystroke data availiable.
465 @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
467 @retval EFI_INVALID_PARAMETER - KeyData is NULL.
472 KeyboardReadKeyStrokeEx (
473 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
474 OUT EFI_KEY_DATA
*KeyData
478 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
480 if (KeyData
== NULL
) {
481 return EFI_INVALID_PARAMETER
;
484 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
485 return KeyboardReadKeyStrokeWorker (ConsoleInDev
, KeyData
);
490 Set certain state for the input device.
492 @param This - Protocol instance pointer.
493 @param KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
494 state for the input device.
496 @retval EFI_SUCCESS - The device state was set successfully.
497 @retval EFI_DEVICE_ERROR - The device is not functioning correctly and could
498 not have the setting adjusted.
499 @retval EFI_UNSUPPORTED - The device does not have the ability to set its state.
500 @retval EFI_INVALID_PARAMETER - KeyToggleState is NULL.
506 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
507 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
512 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
515 if (KeyToggleState
== NULL
) {
516 return EFI_INVALID_PARAMETER
;
519 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
522 // Enter critical section
524 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
526 if (ConsoleInDev
->KeyboardErr
) {
527 Status
= EFI_DEVICE_ERROR
;
531 if (((ConsoleInDev
->KeyState
.KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) ||
532 ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
)) {
533 Status
= EFI_UNSUPPORTED
;
538 // Update the status light
540 ConsoleInDev
->ScrollLock
= FALSE
;
541 ConsoleInDev
->NumLock
= FALSE
;
542 ConsoleInDev
->CapsLock
= FALSE
;
544 if ((*KeyToggleState
& EFI_SCROLL_LOCK_ACTIVE
) == EFI_SCROLL_LOCK_ACTIVE
) {
545 ConsoleInDev
->ScrollLock
= TRUE
;
547 if ((*KeyToggleState
& EFI_NUM_LOCK_ACTIVE
) == EFI_NUM_LOCK_ACTIVE
) {
548 ConsoleInDev
->NumLock
= TRUE
;
550 if ((*KeyToggleState
& EFI_CAPS_LOCK_ACTIVE
) == EFI_CAPS_LOCK_ACTIVE
) {
551 ConsoleInDev
->CapsLock
= TRUE
;
554 Status
= UpdateStatusLights (ConsoleInDev
);
555 if (EFI_ERROR (Status
)) {
556 Status
= EFI_DEVICE_ERROR
;
559 ConsoleInDev
->KeyState
.KeyToggleState
= *KeyToggleState
;
563 // Leave critical section and return
565 gBS
->RestoreTPL (OldTpl
);
572 Register a notification function for a particular keystroke for the input device.
574 @param This - Protocol instance pointer.
575 @param KeyData - A pointer to a buffer that is filled in with the keystroke
576 information data for the key that was pressed.
577 @param KeyNotificationFunction - Points to the function to be called when the key
578 sequence is typed specified by KeyData.
579 @param NotifyHandle - Points to the unique handle assigned to the registered notification.
581 @retval EFI_SUCCESS - The notification function was registered successfully.
582 @retval EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
583 @retval EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
588 KeyboardRegisterKeyNotify (
589 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
590 IN EFI_KEY_DATA
*KeyData
,
591 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
592 OUT EFI_HANDLE
*NotifyHandle
596 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
599 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
600 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
602 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
603 return EFI_INVALID_PARAMETER
;
606 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
609 // Enter critical section
611 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
614 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
616 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
619 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
621 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
623 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
624 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
625 *NotifyHandle
= CurrentNotify
->NotifyHandle
;
626 Status
= EFI_SUCCESS
;
633 // Allocate resource to save the notification function
635 NewNotify
= (KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY
));
636 if (NewNotify
== NULL
) {
637 Status
= EFI_OUT_OF_RESOURCES
;
641 NewNotify
->Signature
= KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
642 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
643 NewNotify
->NotifyHandle
= (EFI_HANDLE
) NewNotify
;
644 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
645 InsertTailList (&ConsoleInDev
->NotifyList
, &NewNotify
->NotifyEntry
);
647 *NotifyHandle
= NewNotify
->NotifyHandle
;
648 Status
= EFI_SUCCESS
;
652 // Leave critical section and return
654 gBS
->RestoreTPL (OldTpl
);
660 Remove a registered notification function from a particular keystroke.
662 @param This - Protocol instance pointer.
663 @param NotificationHandle - The handle of the notification function being unregistered.
666 @retval EFI_SUCCESS - The notification function was unregistered successfully.
667 @retval EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
672 KeyboardUnregisterKeyNotify (
673 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
674 IN EFI_HANDLE NotificationHandle
678 KEYBOARD_CONSOLE_IN_DEV
*ConsoleInDev
;
681 KEYBOARD_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
683 if (NotificationHandle
== NULL
) {
684 return EFI_INVALID_PARAMETER
;
687 if (((KEYBOARD_CONSOLE_IN_EX_NOTIFY
*) NotificationHandle
)->Signature
!= KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
) {
688 return EFI_INVALID_PARAMETER
;
691 ConsoleInDev
= TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This
);
694 // Enter critical section
696 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
698 for (Link
= ConsoleInDev
->NotifyList
.ForwardLink
; Link
!= &ConsoleInDev
->NotifyList
; Link
= Link
->ForwardLink
) {
701 KEYBOARD_CONSOLE_IN_EX_NOTIFY
,
703 KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
705 if (CurrentNotify
->NotifyHandle
== NotificationHandle
) {
707 // Remove the notification function from NotifyList and free resources
709 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
711 gBS
->FreePool (CurrentNotify
);
712 Status
= EFI_SUCCESS
;
718 // Can not find the specified Notification Handle
720 Status
= EFI_INVALID_PARAMETER
;
723 // Leave critical section and return
725 gBS
->RestoreTPL (OldTpl
);