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
) {
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 Mode
->ReceiveFifoDepth
,
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.
566 Status
= SerialIo
->GetControl (SerialIo
, &Control
);
568 if ((Control
& EFI_SERIAL_INPUT_BUFFER_EMPTY
) == 0) {
570 // Fetch all the keys in the serial buffer,
571 // and insert the byte stream into RawFIFO.
573 while (!IsRawFiFoFull (TerminalDevice
)) {
575 Status
= GetOneKeyFromSerial (TerminalDevice
->SerialIo
, &Input
);
577 if (EFI_ERROR (Status
)) {
578 if (Status
== EFI_DEVICE_ERROR
) {
579 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
580 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
581 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_INPUT_ERROR
),
582 TerminalDevice
->DevicePath
588 RawFiFoInsertOneKey (TerminalDevice
, Input
);
593 // Translate all the raw data in RawFIFO into EFI Key,
594 // according to different terminal type supported.
596 TranslateRawDataToEfiKey (TerminalDevice
);
600 Get one key out of serial buffer.
602 @param SerialIo Serial I/O protocol attached to the serial device.
603 @param Output The fetched key.
605 @retval EFI_NOT_READY If serial buffer is empty.
606 @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
607 @retval EFI_SUCCESS If reading serial buffer successfully, put
608 the fetched key to the parameter output.
612 GetOneKeyFromSerial (
613 EFI_SERIAL_IO_PROTOCOL
*SerialIo
,
624 // Read one key from serial I/O device.
626 Status
= SerialIo
->Read (SerialIo
, &Size
, Output
);
628 if (EFI_ERROR (Status
)) {
630 if (Status
== EFI_TIMEOUT
) {
631 return EFI_NOT_READY
;
634 return EFI_DEVICE_ERROR
;
639 return EFI_NOT_READY
;
646 Insert one byte raw data into the Raw Data FIFO.
648 @param TerminalDevice Terminal driver private structure.
649 @param Input The key will be input.
651 @retval TRUE If insert successfully.
652 @retval FALSE If Raw Data buffer is full before key insertion,
657 RawFiFoInsertOneKey (
658 TERMINAL_DEV
*TerminalDevice
,
664 Tail
= TerminalDevice
->RawFiFo
->Tail
;
666 if (IsRawFiFoFull (TerminalDevice
)) {
673 TerminalDevice
->RawFiFo
->Data
[Tail
] = Input
;
675 TerminalDevice
->RawFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
681 Remove one pre-fetched key out of the Raw Data FIFO.
683 @param TerminalDevice Terminal driver private structure.
684 @param Output The key will be removed.
686 @retval TRUE If insert successfully.
687 @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
691 RawFiFoRemoveOneKey (
692 TERMINAL_DEV
*TerminalDevice
,
698 Head
= TerminalDevice
->RawFiFo
->Head
;
700 if (IsRawFiFoEmpty (TerminalDevice
)) {
708 *Output
= TerminalDevice
->RawFiFo
->Data
[Head
];
710 TerminalDevice
->RawFiFo
->Head
= (UINT8
) ((Head
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
716 Clarify whether Raw Data FIFO buffer is empty.
718 @param TerminalDevice Terminal driver private structure
720 @retval TRUE If Raw Data FIFO buffer is empty.
721 @retval FALSE If Raw Data FIFO buffer is not empty.
726 TERMINAL_DEV
*TerminalDevice
729 if (TerminalDevice
->RawFiFo
->Head
== TerminalDevice
->RawFiFo
->Tail
) {
737 Clarify whether Raw Data FIFO buffer is full.
739 @param TerminalDevice Terminal driver private structure
741 @retval TRUE If Raw Data FIFO buffer is full.
742 @retval FALSE If Raw Data FIFO buffer is not full.
747 TERMINAL_DEV
*TerminalDevice
753 Tail
= TerminalDevice
->RawFiFo
->Tail
;
754 Head
= TerminalDevice
->RawFiFo
->Head
;
756 if (((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1)) == Head
) {
765 Insert one pre-fetched key into the FIFO buffer.
767 @param TerminalDevice Terminal driver private structure.
768 @param Key The key will be input.
770 @retval TRUE If insert successfully.
771 @retval FALSE If FIFO buffer is full before key insertion,
776 EfiKeyFiFoInsertOneKey (
777 TERMINAL_DEV
*TerminalDevice
,
783 LIST_ENTRY
*NotifyList
;
784 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
785 EFI_KEY_DATA KeyData
;
787 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
789 CopyMem (&KeyData
.Key
, Key
, sizeof (EFI_INPUT_KEY
));
790 KeyData
.KeyState
.KeyShiftState
= 0;
791 KeyData
.KeyState
.KeyToggleState
= 0;
794 // Invoke notification functions if exist
796 NotifyList
= &TerminalDevice
->NotifyList
;
797 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
800 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
802 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
804 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
805 CurrentNotify
->KeyNotificationFn (&KeyData
);
808 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
810 // Efi Key FIFO is full
815 CopyMem (&TerminalDevice
->EfiKeyFiFo
->Data
[Tail
], Key
, sizeof (EFI_INPUT_KEY
));
817 TerminalDevice
->EfiKeyFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
823 Remove one pre-fetched key out of the FIFO buffer.
825 @param TerminalDevice Terminal driver private structure.
826 @param Output The key will be removed.
828 @retval TRUE If insert successfully.
829 @retval FALSE If FIFO buffer is empty before remove operation.
833 EfiKeyFiFoRemoveOneKey (
834 TERMINAL_DEV
*TerminalDevice
,
835 EFI_INPUT_KEY
*Output
840 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
841 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
843 if (IsEfiKeyFiFoEmpty (TerminalDevice
)) {
847 Output
->ScanCode
= SCAN_NULL
;
848 Output
->UnicodeChar
= 0;
852 CopyMem (Output
, &TerminalDevice
->EfiKeyFiFo
->Data
[Head
], sizeof (EFI_INPUT_KEY
));
854 TerminalDevice
->EfiKeyFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
860 Clarify whether FIFO buffer is empty.
862 @param TerminalDevice Terminal driver private structure
864 @retval TRUE If FIFO buffer is empty.
865 @retval FALSE If FIFO buffer is not empty.
870 TERMINAL_DEV
*TerminalDevice
873 if (TerminalDevice
->EfiKeyFiFo
->Head
== TerminalDevice
->EfiKeyFiFo
->Tail
) {
881 Clarify whether FIFO buffer is full.
883 @param TerminalDevice Terminal driver private structure
885 @retval TRUE If FIFO buffer is full.
886 @retval FALSE If FIFO buffer is not full.
891 TERMINAL_DEV
*TerminalDevice
897 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
898 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
900 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
909 Insert one pre-fetched key into the Unicode FIFO buffer.
911 @param TerminalDevice Terminal driver private structure.
912 @param Input The key will be input.
914 @retval TRUE If insert successfully.
915 @retval FALSE If Unicode FIFO buffer is full before key insertion,
920 UnicodeFiFoInsertOneKey (
921 TERMINAL_DEV
*TerminalDevice
,
927 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
928 ASSERT (Tail
< FIFO_MAX_NUMBER
+ 1);
931 if (IsUnicodeFiFoFull (TerminalDevice
)) {
933 // Unicode FIFO is full
938 TerminalDevice
->UnicodeFiFo
->Data
[Tail
] = Input
;
940 TerminalDevice
->UnicodeFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
946 Remove one pre-fetched key out of the Unicode FIFO buffer.
947 The caller should guarantee that Unicode FIFO buffer is not empty
948 by IsUnicodeFiFoEmpty ().
950 @param TerminalDevice Terminal driver private structure.
951 @param Output The key will be removed.
955 UnicodeFiFoRemoveOneKey (
956 TERMINAL_DEV
*TerminalDevice
,
962 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
963 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
965 *Output
= TerminalDevice
->UnicodeFiFo
->Data
[Head
];
967 TerminalDevice
->UnicodeFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
971 Clarify whether Unicode FIFO buffer is empty.
973 @param TerminalDevice Terminal driver private structure
975 @retval TRUE If Unicode FIFO buffer is empty.
976 @retval FALSE If Unicode FIFO buffer is not empty.
981 TERMINAL_DEV
*TerminalDevice
984 if (TerminalDevice
->UnicodeFiFo
->Head
== TerminalDevice
->UnicodeFiFo
->Tail
) {
992 Clarify whether Unicode FIFO buffer is full.
994 @param TerminalDevice Terminal driver private structure
996 @retval TRUE If Unicode FIFO buffer is full.
997 @retval FALSE If Unicode FIFO buffer is not full.
1002 TERMINAL_DEV
*TerminalDevice
1008 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1009 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1011 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
1020 Count Unicode FIFO buffer.
1022 @param TerminalDevice Terminal driver private structure
1024 @return The count in bytes of Unicode FIFO.
1028 UnicodeFiFoGetKeyCount (
1029 TERMINAL_DEV
*TerminalDevice
1035 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1036 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1039 return (UINT8
) (Tail
- Head
);
1041 return (UINT8
) (Tail
+ FIFO_MAX_NUMBER
+ 1 - Head
);
1046 Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1048 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1052 UnicodeToEfiKeyFlushState (
1053 IN TERMINAL_DEV
*TerminalDevice
1059 InputState
= TerminalDevice
->InputState
;
1061 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
1065 if ((InputState
& INPUT_STATE_ESC
) != 0) {
1066 Key
.ScanCode
= SCAN_ESC
;
1067 Key
.UnicodeChar
= 0;
1068 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1071 if ((InputState
& INPUT_STATE_CSI
) != 0) {
1072 Key
.ScanCode
= SCAN_NULL
;
1073 Key
.UnicodeChar
= CSI
;
1074 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1077 if ((InputState
& INPUT_STATE_LEFTOPENBRACKET
) != 0) {
1078 Key
.ScanCode
= SCAN_NULL
;
1079 Key
.UnicodeChar
= LEFTOPENBRACKET
;
1080 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1083 if ((InputState
& INPUT_STATE_O
) != 0) {
1084 Key
.ScanCode
= SCAN_NULL
;
1085 Key
.UnicodeChar
= 'O';
1086 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1089 if ((InputState
& INPUT_STATE_2
) != 0) {
1090 Key
.ScanCode
= SCAN_NULL
;
1091 Key
.UnicodeChar
= '2';
1092 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1096 // Cancel the timer.
1099 TerminalDevice
->TwoSecondTimeOut
,
1104 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1109 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1110 can be read through the Simple Input Protocol.
1112 The table below shows the keyboard input mappings that this function supports.
1113 If the ESC sequence listed in one of the columns is presented, then it is translated
1114 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
1115 key strokes are converted into EFI Keys.
1117 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
1118 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1119 converted into EFI Keys.
1120 There is one special input sequence that will force the system to reset.
1121 This is ESC R ESC r ESC R.
1123 Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1124 The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1125 DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1127 Symbols used in table below
1128 ===========================
1134 +=========+======+===========+==========+==========+
1135 | | EFI | UEFI 2.0 | | |
1136 | | Scan | | VT100+ | |
1137 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
1138 +=========+======+===========+==========+==========+
1139 | NULL | 0x00 | | | |
1140 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
1141 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
1142 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
1143 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
1144 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
1145 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
1146 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
1147 | | | ESC [ L | | ESC [ L |
1148 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
1149 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
1151 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
1153 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
1154 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
1155 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
1156 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
1157 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
1158 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
1159 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
1160 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
1161 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
1162 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
1163 | Escape | 0x17 | ESC | ESC | ESC |
1164 | F11 | 0x15 | | ESC ! | |
1165 | F12 | 0x16 | | ESC @ | |
1166 +=========+======+===========+==========+==========+
1170 ESC R ESC r ESC R = Reset System
1172 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1177 IN TERMINAL_DEV
*TerminalDevice
1181 EFI_STATUS TimerStatus
;
1184 BOOLEAN SetDefaultResetState
;
1186 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1188 if (!EFI_ERROR (TimerStatus
)) {
1189 UnicodeToEfiKeyFlushState (TerminalDevice
);
1190 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1193 while (!IsUnicodeFiFoEmpty (TerminalDevice
) && !IsEfiKeyFiFoFull (TerminalDevice
)) {
1195 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1197 // Check to see if the 2 seconds timer has expired
1199 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1200 if (!EFI_ERROR (TimerStatus
)) {
1201 UnicodeToEfiKeyFlushState (TerminalDevice
);
1202 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1207 // Fetch one Unicode character from the Unicode FIFO
1209 UnicodeFiFoRemoveOneKey (TerminalDevice
, &UnicodeChar
);
1211 SetDefaultResetState
= TRUE
;
1213 switch (TerminalDevice
->InputState
) {
1214 case INPUT_STATE_DEFAULT
:
1218 case INPUT_STATE_ESC
:
1220 if (UnicodeChar
== LEFTOPENBRACKET
) {
1221 TerminalDevice
->InputState
|= INPUT_STATE_LEFTOPENBRACKET
;
1222 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1226 if (UnicodeChar
== 'O' && TerminalDevice
->TerminalType
== VT100TYPE
) {
1227 TerminalDevice
->InputState
|= INPUT_STATE_O
;
1228 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1232 Key
.ScanCode
= SCAN_NULL
;
1234 if (TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1235 TerminalDevice
->TerminalType
== VTUTF8TYPE
) {
1236 switch (UnicodeChar
) {
1238 Key
.ScanCode
= SCAN_F1
;
1241 Key
.ScanCode
= SCAN_F2
;
1244 Key
.ScanCode
= SCAN_F3
;
1247 Key
.ScanCode
= SCAN_F4
;
1250 Key
.ScanCode
= SCAN_F5
;
1253 Key
.ScanCode
= SCAN_F6
;
1256 Key
.ScanCode
= SCAN_F7
;
1259 Key
.ScanCode
= SCAN_F8
;
1262 Key
.ScanCode
= SCAN_F9
;
1265 Key
.ScanCode
= SCAN_F10
;
1268 Key
.ScanCode
= SCAN_F11
;
1271 Key
.ScanCode
= SCAN_F12
;
1274 Key
.ScanCode
= SCAN_HOME
;
1277 Key
.ScanCode
= SCAN_END
;
1280 Key
.ScanCode
= SCAN_INSERT
;
1283 Key
.ScanCode
= SCAN_DELETE
;
1286 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1289 Key
.ScanCode
= SCAN_PAGE_UP
;
1296 switch (UnicodeChar
) {
1298 if (TerminalDevice
->ResetState
== RESET_STATE_DEFAULT
) {
1299 TerminalDevice
->ResetState
= RESET_STATE_ESC_R
;
1300 SetDefaultResetState
= FALSE
;
1301 } else if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R_ESC_R
) {
1302 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1304 Key
.ScanCode
= SCAN_NULL
;
1307 if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R
) {
1308 TerminalDevice
->ResetState
= RESET_STATE_ESC_R_ESC_R
;
1309 SetDefaultResetState
= FALSE
;
1311 Key
.ScanCode
= SCAN_NULL
;
1317 if (SetDefaultResetState
) {
1318 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1321 if (Key
.ScanCode
!= SCAN_NULL
) {
1322 Key
.UnicodeChar
= 0;
1323 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1324 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1325 UnicodeToEfiKeyFlushState (TerminalDevice
);
1329 UnicodeToEfiKeyFlushState (TerminalDevice
);
1333 case INPUT_STATE_ESC
| INPUT_STATE_O
:
1335 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1337 Key
.ScanCode
= SCAN_NULL
;
1339 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1340 switch (UnicodeChar
) {
1342 Key
.ScanCode
= SCAN_F1
;
1345 Key
.ScanCode
= SCAN_F2
;
1348 Key
.ScanCode
= SCAN_F3
;
1351 Key
.ScanCode
= SCAN_F4
;
1354 Key
.ScanCode
= SCAN_F5
;
1357 Key
.ScanCode
= SCAN_F6
;
1360 Key
.ScanCode
= SCAN_F7
;
1363 Key
.ScanCode
= SCAN_F8
;
1366 Key
.ScanCode
= SCAN_F9
;
1369 Key
.ScanCode
= SCAN_F10
;
1376 if (Key
.ScanCode
!= SCAN_NULL
) {
1377 Key
.UnicodeChar
= 0;
1378 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1379 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1380 UnicodeToEfiKeyFlushState (TerminalDevice
);
1384 UnicodeToEfiKeyFlushState (TerminalDevice
);
1388 case INPUT_STATE_ESC
| INPUT_STATE_LEFTOPENBRACKET
:
1390 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1392 Key
.ScanCode
= SCAN_NULL
;
1394 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1395 TerminalDevice
->TerminalType
== VT100TYPE
||
1396 TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1397 TerminalDevice
->TerminalType
== VTUTF8TYPE
||
1398 TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1399 switch (UnicodeChar
) {
1401 Key
.ScanCode
= SCAN_UP
;
1404 Key
.ScanCode
= SCAN_DOWN
;
1407 Key
.ScanCode
= SCAN_RIGHT
;
1410 Key
.ScanCode
= SCAN_LEFT
;
1413 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1414 TerminalDevice
->TerminalType
== VT100TYPE
) {
1415 Key
.ScanCode
= SCAN_HOME
;
1419 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1420 Key
.ScanCode
= SCAN_END
;
1424 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1425 Key
.ScanCode
= SCAN_END
;
1430 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1431 TerminalDevice
->TerminalType
== VT100TYPE
) {
1432 Key
.ScanCode
= SCAN_INSERT
;
1436 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1437 Key
.ScanCode
= SCAN_DELETE
;
1441 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1442 Key
.ScanCode
= SCAN_DELETE
;
1443 } else if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1444 Key
.ScanCode
= SCAN_F4
;
1448 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1449 Key
.ScanCode
= SCAN_PAGE_UP
;
1453 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1454 Key
.ScanCode
= SCAN_F10
;
1458 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1459 Key
.ScanCode
= SCAN_PAGE_UP
;
1463 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1464 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1468 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1469 Key
.ScanCode
= SCAN_F9
;
1473 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1474 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1478 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1479 Key
.ScanCode
= SCAN_F1
;
1483 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1484 Key
.ScanCode
= SCAN_F2
;
1488 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1489 Key
.ScanCode
= SCAN_F3
;
1493 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1494 Key
.ScanCode
= SCAN_F5
;
1498 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1499 Key
.ScanCode
= SCAN_F6
;
1503 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1504 Key
.ScanCode
= SCAN_F7
;
1508 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1509 Key
.ScanCode
= SCAN_F8
;
1517 if (Key
.ScanCode
!= SCAN_NULL
) {
1518 Key
.UnicodeChar
= 0;
1519 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1520 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1521 UnicodeToEfiKeyFlushState (TerminalDevice
);
1525 UnicodeToEfiKeyFlushState (TerminalDevice
);
1532 // Invalid state. This should never happen.
1536 UnicodeToEfiKeyFlushState (TerminalDevice
);
1541 if (UnicodeChar
== ESC
) {
1542 TerminalDevice
->InputState
= INPUT_STATE_ESC
;
1545 if (UnicodeChar
== CSI
) {
1546 TerminalDevice
->InputState
= INPUT_STATE_CSI
;
1549 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1550 Status
= gBS
->SetTimer(
1551 TerminalDevice
->TwoSecondTimeOut
,
1555 ASSERT_EFI_ERROR (Status
);
1559 if (SetDefaultResetState
) {
1560 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1563 if (UnicodeChar
== DEL
) {
1564 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1565 Key
.ScanCode
= SCAN_NULL
;
1566 Key
.UnicodeChar
= CHAR_BACKSPACE
;
1569 Key
.ScanCode
= SCAN_DELETE
;
1570 Key
.UnicodeChar
= 0;
1573 Key
.ScanCode
= SCAN_NULL
;
1574 Key
.UnicodeChar
= UnicodeChar
;
1577 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);