2 Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2015, 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.
20 Reads the next keystroke from the input device. The WaitForKey Event can
21 be used to test for existence of a keystroke via WaitForEvent () call.
23 @param TerminalDevice Terminal driver private structure
24 @param KeyData A pointer to a buffer that is filled in with the
25 keystroke state data for the key that was
28 @retval EFI_SUCCESS The keystroke information was returned.
29 @retval EFI_NOT_READY There was no keystroke data available.
30 @retval EFI_INVALID_PARAMETER KeyData is NULL.
35 IN TERMINAL_DEV
*TerminalDevice
,
36 OUT EFI_KEY_DATA
*KeyData
39 if (KeyData
== NULL
) {
40 return EFI_INVALID_PARAMETER
;
43 if (!EfiKeyFiFoRemoveOneKey (TerminalDevice
, &KeyData
->Key
)) {
47 KeyData
->KeyState
.KeyShiftState
= 0;
48 KeyData
->KeyState
.KeyToggleState
= 0;
56 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
57 This driver only perform dependent serial device reset regardless of
58 the value of ExtendeVerification
60 @param This Indicates the calling context.
61 @param ExtendedVerification Skip by this driver.
63 @retval EFI_SUCCESS The reset operation succeeds.
64 @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
70 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
71 IN BOOLEAN ExtendedVerification
75 TERMINAL_DEV
*TerminalDevice
;
77 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (This
);
80 // Report progress code here
82 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
84 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_PC_RESET
),
85 TerminalDevice
->DevicePath
88 Status
= TerminalDevice
->SerialIo
->Reset (TerminalDevice
->SerialIo
);
91 // Make all the internal buffer empty for keys
93 TerminalDevice
->RawFiFo
->Head
= TerminalDevice
->RawFiFo
->Tail
;
94 TerminalDevice
->UnicodeFiFo
->Head
= TerminalDevice
->UnicodeFiFo
->Tail
;
95 TerminalDevice
->EfiKeyFiFo
->Head
= TerminalDevice
->EfiKeyFiFo
->Tail
;
97 if (EFI_ERROR (Status
)) {
98 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
99 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
100 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
101 TerminalDevice
->DevicePath
109 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
111 @param This Indicates the calling context.
112 @param Key A pointer to a buffer that is filled in with the
113 keystroke information for the key that was sent
116 @retval EFI_SUCCESS The keystroke information is returned successfully.
117 @retval EFI_NOT_READY There is no keystroke data available.
118 @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
123 TerminalConInReadKeyStroke (
124 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
125 OUT EFI_INPUT_KEY
*Key
128 TERMINAL_DEV
*TerminalDevice
;
130 EFI_KEY_DATA KeyData
;
133 // get TERMINAL_DEV from "This" parameter.
135 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (This
);
137 Status
= ReadKeyStrokeWorker (TerminalDevice
, &KeyData
);
138 if (EFI_ERROR (Status
)) {
142 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
149 Check if the key already has been registered.
151 If both RegsiteredData and InputData is NULL, then ASSERT().
153 @param RegsiteredData A pointer to a buffer that is filled in with the
154 keystroke state data for the key that was
156 @param InputData A pointer to a buffer that is filled in with the
157 keystroke state data for the key that was
160 @retval TRUE Key be pressed matches a registered key.
161 @retval FALSE Match failed.
166 IN EFI_KEY_DATA
*RegsiteredData
,
167 IN EFI_KEY_DATA
*InputData
170 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
172 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
173 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
183 Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
184 Signal the event if there is key available
186 @param Event Indicates the event that invoke this function.
187 @param Context Indicates the calling context.
192 TerminalConInWaitForKeyEx (
197 TerminalConInWaitForKey (Event
, Context
);
201 // Simple Text Input Ex protocol functions
205 Reset the input device and optionally run diagnostics
207 @param This Protocol instance pointer.
208 @param ExtendedVerification Driver may perform diagnostics on reset.
210 @retval EFI_SUCCESS The device was reset.
211 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
217 TerminalConInResetEx (
218 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
219 IN BOOLEAN ExtendedVerification
223 TERMINAL_DEV
*TerminalDevice
;
225 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
227 Status
= TerminalDevice
->SimpleInput
.Reset (&TerminalDevice
->SimpleInput
, ExtendedVerification
);
228 if (EFI_ERROR (Status
)) {
229 return EFI_DEVICE_ERROR
;
238 Reads the next keystroke from the input device. The WaitForKey Event can
239 be used to test for existence of a keystroke via WaitForEvent () call.
241 @param This Protocol instance pointer.
242 @param KeyData A pointer to a buffer that is filled in with the
243 keystroke state data for the key that was
246 @retval EFI_SUCCESS The keystroke information was returned.
247 @retval EFI_NOT_READY There was no keystroke data available.
248 @retval EFI_DEVICE_ERROR The keystroke information was not returned due
250 @retval EFI_INVALID_PARAMETER KeyData is NULL.
255 TerminalConInReadKeyStrokeEx (
256 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
257 OUT EFI_KEY_DATA
*KeyData
260 TERMINAL_DEV
*TerminalDevice
;
262 if (KeyData
== NULL
) {
263 return EFI_INVALID_PARAMETER
;
266 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
268 return ReadKeyStrokeWorker (TerminalDevice
, KeyData
);
274 Set certain state for the input device.
276 @param This Protocol instance pointer.
277 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
278 state for the input device.
280 @retval EFI_SUCCESS The device state was set successfully.
281 @retval EFI_DEVICE_ERROR The device is not functioning correctly and
282 could not have the setting adjusted.
283 @retval EFI_UNSUPPORTED The device does not have the ability to set its
285 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
290 TerminalConInSetState (
291 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
292 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
295 if (KeyToggleState
== NULL
) {
296 return EFI_INVALID_PARAMETER
;
299 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) {
300 return EFI_UNSUPPORTED
;
308 Register a notification function for a particular keystroke for the input device.
310 @param This Protocol instance pointer.
311 @param KeyData A pointer to a buffer that is filled in with the
312 keystroke information data for the key that was
314 @param KeyNotificationFunction Points to the function to be called when the key
315 sequence is typed specified by KeyData.
316 @param NotifyHandle Points to the unique handle assigned to the
317 registered notification.
319 @retval EFI_SUCCESS The notification function was registered
321 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data
323 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
328 TerminalConInRegisterKeyNotify (
329 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
330 IN EFI_KEY_DATA
*KeyData
,
331 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
332 OUT VOID
**NotifyHandle
335 TERMINAL_DEV
*TerminalDevice
;
336 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
338 LIST_ENTRY
*NotifyList
;
339 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
341 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
342 return EFI_INVALID_PARAMETER
;
345 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
348 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
350 NotifyList
= &TerminalDevice
->NotifyList
;
351 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
354 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
356 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
358 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
359 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
360 *NotifyHandle
= CurrentNotify
;
367 // Allocate resource to save the notification function
369 NewNotify
= (TERMINAL_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY
));
370 if (NewNotify
== NULL
) {
371 return EFI_OUT_OF_RESOURCES
;
374 NewNotify
->Signature
= TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
375 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
376 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
377 InsertTailList (&TerminalDevice
->NotifyList
, &NewNotify
->NotifyEntry
);
379 *NotifyHandle
= NewNotify
;
386 Remove a registered notification function from a particular keystroke.
388 @param This Protocol instance pointer.
389 @param NotificationHandle The handle of the notification function being
392 @retval EFI_SUCCESS The notification function was unregistered
394 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
399 TerminalConInUnregisterKeyNotify (
400 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
401 IN VOID
*NotificationHandle
404 TERMINAL_DEV
*TerminalDevice
;
406 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
407 LIST_ENTRY
*NotifyList
;
409 if (NotificationHandle
== NULL
) {
410 return EFI_INVALID_PARAMETER
;
413 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
415 NotifyList
= &TerminalDevice
->NotifyList
;
416 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
419 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
421 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
423 if (CurrentNotify
== NotificationHandle
) {
425 // Remove the notification function from NotifyList and free resources
427 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
429 gBS
->FreePool (CurrentNotify
);
435 // Can not find the matching entry in database.
437 return EFI_INVALID_PARAMETER
;
441 Translate raw data into Unicode (according to different encode), and
442 translate Unicode into key information. (according to different standard).
444 @param TerminalDevice Terminal driver private structure.
448 TranslateRawDataToEfiKey (
449 IN TERMINAL_DEV
*TerminalDevice
452 switch (TerminalDevice
->TerminalType
) {
458 AnsiRawDataToUnicode (TerminalDevice
);
459 UnicodeToEfiKey (TerminalDevice
);
464 // Process all the raw data in the RawFIFO,
465 // put the processed key into UnicodeFIFO.
467 VTUTF8RawDataToUnicode (TerminalDevice
);
470 // Translate all the Unicode data in the UnicodeFIFO to Efi key,
471 // then put into EfiKeyFIFO.
473 UnicodeToEfiKey (TerminalDevice
);
480 Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
481 Signal the event if there is key available
483 @param Event Indicates the event that invoke this function.
484 @param Context Indicates the calling context.
489 TerminalConInWaitForKey (
495 // Someone is waiting on the keystroke event, if there's
496 // a key pending, signal the event
498 if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV
*) Context
)) {
500 gBS
->SignalEvent (Event
);
505 Timer handler to poll the key from serial.
507 @param Event Indicates the event that invoke this function.
508 @param Context Indicates the calling context.
512 TerminalConInTimerHandler (
518 TERMINAL_DEV
*TerminalDevice
;
521 EFI_SERIAL_IO_MODE
*Mode
;
522 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
523 UINTN SerialInTimeOut
;
525 TerminalDevice
= (TERMINAL_DEV
*) Context
;
527 SerialIo
= TerminalDevice
->SerialIo
;
528 if (SerialIo
== NULL
) {
532 // if current timeout value for serial device is not identical with
533 // the value saved in TERMINAL_DEV structure, then recalculate the
534 // timeout value again and set serial attribute according to this value.
536 Mode
= SerialIo
->Mode
;
537 if (Mode
->Timeout
!= TerminalDevice
->SerialInTimeOut
) {
540 if (Mode
->BaudRate
!= 0) {
542 // According to BAUD rate to calculate the timeout value.
544 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
547 Status
= SerialIo
->SetAttributes (
550 0, // the device's default FIFO depth
551 (UINT32
) SerialInTimeOut
,
552 (EFI_PARITY_TYPE
) (Mode
->Parity
),
553 (UINT8
) Mode
->DataBits
,
554 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
557 if (EFI_ERROR (Status
)) {
558 TerminalDevice
->SerialInTimeOut
= 0;
560 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
564 // Check whether serial buffer is empty.
565 // Skip the key transfer loop only if the SerialIo protocol instance
566 // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.
568 Status
= SerialIo
->GetControl (SerialIo
, &Control
);
569 if (EFI_ERROR (Status
) || ((Control
& EFI_SERIAL_INPUT_BUFFER_EMPTY
) == 0)) {
571 // Fetch all the keys in the serial buffer,
572 // and insert the byte stream into RawFIFO.
574 while (!IsRawFiFoFull (TerminalDevice
)) {
576 Status
= GetOneKeyFromSerial (TerminalDevice
->SerialIo
, &Input
);
578 if (EFI_ERROR (Status
)) {
579 if (Status
== EFI_DEVICE_ERROR
) {
580 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
581 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
582 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_INPUT_ERROR
),
583 TerminalDevice
->DevicePath
589 RawFiFoInsertOneKey (TerminalDevice
, Input
);
594 // Translate all the raw data in RawFIFO into EFI Key,
595 // according to different terminal type supported.
597 TranslateRawDataToEfiKey (TerminalDevice
);
601 Get one key out of serial buffer.
603 @param SerialIo Serial I/O protocol attached to the serial device.
604 @param Output The fetched key.
606 @retval EFI_NOT_READY If serial buffer is empty.
607 @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
608 @retval EFI_SUCCESS If reading serial buffer successfully, put
609 the fetched key to the parameter output.
613 GetOneKeyFromSerial (
614 EFI_SERIAL_IO_PROTOCOL
*SerialIo
,
625 // Read one key from serial I/O device.
627 Status
= SerialIo
->Read (SerialIo
, &Size
, Output
);
629 if (EFI_ERROR (Status
)) {
631 if (Status
== EFI_TIMEOUT
) {
632 return EFI_NOT_READY
;
635 return EFI_DEVICE_ERROR
;
640 return EFI_NOT_READY
;
647 Insert one byte raw data into the Raw Data FIFO.
649 @param TerminalDevice Terminal driver private structure.
650 @param Input The key will be input.
652 @retval TRUE If insert successfully.
653 @retval FALSE If Raw Data buffer is full before key insertion,
658 RawFiFoInsertOneKey (
659 TERMINAL_DEV
*TerminalDevice
,
665 Tail
= TerminalDevice
->RawFiFo
->Tail
;
667 if (IsRawFiFoFull (TerminalDevice
)) {
674 TerminalDevice
->RawFiFo
->Data
[Tail
] = Input
;
676 TerminalDevice
->RawFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
682 Remove one pre-fetched key out of the Raw Data FIFO.
684 @param TerminalDevice Terminal driver private structure.
685 @param Output The key will be removed.
687 @retval TRUE If insert successfully.
688 @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
692 RawFiFoRemoveOneKey (
693 TERMINAL_DEV
*TerminalDevice
,
699 Head
= TerminalDevice
->RawFiFo
->Head
;
701 if (IsRawFiFoEmpty (TerminalDevice
)) {
709 *Output
= TerminalDevice
->RawFiFo
->Data
[Head
];
711 TerminalDevice
->RawFiFo
->Head
= (UINT8
) ((Head
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
717 Clarify whether Raw Data FIFO buffer is empty.
719 @param TerminalDevice Terminal driver private structure
721 @retval TRUE If Raw Data FIFO buffer is empty.
722 @retval FALSE If Raw Data FIFO buffer is not empty.
727 TERMINAL_DEV
*TerminalDevice
730 if (TerminalDevice
->RawFiFo
->Head
== TerminalDevice
->RawFiFo
->Tail
) {
738 Clarify whether Raw Data FIFO buffer is full.
740 @param TerminalDevice Terminal driver private structure
742 @retval TRUE If Raw Data FIFO buffer is full.
743 @retval FALSE If Raw Data FIFO buffer is not full.
748 TERMINAL_DEV
*TerminalDevice
754 Tail
= TerminalDevice
->RawFiFo
->Tail
;
755 Head
= TerminalDevice
->RawFiFo
->Head
;
757 if (((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1)) == Head
) {
766 Insert one pre-fetched key into the FIFO buffer.
768 @param TerminalDevice Terminal driver private structure.
769 @param Key The key will be input.
771 @retval TRUE If insert successfully.
772 @retval FALSE If FIFO buffer is full before key insertion,
777 EfiKeyFiFoInsertOneKey (
778 TERMINAL_DEV
*TerminalDevice
,
784 LIST_ENTRY
*NotifyList
;
785 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
786 EFI_KEY_DATA KeyData
;
788 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
790 CopyMem (&KeyData
.Key
, Key
, sizeof (EFI_INPUT_KEY
));
791 KeyData
.KeyState
.KeyShiftState
= 0;
792 KeyData
.KeyState
.KeyToggleState
= 0;
795 // Invoke notification functions if exist
797 NotifyList
= &TerminalDevice
->NotifyList
;
798 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
801 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
803 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
805 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
806 CurrentNotify
->KeyNotificationFn (&KeyData
);
809 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
811 // Efi Key FIFO is full
816 CopyMem (&TerminalDevice
->EfiKeyFiFo
->Data
[Tail
], Key
, sizeof (EFI_INPUT_KEY
));
818 TerminalDevice
->EfiKeyFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
824 Remove one pre-fetched key out of the FIFO buffer.
826 @param TerminalDevice Terminal driver private structure.
827 @param Output The key will be removed.
829 @retval TRUE If insert successfully.
830 @retval FALSE If FIFO buffer is empty before remove operation.
834 EfiKeyFiFoRemoveOneKey (
835 TERMINAL_DEV
*TerminalDevice
,
836 EFI_INPUT_KEY
*Output
841 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
842 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
844 if (IsEfiKeyFiFoEmpty (TerminalDevice
)) {
848 Output
->ScanCode
= SCAN_NULL
;
849 Output
->UnicodeChar
= 0;
853 CopyMem (Output
, &TerminalDevice
->EfiKeyFiFo
->Data
[Head
], sizeof (EFI_INPUT_KEY
));
855 TerminalDevice
->EfiKeyFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
861 Clarify whether FIFO buffer is empty.
863 @param TerminalDevice Terminal driver private structure
865 @retval TRUE If FIFO buffer is empty.
866 @retval FALSE If FIFO buffer is not empty.
871 TERMINAL_DEV
*TerminalDevice
874 if (TerminalDevice
->EfiKeyFiFo
->Head
== TerminalDevice
->EfiKeyFiFo
->Tail
) {
882 Clarify whether FIFO buffer is full.
884 @param TerminalDevice Terminal driver private structure
886 @retval TRUE If FIFO buffer is full.
887 @retval FALSE If FIFO buffer is not full.
892 TERMINAL_DEV
*TerminalDevice
898 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
899 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
901 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
910 Insert one pre-fetched key into the Unicode FIFO buffer.
912 @param TerminalDevice Terminal driver private structure.
913 @param Input The key will be input.
915 @retval TRUE If insert successfully.
916 @retval FALSE If Unicode FIFO buffer is full before key insertion,
921 UnicodeFiFoInsertOneKey (
922 TERMINAL_DEV
*TerminalDevice
,
928 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
929 ASSERT (Tail
< FIFO_MAX_NUMBER
+ 1);
932 if (IsUnicodeFiFoFull (TerminalDevice
)) {
934 // Unicode FIFO is full
939 TerminalDevice
->UnicodeFiFo
->Data
[Tail
] = Input
;
941 TerminalDevice
->UnicodeFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
947 Remove one pre-fetched key out of the Unicode FIFO buffer.
948 The caller should guarantee that Unicode FIFO buffer is not empty
949 by IsUnicodeFiFoEmpty ().
951 @param TerminalDevice Terminal driver private structure.
952 @param Output The key will be removed.
956 UnicodeFiFoRemoveOneKey (
957 TERMINAL_DEV
*TerminalDevice
,
963 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
964 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
966 *Output
= TerminalDevice
->UnicodeFiFo
->Data
[Head
];
968 TerminalDevice
->UnicodeFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
972 Clarify whether Unicode FIFO buffer is empty.
974 @param TerminalDevice Terminal driver private structure
976 @retval TRUE If Unicode FIFO buffer is empty.
977 @retval FALSE If Unicode FIFO buffer is not empty.
982 TERMINAL_DEV
*TerminalDevice
985 if (TerminalDevice
->UnicodeFiFo
->Head
== TerminalDevice
->UnicodeFiFo
->Tail
) {
993 Clarify whether Unicode FIFO buffer is full.
995 @param TerminalDevice Terminal driver private structure
997 @retval TRUE If Unicode FIFO buffer is full.
998 @retval FALSE If Unicode FIFO buffer is not full.
1003 TERMINAL_DEV
*TerminalDevice
1009 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1010 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1012 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
1021 Count Unicode FIFO buffer.
1023 @param TerminalDevice Terminal driver private structure
1025 @return The count in bytes of Unicode FIFO.
1029 UnicodeFiFoGetKeyCount (
1030 TERMINAL_DEV
*TerminalDevice
1036 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1037 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1040 return (UINT8
) (Tail
- Head
);
1042 return (UINT8
) (Tail
+ FIFO_MAX_NUMBER
+ 1 - Head
);
1047 Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1049 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1053 UnicodeToEfiKeyFlushState (
1054 IN TERMINAL_DEV
*TerminalDevice
1060 InputState
= TerminalDevice
->InputState
;
1062 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
1066 if ((InputState
& INPUT_STATE_ESC
) != 0) {
1067 Key
.ScanCode
= SCAN_ESC
;
1068 Key
.UnicodeChar
= 0;
1069 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1072 if ((InputState
& INPUT_STATE_CSI
) != 0) {
1073 Key
.ScanCode
= SCAN_NULL
;
1074 Key
.UnicodeChar
= CSI
;
1075 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1078 if ((InputState
& INPUT_STATE_LEFTOPENBRACKET
) != 0) {
1079 Key
.ScanCode
= SCAN_NULL
;
1080 Key
.UnicodeChar
= LEFTOPENBRACKET
;
1081 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1084 if ((InputState
& INPUT_STATE_O
) != 0) {
1085 Key
.ScanCode
= SCAN_NULL
;
1086 Key
.UnicodeChar
= 'O';
1087 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1090 if ((InputState
& INPUT_STATE_2
) != 0) {
1091 Key
.ScanCode
= SCAN_NULL
;
1092 Key
.UnicodeChar
= '2';
1093 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1097 // Cancel the timer.
1100 TerminalDevice
->TwoSecondTimeOut
,
1105 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1110 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1111 can be read through the Simple Input Protocol.
1113 The table below shows the keyboard input mappings that this function supports.
1114 If the ESC sequence listed in one of the columns is presented, then it is translated
1115 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
1116 key strokes are converted into EFI Keys.
1118 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
1119 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1120 converted into EFI Keys.
1121 There is one special input sequence that will force the system to reset.
1122 This is ESC R ESC r ESC R.
1124 Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1125 The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1126 DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1128 Symbols used in table below
1129 ===========================
1135 +=========+======+===========+==========+==========+
1136 | | EFI | UEFI 2.0 | | |
1137 | | Scan | | VT100+ | |
1138 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
1139 +=========+======+===========+==========+==========+
1140 | NULL | 0x00 | | | |
1141 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
1142 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
1143 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
1144 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
1145 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
1146 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
1147 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
1148 | | | ESC [ L | | ESC [ L |
1149 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
1150 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
1152 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
1154 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
1155 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
1156 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
1157 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
1158 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
1159 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
1160 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
1161 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
1162 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
1163 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
1164 | Escape | 0x17 | ESC | ESC | ESC |
1165 | F11 | 0x15 | | ESC ! | |
1166 | F12 | 0x16 | | ESC @ | |
1167 +=========+======+===========+==========+==========+
1171 ESC R ESC r ESC R = Reset System
1173 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1178 IN TERMINAL_DEV
*TerminalDevice
1182 EFI_STATUS TimerStatus
;
1185 BOOLEAN SetDefaultResetState
;
1187 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1189 if (!EFI_ERROR (TimerStatus
)) {
1190 UnicodeToEfiKeyFlushState (TerminalDevice
);
1191 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1194 while (!IsUnicodeFiFoEmpty (TerminalDevice
) && !IsEfiKeyFiFoFull (TerminalDevice
)) {
1196 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1198 // Check to see if the 2 seconds timer has expired
1200 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1201 if (!EFI_ERROR (TimerStatus
)) {
1202 UnicodeToEfiKeyFlushState (TerminalDevice
);
1203 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1208 // Fetch one Unicode character from the Unicode FIFO
1210 UnicodeFiFoRemoveOneKey (TerminalDevice
, &UnicodeChar
);
1212 SetDefaultResetState
= TRUE
;
1214 switch (TerminalDevice
->InputState
) {
1215 case INPUT_STATE_DEFAULT
:
1219 case INPUT_STATE_ESC
:
1221 if (UnicodeChar
== LEFTOPENBRACKET
) {
1222 TerminalDevice
->InputState
|= INPUT_STATE_LEFTOPENBRACKET
;
1223 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1227 if (UnicodeChar
== 'O' && (TerminalDevice
->TerminalType
== VT100TYPE
||
1228 TerminalDevice
->TerminalType
== TTYTERMTYPE
)) {
1229 TerminalDevice
->InputState
|= INPUT_STATE_O
;
1230 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1234 Key
.ScanCode
= SCAN_NULL
;
1236 if (TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1237 TerminalDevice
->TerminalType
== VTUTF8TYPE
) {
1238 switch (UnicodeChar
) {
1240 Key
.ScanCode
= SCAN_F1
;
1243 Key
.ScanCode
= SCAN_F2
;
1246 Key
.ScanCode
= SCAN_F3
;
1249 Key
.ScanCode
= SCAN_F4
;
1252 Key
.ScanCode
= SCAN_F5
;
1255 Key
.ScanCode
= SCAN_F6
;
1258 Key
.ScanCode
= SCAN_F7
;
1261 Key
.ScanCode
= SCAN_F8
;
1264 Key
.ScanCode
= SCAN_F9
;
1267 Key
.ScanCode
= SCAN_F10
;
1270 Key
.ScanCode
= SCAN_F11
;
1273 Key
.ScanCode
= SCAN_F12
;
1276 Key
.ScanCode
= SCAN_HOME
;
1279 Key
.ScanCode
= SCAN_END
;
1282 Key
.ScanCode
= SCAN_INSERT
;
1285 Key
.ScanCode
= SCAN_DELETE
;
1288 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1291 Key
.ScanCode
= SCAN_PAGE_UP
;
1298 switch (UnicodeChar
) {
1300 if (TerminalDevice
->ResetState
== RESET_STATE_DEFAULT
) {
1301 TerminalDevice
->ResetState
= RESET_STATE_ESC_R
;
1302 SetDefaultResetState
= FALSE
;
1303 } else if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R_ESC_R
) {
1304 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1306 Key
.ScanCode
= SCAN_NULL
;
1309 if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R
) {
1310 TerminalDevice
->ResetState
= RESET_STATE_ESC_R_ESC_R
;
1311 SetDefaultResetState
= FALSE
;
1313 Key
.ScanCode
= SCAN_NULL
;
1319 if (SetDefaultResetState
) {
1320 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1323 if (Key
.ScanCode
!= SCAN_NULL
) {
1324 Key
.UnicodeChar
= 0;
1325 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1326 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1327 UnicodeToEfiKeyFlushState (TerminalDevice
);
1331 UnicodeToEfiKeyFlushState (TerminalDevice
);
1335 case INPUT_STATE_ESC
| INPUT_STATE_O
:
1337 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1339 Key
.ScanCode
= SCAN_NULL
;
1341 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1342 switch (UnicodeChar
) {
1344 Key
.ScanCode
= SCAN_F1
;
1347 Key
.ScanCode
= SCAN_F2
;
1350 Key
.ScanCode
= SCAN_F3
;
1353 Key
.ScanCode
= SCAN_F4
;
1356 Key
.ScanCode
= SCAN_F5
;
1359 Key
.ScanCode
= SCAN_F6
;
1362 Key
.ScanCode
= SCAN_F7
;
1365 Key
.ScanCode
= SCAN_F8
;
1368 Key
.ScanCode
= SCAN_F9
;
1371 Key
.ScanCode
= SCAN_F10
;
1376 } else if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1377 /* Also accept VT100 escape codes for F1-F4 for TTY term */
1378 switch (UnicodeChar
) {
1380 Key
.ScanCode
= SCAN_F1
;
1383 Key
.ScanCode
= SCAN_F2
;
1386 Key
.ScanCode
= SCAN_F3
;
1389 Key
.ScanCode
= SCAN_F4
;
1394 if (Key
.ScanCode
!= SCAN_NULL
) {
1395 Key
.UnicodeChar
= 0;
1396 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1397 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1398 UnicodeToEfiKeyFlushState (TerminalDevice
);
1402 UnicodeToEfiKeyFlushState (TerminalDevice
);
1406 case INPUT_STATE_ESC
| INPUT_STATE_LEFTOPENBRACKET
:
1408 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1410 Key
.ScanCode
= SCAN_NULL
;
1412 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1413 TerminalDevice
->TerminalType
== VT100TYPE
||
1414 TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1415 TerminalDevice
->TerminalType
== VTUTF8TYPE
||
1416 TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1417 switch (UnicodeChar
) {
1419 Key
.ScanCode
= SCAN_UP
;
1422 Key
.ScanCode
= SCAN_DOWN
;
1425 Key
.ScanCode
= SCAN_RIGHT
;
1428 Key
.ScanCode
= SCAN_LEFT
;
1431 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1432 TerminalDevice
->TerminalType
== VT100TYPE
) {
1433 Key
.ScanCode
= SCAN_HOME
;
1437 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1438 Key
.ScanCode
= SCAN_END
;
1442 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1443 Key
.ScanCode
= SCAN_END
;
1448 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1449 TerminalDevice
->TerminalType
== VT100TYPE
) {
1450 Key
.ScanCode
= SCAN_INSERT
;
1454 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1455 Key
.ScanCode
= SCAN_DELETE
;
1459 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1460 Key
.ScanCode
= SCAN_DELETE
;
1461 } else if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1462 Key
.ScanCode
= SCAN_F4
;
1466 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1467 Key
.ScanCode
= SCAN_PAGE_UP
;
1471 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1472 Key
.ScanCode
= SCAN_F10
;
1476 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1477 Key
.ScanCode
= SCAN_PAGE_UP
;
1481 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1482 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1486 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1487 Key
.ScanCode
= SCAN_F9
;
1491 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1492 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1496 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1497 Key
.ScanCode
= SCAN_F1
;
1501 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1502 Key
.ScanCode
= SCAN_F2
;
1506 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1507 Key
.ScanCode
= SCAN_F3
;
1511 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1512 Key
.ScanCode
= SCAN_F5
;
1516 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1517 Key
.ScanCode
= SCAN_F6
;
1521 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1522 Key
.ScanCode
= SCAN_F7
;
1526 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1527 Key
.ScanCode
= SCAN_F8
;
1536 * The VT220 escape codes that the TTY terminal accepts all have
1537 * numeric codes, and there are no ambiguous prefixes shared with
1538 * other terminal types.
1540 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
&&
1541 Key
.ScanCode
== SCAN_NULL
&&
1542 UnicodeChar
>= '0' &&
1543 UnicodeChar
<= '9') {
1544 TerminalDevice
->TtyEscapeStr
[0] = UnicodeChar
;
1545 TerminalDevice
->TtyEscapeIndex
= 1;
1546 TerminalDevice
->InputState
|= INPUT_STATE_LEFTOPENBRACKET_2
;
1550 if (Key
.ScanCode
!= SCAN_NULL
) {
1551 Key
.UnicodeChar
= 0;
1552 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1553 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1554 UnicodeToEfiKeyFlushState (TerminalDevice
);
1558 UnicodeToEfiKeyFlushState (TerminalDevice
);
1563 case INPUT_STATE_ESC
| INPUT_STATE_LEFTOPENBRACKET
| INPUT_STATE_LEFTOPENBRACKET_2
:
1565 * Here we handle the VT220 escape codes that we accept. This
1566 * state is only used by the TTY terminal type.
1568 Key
.ScanCode
= SCAN_NULL
;
1569 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1571 if (UnicodeChar
== '~' && TerminalDevice
->TtyEscapeIndex
<= 2) {
1573 TerminalDevice
->TtyEscapeStr
[TerminalDevice
->TtyEscapeIndex
] = 0; /* Terminate string */
1574 EscCode
= (UINT16
) StrDecimalToUintn(TerminalDevice
->TtyEscapeStr
);
1577 Key
.ScanCode
= SCAN_DELETE
;
1584 Key
.ScanCode
= SCAN_F1
+ EscCode
- 11;
1591 Key
.ScanCode
= SCAN_F6
+ EscCode
- 17;
1595 Key
.ScanCode
= SCAN_F11
+ EscCode
- 23;
1600 } else if (TerminalDevice
->TtyEscapeIndex
== 1){
1601 /* 2 character escape code */
1602 TerminalDevice
->TtyEscapeStr
[TerminalDevice
->TtyEscapeIndex
++] = UnicodeChar
;
1606 DEBUG ((EFI_D_ERROR
, "Unexpected state in escape2\n"));
1609 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1611 if (Key
.ScanCode
!= SCAN_NULL
) {
1612 Key
.UnicodeChar
= 0;
1613 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1614 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1615 UnicodeToEfiKeyFlushState (TerminalDevice
);
1619 UnicodeToEfiKeyFlushState (TerminalDevice
);
1624 // Invalid state. This should never happen.
1628 UnicodeToEfiKeyFlushState (TerminalDevice
);
1633 if (UnicodeChar
== ESC
) {
1634 TerminalDevice
->InputState
= INPUT_STATE_ESC
;
1637 if (UnicodeChar
== CSI
) {
1638 TerminalDevice
->InputState
= INPUT_STATE_CSI
;
1641 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1642 Status
= gBS
->SetTimer(
1643 TerminalDevice
->TwoSecondTimeOut
,
1647 ASSERT_EFI_ERROR (Status
);
1651 if (SetDefaultResetState
) {
1652 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1655 if (UnicodeChar
== DEL
) {
1656 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1657 Key
.ScanCode
= SCAN_NULL
;
1658 Key
.UnicodeChar
= CHAR_BACKSPACE
;
1661 Key
.ScanCode
= SCAN_DELETE
;
1662 Key
.UnicodeChar
= 0;
1665 Key
.ScanCode
= SCAN_NULL
;
1666 Key
.UnicodeChar
= UnicodeChar
;
1669 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);