]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
MdeModulePkg: Change OPTIONAL keyword usage style
[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 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (C) 2016 Silicon Graphics, Inc. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "Terminal.h"
11
12 //
13 // This list is used to define the valid extend chars.
14 // It also provides a mapping from Unicode to PCANSI or
15 // ASCII. The ASCII mapping we just made up.
16 //
17 //
18 UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = {
19 { BOXDRAW_HORIZONTAL, 0xc4, L'-' },
20 { BOXDRAW_VERTICAL, 0xb3, L'|' },
21 { BOXDRAW_DOWN_RIGHT, 0xda, L'/' },
22 { BOXDRAW_DOWN_LEFT, 0xbf, L'\\' },
23 { BOXDRAW_UP_RIGHT, 0xc0, L'\\' },
24 { BOXDRAW_UP_LEFT, 0xd9, L'/' },
25 { BOXDRAW_VERTICAL_RIGHT, 0xc3, L'|' },
26 { BOXDRAW_VERTICAL_LEFT, 0xb4, L'|' },
27 { BOXDRAW_DOWN_HORIZONTAL, 0xc2, L'+' },
28 { BOXDRAW_UP_HORIZONTAL, 0xc1, L'+' },
29 { BOXDRAW_VERTICAL_HORIZONTAL, 0xc5, L'+' },
30 { BOXDRAW_DOUBLE_HORIZONTAL, 0xcd, L'-' },
31 { BOXDRAW_DOUBLE_VERTICAL, 0xba, L'|' },
32 { BOXDRAW_DOWN_RIGHT_DOUBLE, 0xd5, L'/' },
33 { BOXDRAW_DOWN_DOUBLE_RIGHT, 0xd6, L'/' },
34 { BOXDRAW_DOUBLE_DOWN_RIGHT, 0xc9, L'/' },
35 { BOXDRAW_DOWN_LEFT_DOUBLE, 0xb8, L'\\' },
36 { BOXDRAW_DOWN_DOUBLE_LEFT, 0xb7, L'\\' },
37 { BOXDRAW_DOUBLE_DOWN_LEFT, 0xbb, L'\\' },
38 { BOXDRAW_UP_RIGHT_DOUBLE, 0xd4, L'\\' },
39 { BOXDRAW_UP_DOUBLE_RIGHT, 0xd3, L'\\' },
40 { BOXDRAW_DOUBLE_UP_RIGHT, 0xc8, L'\\' },
41 { BOXDRAW_UP_LEFT_DOUBLE, 0xbe, L'/' },
42 { BOXDRAW_UP_DOUBLE_LEFT, 0xbd, L'/' },
43 { BOXDRAW_DOUBLE_UP_LEFT, 0xbc, L'/' },
44 { BOXDRAW_VERTICAL_RIGHT_DOUBLE, 0xc6, L'|' },
45 { BOXDRAW_VERTICAL_DOUBLE_RIGHT, 0xc7, L'|' },
46 { BOXDRAW_DOUBLE_VERTICAL_RIGHT, 0xcc, L'|' },
47 { BOXDRAW_VERTICAL_LEFT_DOUBLE, 0xb5, L'|' },
48 { BOXDRAW_VERTICAL_DOUBLE_LEFT, 0xb6, L'|' },
49 { BOXDRAW_DOUBLE_VERTICAL_LEFT, 0xb9, L'|' },
50 { BOXDRAW_DOWN_HORIZONTAL_DOUBLE, 0xd1, L'+' },
51 { BOXDRAW_DOWN_DOUBLE_HORIZONTAL, 0xd2, L'+' },
52 { BOXDRAW_DOUBLE_DOWN_HORIZONTAL, 0xcb, L'+' },
53 { BOXDRAW_UP_HORIZONTAL_DOUBLE, 0xcf, L'+' },
54 { BOXDRAW_UP_DOUBLE_HORIZONTAL, 0xd0, L'+' },
55 { BOXDRAW_DOUBLE_UP_HORIZONTAL, 0xca, L'+' },
56 { BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE, 0xd8, L'+' },
57 { BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL, 0xd7, L'+' },
58 { BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL, 0xce, L'+' },
59
60 { BLOCKELEMENT_FULL_BLOCK, 0xdb, L'*' },
61 { BLOCKELEMENT_LIGHT_SHADE, 0xb0, L'+' },
62
63 { GEOMETRICSHAPE_UP_TRIANGLE, '^', L'^' },
64 { GEOMETRICSHAPE_RIGHT_TRIANGLE, '>', L'>' },
65 { GEOMETRICSHAPE_DOWN_TRIANGLE, 'v', L'v' },
66 { GEOMETRICSHAPE_LEFT_TRIANGLE, '<', L'<' },
67
68 { ARROW_LEFT, '<', L'<' },
69 { ARROW_UP, '^', L'^' },
70 { ARROW_RIGHT, '>', L'>' },
71 { ARROW_DOWN, 'v', L'v' },
72
73 { 0x0000, 0x00, L'\0' }
74 };
75
76 CHAR16 mSetModeString[] = { ESC, '[', '=', '3', 'h', 0 };
77 CHAR16 mSetAttributeString[] = { ESC, '[', '0', 'm', ESC, '[', '4', '0', 'm', ESC, '[', '4', '0', 'm', 0 };
78 CHAR16 mClearScreenString[] = { ESC, '[', '2', 'J', 0 };
79 CHAR16 mSetCursorPositionString[] = { ESC, '[', '0', '0', ';', '0', '0', 'H', 0 };
80 CHAR16 mCursorForwardString[] = { ESC, '[', '0', '0', 'C', 0 };
81 CHAR16 mCursorBackwardString[] = { ESC, '[', '0', '0', 'D', 0 };
82
83 //
84 // Body of the ConOut functions
85 //
86
87 /**
88 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
89
90 If ExtendeVerification is TRUE, then perform dependent serial device reset,
91 and set display mode to mode 0.
92 If ExtendedVerification is FALSE, only set display mode to mode 0.
93
94 @param This Indicates the calling context.
95 @param ExtendedVerification Indicates that the driver may perform a more
96 exhaustive verification operation of the device
97 during reset.
98
99 @retval EFI_SUCCESS The reset operation succeeds.
100 @retval EFI_DEVICE_ERROR The terminal is not functioning correctly or the serial port reset fails.
101
102 **/
103 EFI_STATUS
104 EFIAPI
105 TerminalConOutReset (
106 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
107 IN BOOLEAN ExtendedVerification
108 )
109 {
110 EFI_STATUS Status;
111 TERMINAL_DEV *TerminalDevice;
112
113 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
114
115 //
116 // Perform a more exhaustive reset by resetting the serial port.
117 //
118 if (ExtendedVerification) {
119 //
120 // Report progress code here
121 //
122 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
123 EFI_PROGRESS_CODE,
124 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_PC_RESET),
125 TerminalDevice->DevicePath
126 );
127
128 Status = TerminalDevice->SerialIo->Reset (TerminalDevice->SerialIo);
129 if (EFI_ERROR (Status)) {
130 //
131 // Report error code here
132 //
133 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
134 EFI_ERROR_CODE | EFI_ERROR_MINOR,
135 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_CONTROLLER_ERROR),
136 TerminalDevice->DevicePath
137 );
138
139 return Status;
140 }
141 }
142
143 This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK));
144
145 Status = This->SetMode (This, 0);
146
147 return Status;
148 }
149
150
151 /**
152 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
153
154 The Unicode string will be converted to terminal expressible data stream
155 and send to terminal via serial port.
156
157 @param This Indicates the calling context.
158 @param WString The Null-terminated Unicode string to be displayed
159 on the terminal screen.
160
161 @retval EFI_SUCCESS The string is output successfully.
162 @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
163 @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
164 be rendered and are skipped.
165 @retval EFI_UNSUPPORTED If current display mode is out of range.
166
167 **/
168 EFI_STATUS
169 EFIAPI
170 TerminalConOutOutputString (
171 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
172 IN CHAR16 *WString
173 )
174 {
175 TERMINAL_DEV *TerminalDevice;
176 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
177 UINTN MaxColumn;
178 UINTN MaxRow;
179 UINTN Length;
180 UTF8_CHAR Utf8Char;
181 CHAR8 GraphicChar;
182 CHAR8 AsciiChar;
183 EFI_STATUS Status;
184 UINT8 ValidBytes;
185 CHAR8 CrLfStr[2];
186 //
187 // flag used to indicate whether condition happens which will cause
188 // return EFI_WARN_UNKNOWN_GLYPH
189 //
190 BOOLEAN Warning;
191
192 ValidBytes = 0;
193 Warning = FALSE;
194 AsciiChar = 0;
195
196 //
197 // get Terminal device data structure pointer.
198 //
199 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
200
201 //
202 // Get current display mode
203 //
204 Mode = This->Mode;
205
206 if (Mode->Mode >= Mode->MaxMode) {
207 return EFI_UNSUPPORTED;
208 }
209
210 This->QueryMode (
211 This,
212 Mode->Mode,
213 &MaxColumn,
214 &MaxRow
215 );
216
217 for (; *WString != CHAR_NULL; WString++) {
218
219 switch (TerminalDevice->TerminalType) {
220
221 case TerminalTypePcAnsi:
222 case TerminalTypeVt100:
223 case TerminalTypeVt100Plus:
224 case TerminalTypeTtyTerm:
225 case TerminalTypeLinux:
226 case TerminalTypeXtermR6:
227 case TerminalTypeVt400:
228 case TerminalTypeSCO:
229
230 if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) {
231 //
232 // If it's not a graphic character convert Unicode to ASCII.
233 //
234 GraphicChar = (CHAR8) *WString;
235
236 if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) {
237 //
238 // when this driver use the OutputString to output control string,
239 // TerminalDevice->OutputEscChar is set to let the Esc char
240 // to be output to the terminal emulation software.
241 //
242 if ((GraphicChar == 27) && TerminalDevice->OutputEscChar) {
243 GraphicChar = 27;
244 } else {
245 GraphicChar = '?';
246 Warning = TRUE;
247 }
248 }
249
250 AsciiChar = GraphicChar;
251
252 }
253
254 if (TerminalDevice->TerminalType != TerminalTypePcAnsi) {
255 GraphicChar = AsciiChar;
256 }
257
258 Length = 1;
259
260 Status = TerminalDevice->SerialIo->Write (
261 TerminalDevice->SerialIo,
262 &Length,
263 &GraphicChar
264 );
265
266 if (EFI_ERROR (Status)) {
267 goto OutputError;
268 }
269
270 break;
271
272 case TerminalTypeVtUtf8:
273 UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes);
274 Length = ValidBytes;
275 Status = TerminalDevice->SerialIo->Write (
276 TerminalDevice->SerialIo,
277 &Length,
278 (UINT8 *) &Utf8Char
279 );
280 if (EFI_ERROR (Status)) {
281 goto OutputError;
282 }
283 break;
284 }
285 //
286 // Update cursor position.
287 //
288 switch (*WString) {
289
290 case CHAR_BACKSPACE:
291 if (Mode->CursorColumn > 0) {
292 Mode->CursorColumn--;
293 }
294 break;
295
296 case CHAR_LINEFEED:
297 if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
298 Mode->CursorRow++;
299 }
300 break;
301
302 case CHAR_CARRIAGE_RETURN:
303 Mode->CursorColumn = 0;
304 break;
305
306 default:
307 if (Mode->CursorColumn < (INT32) (MaxColumn - 1)) {
308
309 Mode->CursorColumn++;
310
311 } else {
312
313 Mode->CursorColumn = 0;
314 if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
315 Mode->CursorRow++;
316 }
317
318 if (TerminalDevice->TerminalType == TerminalTypeTtyTerm &&
319 !TerminalDevice->OutputEscChar) {
320 //
321 // We've written the last character on the line. The
322 // terminal doesn't actually wrap its cursor until we print
323 // the next character, but the driver thinks it has wrapped
324 // already. Print CR LF to synchronize the terminal with
325 // the driver, but only if we're not in the middle of
326 // printing an escape sequence.
327 //
328 CrLfStr[0] = '\r';
329 CrLfStr[1] = '\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 TerminalTypePcAnsi:
400 case TerminalTypeVt100:
401 case TerminalTypeVt100Plus:
402 case TerminalTypeTtyTerm:
403 Status = AnsiTestString (TerminalDevice, WString);
404 break;
405
406 case TerminalTypeVtUtf8:
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 == TerminalTypeTtyTerm &&
793 (UINTN)Mode->CursorRow == Row) {
794 if ((UINTN)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 > (UINTN)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 }