]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
e9b5ed07cf00e432659cdb26ade44716efd97145
[mirror_edk2.git] / MdeModulePkg / Universal / Console / TerminalDxe / TerminalConOut.c
1 /** @file
2 Implementation for EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL protocol.
3
4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
5 Copyright (C) 2016 Silicon Graphics, Inc. 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
10
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.
13
14 **/
15
16 #include "Terminal.h"
17
18 //
19 // This list is used to define the valid extend chars.
20 // It also provides a mapping from Unicode to PCANSI or
21 // ASCII. The ASCII mapping we just made up.
22 //
23 //
24 UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = {
25 { BOXDRAW_HORIZONTAL, 0xc4, L'-' },
26 { BOXDRAW_VERTICAL, 0xb3, L'|' },
27 { BOXDRAW_DOWN_RIGHT, 0xda, L'/' },
28 { BOXDRAW_DOWN_LEFT, 0xbf, L'\\' },
29 { BOXDRAW_UP_RIGHT, 0xc0, L'\\' },
30 { BOXDRAW_UP_LEFT, 0xd9, L'/' },
31 { BOXDRAW_VERTICAL_RIGHT, 0xc3, L'|' },
32 { BOXDRAW_VERTICAL_LEFT, 0xb4, L'|' },
33 { BOXDRAW_DOWN_HORIZONTAL, 0xc2, L'+' },
34 { BOXDRAW_UP_HORIZONTAL, 0xc1, L'+' },
35 { BOXDRAW_VERTICAL_HORIZONTAL, 0xc5, L'+' },
36 { BOXDRAW_DOUBLE_HORIZONTAL, 0xcd, L'-' },
37 { BOXDRAW_DOUBLE_VERTICAL, 0xba, L'|' },
38 { BOXDRAW_DOWN_RIGHT_DOUBLE, 0xd5, L'/' },
39 { BOXDRAW_DOWN_DOUBLE_RIGHT, 0xd6, L'/' },
40 { BOXDRAW_DOUBLE_DOWN_RIGHT, 0xc9, L'/' },
41 { BOXDRAW_DOWN_LEFT_DOUBLE, 0xb8, L'\\' },
42 { BOXDRAW_DOWN_DOUBLE_LEFT, 0xb7, L'\\' },
43 { BOXDRAW_DOUBLE_DOWN_LEFT, 0xbb, L'\\' },
44 { BOXDRAW_UP_RIGHT_DOUBLE, 0xd4, L'\\' },
45 { BOXDRAW_UP_DOUBLE_RIGHT, 0xd3, L'\\' },
46 { BOXDRAW_DOUBLE_UP_RIGHT, 0xc8, L'\\' },
47 { BOXDRAW_UP_LEFT_DOUBLE, 0xbe, L'/' },
48 { BOXDRAW_UP_DOUBLE_LEFT, 0xbd, L'/' },
49 { BOXDRAW_DOUBLE_UP_LEFT, 0xbc, L'/' },
50 { BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0xc6, L'|' },
51 { BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0xc7, L'|' },
52 { BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0xcc, L'|' },
53 { BOXDRAW_VERTICAL_LEFT_DOUBLE, 0xb5, L'|' },
54 { BOXDRAW_VERTICAL_DOUBLE_LEFT, 0xb6, L'|' },
55 { BOXDRAW_DOUBLE_VERTICAL_LEFT, 0xb9, L'|' },
56 { BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0xd1, L'+' },
57 { BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0xd2, L'+' },
58 { BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0xcb, L'+' },
59 { BOXDRAW_UP_HORIZONTAL_DOUBLE, 0xcf, L'+' },
60 { BOXDRAW_UP_DOUBLE_HORIZONTAL, 0xd0, L'+' },
61 { BOXDRAW_DOUBLE_UP_HORIZONTAL, 0xca, L'+' },
62 { BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0xd8, L'+' },
63 { BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0xd7, L'+' },
64 { BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0xce, L'+' },
65
66 { BLOCKELEMENT_FULL_BLOCK, 0xdb, L'*' },
67 { BLOCKELEMENT_LIGHT_SHADE, 0xb0, L'+' },
68
69 { GEOMETRICSHAPE_UP_TRIANGLE, 0x1e, L'^' },
70 { GEOMETRICSHAPE_RIGHT_TRIANGLE, 0x10, L'>' },
71 { GEOMETRICSHAPE_DOWN_TRIANGLE, 0x1f, L'v' },
72 { GEOMETRICSHAPE_LEFT_TRIANGLE, 0x11, L'<' },
73
74 { ARROW_LEFT, 0x3c, L'<' },
75 { ARROW_UP, 0x18, L'^' },
76 { ARROW_RIGHT, 0x3e, L'>' },
77 { ARROW_DOWN, 0x19, L'v' },
78
79 { 0x0000, 0x00, L'\0' }
80 };
81
82 CHAR16 mSetModeString[] = { ESC, '[', '=', '3', 'h', 0 };
83 CHAR16 mSetAttributeString[] = { ESC, '[', '0', 'm', ESC, '[', '4', '0', 'm', ESC, '[', '4', '0', 'm', 0 };
84 CHAR16 mClearScreenString[] = { ESC, '[', '2', 'J', 0 };
85 CHAR16 mSetCursorPositionString[] = { ESC, '[', '0', '0', ';', '0', '0', 'H', 0 };
86 CHAR16 mCursorForwardString[] = { ESC, '[', '0', '0', 'C', 0 };
87 CHAR16 mCursorBackwardString[] = { ESC, '[', '0', '0', 'D', 0 };
88
89 //
90 // Body of the ConOut functions
91 //
92
93 /**
94 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
95
96 If ExtendeVerification is TRUE, then perform dependent serial device reset,
97 and set display mode to mode 0.
98 If ExtendedVerification is FALSE, only set display mode to mode 0.
99
100 @param This Indicates the calling context.
101 @param ExtendedVerification Indicates that the driver may perform a more
102 exhaustive verification operation of the device
103 during reset.
104
105 @retval EFI_SUCCESS The reset operation succeeds.
106 @retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
107
108 **/
109 EFI_STATUS
110 EFIAPI
111 TerminalConOutReset (
112 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
113 IN BOOLEAN ExtendedVerification
114 )
115 {
116 EFI_STATUS Status;
117 TERMINAL_DEV *TerminalDevice;
118
119 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
120
121 //
122 // Perform a more exhaustive reset by resetting the serial port.
123 //
124 if (ExtendedVerification) {
125 //
126 // Report progress code here
127 //
128 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
129 EFI_PROGRESS_CODE,
130 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
131 TerminalDevice->DevicePath
132 );
133
134 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
135 if (EFI_ERROR (Status)) {
136 //
137 // Report error code here
138 //
139 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
140 EFI_ERROR_CODE | EFI_ERROR_MINOR,
141 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
142 TerminalDevice->DevicePath
143 );
144
145 return Status;
146 }
147 }
148
149 This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
150
151 Status = This->SetMode (This, 0);
152
153 return Status;
154 }
155
156
157 /**
158 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
159
160 The Unicode string will be converted to terminal expressible data stream
161 and send to terminal via serial port.
162
163 @param This Indicates the calling context.
164 @param WString The Null-terminated Unicode string to be displayed
165 on the terminal screen.
166
167 @retval EFI_SUCCESS The string is output successfully.
168 @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
169 @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
170 be rendered and are skipped.
171 @retval EFI_UNSUPPORTED If current display mode is out of range.
172
173 **/
174 EFI_STATUS
175 EFIAPI
176 TerminalConOutOutputString (
177 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
178 IN CHAR16 *WString
179 )
180 {
181 TERMINAL_DEV *TerminalDevice;
182 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
183 UINTN MaxColumn;
184 UINTN MaxRow;
185 UINTN Length;
186 UTF8_CHAR Utf8Char;
187 CHAR8 GraphicChar;
188 CHAR8 AsciiChar;
189 EFI_STATUS Status;
190 UINT8 ValidBytes;
191 //
192 // flag used to indicate whether condition happens which will cause
193 // return EFI_WARN_UNKNOWN_GLYPH
194 //
195 BOOLEAN Warning;
196
197 ValidBytes = 0;
198 Warning = FALSE;
199 AsciiChar = 0;
200
201 //
202 // get Terminal device data structure pointer.
203 //
204 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
205
206 //
207 // Get current display mode
208 //
209 Mode = This->Mode;
210
211 if (Mode->Mode >= Mode->MaxMode) {
212 return EFI_UNSUPPORTED;
213 }
214
215 This->QueryMode (
216 This,
217 Mode->Mode,
218 &MaxColumn,
219 &MaxRow
220 );
221
222 for (; *WString != CHAR_NULL; WString++) {
223
224 switch (TerminalDevice->TerminalType) {
225
226 case PCANSITYPE:
227 case VT100TYPE:
228 case VT100PLUSTYPE:
229 case TTYTERMTYPE:
230
231 if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) {
232 //
233 // If it's not a graphic character convert Unicode to ASCII.
234 //
235 GraphicChar = (CHAR8) *WString;
236
237 if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) {
238 //
239 // when this driver use the OutputString to output control string,
240 // TerminalDevice->OutputEscChar is set to let the Esc char
241 // to be output to the terminal emulation software.
242 //
243 if ((GraphicChar == 27) && TerminalDevice->OutputEscChar) {
244 GraphicChar = 27;
245 } else {
246 GraphicChar = '?';
247 Warning = TRUE;
248 }
249 }
250
251 AsciiChar = GraphicChar;
252
253 }
254
255 if (TerminalDevice->TerminalType != PCANSITYPE) {
256 GraphicChar = AsciiChar;
257 }
258
259 Length = 1;
260
261 Status = TerminalDevice->SerialIo->Write (
262 TerminalDevice->SerialIo,
263 &Length,
264 &GraphicChar
265 );
266
267 if (EFI_ERROR (Status)) {
268 goto OutputError;
269 }
270
271 break;
272
273 case VTUTF8TYPE:
274 UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes);
275 Length = ValidBytes;
276 Status = TerminalDevice->SerialIo->Write (
277 TerminalDevice->SerialIo,
278 &Length,
279 (UINT8 *) &Utf8Char
280 );
281 if (EFI_ERROR (Status)) {
282 goto OutputError;
283 }
284 break;
285 }
286 //
287 // Update cursor position.
288 //
289 switch (*WString) {
290
291 case CHAR_BACKSPACE:
292 if (Mode->CursorColumn > 0) {
293 Mode->CursorColumn--;
294 }
295 break;
296
297 case CHAR_LINEFEED:
298 if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
299 Mode->CursorRow++;
300 }
301 break;
302
303 case CHAR_CARRIAGE_RETURN:
304 Mode->CursorColumn = 0;
305 break;
306
307 default:
308 if (Mode->CursorColumn < (INT32) (MaxColumn - 1)) {
309
310 Mode->CursorColumn++;
311
312 } else {
313
314 Mode->CursorColumn = 0;
315 if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
316 Mode->CursorRow++;
317 }
318
319 if (TerminalDevice->TerminalType == TTYTERMTYPE &&
320 !TerminalDevice->OutputEscChar) {
321 //
322 // We've written the last character on the line. The
323 // terminal doesn't actually wrap its cursor until we print
324 // the next character, but the driver thinks it has wrapped
325 // already. Print CR LF to synchronize the terminal with
326 // the driver, but only if we're not in the middle of
327 // printing an escape sequence.
328 //
329 CHAR8 CrLfStr[] = {'\r', '\n'};
330
331 Length = sizeof(CrLfStr);
332
333 Status = TerminalDevice->SerialIo->Write (
334 TerminalDevice->SerialIo,
335 &Length,
336 CrLfStr
337 );
338
339 if (EFI_ERROR (Status)) {
340 goto OutputError;
341 }
342 }
343 }
344 break;
345
346 };
347
348 }
349
350 if (Warning) {
351 return EFI_WARN_UNKNOWN_GLYPH;
352 }
353
354 return EFI_SUCCESS;
355
356 OutputError:
357 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
358 EFI_ERROR_CODE | EFI_ERROR_MINOR,
359 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_OUTPUT_ERROR),
360 TerminalDevice->DevicePath
361 );
362
363 return EFI_DEVICE_ERROR;
364 }
365
366
367 /**
368 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
369
370 If one of the characters in the *Wstring is
371 neither valid Unicode drawing characters,
372 not ASCII code, then this function will return
373 EFI_UNSUPPORTED.
374
375 @param This Indicates the calling context.
376 @param WString The Null-terminated Unicode string to be tested.
377
378 @retval EFI_SUCCESS The terminal is capable of rendering the output string.
379 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
380
381 **/
382 EFI_STATUS
383 EFIAPI
384 TerminalConOutTestString (
385 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
386 IN CHAR16 *WString
387 )
388 {
389 TERMINAL_DEV *TerminalDevice;
390 EFI_STATUS Status;
391
392 //
393 // get Terminal device data structure pointer.
394 //
395 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
396
397 switch (TerminalDevice->TerminalType) {
398
399 case PCANSITYPE:
400 case VT100TYPE:
401 case VT100PLUSTYPE:
402 case TTYTERMTYPE:
403 Status = AnsiTestString (TerminalDevice, WString);
404 break;
405
406 case VTUTF8TYPE:
407 Status = VTUTF8TestString (TerminalDevice, WString);
408 break;
409
410 default:
411 Status = EFI_UNSUPPORTED;
412 break;
413 }
414
415 return Status;
416 }
417
418
419 /**
420 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
421
422 It returns information for an available text mode
423 that the terminal supports.
424
425 @param This Indicates the calling context.
426 @param ModeNumber The mode number to return information on.
427 @param Columns The returned columns of the requested mode.
428 @param Rows The returned rows of the requested mode.
429
430 @retval EFI_SUCCESS The requested mode information is returned.
431 @retval EFI_UNSUPPORTED The mode number is not valid.
432
433 **/
434 EFI_STATUS
435 EFIAPI
436 TerminalConOutQueryMode (
437 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
438 IN UINTN ModeNumber,
439 OUT UINTN *Columns,
440 OUT UINTN *Rows
441 )
442 {
443 TERMINAL_DEV *TerminalDevice;
444
445 if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
446 return EFI_UNSUPPORTED;
447 }
448
449 //
450 // Get Terminal device data structure pointer.
451 //
452 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
453 *Columns = TerminalDevice->TerminalConsoleModeData[ModeNumber].Columns;
454 *Rows = TerminalDevice->TerminalConsoleModeData[ModeNumber].Rows;
455
456 return EFI_SUCCESS;
457 }
458
459
460 /**
461 Implements EFI_SIMPLE_TEXT_OUT.SetMode().
462
463 Set the terminal to a specified display mode.
464 In this driver, we only support mode 0.
465
466 @param This Indicates the calling context.
467 @param ModeNumber The text mode to set.
468
469 @retval EFI_SUCCESS The requested text mode is set.
470 @retval EFI_DEVICE_ERROR The requested text mode cannot be set
471 because of serial device error.
472 @retval EFI_UNSUPPORTED The text mode number is not valid.
473
474 **/
475 EFI_STATUS
476 EFIAPI
477 TerminalConOutSetMode (
478 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
479 IN UINTN ModeNumber
480 )
481 {
482 EFI_STATUS Status;
483 TERMINAL_DEV *TerminalDevice;
484
485 //
486 // get Terminal device data structure pointer.
487 //
488 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
489
490 if (ModeNumber >= (UINTN) This->Mode->MaxMode) {
491 return EFI_UNSUPPORTED;
492 }
493
494 //
495 // Set the current mode
496 //
497 This->Mode->Mode = (INT32) ModeNumber;
498
499 This->ClearScreen (This);
500
501 TerminalDevice->OutputEscChar = TRUE;
502 Status = This->OutputString (This, mSetModeString);
503 TerminalDevice->OutputEscChar = FALSE;
504
505 if (EFI_ERROR (Status)) {
506 return EFI_DEVICE_ERROR;
507 }
508
509 This->Mode->Mode = (INT32) ModeNumber;
510
511 Status = This->ClearScreen (This);
512 if (EFI_ERROR (Status)) {
513 return EFI_DEVICE_ERROR;
514 }
515
516 return EFI_SUCCESS;
517
518 }
519
520
521 /**
522 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
523
524 @param This Indicates the calling context.
525 @param Attribute The attribute to set. Only bit0..6 are valid, all other bits
526 are undefined and must be zero.
527
528 @retval EFI_SUCCESS The requested attribute is set.
529 @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
530 @retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
531
532 **/
533 EFI_STATUS
534 EFIAPI
535 TerminalConOutSetAttribute (
536 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
537 IN UINTN Attribute
538 )
539 {
540 UINT8 ForegroundControl;
541 UINT8 BackgroundControl;
542 UINT8 BrightControl;
543 INT32 SavedColumn;
544 INT32 SavedRow;
545 EFI_STATUS Status;
546 TERMINAL_DEV *TerminalDevice;
547
548 SavedColumn = 0;
549 SavedRow = 0;
550
551 //
552 // get Terminal device data structure pointer.
553 //
554 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
555
556 //
557 // only the bit0..6 of the Attribute is valid
558 //
559 if ((Attribute | 0x7f) != 0x7f) {
560 return EFI_UNSUPPORTED;
561 }
562
563 //
564 // Skip outputting the command string for the same attribute
565 // It improves the terminal performance significantly
566 //
567 if (This->Mode->Attribute == (INT32) Attribute) {
568 return EFI_SUCCESS;
569 }
570
571 //
572 // convert Attribute value to terminal emulator
573 // understandable foreground color
574 //
575 switch (Attribute & 0x07) {
576
577 case EFI_BLACK:
578 ForegroundControl = 30;
579 break;
580
581 case EFI_BLUE:
582 ForegroundControl = 34;
583 break;
584
585 case EFI_GREEN:
586 ForegroundControl = 32;
587 break;
588
589 case EFI_CYAN:
590 ForegroundControl = 36;
591 break;
592
593 case EFI_RED:
594 ForegroundControl = 31;
595 break;
596
597 case EFI_MAGENTA:
598 ForegroundControl = 35;
599 break;
600
601 case EFI_BROWN:
602 ForegroundControl = 33;
603 break;
604
605 default:
606
607 case EFI_LIGHTGRAY:
608 ForegroundControl = 37;
609 break;
610
611 }
612 //
613 // bit4 of the Attribute indicates bright control
614 // of terminal emulator.
615 //
616 BrightControl = (UINT8) ((Attribute >> 3) & 1);
617
618 //
619 // convert Attribute value to terminal emulator
620 // understandable background color.
621 //
622 switch ((Attribute >> 4) & 0x07) {
623
624 case EFI_BLACK:
625 BackgroundControl = 40;
626 break;
627
628 case EFI_BLUE:
629 BackgroundControl = 44;
630 break;
631
632 case EFI_GREEN:
633 BackgroundControl = 42;
634 break;
635
636 case EFI_CYAN:
637 BackgroundControl = 46;
638 break;
639
640 case EFI_RED:
641 BackgroundControl = 41;
642 break;
643
644 case EFI_MAGENTA:
645 BackgroundControl = 45;
646 break;
647
648 case EFI_BROWN:
649 BackgroundControl = 43;
650 break;
651
652 default:
653
654 case EFI_LIGHTGRAY:
655 BackgroundControl = 47;
656 break;
657 }
658 //
659 // terminal emulator's control sequence to set attributes
660 //
661 mSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16) ('0' + BrightControl);
662 mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (ForegroundControl / 10));
663 mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (ForegroundControl % 10));
664 mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16) ('0' + (BackgroundControl / 10));
665 mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16) ('0' + (BackgroundControl % 10));
666
667 //
668 // save current column and row
669 // for future scrolling back use.
670 //
671 SavedColumn = This->Mode->CursorColumn;
672 SavedRow = This->Mode->CursorRow;
673
674 TerminalDevice->OutputEscChar = TRUE;
675 Status = This->OutputString (This, mSetAttributeString);
676 TerminalDevice->OutputEscChar = FALSE;
677
678 if (EFI_ERROR (Status)) {
679 return EFI_DEVICE_ERROR;
680 }
681 //
682 // scroll back to saved cursor position.
683 //
684 This->Mode->CursorColumn = SavedColumn;
685 This->Mode->CursorRow = SavedRow;
686
687 This->Mode->Attribute = (INT32) Attribute;
688
689 return EFI_SUCCESS;
690
691 }
692
693
694 /**
695 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
696 It clears the ANSI terminal's display to the
697 currently selected background color.
698
699 @param This Indicates the calling context.
700
701 @retval EFI_SUCCESS The operation completed successfully.
702 @retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
703 @retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
704
705 **/
706 EFI_STATUS
707 EFIAPI
708 TerminalConOutClearScreen (
709 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
710 )
711 {
712 EFI_STATUS Status;
713 TERMINAL_DEV *TerminalDevice;
714
715 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
716
717 //
718 // control sequence for clear screen request
719 //
720 TerminalDevice->OutputEscChar = TRUE;
721 Status = This->OutputString (This, mClearScreenString);
722 TerminalDevice->OutputEscChar = FALSE;
723
724 if (EFI_ERROR (Status)) {
725 return EFI_DEVICE_ERROR;
726 }
727
728 Status = This->SetCursorPosition (This, 0, 0);
729
730 return Status;
731 }
732
733
734 /**
735 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
736
737 @param This Indicates the calling context.
738 @param Column The row to set cursor to.
739 @param Row The column to set cursor to.
740
741 @retval EFI_SUCCESS The operation completed successfully.
742 @retval EFI_DEVICE_ERROR The request fails due to serial port error.
743 @retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
744 is invalid for current mode.
745
746 **/
747 EFI_STATUS
748 EFIAPI
749 TerminalConOutSetCursorPosition (
750 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
751 IN UINTN Column,
752 IN UINTN Row
753 )
754 {
755 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
756 UINTN MaxColumn;
757 UINTN MaxRow;
758 EFI_STATUS Status;
759 TERMINAL_DEV *TerminalDevice;
760 CHAR16 *String;
761
762 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
763
764 //
765 // get current mode
766 //
767 Mode = This->Mode;
768
769 //
770 // get geometry of current mode
771 //
772 Status = This->QueryMode (
773 This,
774 Mode->Mode,
775 &MaxColumn,
776 &MaxRow
777 );
778 if (EFI_ERROR (Status)) {
779 return EFI_UNSUPPORTED;
780 }
781
782 if (Column >= MaxColumn || Row >= MaxRow) {
783 return EFI_UNSUPPORTED;
784 }
785 //
786 // control sequence to move the cursor
787 //
788 // Optimize cursor motion control sequences for TtyTerm. Move
789 // within the current line if possible, and don't output anyting if
790 // it isn't necessary.
791 //
792 if (TerminalDevice->TerminalType == TTYTERMTYPE &&
793 Mode->CursorRow == Row) {
794 if (Mode->CursorColumn > Column) {
795 mCursorBackwardString[FW_BACK_OFFSET + 0] = (CHAR16) ('0' + ((Mode->CursorColumn - Column) / 10));
796 mCursorBackwardString[FW_BACK_OFFSET + 1] = (CHAR16) ('0' + ((Mode->CursorColumn - Column) % 10));
797 String = mCursorBackwardString;
798 }
799 else if (Column > Mode->CursorColumn) {
800 mCursorForwardString[FW_BACK_OFFSET + 0] = (CHAR16) ('0' + ((Column - Mode->CursorColumn) / 10));
801 mCursorForwardString[FW_BACK_OFFSET + 1] = (CHAR16) ('0' + ((Column - Mode->CursorColumn) % 10));
802 String = mCursorForwardString;
803 }
804 else {
805 String = L""; // No cursor motion necessary
806 }
807 }
808 else {
809 mSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16) ('0' + ((Row + 1) / 10));
810 mSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16) ('0' + ((Row + 1) % 10));
811 mSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16) ('0' + ((Column + 1) / 10));
812 mSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16) ('0' + ((Column + 1) % 10));
813 String = mSetCursorPositionString;
814 }
815
816 TerminalDevice->OutputEscChar = TRUE;
817 Status = This->OutputString (This, String);
818 TerminalDevice->OutputEscChar = FALSE;
819
820 if (EFI_ERROR (Status)) {
821 return EFI_DEVICE_ERROR;
822 }
823 //
824 // update current cursor position
825 // in the Mode data structure.
826 //
827 Mode->CursorColumn = (INT32) Column;
828 Mode->CursorRow = (INT32) Row;
829
830 return EFI_SUCCESS;
831 }
832
833
834 /**
835 Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
836
837 In this driver, the cursor cannot be hidden.
838
839 @param This Indicates the calling context.
840 @param Visible If TRUE, the cursor is set to be visible,
841 If FALSE, the cursor is set to be invisible.
842
843 @retval EFI_SUCCESS The request is valid.
844 @retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
845
846 **/
847 EFI_STATUS
848 EFIAPI
849 TerminalConOutEnableCursor (
850 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
851 IN BOOLEAN Visible
852 )
853 {
854 if (!Visible) {
855 return EFI_UNSUPPORTED;
856 }
857
858 return EFI_SUCCESS;
859 }
860
861
862 /**
863 Detects if a Unicode char is for Box Drawing text graphics.
864
865 @param Graphic Unicode char to test.
866 @param PcAnsi Optional pointer to return PCANSI equivalent of
867 Graphic.
868 @param Ascii Optional pointer to return ASCII equivalent of
869 Graphic.
870
871 @retval TRUE If Graphic is a supported Unicode Box Drawing character.
872
873 **/
874 BOOLEAN
875 TerminalIsValidTextGraphics (
876 IN CHAR16 Graphic,
877 OUT CHAR8 *PcAnsi, OPTIONAL
878 OUT CHAR8 *Ascii OPTIONAL
879 )
880 {
881 UNICODE_TO_CHAR *Table;
882
883 if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) {
884 //
885 // Unicode drawing code charts are all in the 0x25xx range,
886 // arrows are 0x21xx
887 //
888 return FALSE;
889 }
890
891 for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) {
892 if (Graphic == Table->Unicode) {
893 if (PcAnsi != NULL) {
894 *PcAnsi = Table->PcAnsi;
895 }
896
897 if (Ascii != NULL) {
898 *Ascii = Table->Ascii;
899 }
900
901 return TRUE;
902 }
903 }
904
905 return FALSE;
906 }
907
908 /**
909 Detects if a valid ASCII char.
910
911 @param Ascii An ASCII character.
912
913 @retval TRUE If it is a valid ASCII character.
914 @retval FALSE If it is not a valid ASCII character.
915
916 **/
917 BOOLEAN
918 TerminalIsValidAscii (
919 IN CHAR16 Ascii
920 )
921 {
922 //
923 // valid ascii code lies in the extent of 0x20 ~ 0x7f
924 //
925 if ((Ascii >= 0x20) && (Ascii <= 0x7f)) {
926 return TRUE;
927 }
928
929 return FALSE;
930 }
931
932 /**
933 Detects if a valid EFI control character.
934
935 @param CharC An input EFI Control character.
936
937 @retval TRUE If it is a valid EFI control character.
938 @retval FALSE If it is not a valid EFI control character.
939
940 **/
941 BOOLEAN
942 TerminalIsValidEfiCntlChar (
943 IN CHAR16 CharC
944 )
945 {
946 //
947 // only support four control characters.
948 //
949 if (CharC == CHAR_NULL ||
950 CharC == CHAR_BACKSPACE ||
951 CharC == CHAR_LINEFEED ||
952 CharC == CHAR_CARRIAGE_RETURN ||
953 CharC == CHAR_TAB
954 ) {
955 return TRUE;
956 }
957
958 return FALSE;
959 }