3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 // Include common header file for this module.
25 #include "CommonHeader.h"
29 #include "FrameworkDxe.h"
32 // This list is used to define the valid extend chars.
33 // It also provides a mapping from Unicode to PCANSI or
34 // ASCII. The ASCII mapping we just made up.
37 STATIC UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii
[] = {
38 { BOXDRAW_HORIZONTAL
, 0xc4, L
'-' },
39 { BOXDRAW_VERTICAL
, 0xb3, L
'|' },
40 { BOXDRAW_DOWN_RIGHT
, 0xda, L
'/' },
41 { BOXDRAW_DOWN_LEFT
, 0xbf, L
'\\' },
42 { BOXDRAW_UP_RIGHT
, 0xc0, L
'\\' },
43 { BOXDRAW_UP_LEFT
, 0xd9, L
'/' },
44 { BOXDRAW_VERTICAL_RIGHT
, 0xc3, L
'|' },
45 { BOXDRAW_VERTICAL_LEFT
, 0xb4, L
'|' },
46 { BOXDRAW_DOWN_HORIZONTAL
, 0xc2, L
'+' },
47 { BOXDRAW_UP_HORIZONTAL
, 0xc1, L
'+' },
48 { BOXDRAW_VERTICAL_HORIZONTAL
, 0xc5, L
'+' },
49 { BOXDRAW_DOUBLE_HORIZONTAL
, 0xcd, L
'-' },
50 { BOXDRAW_DOUBLE_VERTICAL
, 0xba, L
'|' },
51 { BOXDRAW_DOWN_RIGHT_DOUBLE
, 0xd5, L
'/' },
52 { BOXDRAW_DOWN_DOUBLE_RIGHT
, 0xd6, L
'/' },
53 { BOXDRAW_DOUBLE_DOWN_RIGHT
, 0xc9, L
'/' },
54 { BOXDRAW_DOWN_LEFT_DOUBLE
, 0xb8, L
'\\' },
55 { BOXDRAW_DOWN_DOUBLE_LEFT
, 0xb7, L
'\\' },
56 { BOXDRAW_DOUBLE_DOWN_LEFT
, 0xbb, L
'\\' },
57 { BOXDRAW_UP_RIGHT_DOUBLE
, 0xd4, L
'\\' },
58 { BOXDRAW_UP_DOUBLE_RIGHT
, 0xd3, L
'\\' },
59 { BOXDRAW_DOUBLE_UP_RIGHT
, 0xc8, L
'\\' },
60 { BOXDRAW_UP_LEFT_DOUBLE
, 0xbe, L
'/' },
61 { BOXDRAW_UP_DOUBLE_LEFT
, 0xbd, L
'/' },
62 { BOXDRAW_DOUBLE_UP_LEFT
, 0xbc, L
'/' },
63 { BOXDRAW_VERTICAL_RIGHT_DOUBLE
, 0xc6, L
'|' },
64 { BOXDRAW_VERTICAL_DOUBLE_RIGHT
, 0xc7, L
'|' },
65 { BOXDRAW_DOUBLE_VERTICAL_RIGHT
, 0xcc, L
'|' },
66 { BOXDRAW_VERTICAL_LEFT_DOUBLE
, 0xb5, L
'|' },
67 { BOXDRAW_VERTICAL_DOUBLE_LEFT
, 0xb6, L
'|' },
68 { BOXDRAW_DOUBLE_VERTICAL_LEFT
, 0xb9, L
'|' },
69 { BOXDRAW_DOWN_HORIZONTAL_DOUBLE
, 0xd1, L
'+' },
70 { BOXDRAW_DOWN_DOUBLE_HORIZONTAL
, 0xd2, L
'+' },
71 { BOXDRAW_DOUBLE_DOWN_HORIZONTAL
, 0xcb, L
'+' },
72 { BOXDRAW_UP_HORIZONTAL_DOUBLE
, 0xcf, L
'+' },
73 { BOXDRAW_UP_DOUBLE_HORIZONTAL
, 0xd0, L
'+' },
74 { BOXDRAW_DOUBLE_UP_HORIZONTAL
, 0xca, L
'+' },
75 { BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE
, 0xd8, L
'+' },
76 { BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL
, 0xd7, L
'+' },
77 { BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL
, 0xce, L
'+' },
79 { BLOCKELEMENT_FULL_BLOCK
, 0xdb, L
'*' },
80 { BLOCKELEMENT_LIGHT_SHADE
, 0xb0, L
'+' },
82 { GEOMETRICSHAPE_UP_TRIANGLE
, 0x1e, L
'^' },
83 { GEOMETRICSHAPE_RIGHT_TRIANGLE
, 0x10, L
'>' },
84 { GEOMETRICSHAPE_DOWN_TRIANGLE
, 0x1f, L
'v' },
85 { GEOMETRICSHAPE_LEFT_TRIANGLE
, 0x11, L
'<' },
87 { ARROW_LEFT
, 0x3c, L
'<' },
88 { ARROW_UP
, 0x18, L
'^' },
89 { ARROW_RIGHT
, 0x3e, L
'>' },
90 { ARROW_DOWN
, 0x19, L
'v' },
92 { 0x0000, 0x00, L
'\0' }
95 CHAR16 mSetModeString
[] = { ESC
, '[', '=', '3', 'h', 0 };
96 CHAR16 mSetAttributeString
[] = { ESC
, '[', '0', 'm', ESC
, '[', '4', '0', 'm', ESC
, '[', '4', '0', 'm', 0 };
97 CHAR16 mClearScreenString
[] = { ESC
, '[', '2', 'J', 0 };
98 CHAR16 mSetCursorPositionString
[] = { ESC
, '[', '0', '0', ';', '0', '0', 'H', 0 };
101 // Body of the ConOut functions
105 TerminalConOutReset (
106 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
107 IN BOOLEAN ExtendedVerification
112 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
113 If ExtendeVerification is TRUE, then perform dependent serial device reset,
114 and set display mode to mode 0.
115 If ExtendedVerification is FALSE, only set display mode to mode 0.
119 This - Indicates the calling context.
121 ExtendedVerification - Indicates that the driver may perform a more exhaustive
122 verification operation of the device during reset.
127 The reset operation succeeds.
130 The terminal is not functioning correctly or the serial port reset fails.
135 TERMINAL_DEV
*TerminalDevice
;
137 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
140 // Perform a more exhaustive reset by resetting the serial port.
142 if (ExtendedVerification
) {
144 // Report progress code here
146 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
148 EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_PC_RESET
,
149 TerminalDevice
->DevicePath
152 Status
= TerminalDevice
->SerialIo
->Reset (TerminalDevice
->SerialIo
);
153 if (EFI_ERROR (Status
)) {
155 // Report error code here
157 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
158 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
159 EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
,
160 TerminalDevice
->DevicePath
167 This
->SetAttribute (This
, EFI_TEXT_ATTR (This
->Mode
->Attribute
& 0x0F, EFI_BACKGROUND_BLACK
));
169 Status
= This
->SetMode (This
, 0);
176 TerminalConOutOutputString (
177 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
183 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
184 The Unicode string will be converted to terminal expressible data stream
185 and send to terminal via serial port.
190 This - Indicates the calling context.
192 WString - The Null-terminated Unicode string to be displayed on
198 The string is output successfully.
201 The serial port fails to send the string out.
203 EFI_WARN_UNKNOWN_GLYPH
204 Indicates that some of the characters in the Unicode string could not
205 be rendered and are skipped.
211 TERMINAL_DEV
*TerminalDevice
;
212 EFI_SIMPLE_TEXT_OUTPUT_MODE
*Mode
;
222 // flag used to indicate whether condition happens which will cause
223 // return EFI_WARN_UNKNOWN_GLYPH
231 // get Terminal device data structure pointer.
233 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
236 // get current display mode
237 // Terminal driver only support mode 0
240 if (Mode
->Mode
!= 0) {
241 return EFI_UNSUPPORTED
;
251 for (; *WString
!= CHAR_NULL
; WString
++) {
253 switch (TerminalDevice
->TerminalType
) {
259 if (!TerminalIsValidTextGraphics (*WString
, &GraphicChar
, &AsciiChar
)) {
261 // If it's not a graphic character convert Unicode to ASCII.
263 GraphicChar
= (CHAR8
) *WString
;
265 if (!(TerminalIsValidAscii (GraphicChar
) || TerminalIsValidEfiCntlChar (GraphicChar
))) {
267 // when this driver use the OutputString to output control string,
268 // TerminalDevice->OutputEscChar is set to let the Esc char
269 // to be output to the terminal emulation software.
271 if ((GraphicChar
== 27) && TerminalDevice
->OutputEscChar
) {
279 AsciiChar
= GraphicChar
;
283 if (TerminalDevice
->TerminalType
!= PcAnsiType
) {
284 GraphicChar
= AsciiChar
;
289 Status
= TerminalDevice
->SerialIo
->Write (
290 TerminalDevice
->SerialIo
,
295 if (EFI_ERROR (Status
)) {
302 UnicodeToUtf8 (*WString
, &Utf8Char
, &ValidBytes
);
304 Status
= TerminalDevice
->SerialIo
->Write (
305 TerminalDevice
->SerialIo
,
309 if (EFI_ERROR (Status
)) {
315 // Update cursor position.
320 if (Mode
->CursorColumn
> 0) {
321 Mode
->CursorColumn
--;
326 if (Mode
->CursorRow
< (INT32
) (MaxRow
- 1)) {
331 case CHAR_CARRIAGE_RETURN
:
332 Mode
->CursorColumn
= 0;
336 if (Mode
->CursorColumn
< (INT32
) (MaxColumn
- 1)) {
338 Mode
->CursorColumn
++;
342 Mode
->CursorColumn
= 0;
343 if (Mode
->CursorRow
< (INT32
) (MaxRow
- 1)) {
355 return EFI_WARN_UNKNOWN_GLYPH
;
361 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
362 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
363 EFI_PERIPHERAL_REMOTE_CONSOLE
| EFI_P_EC_OUTPUT_ERROR
,
364 TerminalDevice
->DevicePath
367 return EFI_DEVICE_ERROR
;
372 TerminalConOutTestString (
373 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
379 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
380 If one of the characters in the *Wstring is
381 neither valid Unicode drawing characters,
382 not ASCII code, then this function will return
388 This - Indicates the calling context.
390 WString - The Null-terminated Unicode string to be tested.
395 The terminal is capable of rendering the output string.
398 Some of the characters in the Unicode string cannot be rendered.
402 TERMINAL_DEV
*TerminalDevice
;
406 // get Terminal device data structure pointer.
408 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
410 switch (TerminalDevice
->TerminalType
) {
415 Status
= AnsiTestString (TerminalDevice
, WString
);
419 Status
= VTUTF8TestString (TerminalDevice
, WString
);
423 Status
= EFI_UNSUPPORTED
;
432 TerminalConOutQueryMode (
433 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
441 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
442 It returns information for an available text mode
443 that the terminal supports.
444 In this driver, we only support text mode 80x25, which is
451 Indicates the calling context.
454 The mode number to return information on.
457 The returned columns of the requested mode.
460 The returned rows of the requested mode.
465 The requested mode information is returned.
468 The mode number is not valid.
474 if (This
->Mode
->MaxMode
> 1) {
475 return EFI_DEVICE_ERROR
;
478 if (ModeNumber
== 0) {
480 *Columns
= MODE0_COLUMN_COUNT
;
481 *Rows
= MODE0_ROW_COUNT
;
486 return EFI_UNSUPPORTED
;
491 TerminalConOutSetMode (
492 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
498 Implements EFI_SIMPLE_TEXT_OUT.SetMode().
499 Set the terminal to a specified display mode.
500 In this driver, we only support mode 0.
505 Indicates the calling context.
508 The text mode to set.
513 The requested text mode is set.
516 The requested text mode cannot be set because of serial device error.
519 The text mode number is not valid.
524 TERMINAL_DEV
*TerminalDevice
;
527 // get Terminal device data structure pointer.
529 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
531 if (ModeNumber
!= 0) {
532 return EFI_UNSUPPORTED
;
535 This
->Mode
->Mode
= 0;
537 This
->ClearScreen (This
);
539 TerminalDevice
->OutputEscChar
= TRUE
;
540 Status
= This
->OutputString (This
, mSetModeString
);
541 TerminalDevice
->OutputEscChar
= FALSE
;
543 if (EFI_ERROR (Status
)) {
544 return EFI_DEVICE_ERROR
;
547 This
->Mode
->Mode
= 0;
549 Status
= This
->ClearScreen (This
);
550 if (EFI_ERROR (Status
)) {
551 return EFI_DEVICE_ERROR
;
560 TerminalConOutSetAttribute (
561 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
567 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
572 Indicates the calling context.
575 The attribute to set. Only bit0..6 are valid, all other bits
576 are undefined and must be zero.
581 The requested attribute is set.
584 The requested attribute cannot be set due to serial port error.
587 The attribute requested is not defined by EFI spec.
591 UINT8 ForegroundControl
;
592 UINT8 BackgroundControl
;
597 TERMINAL_DEV
*TerminalDevice
;
603 // get Terminal device data structure pointer.
605 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
608 // only the bit0..6 of the Attribute is valid
610 if ((Attribute
| 0x7f) != 0x7f) {
611 return EFI_UNSUPPORTED
;
614 // convert Attribute value to terminal emulator
615 // understandable foreground color
617 switch (Attribute
& 0x07) {
620 ForegroundControl
= 30;
624 ForegroundControl
= 34;
628 ForegroundControl
= 32;
632 ForegroundControl
= 36;
636 ForegroundControl
= 31;
640 ForegroundControl
= 35;
644 ForegroundControl
= 33;
650 ForegroundControl
= 37;
655 // bit4 of the Attribute indicates bright control
656 // of terminal emulator.
658 BrightControl
= (UINT8
) ((Attribute
>> 3) & 1);
661 // convert Attribute value to terminal emulator
662 // understandable background color.
664 switch ((Attribute
>> 4) & 0x07) {
667 BackgroundControl
= 40;
671 BackgroundControl
= 44;
675 BackgroundControl
= 42;
679 BackgroundControl
= 46;
683 BackgroundControl
= 41;
687 BackgroundControl
= 45;
691 BackgroundControl
= 43;
697 BackgroundControl
= 47;
701 // terminal emulator's control sequence to set attributes
703 mSetAttributeString
[BRIGHT_CONTROL_OFFSET
] = (CHAR16
) ('0' + BrightControl
);
704 mSetAttributeString
[FOREGROUND_CONTROL_OFFSET
+ 0] = (CHAR16
) ('0' + (ForegroundControl
/ 10));
705 mSetAttributeString
[FOREGROUND_CONTROL_OFFSET
+ 1] = (CHAR16
) ('0' + (ForegroundControl
% 10));
706 mSetAttributeString
[BACKGROUND_CONTROL_OFFSET
+ 0] = (CHAR16
) ('0' + (BackgroundControl
/ 10));
707 mSetAttributeString
[BACKGROUND_CONTROL_OFFSET
+ 1] = (CHAR16
) ('0' + (BackgroundControl
% 10));
710 // save current column and row
711 // for future scrolling back use.
713 SavedColumn
= This
->Mode
->CursorColumn
;
714 SavedRow
= This
->Mode
->CursorRow
;
716 TerminalDevice
->OutputEscChar
= TRUE
;
717 Status
= This
->OutputString (This
, mSetAttributeString
);
718 TerminalDevice
->OutputEscChar
= FALSE
;
720 if (EFI_ERROR (Status
)) {
721 return EFI_DEVICE_ERROR
;
724 // scroll back to saved cursor position.
726 This
->Mode
->CursorColumn
= SavedColumn
;
727 This
->Mode
->CursorRow
= SavedRow
;
729 This
->Mode
->Attribute
= (INT32
) Attribute
;
737 TerminalConOutClearScreen (
738 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
743 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
744 It clears the ANSI terminal's display to the
745 currently selected background color.
751 Indicates the calling context.
756 The operation completed successfully.
759 The terminal screen cannot be cleared due to serial port error.
762 The terminal is not in a valid display mode.
767 TERMINAL_DEV
*TerminalDevice
;
769 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
772 // control sequence for clear screen request
774 TerminalDevice
->OutputEscChar
= TRUE
;
775 Status
= This
->OutputString (This
, mClearScreenString
);
776 TerminalDevice
->OutputEscChar
= FALSE
;
778 if (EFI_ERROR (Status
)) {
779 return EFI_DEVICE_ERROR
;
782 Status
= This
->SetCursorPosition (This
, 0, 0);
789 TerminalConOutSetCursorPosition (
790 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
797 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
802 Indicates the calling context.
805 The row to set cursor to.
808 The column to set cursor to.
813 The operation completed successfully.
816 The request fails due to serial port error.
819 The terminal is not in a valid text mode, or the cursor position
820 is invalid for current mode.
824 EFI_SIMPLE_TEXT_OUTPUT_MODE
*Mode
;
828 TERMINAL_DEV
*TerminalDevice
;
830 TerminalDevice
= TERMINAL_CON_OUT_DEV_FROM_THIS (This
);
838 // get geometry of current mode
840 Status
= This
->QueryMode (
846 if (EFI_ERROR (Status
)) {
847 return EFI_UNSUPPORTED
;
850 if (Column
>= MaxColumn
|| Row
>= MaxRow
) {
851 return EFI_UNSUPPORTED
;
854 // control sequence to move the cursor
856 mSetCursorPositionString
[ROW_OFFSET
+ 0] = (CHAR16
) ('0' + ((Row
+ 1) / 10));
857 mSetCursorPositionString
[ROW_OFFSET
+ 1] = (CHAR16
) ('0' + ((Row
+ 1) % 10));
858 mSetCursorPositionString
[COLUMN_OFFSET
+ 0] = (CHAR16
) ('0' + ((Column
+ 1) / 10));
859 mSetCursorPositionString
[COLUMN_OFFSET
+ 1] = (CHAR16
) ('0' + ((Column
+ 1) % 10));
861 TerminalDevice
->OutputEscChar
= TRUE
;
862 Status
= This
->OutputString (This
, mSetCursorPositionString
);
863 TerminalDevice
->OutputEscChar
= FALSE
;
865 if (EFI_ERROR (Status
)) {
866 return EFI_DEVICE_ERROR
;
869 // update current cursor position
870 // in the Mode data structure.
872 Mode
->CursorColumn
= (INT32
) Column
;
873 Mode
->CursorRow
= (INT32
) Row
;
880 TerminalConOutEnableCursor (
881 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*This
,
887 Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
888 In this driver, the cursor cannot be hidden.
893 Indicates the calling context.
896 If TRUE, the cursor is set to be visible,
897 If FALSE, the cursor is set to be invisible.
902 The request is valid.
905 The terminal does not support cursor hidden.
910 return EFI_UNSUPPORTED
;
917 TerminalIsValidTextGraphics (
919 OUT CHAR8
*PcAnsi
, OPTIONAL
920 OUT CHAR8
*Ascii OPTIONAL
926 Detects if a Unicode char is for Box Drawing text graphics.
930 Graphic - Unicode char to test.
932 PcAnsi - Optional pointer to return PCANSI equivalent of Graphic.
934 Ascii - Optional pointer to return ASCII equivalent of Graphic.
938 TRUE if Graphic is a supported Unicode Box Drawing character.
942 UNICODE_TO_CHAR
*Table
;
944 if ((((Graphic
& 0xff00) != 0x2500) && ((Graphic
& 0xff00) != 0x2100))) {
946 // Unicode drawing code charts are all in the 0x25xx range,
952 for (Table
= UnicodeToPcAnsiOrAscii
; Table
->Unicode
!= 0x0000; Table
++) {
953 if (Graphic
== Table
->Unicode
) {
954 if (PcAnsi
!= NULL
) {
955 *PcAnsi
= Table
->PcAnsi
;
959 *Ascii
= Table
->Ascii
;
970 TerminalIsValidAscii (
975 // valid ascii code lies in the extent of 0x20 ~ 0x7f
977 if ((Ascii
>= 0x20) && (Ascii
<= 0x7f)) {
985 TerminalIsValidEfiCntlChar (
990 // only support four control characters.
992 if (CharC
== CHAR_NULL
||
993 CharC
== CHAR_BACKSPACE
||
994 CharC
== CHAR_LINEFEED
||
995 CharC
== CHAR_CARRIAGE_RETURN
||