2 Implementation for EFI_SIMPLE_TEXT_INPUT_PROTOCOL protocol.
4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2006 - 2014, 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
) {
457 AnsiRawDataToUnicode (TerminalDevice
);
458 UnicodeToEfiKey (TerminalDevice
);
463 // Process all the raw data in the RawFIFO,
464 // put the processed key into UnicodeFIFO.
466 VTUTF8RawDataToUnicode (TerminalDevice
);
469 // Translate all the Unicode data in the UnicodeFIFO to Efi key,
470 // then put into EfiKeyFIFO.
472 UnicodeToEfiKey (TerminalDevice
);
479 Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
480 Signal the event if there is key available
482 @param Event Indicates the event that invoke this function.
483 @param Context Indicates the calling context.
488 TerminalConInWaitForKey (
494 // Someone is waiting on the keystroke event, if there's
495 // a key pending, signal the event
497 if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV
*) Context
)) {
499 gBS
->SignalEvent (Event
);
504 Timer handler to poll the key from serial.
506 @param Event Indicates the event that invoke this function.
507 @param Context Indicates the calling context.
511 TerminalConInTimerHandler (
517 TERMINAL_DEV
*TerminalDevice
;
520 EFI_SERIAL_IO_MODE
*Mode
;
521 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
522 UINTN SerialInTimeOut
;
524 TerminalDevice
= (TERMINAL_DEV
*) Context
;
526 SerialIo
= TerminalDevice
->SerialIo
;
527 if (SerialIo
== NULL
) {
531 // if current timeout value for serial device is not identical with
532 // the value saved in TERMINAL_DEV structure, then recalculate the
533 // timeout value again and set serial attribute according to this value.
535 Mode
= SerialIo
->Mode
;
536 if (Mode
->Timeout
!= TerminalDevice
->SerialInTimeOut
) {
539 if (Mode
->BaudRate
!= 0) {
541 // According to BAUD rate to calculate the timeout value.
543 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
546 Status
= SerialIo
->SetAttributes (
549 Mode
->ReceiveFifoDepth
,
550 (UINT32
) SerialInTimeOut
,
551 (EFI_PARITY_TYPE
) (Mode
->Parity
),
552 (UINT8
) Mode
->DataBits
,
553 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
556 if (EFI_ERROR (Status
)) {
557 TerminalDevice
->SerialInTimeOut
= 0;
559 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
563 // Check whether serial buffer is empty.
565 Status
= SerialIo
->GetControl (SerialIo
, &Control
);
567 if ((Control
& EFI_SERIAL_INPUT_BUFFER_EMPTY
) == 0) {
569 // Fetch all the keys in the serial buffer,
570 // and insert the byte stream into RawFIFO.
572 while (!IsRawFiFoFull (TerminalDevice
)) {
574 Status
= GetOneKeyFromSerial (TerminalDevice
->SerialIo
, &Input
);
576 if (EFI_ERROR (Status
)) {
577 if (Status
== EFI_DEVICE_ERROR
) {
578 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
579 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
580 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_INPUT_ERROR
),
581 TerminalDevice
->DevicePath
587 RawFiFoInsertOneKey (TerminalDevice
, Input
);
592 // Translate all the raw data in RawFIFO into EFI Key,
593 // according to different terminal type supported.
595 TranslateRawDataToEfiKey (TerminalDevice
);
599 Get one key out of serial buffer.
601 @param SerialIo Serial I/O protocol attached to the serial device.
602 @param Output The fetched key.
604 @retval EFI_NOT_READY If serial buffer is empty.
605 @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
606 @retval EFI_SUCCESS If reading serial buffer successfully, put
607 the fetched key to the parameter output.
611 GetOneKeyFromSerial (
612 EFI_SERIAL_IO_PROTOCOL
*SerialIo
,
623 // Read one key from serial I/O device.
625 Status
= SerialIo
->Read (SerialIo
, &Size
, Output
);
627 if (EFI_ERROR (Status
)) {
629 if (Status
== EFI_TIMEOUT
) {
630 return EFI_NOT_READY
;
633 return EFI_DEVICE_ERROR
;
638 return EFI_NOT_READY
;
645 Insert one byte raw data into the Raw Data FIFO.
647 @param TerminalDevice Terminal driver private structure.
648 @param Input The key will be input.
650 @retval TRUE If insert successfully.
651 @retval FALSE If Raw Data buffer is full before key insertion,
656 RawFiFoInsertOneKey (
657 TERMINAL_DEV
*TerminalDevice
,
663 Tail
= TerminalDevice
->RawFiFo
->Tail
;
665 if (IsRawFiFoFull (TerminalDevice
)) {
672 TerminalDevice
->RawFiFo
->Data
[Tail
] = Input
;
674 TerminalDevice
->RawFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
680 Remove one pre-fetched key out of the Raw Data FIFO.
682 @param TerminalDevice Terminal driver private structure.
683 @param Output The key will be removed.
685 @retval TRUE If insert successfully.
686 @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
690 RawFiFoRemoveOneKey (
691 TERMINAL_DEV
*TerminalDevice
,
697 Head
= TerminalDevice
->RawFiFo
->Head
;
699 if (IsRawFiFoEmpty (TerminalDevice
)) {
707 *Output
= TerminalDevice
->RawFiFo
->Data
[Head
];
709 TerminalDevice
->RawFiFo
->Head
= (UINT8
) ((Head
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
715 Clarify whether Raw Data FIFO buffer is empty.
717 @param TerminalDevice Terminal driver private structure
719 @retval TRUE If Raw Data FIFO buffer is empty.
720 @retval FALSE If Raw Data FIFO buffer is not empty.
725 TERMINAL_DEV
*TerminalDevice
728 if (TerminalDevice
->RawFiFo
->Head
== TerminalDevice
->RawFiFo
->Tail
) {
736 Clarify whether Raw Data FIFO buffer is full.
738 @param TerminalDevice Terminal driver private structure
740 @retval TRUE If Raw Data FIFO buffer is full.
741 @retval FALSE If Raw Data FIFO buffer is not full.
746 TERMINAL_DEV
*TerminalDevice
752 Tail
= TerminalDevice
->RawFiFo
->Tail
;
753 Head
= TerminalDevice
->RawFiFo
->Head
;
755 if (((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1)) == Head
) {
764 Insert one pre-fetched key into the FIFO buffer.
766 @param TerminalDevice Terminal driver private structure.
767 @param Key The key will be input.
769 @retval TRUE If insert successfully.
770 @retval FALSE If FIFO buffer is full before key insertion,
775 EfiKeyFiFoInsertOneKey (
776 TERMINAL_DEV
*TerminalDevice
,
782 LIST_ENTRY
*NotifyList
;
783 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
784 EFI_KEY_DATA KeyData
;
786 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
788 CopyMem (&KeyData
.Key
, Key
, sizeof (EFI_INPUT_KEY
));
789 KeyData
.KeyState
.KeyShiftState
= 0;
790 KeyData
.KeyState
.KeyToggleState
= 0;
793 // Invoke notification functions if exist
795 NotifyList
= &TerminalDevice
->NotifyList
;
796 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
799 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
801 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
803 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
804 CurrentNotify
->KeyNotificationFn (&KeyData
);
807 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
809 // Efi Key FIFO is full
814 CopyMem (&TerminalDevice
->EfiKeyFiFo
->Data
[Tail
], Key
, sizeof (EFI_INPUT_KEY
));
816 TerminalDevice
->EfiKeyFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
822 Remove one pre-fetched key out of the FIFO buffer.
824 @param TerminalDevice Terminal driver private structure.
825 @param Output The key will be removed.
827 @retval TRUE If insert successfully.
828 @retval FALSE If FIFO buffer is empty before remove operation.
832 EfiKeyFiFoRemoveOneKey (
833 TERMINAL_DEV
*TerminalDevice
,
834 EFI_INPUT_KEY
*Output
839 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
840 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
842 if (IsEfiKeyFiFoEmpty (TerminalDevice
)) {
846 Output
->ScanCode
= SCAN_NULL
;
847 Output
->UnicodeChar
= 0;
851 CopyMem (Output
, &TerminalDevice
->EfiKeyFiFo
->Data
[Head
], sizeof (EFI_INPUT_KEY
));
853 TerminalDevice
->EfiKeyFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
859 Clarify whether FIFO buffer is empty.
861 @param TerminalDevice Terminal driver private structure
863 @retval TRUE If FIFO buffer is empty.
864 @retval FALSE If FIFO buffer is not empty.
869 TERMINAL_DEV
*TerminalDevice
872 if (TerminalDevice
->EfiKeyFiFo
->Head
== TerminalDevice
->EfiKeyFiFo
->Tail
) {
880 Clarify whether FIFO buffer is full.
882 @param TerminalDevice Terminal driver private structure
884 @retval TRUE If FIFO buffer is full.
885 @retval FALSE If FIFO buffer is not full.
890 TERMINAL_DEV
*TerminalDevice
896 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
897 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
899 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
908 Insert one pre-fetched key into the Unicode FIFO buffer.
910 @param TerminalDevice Terminal driver private structure.
911 @param Input The key will be input.
913 @retval TRUE If insert successfully.
914 @retval FALSE If Unicode FIFO buffer is full before key insertion,
919 UnicodeFiFoInsertOneKey (
920 TERMINAL_DEV
*TerminalDevice
,
926 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
927 ASSERT (Tail
< FIFO_MAX_NUMBER
+ 1);
930 if (IsUnicodeFiFoFull (TerminalDevice
)) {
932 // Unicode FIFO is full
937 TerminalDevice
->UnicodeFiFo
->Data
[Tail
] = Input
;
939 TerminalDevice
->UnicodeFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
945 Remove one pre-fetched key out of the Unicode FIFO buffer.
946 The caller should guarantee that Unicode FIFO buffer is not empty
947 by IsUnicodeFiFoEmpty ().
949 @param TerminalDevice Terminal driver private structure.
950 @param Output The key will be removed.
954 UnicodeFiFoRemoveOneKey (
955 TERMINAL_DEV
*TerminalDevice
,
961 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
962 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
964 *Output
= TerminalDevice
->UnicodeFiFo
->Data
[Head
];
966 TerminalDevice
->UnicodeFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
970 Clarify whether Unicode FIFO buffer is empty.
972 @param TerminalDevice Terminal driver private structure
974 @retval TRUE If Unicode FIFO buffer is empty.
975 @retval FALSE If Unicode FIFO buffer is not empty.
980 TERMINAL_DEV
*TerminalDevice
983 if (TerminalDevice
->UnicodeFiFo
->Head
== TerminalDevice
->UnicodeFiFo
->Tail
) {
991 Clarify whether Unicode FIFO buffer is full.
993 @param TerminalDevice Terminal driver private structure
995 @retval TRUE If Unicode FIFO buffer is full.
996 @retval FALSE If Unicode FIFO buffer is not full.
1001 TERMINAL_DEV
*TerminalDevice
1007 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1008 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1010 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
1019 Count Unicode FIFO buffer.
1021 @param TerminalDevice Terminal driver private structure
1023 @return The count in bytes of Unicode FIFO.
1027 UnicodeFiFoGetKeyCount (
1028 TERMINAL_DEV
*TerminalDevice
1034 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1035 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1038 return (UINT8
) (Tail
- Head
);
1040 return (UINT8
) (Tail
+ FIFO_MAX_NUMBER
+ 1 - Head
);
1045 Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1047 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1051 UnicodeToEfiKeyFlushState (
1052 IN TERMINAL_DEV
*TerminalDevice
1058 InputState
= TerminalDevice
->InputState
;
1060 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
1064 if ((InputState
& INPUT_STATE_ESC
) != 0) {
1065 Key
.ScanCode
= SCAN_ESC
;
1066 Key
.UnicodeChar
= 0;
1067 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1070 if ((InputState
& INPUT_STATE_CSI
) != 0) {
1071 Key
.ScanCode
= SCAN_NULL
;
1072 Key
.UnicodeChar
= CSI
;
1073 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1076 if ((InputState
& INPUT_STATE_LEFTOPENBRACKET
) != 0) {
1077 Key
.ScanCode
= SCAN_NULL
;
1078 Key
.UnicodeChar
= LEFTOPENBRACKET
;
1079 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1082 if ((InputState
& INPUT_STATE_O
) != 0) {
1083 Key
.ScanCode
= SCAN_NULL
;
1084 Key
.UnicodeChar
= 'O';
1085 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1088 if ((InputState
& INPUT_STATE_2
) != 0) {
1089 Key
.ScanCode
= SCAN_NULL
;
1090 Key
.UnicodeChar
= '2';
1091 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1095 // Cancel the timer.
1098 TerminalDevice
->TwoSecondTimeOut
,
1103 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1108 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1109 can be read through the Simple Input Protocol.
1111 The table below shows the keyboard input mappings that this function supports.
1112 If the ESC sequence listed in one of the columns is presented, then it is translated
1113 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
1114 key strokes are converted into EFI Keys.
1116 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
1117 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1118 converted into EFI Keys.
1119 There is one special input sequence that will force the system to reset.
1120 This is ESC R ESC r ESC R.
1122 Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1123 The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1124 DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1126 Symbols used in table below
1127 ===========================
1133 +=========+======+===========+==========+==========+
1134 | | EFI | UEFI 2.0 | | |
1135 | | Scan | | VT100+ | |
1136 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
1137 +=========+======+===========+==========+==========+
1138 | NULL | 0x00 | | | |
1139 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
1140 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
1141 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
1142 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
1143 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
1144 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
1145 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
1146 | | | ESC [ L | | ESC [ L |
1147 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
1148 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
1150 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
1152 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
1153 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
1154 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
1155 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
1156 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
1157 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
1158 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
1159 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
1160 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
1161 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
1162 | Escape | 0x17 | ESC | ESC | ESC |
1163 | F11 | 0x15 | | ESC ! | |
1164 | F12 | 0x16 | | ESC @ | |
1165 +=========+======+===========+==========+==========+
1169 ESC R ESC r ESC R = Reset System
1171 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1176 IN TERMINAL_DEV
*TerminalDevice
1180 EFI_STATUS TimerStatus
;
1183 BOOLEAN SetDefaultResetState
;
1185 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1187 if (!EFI_ERROR (TimerStatus
)) {
1188 UnicodeToEfiKeyFlushState (TerminalDevice
);
1189 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1192 while (!IsUnicodeFiFoEmpty (TerminalDevice
) && !IsEfiKeyFiFoFull (TerminalDevice
)) {
1194 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1196 // Check to see if the 2 seconds timer has expired
1198 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1199 if (!EFI_ERROR (TimerStatus
)) {
1200 UnicodeToEfiKeyFlushState (TerminalDevice
);
1201 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1206 // Fetch one Unicode character from the Unicode FIFO
1208 UnicodeFiFoRemoveOneKey (TerminalDevice
, &UnicodeChar
);
1210 SetDefaultResetState
= TRUE
;
1212 switch (TerminalDevice
->InputState
) {
1213 case INPUT_STATE_DEFAULT
:
1217 case INPUT_STATE_ESC
:
1219 if (UnicodeChar
== LEFTOPENBRACKET
) {
1220 TerminalDevice
->InputState
|= INPUT_STATE_LEFTOPENBRACKET
;
1221 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1225 if (UnicodeChar
== 'O' && TerminalDevice
->TerminalType
== VT100TYPE
) {
1226 TerminalDevice
->InputState
|= INPUT_STATE_O
;
1227 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1231 Key
.ScanCode
= SCAN_NULL
;
1233 if (TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1234 TerminalDevice
->TerminalType
== VTUTF8TYPE
) {
1235 switch (UnicodeChar
) {
1237 Key
.ScanCode
= SCAN_F1
;
1240 Key
.ScanCode
= SCAN_F2
;
1243 Key
.ScanCode
= SCAN_F3
;
1246 Key
.ScanCode
= SCAN_F4
;
1249 Key
.ScanCode
= SCAN_F5
;
1252 Key
.ScanCode
= SCAN_F6
;
1255 Key
.ScanCode
= SCAN_F7
;
1258 Key
.ScanCode
= SCAN_F8
;
1261 Key
.ScanCode
= SCAN_F9
;
1264 Key
.ScanCode
= SCAN_F10
;
1267 Key
.ScanCode
= SCAN_F11
;
1270 Key
.ScanCode
= SCAN_F12
;
1273 Key
.ScanCode
= SCAN_HOME
;
1276 Key
.ScanCode
= SCAN_END
;
1279 Key
.ScanCode
= SCAN_INSERT
;
1282 Key
.ScanCode
= SCAN_DELETE
;
1285 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1288 Key
.ScanCode
= SCAN_PAGE_UP
;
1295 switch (UnicodeChar
) {
1297 if (TerminalDevice
->ResetState
== RESET_STATE_DEFAULT
) {
1298 TerminalDevice
->ResetState
= RESET_STATE_ESC_R
;
1299 SetDefaultResetState
= FALSE
;
1300 } else if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R_ESC_R
) {
1301 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1303 Key
.ScanCode
= SCAN_NULL
;
1306 if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R
) {
1307 TerminalDevice
->ResetState
= RESET_STATE_ESC_R_ESC_R
;
1308 SetDefaultResetState
= FALSE
;
1310 Key
.ScanCode
= SCAN_NULL
;
1316 if (SetDefaultResetState
) {
1317 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1320 if (Key
.ScanCode
!= SCAN_NULL
) {
1321 Key
.UnicodeChar
= 0;
1322 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1323 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1324 UnicodeToEfiKeyFlushState (TerminalDevice
);
1328 UnicodeToEfiKeyFlushState (TerminalDevice
);
1332 case INPUT_STATE_ESC
| INPUT_STATE_O
:
1334 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1336 Key
.ScanCode
= SCAN_NULL
;
1338 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1339 switch (UnicodeChar
) {
1341 Key
.ScanCode
= SCAN_F1
;
1344 Key
.ScanCode
= SCAN_F2
;
1347 Key
.ScanCode
= SCAN_F3
;
1350 Key
.ScanCode
= SCAN_F4
;
1353 Key
.ScanCode
= SCAN_F5
;
1356 Key
.ScanCode
= SCAN_F6
;
1359 Key
.ScanCode
= SCAN_F7
;
1362 Key
.ScanCode
= SCAN_F8
;
1365 Key
.ScanCode
= SCAN_F9
;
1368 Key
.ScanCode
= SCAN_F10
;
1375 if (Key
.ScanCode
!= SCAN_NULL
) {
1376 Key
.UnicodeChar
= 0;
1377 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1378 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1379 UnicodeToEfiKeyFlushState (TerminalDevice
);
1383 UnicodeToEfiKeyFlushState (TerminalDevice
);
1387 case INPUT_STATE_ESC
| INPUT_STATE_LEFTOPENBRACKET
:
1389 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1391 Key
.ScanCode
= SCAN_NULL
;
1393 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1394 TerminalDevice
->TerminalType
== VT100TYPE
||
1395 TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1396 TerminalDevice
->TerminalType
== VTUTF8TYPE
) {
1397 switch (UnicodeChar
) {
1399 Key
.ScanCode
= SCAN_UP
;
1402 Key
.ScanCode
= SCAN_DOWN
;
1405 Key
.ScanCode
= SCAN_RIGHT
;
1408 Key
.ScanCode
= SCAN_LEFT
;
1411 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1412 TerminalDevice
->TerminalType
== VT100TYPE
) {
1413 Key
.ScanCode
= SCAN_HOME
;
1417 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1418 Key
.ScanCode
= SCAN_END
;
1422 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1423 Key
.ScanCode
= SCAN_END
;
1428 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1429 TerminalDevice
->TerminalType
== VT100TYPE
) {
1430 Key
.ScanCode
= SCAN_INSERT
;
1434 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1435 Key
.ScanCode
= SCAN_DELETE
;
1439 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1440 Key
.ScanCode
= SCAN_DELETE
;
1441 } else if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1442 Key
.ScanCode
= SCAN_F4
;
1446 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1447 Key
.ScanCode
= SCAN_PAGE_UP
;
1451 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1452 Key
.ScanCode
= SCAN_F10
;
1456 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1457 Key
.ScanCode
= SCAN_PAGE_UP
;
1461 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1462 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1466 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1467 Key
.ScanCode
= SCAN_F9
;
1471 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1472 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1476 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1477 Key
.ScanCode
= SCAN_F1
;
1481 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1482 Key
.ScanCode
= SCAN_F2
;
1486 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1487 Key
.ScanCode
= SCAN_F3
;
1491 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1492 Key
.ScanCode
= SCAN_F5
;
1496 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1497 Key
.ScanCode
= SCAN_F6
;
1501 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1502 Key
.ScanCode
= SCAN_F7
;
1506 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1507 Key
.ScanCode
= SCAN_F8
;
1515 if (Key
.ScanCode
!= SCAN_NULL
) {
1516 Key
.UnicodeChar
= 0;
1517 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1518 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1519 UnicodeToEfiKeyFlushState (TerminalDevice
);
1523 UnicodeToEfiKeyFlushState (TerminalDevice
);
1530 // Invalid state. This should never happen.
1534 UnicodeToEfiKeyFlushState (TerminalDevice
);
1539 if (UnicodeChar
== ESC
) {
1540 TerminalDevice
->InputState
= INPUT_STATE_ESC
;
1543 if (UnicodeChar
== CSI
) {
1544 TerminalDevice
->InputState
= INPUT_STATE_CSI
;
1547 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1548 Status
= gBS
->SetTimer(
1549 TerminalDevice
->TwoSecondTimeOut
,
1553 ASSERT_EFI_ERROR (Status
);
1557 if (SetDefaultResetState
) {
1558 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1561 if (UnicodeChar
== DEL
) {
1562 Key
.ScanCode
= SCAN_DELETE
;
1563 Key
.UnicodeChar
= 0;
1565 Key
.ScanCode
= SCAN_NULL
;
1566 Key
.UnicodeChar
= UnicodeChar
;
1569 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);