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 Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Reads the next keystroke from the input device. The WaitForKey Event can
22 be used to test for existence of a keystroke via WaitForEvent () call.
24 @param TerminalDevice Terminal driver private structure
25 @param KeyData A pointer to a buffer that is filled in with the
26 keystroke state data for the key that was
29 @retval EFI_SUCCESS The keystroke information was returned.
30 @retval EFI_NOT_READY There was no keystroke data available.
31 @retval EFI_INVALID_PARAMETER KeyData is NULL.
36 IN TERMINAL_DEV
*TerminalDevice
,
37 OUT EFI_KEY_DATA
*KeyData
40 if (KeyData
== NULL
) {
41 return EFI_INVALID_PARAMETER
;
44 if (!EfiKeyFiFoRemoveOneKey (TerminalDevice
, &KeyData
->Key
)) {
48 KeyData
->KeyState
.KeyShiftState
= 0;
49 KeyData
->KeyState
.KeyToggleState
= 0;
57 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset().
58 This driver only perform dependent serial device reset regardless of
59 the value of ExtendeVerification
61 @param This Indicates the calling context.
62 @param ExtendedVerification Skip by this driver.
64 @retval EFI_SUCCESS The reset operation succeeds.
65 @retval EFI_DEVICE_ERROR The dependent serial port reset fails.
71 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
72 IN BOOLEAN ExtendedVerification
76 TERMINAL_DEV
*TerminalDevice
;
78 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (This
);
81 // Report progress code here
83 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
85 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_PC_RESET
),
86 TerminalDevice
->DevicePath
89 Status
= TerminalDevice
->SerialIo
->Reset (TerminalDevice
->SerialIo
);
92 // Make all the internal buffer empty for keys
94 TerminalDevice
->RawFiFo
->Head
= TerminalDevice
->RawFiFo
->Tail
;
95 TerminalDevice
->UnicodeFiFo
->Head
= TerminalDevice
->UnicodeFiFo
->Tail
;
96 TerminalDevice
->EfiKeyFiFo
->Head
= TerminalDevice
->EfiKeyFiFo
->Tail
;
98 if (EFI_ERROR (Status
)) {
99 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
100 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
101 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
),
102 TerminalDevice
->DevicePath
110 Implements EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke().
112 @param This Indicates the calling context.
113 @param Key A pointer to a buffer that is filled in with the
114 keystroke information for the key that was sent
117 @retval EFI_SUCCESS The keystroke information is returned successfully.
118 @retval EFI_NOT_READY There is no keystroke data available.
119 @retval EFI_DEVICE_ERROR The dependent serial device encounters error.
124 TerminalConInReadKeyStroke (
125 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*This
,
126 OUT EFI_INPUT_KEY
*Key
129 TERMINAL_DEV
*TerminalDevice
;
131 EFI_KEY_DATA KeyData
;
134 // get TERMINAL_DEV from "This" parameter.
136 TerminalDevice
= TERMINAL_CON_IN_DEV_FROM_THIS (This
);
138 Status
= ReadKeyStrokeWorker (TerminalDevice
, &KeyData
);
139 if (EFI_ERROR (Status
)) {
143 CopyMem (Key
, &KeyData
.Key
, sizeof (EFI_INPUT_KEY
));
150 Check if the key already has been registered.
152 If both RegsiteredData and InputData is NULL, then ASSERT().
154 @param RegsiteredData A pointer to a buffer that is filled in with the
155 keystroke state data for the key that was
157 @param InputData A pointer to a buffer that is filled in with the
158 keystroke state data for the key that was
161 @retval TRUE Key be pressed matches a registered key.
162 @retval FALSE Match failed.
167 IN EFI_KEY_DATA
*RegsiteredData
,
168 IN EFI_KEY_DATA
*InputData
171 ASSERT (RegsiteredData
!= NULL
&& InputData
!= NULL
);
173 if ((RegsiteredData
->Key
.ScanCode
!= InputData
->Key
.ScanCode
) ||
174 (RegsiteredData
->Key
.UnicodeChar
!= InputData
->Key
.UnicodeChar
)) {
184 Event notification function for EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
185 Signal the event if there is key available
187 @param Event Indicates the event that invoke this function.
188 @param Context Indicates the calling context.
193 TerminalConInWaitForKeyEx (
198 TerminalConInWaitForKey (Event
, Context
);
202 // Simple Text Input Ex protocol functions
206 Reset the input device and optionally run diagnostics
208 @param This Protocol instance pointer.
209 @param ExtendedVerification Driver may perform diagnostics on reset.
211 @retval EFI_SUCCESS The device was reset.
212 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
218 TerminalConInResetEx (
219 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
220 IN BOOLEAN ExtendedVerification
224 TERMINAL_DEV
*TerminalDevice
;
226 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
228 Status
= TerminalDevice
->SimpleInput
.Reset (&TerminalDevice
->SimpleInput
, ExtendedVerification
);
229 if (EFI_ERROR (Status
)) {
230 return EFI_DEVICE_ERROR
;
239 Reads the next keystroke from the input device. The WaitForKey Event can
240 be used to test for existence of a keystroke via WaitForEvent () call.
242 @param This Protocol instance pointer.
243 @param KeyData A pointer to a buffer that is filled in with the
244 keystroke state data for the key that was
247 @retval EFI_SUCCESS The keystroke information was returned.
248 @retval EFI_NOT_READY There was no keystroke data available.
249 @retval EFI_DEVICE_ERROR The keystroke information was not returned due
251 @retval EFI_INVALID_PARAMETER KeyData is NULL.
256 TerminalConInReadKeyStrokeEx (
257 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
258 OUT EFI_KEY_DATA
*KeyData
261 TERMINAL_DEV
*TerminalDevice
;
263 if (KeyData
== NULL
) {
264 return EFI_INVALID_PARAMETER
;
267 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
269 return ReadKeyStrokeWorker (TerminalDevice
, KeyData
);
275 Set certain state for the input device.
277 @param This Protocol instance pointer.
278 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
279 state for the input device.
281 @retval EFI_SUCCESS The device state was set successfully.
282 @retval EFI_DEVICE_ERROR The device is not functioning correctly and
283 could not have the setting adjusted.
284 @retval EFI_UNSUPPORTED The device does not have the ability to set its
286 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
291 TerminalConInSetState (
292 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
293 IN EFI_KEY_TOGGLE_STATE
*KeyToggleState
296 if (KeyToggleState
== NULL
) {
297 return EFI_INVALID_PARAMETER
;
300 if ((*KeyToggleState
& EFI_TOGGLE_STATE_VALID
) != EFI_TOGGLE_STATE_VALID
) {
301 return EFI_UNSUPPORTED
;
309 Register a notification function for a particular keystroke for the input device.
311 @param This Protocol instance pointer.
312 @param KeyData A pointer to a buffer that is filled in with the
313 keystroke information data for the key that was
315 @param KeyNotificationFunction Points to the function to be called when the key
316 sequence is typed specified by KeyData.
317 @param NotifyHandle Points to the unique handle assigned to the
318 registered notification.
320 @retval EFI_SUCCESS The notification function was registered
322 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data
324 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
329 TerminalConInRegisterKeyNotify (
330 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
331 IN EFI_KEY_DATA
*KeyData
,
332 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction
,
333 OUT VOID
**NotifyHandle
336 TERMINAL_DEV
*TerminalDevice
;
337 TERMINAL_CONSOLE_IN_EX_NOTIFY
*NewNotify
;
339 LIST_ENTRY
*NotifyList
;
340 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
342 if (KeyData
== NULL
|| NotifyHandle
== NULL
|| KeyNotificationFunction
== NULL
) {
343 return EFI_INVALID_PARAMETER
;
346 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
349 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
351 NotifyList
= &TerminalDevice
->NotifyList
;
352 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
355 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
357 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
359 if (IsKeyRegistered (&CurrentNotify
->KeyData
, KeyData
)) {
360 if (CurrentNotify
->KeyNotificationFn
== KeyNotificationFunction
) {
361 *NotifyHandle
= CurrentNotify
;
368 // Allocate resource to save the notification function
370 NewNotify
= (TERMINAL_CONSOLE_IN_EX_NOTIFY
*) AllocateZeroPool (sizeof (TERMINAL_CONSOLE_IN_EX_NOTIFY
));
371 if (NewNotify
== NULL
) {
372 return EFI_OUT_OF_RESOURCES
;
375 NewNotify
->Signature
= TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
;
376 NewNotify
->KeyNotificationFn
= KeyNotificationFunction
;
377 CopyMem (&NewNotify
->KeyData
, KeyData
, sizeof (EFI_KEY_DATA
));
378 InsertTailList (&TerminalDevice
->NotifyList
, &NewNotify
->NotifyEntry
);
380 *NotifyHandle
= NewNotify
;
387 Remove a registered notification function from a particular keystroke.
389 @param This Protocol instance pointer.
390 @param NotificationHandle The handle of the notification function being
393 @retval EFI_SUCCESS The notification function was unregistered
395 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
400 TerminalConInUnregisterKeyNotify (
401 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*This
,
402 IN VOID
*NotificationHandle
405 TERMINAL_DEV
*TerminalDevice
;
407 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
408 LIST_ENTRY
*NotifyList
;
410 if (NotificationHandle
== NULL
) {
411 return EFI_INVALID_PARAMETER
;
414 TerminalDevice
= TERMINAL_CON_IN_EX_DEV_FROM_THIS (This
);
416 NotifyList
= &TerminalDevice
->NotifyList
;
417 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
420 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
422 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
424 if (CurrentNotify
== NotificationHandle
) {
426 // Remove the notification function from NotifyList and free resources
428 RemoveEntryList (&CurrentNotify
->NotifyEntry
);
430 gBS
->FreePool (CurrentNotify
);
436 // Can not find the matching entry in database.
438 return EFI_INVALID_PARAMETER
;
442 Translate raw data into Unicode (according to different encode), and
443 translate Unicode into key information. (according to different standard).
445 @param TerminalDevice Terminal driver private structure.
449 TranslateRawDataToEfiKey (
450 IN TERMINAL_DEV
*TerminalDevice
453 switch (TerminalDevice
->TerminalType
) {
459 AnsiRawDataToUnicode (TerminalDevice
);
460 UnicodeToEfiKey (TerminalDevice
);
465 // Process all the raw data in the RawFIFO,
466 // put the processed key into UnicodeFIFO.
468 VTUTF8RawDataToUnicode (TerminalDevice
);
471 // Translate all the Unicode data in the UnicodeFIFO to Efi key,
472 // then put into EfiKeyFIFO.
474 UnicodeToEfiKey (TerminalDevice
);
481 Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event
482 Signal the event if there is key available
484 @param Event Indicates the event that invoke this function.
485 @param Context Indicates the calling context.
490 TerminalConInWaitForKey (
496 // Someone is waiting on the keystroke event, if there's
497 // a key pending, signal the event
499 if (!IsEfiKeyFiFoEmpty ((TERMINAL_DEV
*) Context
)) {
501 gBS
->SignalEvent (Event
);
506 Timer handler to poll the key from serial.
508 @param Event Indicates the event that invoke this function.
509 @param Context Indicates the calling context.
513 TerminalConInTimerHandler (
519 TERMINAL_DEV
*TerminalDevice
;
522 EFI_SERIAL_IO_MODE
*Mode
;
523 EFI_SERIAL_IO_PROTOCOL
*SerialIo
;
524 UINTN SerialInTimeOut
;
526 TerminalDevice
= (TERMINAL_DEV
*) Context
;
528 SerialIo
= TerminalDevice
->SerialIo
;
529 if (SerialIo
== NULL
) {
533 // if current timeout value for serial device is not identical with
534 // the value saved in TERMINAL_DEV structure, then recalculate the
535 // timeout value again and set serial attribute according to this value.
537 Mode
= SerialIo
->Mode
;
538 if (Mode
->Timeout
!= TerminalDevice
->SerialInTimeOut
) {
541 if (Mode
->BaudRate
!= 0) {
543 // According to BAUD rate to calculate the timeout value.
545 SerialInTimeOut
= (1 + Mode
->DataBits
+ Mode
->StopBits
) * 2 * 1000000 / (UINTN
) Mode
->BaudRate
;
548 Status
= SerialIo
->SetAttributes (
551 Mode
->ReceiveFifoDepth
,
552 (UINT32
) SerialInTimeOut
,
553 (EFI_PARITY_TYPE
) (Mode
->Parity
),
554 (UINT8
) Mode
->DataBits
,
555 (EFI_STOP_BITS_TYPE
) (Mode
->StopBits
)
558 if (EFI_ERROR (Status
)) {
559 TerminalDevice
->SerialInTimeOut
= 0;
561 TerminalDevice
->SerialInTimeOut
= SerialInTimeOut
;
565 // Check whether serial buffer is empty.
566 // Skip the key transfer loop only if the SerialIo protocol instance
567 // successfully reports EFI_SERIAL_INPUT_BUFFER_EMPTY.
569 Status
= SerialIo
->GetControl (SerialIo
, &Control
);
570 if (EFI_ERROR (Status
) || ((Control
& EFI_SERIAL_INPUT_BUFFER_EMPTY
) == 0)) {
572 // Fetch all the keys in the serial buffer,
573 // and insert the byte stream into RawFIFO.
575 while (!IsRawFiFoFull (TerminalDevice
)) {
577 Status
= GetOneKeyFromSerial (TerminalDevice
->SerialIo
, &Input
);
579 if (EFI_ERROR (Status
)) {
580 if (Status
== EFI_DEVICE_ERROR
) {
581 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
582 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
583 (EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_INPUT_ERROR
),
584 TerminalDevice
->DevicePath
590 RawFiFoInsertOneKey (TerminalDevice
, Input
);
595 // Translate all the raw data in RawFIFO into EFI Key,
596 // according to different terminal type supported.
598 TranslateRawDataToEfiKey (TerminalDevice
);
602 Get one key out of serial buffer.
604 @param SerialIo Serial I/O protocol attached to the serial device.
605 @param Output The fetched key.
607 @retval EFI_NOT_READY If serial buffer is empty.
608 @retval EFI_DEVICE_ERROR If reading serial buffer encounter error.
609 @retval EFI_SUCCESS If reading serial buffer successfully, put
610 the fetched key to the parameter output.
614 GetOneKeyFromSerial (
615 EFI_SERIAL_IO_PROTOCOL
*SerialIo
,
626 // Read one key from serial I/O device.
628 Status
= SerialIo
->Read (SerialIo
, &Size
, Output
);
630 if (EFI_ERROR (Status
)) {
632 if (Status
== EFI_TIMEOUT
) {
633 return EFI_NOT_READY
;
636 return EFI_DEVICE_ERROR
;
641 return EFI_NOT_READY
;
648 Insert one byte raw data into the Raw Data FIFO.
650 @param TerminalDevice Terminal driver private structure.
651 @param Input The key will be input.
653 @retval TRUE If insert successfully.
654 @retval FALSE If Raw Data buffer is full before key insertion,
659 RawFiFoInsertOneKey (
660 TERMINAL_DEV
*TerminalDevice
,
666 Tail
= TerminalDevice
->RawFiFo
->Tail
;
668 if (IsRawFiFoFull (TerminalDevice
)) {
675 TerminalDevice
->RawFiFo
->Data
[Tail
] = Input
;
677 TerminalDevice
->RawFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
683 Remove one pre-fetched key out of the Raw Data FIFO.
685 @param TerminalDevice Terminal driver private structure.
686 @param Output The key will be removed.
688 @retval TRUE If insert successfully.
689 @retval FALSE If Raw Data FIFO buffer is empty before remove operation.
693 RawFiFoRemoveOneKey (
694 TERMINAL_DEV
*TerminalDevice
,
700 Head
= TerminalDevice
->RawFiFo
->Head
;
702 if (IsRawFiFoEmpty (TerminalDevice
)) {
710 *Output
= TerminalDevice
->RawFiFo
->Data
[Head
];
712 TerminalDevice
->RawFiFo
->Head
= (UINT8
) ((Head
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1));
718 Clarify whether Raw Data FIFO buffer is empty.
720 @param TerminalDevice Terminal driver private structure
722 @retval TRUE If Raw Data FIFO buffer is empty.
723 @retval FALSE If Raw Data FIFO buffer is not empty.
728 TERMINAL_DEV
*TerminalDevice
731 if (TerminalDevice
->RawFiFo
->Head
== TerminalDevice
->RawFiFo
->Tail
) {
739 Clarify whether Raw Data FIFO buffer is full.
741 @param TerminalDevice Terminal driver private structure
743 @retval TRUE If Raw Data FIFO buffer is full.
744 @retval FALSE If Raw Data FIFO buffer is not full.
749 TERMINAL_DEV
*TerminalDevice
755 Tail
= TerminalDevice
->RawFiFo
->Tail
;
756 Head
= TerminalDevice
->RawFiFo
->Head
;
758 if (((Tail
+ 1) % (RAW_FIFO_MAX_NUMBER
+ 1)) == Head
) {
767 Insert one pre-fetched key into the FIFO buffer.
769 @param TerminalDevice Terminal driver private structure.
770 @param Key The key will be input.
772 @retval TRUE If insert successfully.
773 @retval FALSE If FIFO buffer is full before key insertion,
778 EfiKeyFiFoInsertOneKey (
779 TERMINAL_DEV
*TerminalDevice
,
785 LIST_ENTRY
*NotifyList
;
786 TERMINAL_CONSOLE_IN_EX_NOTIFY
*CurrentNotify
;
787 EFI_KEY_DATA KeyData
;
789 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
791 CopyMem (&KeyData
.Key
, Key
, sizeof (EFI_INPUT_KEY
));
792 KeyData
.KeyState
.KeyShiftState
= 0;
793 KeyData
.KeyState
.KeyToggleState
= 0;
796 // Invoke notification functions if exist
798 NotifyList
= &TerminalDevice
->NotifyList
;
799 for (Link
= GetFirstNode (NotifyList
); !IsNull (NotifyList
,Link
); Link
= GetNextNode (NotifyList
,Link
)) {
802 TERMINAL_CONSOLE_IN_EX_NOTIFY
,
804 TERMINAL_CONSOLE_IN_EX_NOTIFY_SIGNATURE
806 if (IsKeyRegistered (&CurrentNotify
->KeyData
, &KeyData
)) {
807 CurrentNotify
->KeyNotificationFn (&KeyData
);
810 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
812 // Efi Key FIFO is full
817 CopyMem (&TerminalDevice
->EfiKeyFiFo
->Data
[Tail
], Key
, sizeof (EFI_INPUT_KEY
));
819 TerminalDevice
->EfiKeyFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
825 Remove one pre-fetched key out of the FIFO buffer.
827 @param TerminalDevice Terminal driver private structure.
828 @param Output The key will be removed.
830 @retval TRUE If insert successfully.
831 @retval FALSE If FIFO buffer is empty before remove operation.
835 EfiKeyFiFoRemoveOneKey (
836 TERMINAL_DEV
*TerminalDevice
,
837 EFI_INPUT_KEY
*Output
842 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
843 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
845 if (IsEfiKeyFiFoEmpty (TerminalDevice
)) {
849 Output
->ScanCode
= SCAN_NULL
;
850 Output
->UnicodeChar
= 0;
854 CopyMem (Output
, &TerminalDevice
->EfiKeyFiFo
->Data
[Head
], sizeof (EFI_INPUT_KEY
));
856 TerminalDevice
->EfiKeyFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
862 Clarify whether FIFO buffer is empty.
864 @param TerminalDevice Terminal driver private structure
866 @retval TRUE If FIFO buffer is empty.
867 @retval FALSE If FIFO buffer is not empty.
872 TERMINAL_DEV
*TerminalDevice
875 if (TerminalDevice
->EfiKeyFiFo
->Head
== TerminalDevice
->EfiKeyFiFo
->Tail
) {
883 Clarify whether FIFO buffer is full.
885 @param TerminalDevice Terminal driver private structure
887 @retval TRUE If FIFO buffer is full.
888 @retval FALSE If FIFO buffer is not full.
893 TERMINAL_DEV
*TerminalDevice
899 Tail
= TerminalDevice
->EfiKeyFiFo
->Tail
;
900 Head
= TerminalDevice
->EfiKeyFiFo
->Head
;
902 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
911 Insert one pre-fetched key into the Unicode FIFO buffer.
913 @param TerminalDevice Terminal driver private structure.
914 @param Input The key will be input.
916 @retval TRUE If insert successfully.
917 @retval FALSE If Unicode FIFO buffer is full before key insertion,
922 UnicodeFiFoInsertOneKey (
923 TERMINAL_DEV
*TerminalDevice
,
929 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
930 ASSERT (Tail
< FIFO_MAX_NUMBER
+ 1);
933 if (IsUnicodeFiFoFull (TerminalDevice
)) {
935 // Unicode FIFO is full
940 TerminalDevice
->UnicodeFiFo
->Data
[Tail
] = Input
;
942 TerminalDevice
->UnicodeFiFo
->Tail
= (UINT8
) ((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1));
948 Remove one pre-fetched key out of the Unicode FIFO buffer.
949 The caller should guarantee that Unicode FIFO buffer is not empty
950 by IsUnicodeFiFoEmpty ().
952 @param TerminalDevice Terminal driver private structure.
953 @param Output The key will be removed.
957 UnicodeFiFoRemoveOneKey (
958 TERMINAL_DEV
*TerminalDevice
,
964 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
965 ASSERT (Head
< FIFO_MAX_NUMBER
+ 1);
967 *Output
= TerminalDevice
->UnicodeFiFo
->Data
[Head
];
969 TerminalDevice
->UnicodeFiFo
->Head
= (UINT8
) ((Head
+ 1) % (FIFO_MAX_NUMBER
+ 1));
973 Clarify whether Unicode FIFO buffer is empty.
975 @param TerminalDevice Terminal driver private structure
977 @retval TRUE If Unicode FIFO buffer is empty.
978 @retval FALSE If Unicode FIFO buffer is not empty.
983 TERMINAL_DEV
*TerminalDevice
986 if (TerminalDevice
->UnicodeFiFo
->Head
== TerminalDevice
->UnicodeFiFo
->Tail
) {
994 Clarify whether Unicode FIFO buffer is full.
996 @param TerminalDevice Terminal driver private structure
998 @retval TRUE If Unicode FIFO buffer is full.
999 @retval FALSE If Unicode FIFO buffer is not full.
1004 TERMINAL_DEV
*TerminalDevice
1010 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1011 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1013 if (((Tail
+ 1) % (FIFO_MAX_NUMBER
+ 1)) == Head
) {
1022 Count Unicode FIFO buffer.
1024 @param TerminalDevice Terminal driver private structure
1026 @return The count in bytes of Unicode FIFO.
1030 UnicodeFiFoGetKeyCount (
1031 TERMINAL_DEV
*TerminalDevice
1037 Tail
= TerminalDevice
->UnicodeFiFo
->Tail
;
1038 Head
= TerminalDevice
->UnicodeFiFo
->Head
;
1041 return (UINT8
) (Tail
- Head
);
1043 return (UINT8
) (Tail
+ FIFO_MAX_NUMBER
+ 1 - Head
);
1048 Update the Unicode characters from a terminal input device into EFI Keys FIFO.
1050 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1054 UnicodeToEfiKeyFlushState (
1055 IN TERMINAL_DEV
*TerminalDevice
1061 InputState
= TerminalDevice
->InputState
;
1063 if (IsEfiKeyFiFoFull (TerminalDevice
)) {
1067 if ((InputState
& INPUT_STATE_ESC
) != 0) {
1068 Key
.ScanCode
= SCAN_ESC
;
1069 Key
.UnicodeChar
= 0;
1070 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1073 if ((InputState
& INPUT_STATE_CSI
) != 0) {
1074 Key
.ScanCode
= SCAN_NULL
;
1075 Key
.UnicodeChar
= CSI
;
1076 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1079 if ((InputState
& INPUT_STATE_LEFTOPENBRACKET
) != 0) {
1080 Key
.ScanCode
= SCAN_NULL
;
1081 Key
.UnicodeChar
= LEFTOPENBRACKET
;
1082 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1085 if ((InputState
& INPUT_STATE_O
) != 0) {
1086 Key
.ScanCode
= SCAN_NULL
;
1087 Key
.UnicodeChar
= 'O';
1088 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1091 if ((InputState
& INPUT_STATE_2
) != 0) {
1092 Key
.ScanCode
= SCAN_NULL
;
1093 Key
.UnicodeChar
= '2';
1094 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1098 // Cancel the timer.
1101 TerminalDevice
->TwoSecondTimeOut
,
1106 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1111 Converts a stream of Unicode characters from a terminal input device into EFI Keys that
1112 can be read through the Simple Input Protocol.
1114 The table below shows the keyboard input mappings that this function supports.
1115 If the ESC sequence listed in one of the columns is presented, then it is translated
1116 into the corresponding EFI Scan Code. If a matching sequence is not found, then the raw
1117 key strokes are converted into EFI Keys.
1119 2 seconds are allowed for an ESC sequence to be completed. If the ESC sequence is not
1120 completed in 2 seconds, then the raw key strokes of the partial ESC sequence are
1121 converted into EFI Keys.
1122 There is one special input sequence that will force the system to reset.
1123 This is ESC R ESC r ESC R.
1125 Note: current implementation support terminal types include: PC ANSI, VT100+/VTUTF8, VT100.
1126 The table below is not same with UEFI Spec 2.3 Appendix B Table 201(not support ANSI X3.64 /
1127 DEC VT200-500 and extra support PC ANSI, VT100)since UEFI Table 201 is just an example.
1129 Symbols used in table below
1130 ===========================
1136 +=========+======+===========+==========+==========+
1137 | | EFI | UEFI 2.0 | | |
1138 | | Scan | | VT100+ | |
1139 | KEY | Code | PC ANSI | VTUTF8 | VT100 |
1140 +=========+======+===========+==========+==========+
1141 | NULL | 0x00 | | | |
1142 | UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
1143 | DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
1144 | RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
1145 | LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
1146 | HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
1147 | END | 0x06 | ESC [ F | ESC k | ESC [ K |
1148 | INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
1149 | | | ESC [ L | | ESC [ L |
1150 | DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
1151 | PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
1153 | PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
1155 | F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
1156 | F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
1157 | F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
1158 | F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
1159 | F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
1160 | F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
1161 | F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
1162 | F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
1163 | F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
1164 | F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
1165 | Escape | 0x17 | ESC | ESC | ESC |
1166 | F11 | 0x15 | | ESC ! | |
1167 | F12 | 0x16 | | ESC @ | |
1168 +=========+======+===========+==========+==========+
1172 ESC R ESC r ESC R = Reset System
1174 @param TerminalDevice The terminal device to use to translate raw input into EFI Keys
1179 IN TERMINAL_DEV
*TerminalDevice
1183 EFI_STATUS TimerStatus
;
1186 BOOLEAN SetDefaultResetState
;
1188 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1190 if (!EFI_ERROR (TimerStatus
)) {
1191 UnicodeToEfiKeyFlushState (TerminalDevice
);
1192 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1195 while (!IsUnicodeFiFoEmpty (TerminalDevice
) && !IsEfiKeyFiFoFull (TerminalDevice
)) {
1197 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1199 // Check to see if the 2 seconds timer has expired
1201 TimerStatus
= gBS
->CheckEvent (TerminalDevice
->TwoSecondTimeOut
);
1202 if (!EFI_ERROR (TimerStatus
)) {
1203 UnicodeToEfiKeyFlushState (TerminalDevice
);
1204 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1209 // Fetch one Unicode character from the Unicode FIFO
1211 UnicodeFiFoRemoveOneKey (TerminalDevice
, &UnicodeChar
);
1213 SetDefaultResetState
= TRUE
;
1215 switch (TerminalDevice
->InputState
) {
1216 case INPUT_STATE_DEFAULT
:
1220 case INPUT_STATE_ESC
:
1222 if (UnicodeChar
== LEFTOPENBRACKET
) {
1223 TerminalDevice
->InputState
|= INPUT_STATE_LEFTOPENBRACKET
;
1224 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1228 if (UnicodeChar
== 'O' && (TerminalDevice
->TerminalType
== VT100TYPE
||
1229 TerminalDevice
->TerminalType
== TTYTERMTYPE
)) {
1230 TerminalDevice
->InputState
|= INPUT_STATE_O
;
1231 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1235 Key
.ScanCode
= SCAN_NULL
;
1237 if (TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1238 TerminalDevice
->TerminalType
== VTUTF8TYPE
) {
1239 switch (UnicodeChar
) {
1241 Key
.ScanCode
= SCAN_F1
;
1244 Key
.ScanCode
= SCAN_F2
;
1247 Key
.ScanCode
= SCAN_F3
;
1250 Key
.ScanCode
= SCAN_F4
;
1253 Key
.ScanCode
= SCAN_F5
;
1256 Key
.ScanCode
= SCAN_F6
;
1259 Key
.ScanCode
= SCAN_F7
;
1262 Key
.ScanCode
= SCAN_F8
;
1265 Key
.ScanCode
= SCAN_F9
;
1268 Key
.ScanCode
= SCAN_F10
;
1271 Key
.ScanCode
= SCAN_F11
;
1274 Key
.ScanCode
= SCAN_F12
;
1277 Key
.ScanCode
= SCAN_HOME
;
1280 Key
.ScanCode
= SCAN_END
;
1283 Key
.ScanCode
= SCAN_INSERT
;
1286 Key
.ScanCode
= SCAN_DELETE
;
1289 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1292 Key
.ScanCode
= SCAN_PAGE_UP
;
1299 switch (UnicodeChar
) {
1301 if (TerminalDevice
->ResetState
== RESET_STATE_DEFAULT
) {
1302 TerminalDevice
->ResetState
= RESET_STATE_ESC_R
;
1303 SetDefaultResetState
= FALSE
;
1304 } else if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R_ESC_R
) {
1305 gRT
->ResetSystem (EfiResetWarm
, EFI_SUCCESS
, 0, NULL
);
1307 Key
.ScanCode
= SCAN_NULL
;
1310 if (TerminalDevice
->ResetState
== RESET_STATE_ESC_R
) {
1311 TerminalDevice
->ResetState
= RESET_STATE_ESC_R_ESC_R
;
1312 SetDefaultResetState
= FALSE
;
1314 Key
.ScanCode
= SCAN_NULL
;
1320 if (SetDefaultResetState
) {
1321 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1324 if (Key
.ScanCode
!= SCAN_NULL
) {
1325 Key
.UnicodeChar
= 0;
1326 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1327 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1328 UnicodeToEfiKeyFlushState (TerminalDevice
);
1332 UnicodeToEfiKeyFlushState (TerminalDevice
);
1336 case INPUT_STATE_ESC
| INPUT_STATE_O
:
1338 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1340 Key
.ScanCode
= SCAN_NULL
;
1342 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1343 switch (UnicodeChar
) {
1345 Key
.ScanCode
= SCAN_F1
;
1348 Key
.ScanCode
= SCAN_F2
;
1351 Key
.ScanCode
= SCAN_F3
;
1354 Key
.ScanCode
= SCAN_F4
;
1357 Key
.ScanCode
= SCAN_F5
;
1360 Key
.ScanCode
= SCAN_F6
;
1363 Key
.ScanCode
= SCAN_F7
;
1366 Key
.ScanCode
= SCAN_F8
;
1369 Key
.ScanCode
= SCAN_F9
;
1372 Key
.ScanCode
= SCAN_F10
;
1377 } else if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1378 /* Also accept VT100 escape codes for F1-F4, HOME and END for TTY term */
1379 switch (UnicodeChar
) {
1381 Key
.ScanCode
= SCAN_F1
;
1384 Key
.ScanCode
= SCAN_F2
;
1387 Key
.ScanCode
= SCAN_F3
;
1390 Key
.ScanCode
= SCAN_F4
;
1393 Key
.ScanCode
= SCAN_HOME
;
1396 Key
.ScanCode
= SCAN_END
;
1401 if (Key
.ScanCode
!= SCAN_NULL
) {
1402 Key
.UnicodeChar
= 0;
1403 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1404 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1405 UnicodeToEfiKeyFlushState (TerminalDevice
);
1409 UnicodeToEfiKeyFlushState (TerminalDevice
);
1413 case INPUT_STATE_ESC
| INPUT_STATE_LEFTOPENBRACKET
:
1415 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1417 Key
.ScanCode
= SCAN_NULL
;
1419 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1420 TerminalDevice
->TerminalType
== VT100TYPE
||
1421 TerminalDevice
->TerminalType
== VT100PLUSTYPE
||
1422 TerminalDevice
->TerminalType
== VTUTF8TYPE
||
1423 TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1424 switch (UnicodeChar
) {
1426 Key
.ScanCode
= SCAN_UP
;
1429 Key
.ScanCode
= SCAN_DOWN
;
1432 Key
.ScanCode
= SCAN_RIGHT
;
1435 Key
.ScanCode
= SCAN_LEFT
;
1438 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1439 TerminalDevice
->TerminalType
== VT100TYPE
||
1440 TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1441 Key
.ScanCode
= SCAN_HOME
;
1445 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1446 TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1447 Key
.ScanCode
= SCAN_END
;
1451 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1452 Key
.ScanCode
= SCAN_END
;
1457 if (TerminalDevice
->TerminalType
== PCANSITYPE
||
1458 TerminalDevice
->TerminalType
== VT100TYPE
) {
1459 Key
.ScanCode
= SCAN_INSERT
;
1463 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1464 Key
.ScanCode
= SCAN_DELETE
;
1468 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1469 Key
.ScanCode
= SCAN_DELETE
;
1470 } else if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1471 Key
.ScanCode
= SCAN_F4
;
1475 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1476 Key
.ScanCode
= SCAN_PAGE_UP
;
1480 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1481 Key
.ScanCode
= SCAN_F10
;
1485 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1486 Key
.ScanCode
= SCAN_PAGE_UP
;
1490 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1491 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1495 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1496 Key
.ScanCode
= SCAN_F9
;
1500 if (TerminalDevice
->TerminalType
== VT100TYPE
) {
1501 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1505 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1506 Key
.ScanCode
= SCAN_F1
;
1510 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1511 Key
.ScanCode
= SCAN_F2
;
1515 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1516 Key
.ScanCode
= SCAN_F3
;
1520 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1521 Key
.ScanCode
= SCAN_F5
;
1525 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1526 Key
.ScanCode
= SCAN_F6
;
1530 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1531 Key
.ScanCode
= SCAN_F7
;
1535 if (TerminalDevice
->TerminalType
== PCANSITYPE
) {
1536 Key
.ScanCode
= SCAN_F8
;
1545 * The VT220 escape codes that the TTY terminal accepts all have
1546 * numeric codes, and there are no ambiguous prefixes shared with
1547 * other terminal types.
1549 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
&&
1550 Key
.ScanCode
== SCAN_NULL
&&
1551 UnicodeChar
>= '0' &&
1552 UnicodeChar
<= '9') {
1553 TerminalDevice
->TtyEscapeStr
[0] = UnicodeChar
;
1554 TerminalDevice
->TtyEscapeIndex
= 1;
1555 TerminalDevice
->InputState
|= INPUT_STATE_LEFTOPENBRACKET_2
;
1559 if (Key
.ScanCode
!= SCAN_NULL
) {
1560 Key
.UnicodeChar
= 0;
1561 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1562 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1563 UnicodeToEfiKeyFlushState (TerminalDevice
);
1567 UnicodeToEfiKeyFlushState (TerminalDevice
);
1572 case INPUT_STATE_ESC
| INPUT_STATE_LEFTOPENBRACKET
| INPUT_STATE_LEFTOPENBRACKET_2
:
1574 * Here we handle the VT220 escape codes that we accept. This
1575 * state is only used by the TTY terminal type.
1577 Key
.ScanCode
= SCAN_NULL
;
1578 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1580 if (UnicodeChar
== '~' && TerminalDevice
->TtyEscapeIndex
<= 2) {
1582 TerminalDevice
->TtyEscapeStr
[TerminalDevice
->TtyEscapeIndex
] = 0; /* Terminate string */
1583 EscCode
= (UINT16
) StrDecimalToUintn(TerminalDevice
->TtyEscapeStr
);
1586 Key
.ScanCode
= SCAN_INSERT
;
1589 Key
.ScanCode
= SCAN_DELETE
;
1592 Key
.ScanCode
= SCAN_PAGE_UP
;
1595 Key
.ScanCode
= SCAN_PAGE_DOWN
;
1602 Key
.ScanCode
= SCAN_F1
+ EscCode
- 11;
1609 Key
.ScanCode
= SCAN_F6
+ EscCode
- 17;
1613 Key
.ScanCode
= SCAN_F11
+ EscCode
- 23;
1618 } else if (TerminalDevice
->TtyEscapeIndex
== 1){
1619 /* 2 character escape code */
1620 TerminalDevice
->TtyEscapeStr
[TerminalDevice
->TtyEscapeIndex
++] = UnicodeChar
;
1624 DEBUG ((EFI_D_ERROR
, "Unexpected state in escape2\n"));
1627 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1629 if (Key
.ScanCode
!= SCAN_NULL
) {
1630 Key
.UnicodeChar
= 0;
1631 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);
1632 TerminalDevice
->InputState
= INPUT_STATE_DEFAULT
;
1633 UnicodeToEfiKeyFlushState (TerminalDevice
);
1637 UnicodeToEfiKeyFlushState (TerminalDevice
);
1642 // Invalid state. This should never happen.
1646 UnicodeToEfiKeyFlushState (TerminalDevice
);
1651 if (UnicodeChar
== ESC
) {
1652 TerminalDevice
->InputState
= INPUT_STATE_ESC
;
1655 if (UnicodeChar
== CSI
) {
1656 TerminalDevice
->InputState
= INPUT_STATE_CSI
;
1659 if (TerminalDevice
->InputState
!= INPUT_STATE_DEFAULT
) {
1660 Status
= gBS
->SetTimer(
1661 TerminalDevice
->TwoSecondTimeOut
,
1665 ASSERT_EFI_ERROR (Status
);
1669 if (SetDefaultResetState
) {
1670 TerminalDevice
->ResetState
= RESET_STATE_DEFAULT
;
1673 if (UnicodeChar
== DEL
) {
1674 if (TerminalDevice
->TerminalType
== TTYTERMTYPE
) {
1675 Key
.ScanCode
= SCAN_NULL
;
1676 Key
.UnicodeChar
= CHAR_BACKSPACE
;
1679 Key
.ScanCode
= SCAN_DELETE
;
1680 Key
.UnicodeChar
= 0;
1683 Key
.ScanCode
= SCAN_NULL
;
1684 Key
.UnicodeChar
= UnicodeChar
;
1687 EfiKeyFiFoInsertOneKey (TerminalDevice
, &Key
);