2009-12-06 02:57:05 +01:00
|
|
|
/** @file
|
2014-08-19 15:29:52 +02:00
|
|
|
Simple Console that sits on a SerialLib.
|
2009-12-06 02:57:05 +01:00
|
|
|
|
2010-04-29 14:40:51 +02:00
|
|
|
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2019-04-04 01:03:38 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
2014-08-19 15:29:52 +02:00
|
|
|
/*
|
2009-12-06 02:57:05 +01:00
|
|
|
Symbols used in table below
|
|
|
|
===========================
|
|
|
|
ESC = 0x1B
|
|
|
|
CSI = 0x9B
|
|
|
|
DEL = 0x7f
|
|
|
|
^ = CTRL
|
|
|
|
|
|
|
|
+=========+======+===========+==========+==========+
|
|
|
|
| | EFI | UEFI 2.0 | | |
|
|
|
|
| | Scan | | VT100+ | |
|
|
|
|
| KEY | Code | PC ANSI | VTUTF8 | VT100 |
|
|
|
|
+=========+======+===========+==========+==========+
|
|
|
|
| NULL | 0x00 | | | |
|
|
|
|
| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A |
|
|
|
|
| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B |
|
|
|
|
| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C |
|
|
|
|
| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D |
|
|
|
|
| HOME | 0x05 | ESC [ H | ESC h | ESC [ H |
|
|
|
|
| END | 0x06 | ESC [ F | ESC k | ESC [ K |
|
|
|
|
| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ |
|
|
|
|
| | | ESC [ L | | ESC [ L |
|
|
|
|
| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P |
|
|
|
|
| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V |
|
|
|
|
| | | | | ESC [ ? |
|
|
|
|
| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U |
|
|
|
|
| | | | | ESC [ / |
|
|
|
|
| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P |
|
|
|
|
| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q |
|
|
|
|
| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w |
|
|
|
|
| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x |
|
|
|
|
| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t |
|
|
|
|
| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u |
|
|
|
|
| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q |
|
|
|
|
| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r |
|
|
|
|
| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p |
|
|
|
|
| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M |
|
|
|
|
| Escape | 0x17 | ESC | ESC | ESC |
|
|
|
|
| F11 | 0x15 | | ESC ! | |
|
|
|
|
| F12 | 0x16 | | ESC @ | |
|
|
|
|
+=========+======+===========+==========+==========+
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <PiDxe.h>
|
|
|
|
#include <Library/UefiLib.h>
|
|
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include <Library/DebugLib.h>
|
|
|
|
#include <Library/SerialPortLib.h>
|
2010-02-15 21:40:51 +01:00
|
|
|
#include <Library/PcdLib.h>
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
#include <Protocol/SerialIo.h>
|
|
|
|
#include <Protocol/SimpleTextIn.h>
|
|
|
|
#include <Protocol/SimpleTextOut.h>
|
2010-02-15 21:40:51 +01:00
|
|
|
#include <Protocol/DevicePath.h>
|
2009-12-06 02:57:05 +01:00
|
|
|
|
|
|
|
#define MODE0_COLUMN_COUNT 80
|
|
|
|
#define MODE0_ROW_COUNT 25
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
TextInReset (
|
|
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ReadKeyStroke (
|
|
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
|
|
|
|
OUT EFI_INPUT_KEY *Key
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
TextOutReset (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
);
|
|
|
|
|
|
|
|
CHAR8 *
|
|
|
|
EFIAPI
|
|
|
|
SafeUnicodeStrToAsciiStr (
|
|
|
|
IN CONST CHAR16 *Source,
|
|
|
|
OUT CHAR8 *Destination
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
OutputString (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN CHAR16 *String
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
TestString (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN CHAR16 *String
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
QueryMode (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN ModeNumber,
|
|
|
|
OUT UINTN *Columns,
|
|
|
|
OUT UINTN *Rows
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetMode (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN ModeNumber
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetAttribute (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN Attribute
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ClearScreen (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetCursorPosition (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN Column,
|
|
|
|
IN UINTN Row
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
EnableCursor (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN BOOLEAN Enable
|
|
|
|
);
|
|
|
|
|
|
|
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
|
|
|
|
TextInReset,
|
|
|
|
ReadKeyStroke,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = {
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
TRUE
|
|
|
|
};
|
|
|
|
|
|
|
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = {
|
|
|
|
TextOutReset,
|
|
|
|
OutputString,
|
|
|
|
TestString,
|
|
|
|
QueryMode,
|
|
|
|
SetMode,
|
|
|
|
SetAttribute,
|
|
|
|
ClearScreen,
|
|
|
|
SetCursorPosition,
|
|
|
|
EnableCursor,
|
|
|
|
&mSimpleTextOutMode
|
|
|
|
};
|
|
|
|
|
2010-02-15 21:40:51 +01:00
|
|
|
EFI_HANDLE mInstallHandle = NULL;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
VENDOR_DEVICE_PATH Guid;
|
|
|
|
UART_DEVICE_PATH Uart;
|
|
|
|
EFI_DEVICE_PATH_PROTOCOL End;
|
|
|
|
} SIMPLE_TEXT_OUT_DEVICE_PATH;
|
|
|
|
|
|
|
|
SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
|
|
|
|
{
|
2014-06-20 20:24:51 +02:00
|
|
|
{ HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 }
|
|
|
|
},
|
2010-02-15 21:40:51 +01:00
|
|
|
EFI_CALLER_ID_GUID
|
|
|
|
},
|
|
|
|
{
|
2014-06-20 20:24:51 +02:00
|
|
|
{ MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0 }
|
|
|
|
},
|
2010-02-15 21:40:51 +01:00
|
|
|
0, // Reserved
|
|
|
|
FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
|
|
|
|
FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
|
|
|
|
FixedPcdGet8 (PcdUartDefaultParity), // Parity (N)
|
|
|
|
FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
|
|
|
|
},
|
2014-06-20 20:24:51 +02:00
|
|
|
{ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
|
|
|
|
}
|
2010-02-15 21:40:51 +01:00
|
|
|
};
|
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
BOOLEAN
|
|
|
|
TextOutIsValidAscii (
|
|
|
|
IN CHAR16 Ascii
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// valid ASCII code lies in the extent of 0x20 - 0x7F
|
|
|
|
//
|
|
|
|
if ((Ascii >= 0x20) && (Ascii <= 0x7F)) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
TextOutIsValidEfiCntlChar (
|
|
|
|
IN CHAR16 Char
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// only support four control characters.
|
|
|
|
//
|
|
|
|
if ((Char == CHAR_NULL) ||
|
|
|
|
(Char == CHAR_BACKSPACE) ||
|
|
|
|
(Char == CHAR_LINEFEED) ||
|
|
|
|
(Char == CHAR_CARRIAGE_RETURN) ||
|
|
|
|
(Char == CHAR_TAB))
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
WaitForKeyEvent (
|
|
|
|
IN EFI_EVENT Event,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (SerialPortPoll ()) {
|
|
|
|
gBS->SignalEvent (Event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
TextInReset (
|
|
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ReadKeyStroke (
|
|
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
|
|
|
|
OUT EFI_INPUT_KEY *Key
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CHAR8 Char;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2010-02-15 21:40:51 +01:00
|
|
|
if (!SerialPortPoll ()) {
|
|
|
|
return EFI_NOT_READY;
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
SerialPortRead ((UINT8 *)&Char, 1);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
//
|
2019-07-03 15:25:30 +02:00
|
|
|
// Check for ESC sequence. This code is not technically correct VT100 code.
|
2009-12-06 02:57:05 +01:00
|
|
|
// An illegal ESC sequence represents an ESC and the characters that follow.
|
2014-08-19 15:29:52 +02:00
|
|
|
// This code will eat one or two chars after an escape. This is done to
|
2009-12-06 02:57:05 +01:00
|
|
|
// prevent some complex FIFOing of the data. It is good enough to get
|
|
|
|
// the arrow and delete keys working
|
|
|
|
//
|
|
|
|
Key->UnicodeChar = 0;
|
|
|
|
Key->ScanCode = SCAN_NULL;
|
|
|
|
if (Char == 0x1b) {
|
|
|
|
SerialPortRead ((UINT8 *)&Char, 1);
|
|
|
|
if (Char == '[') {
|
|
|
|
SerialPortRead ((UINT8 *)&Char, 1);
|
|
|
|
switch (Char) {
|
|
|
|
case 'A':
|
|
|
|
Key->ScanCode = SCAN_UP;
|
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
Key->ScanCode = SCAN_DOWN;
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
Key->ScanCode = SCAN_RIGHT;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
Key->ScanCode = SCAN_LEFT;
|
|
|
|
break;
|
|
|
|
case 'H':
|
|
|
|
Key->ScanCode = SCAN_HOME;
|
|
|
|
break;
|
|
|
|
case 'K':
|
2014-08-19 15:29:52 +02:00
|
|
|
case 'F': // PC ANSI
|
2009-12-06 02:57:05 +01:00
|
|
|
Key->ScanCode = SCAN_END;
|
|
|
|
break;
|
|
|
|
case '@':
|
|
|
|
case 'L':
|
|
|
|
Key->ScanCode = SCAN_INSERT;
|
|
|
|
break;
|
|
|
|
case 'P':
|
2014-08-19 15:29:52 +02:00
|
|
|
case 'X': // PC ANSI
|
2009-12-06 02:57:05 +01:00
|
|
|
Key->ScanCode = SCAN_DELETE;
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
case '/':
|
|
|
|
case 'G': // PC ANSI
|
|
|
|
Key->ScanCode = SCAN_PAGE_DOWN;
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
case '?':
|
|
|
|
case 'I': // PC ANSI
|
|
|
|
Key->ScanCode = SCAN_PAGE_UP;
|
|
|
|
break;
|
2021-12-05 23:53:56 +01:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
// PCANSI that does not conflict with VT100
|
|
|
|
case 'M':
|
|
|
|
Key->ScanCode = SCAN_F1;
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
Key->ScanCode = SCAN_F2;
|
|
|
|
break;
|
|
|
|
case 'O':
|
|
|
|
Key->ScanCode = SCAN_F3;
|
|
|
|
break;
|
|
|
|
case 'Q':
|
|
|
|
Key->ScanCode = SCAN_F5;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
Key->ScanCode = SCAN_F6;
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
Key->ScanCode = SCAN_F7;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
Key->ScanCode = SCAN_F8;
|
|
|
|
break;
|
2021-12-05 23:53:56 +01:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
default:
|
|
|
|
Key->UnicodeChar = Char;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (Char == '0') {
|
|
|
|
SerialPortRead ((UINT8 *)&Char, 1);
|
|
|
|
switch (Char) {
|
|
|
|
case 'P':
|
|
|
|
Key->ScanCode = SCAN_F1;
|
|
|
|
break;
|
|
|
|
case 'Q':
|
|
|
|
Key->ScanCode = SCAN_F2;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
Key->ScanCode = SCAN_F3;
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
Key->ScanCode = SCAN_F4;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
Key->ScanCode = SCAN_F5;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
Key->ScanCode = SCAN_F6;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
Key->ScanCode = SCAN_F7;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
Key->ScanCode = SCAN_F8;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
Key->ScanCode = SCAN_F9;
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
Key->ScanCode = SCAN_F10;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (Char < ' ') {
|
2014-08-19 15:29:52 +02:00
|
|
|
if ((Char == CHAR_BACKSPACE) ||
|
|
|
|
(Char == CHAR_TAB) ||
|
|
|
|
(Char == CHAR_LINEFEED) ||
|
2009-12-06 02:57:05 +01:00
|
|
|
(Char == CHAR_CARRIAGE_RETURN))
|
|
|
|
{
|
|
|
|
// Only let through EFI required control characters
|
2014-08-19 15:29:52 +02:00
|
|
|
Key->UnicodeChar = (CHAR16)Char;
|
2009-12-06 02:57:05 +01:00
|
|
|
}
|
|
|
|
} else if (Char == 0x7f) {
|
|
|
|
Key->ScanCode = SCAN_DELETE;
|
|
|
|
} else {
|
|
|
|
Key->UnicodeChar = (CHAR16)Char;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
TextOutReset (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN BOOLEAN ExtendedVerification
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
This->SetAttribute (
|
|
|
|
This,
|
|
|
|
EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)
|
|
|
|
);
|
|
|
|
|
|
|
|
Status = This->SetMode (This, 0);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
CHAR8 *
|
|
|
|
EFIAPI
|
|
|
|
SafeUnicodeStrToAsciiStr (
|
|
|
|
IN CONST CHAR16 *Source,
|
|
|
|
OUT CHAR8 *Destination
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CHAR8 *ReturnValue;
|
|
|
|
|
|
|
|
ASSERT (Destination != NULL);
|
|
|
|
|
|
|
|
//
|
|
|
|
// ASSERT if Source is long than PcdMaximumUnicodeStringLength.
|
|
|
|
// Length tests are performed inside StrLen().
|
|
|
|
//
|
|
|
|
ASSERT (StrSize (Source) != 0);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Source and Destination should not overlap
|
|
|
|
//
|
|
|
|
ASSERT ((UINTN)((CHAR16 *)Destination - Source) > StrLen (Source));
|
|
|
|
ASSERT ((UINTN)((CHAR8 *)Source - Destination) > StrLen (Source));
|
|
|
|
|
|
|
|
ReturnValue = Destination;
|
|
|
|
while (*Source != '\0') {
|
|
|
|
//
|
|
|
|
// If any non-ascii characters in Source then replace it with '?'.
|
|
|
|
//
|
|
|
|
if (*Source < 0x80) {
|
|
|
|
*Destination = (CHAR8)*Source;
|
|
|
|
} else {
|
|
|
|
*Destination = '?';
|
|
|
|
|
|
|
|
// Surrogate pair check.
|
|
|
|
if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) {
|
|
|
|
Source++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Destination++;
|
|
|
|
Source++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*Destination = '\0';
|
|
|
|
|
|
|
|
//
|
|
|
|
// ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
|
|
|
|
// Length tests are performed inside AsciiStrLen().
|
|
|
|
//
|
|
|
|
ASSERT (AsciiStrSize (ReturnValue) != 0);
|
|
|
|
|
|
|
|
return ReturnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
OutputString (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN CHAR16 *String
|
|
|
|
)
|
|
|
|
{
|
2011-06-03 11:11:55 +02:00
|
|
|
UINTN Size;
|
|
|
|
CHAR8 *OutputString;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
|
|
|
|
UINTN MaxColumn;
|
|
|
|
UINTN MaxRow;
|
2021-12-05 23:53:56 +01:00
|
|
|
|
2011-06-03 11:11:55 +02:00
|
|
|
Size = StrLen (String) + 1;
|
|
|
|
OutputString = AllocatePool (Size);
|
2021-12-05 23:53:56 +01:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
// If there is any non-ascii characters in String buffer then replace it with '?'
|
|
|
|
// Eventually, UnicodeStrToAsciiStr API should be fixed.
|
2014-08-19 15:29:52 +02:00
|
|
|
SafeUnicodeStrToAsciiStr (String, OutputString);
|
2009-12-06 02:57:05 +01:00
|
|
|
SerialPortWrite ((UINT8 *)OutputString, Size - 1);
|
|
|
|
|
2011-06-03 11:11:55 +02:00
|
|
|
//
|
|
|
|
// Parse each character of the string to output
|
|
|
|
// to update the cursor position information
|
|
|
|
//
|
|
|
|
Mode = This->Mode;
|
|
|
|
|
|
|
|
Status = This->QueryMode (
|
|
|
|
This,
|
|
|
|
Mode->Mode,
|
|
|
|
&MaxColumn,
|
|
|
|
&MaxRow
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( ; *String != CHAR_NULL; String++) {
|
|
|
|
switch (*String) {
|
|
|
|
case CHAR_BACKSPACE:
|
|
|
|
if (Mode->CursorColumn > 0) {
|
|
|
|
Mode->CursorColumn--;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHAR_LINEFEED:
|
|
|
|
if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
|
|
|
|
Mode->CursorRow++;
|
|
|
|
}
|
2021-12-05 23:53:56 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2011-06-03 11:11:55 +02:00
|
|
|
case CHAR_CARRIAGE_RETURN:
|
|
|
|
Mode->CursorColumn = 0;
|
2021-12-05 23:53:56 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2011-06-03 11:11:55 +02:00
|
|
|
if (Mode->CursorColumn >= (INT32)(MaxColumn - 1)) {
|
|
|
|
// Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
|
|
|
|
// CHAR_LINEFEED
|
|
|
|
if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
|
|
|
|
Mode->CursorRow++;
|
2021-12-05 23:53:56 +01:00
|
|
|
}
|
|
|
|
|
2011-06-03 11:11:55 +02:00
|
|
|
// CHAR_CARIAGE_RETURN
|
|
|
|
Mode->CursorColumn = 0;
|
|
|
|
} else {
|
|
|
|
Mode->CursorColumn++;
|
|
|
|
}
|
2021-12-05 23:53:56 +01:00
|
|
|
|
2011-06-03 11:11:55 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
FreePool (OutputString);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
TestString (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN CHAR16 *String
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CHAR8 Character;
|
|
|
|
|
|
|
|
for ( ; *String != CHAR_NULL; String++) {
|
|
|
|
Character = (CHAR8)*String;
|
|
|
|
if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
QueryMode (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN ModeNumber,
|
|
|
|
OUT UINTN *Columns,
|
|
|
|
OUT UINTN *Rows
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (This->Mode->MaxMode > 1) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ModeNumber == 0) {
|
|
|
|
*Columns = MODE0_COLUMN_COUNT;
|
|
|
|
*Rows = MODE0_ROW_COUNT;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetMode (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN ModeNumber
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (ModeNumber != 0) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
This->Mode->Mode = 0;
|
|
|
|
This->ClearScreen (This);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetAttribute (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN Attribute
|
|
|
|
)
|
|
|
|
{
|
|
|
|
This->Mode->Attribute = (INT32)Attribute;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
ClearScreen (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = This->SetCursorPosition (This, 0, 0);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SetCursorPosition (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN UINTN Column,
|
|
|
|
IN UINTN Row
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN MaxColumn;
|
|
|
|
UINTN MaxRow;
|
|
|
|
|
|
|
|
Mode = This->Mode;
|
|
|
|
|
|
|
|
Status = This->QueryMode (
|
|
|
|
This,
|
|
|
|
Mode->Mode,
|
|
|
|
&MaxColumn,
|
2014-08-19 15:29:52 +02:00
|
|
|
&MaxRow
|
2009-12-06 02:57:05 +01:00
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Column >= MaxColumn) || (Row >= MaxRow)) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mode->CursorColumn = (INT32)Column;
|
|
|
|
Mode->CursorRow = (INT32)Row;
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
EnableCursor (
|
|
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
|
|
IN BOOLEAN Enable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (!Enable) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SimpleTextInOutEntryPoint (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = gBS->CreateEvent (
|
|
|
|
EVT_NOTIFY_WAIT,
|
|
|
|
TPL_NOTIFY,
|
|
|
|
WaitForKeyEvent,
|
|
|
|
NULL,
|
|
|
|
&mSimpleTextIn.WaitForKey
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
|
|
&mInstallHandle,
|
|
|
|
&gEfiSimpleTextInProtocolGuid,
|
|
|
|
&mSimpleTextIn,
|
|
|
|
&gEfiSimpleTextOutProtocolGuid,
|
|
|
|
&mSimpleTextOut,
|
2010-02-15 21:40:51 +01:00
|
|
|
&gEfiDevicePathProtocolGuid,
|
|
|
|
&mDevicePath,
|
|
|
|
NULL
|
2009-12-06 02:57:05 +01:00
|
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
gST->ConOut = &mSimpleTextOut;
|
|
|
|
gST->ConIn = &mSimpleTextIn;
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
2009-12-06 02:57:05 +01:00
|
|
|
return Status;
|
|
|
|
}
|