]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Console/TerminalDxe/TerminalConOut.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
152
153 The Unicode string will be converted to terminal expressible data stream
154 and send to terminal via serial port.
155
156 @param This Indicates the calling context.
157 @param WString The Null-terminated Unicode string to be displayed
158 on the terminal screen.
159
160 @retval EFI_SUCCESS The string is output successfully.
161 @retval EFI_DEVICE_ERROR The serial port fails to send the string out.
162 @retval EFI_WARN_UNKNOWN_GLYPH Indicates that some of the characters in the Unicode string could not
163 be rendered and are skipped.
164 @retval EFI_UNSUPPORTED If current display mode is out of range.
165
166 **/
167 EFI_STATUS
168 EFIAPI
169 TerminalConOutOutputString (
170 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
171 IN CHAR16 *WString
172 )
173 {
174 TERMINAL_DEV *TerminalDevice;
175 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
176 UINTN MaxColumn;
177 UINTN MaxRow;
178 UINTN Length;
179 UTF8_CHAR Utf8Char;
180 CHAR8 GraphicChar;
181 CHAR8 AsciiChar;
182 EFI_STATUS Status;
183 UINT8 ValidBytes;
184 CHAR8 CrLfStr[2];
185 //
186 // flag used to indicate whether condition happens which will cause
187 // return EFI_WARN_UNKNOWN_GLYPH
188 //
189 BOOLEAN Warning;
190
191 ValidBytes = 0;
192 Warning = FALSE;
193 AsciiChar = 0;
194
195 //
196 // get Terminal device data structure pointer.
197 //
198 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
199
200 //
201 // Get current display mode
202 //
203 Mode = This->Mode;
204
205 if (Mode->Mode >= Mode->MaxMode) {
206 return EFI_UNSUPPORTED;
207 }
208
209 This->QueryMode (
210 This,
211 Mode->Mode,
212 &MaxColumn,
213 &MaxRow
214 );
215
216 for ( ; *WString != CHAR_NULL; WString++) {
217 switch (TerminalDevice->TerminalType) {
218 case TerminalTypePcAnsi:
219 case TerminalTypeVt100:
220 case TerminalTypeVt100Plus:
221 case TerminalTypeTtyTerm:
222 case TerminalTypeLinux:
223 case TerminalTypeXtermR6:
224 case TerminalTypeVt400:
225 case TerminalTypeSCO:
226
227 if (!TerminalIsValidTextGraphics (*WString, &GraphicChar, &AsciiChar)) {
228 //
229 // If it's not a graphic character convert Unicode to ASCII.
230 //
231 GraphicChar = (CHAR8)*WString;
232
233 if (!(TerminalIsValidAscii (GraphicChar) || TerminalIsValidEfiCntlChar (GraphicChar))) {
234 //
235 // when this driver use the OutputString to output control string,
236 // TerminalDevice->OutputEscChar is set to let the Esc char
237 // to be output to the terminal emulation software.
238 //
239 if ((GraphicChar == 27) && TerminalDevice->OutputEscChar) {
240 GraphicChar = 27;
241 } else {
242 GraphicChar = '?';
243 Warning = TRUE;
244 }
245 }
246
247 AsciiChar = GraphicChar;
248 }
249
250 if (TerminalDevice->TerminalType != TerminalTypePcAnsi) {
251 GraphicChar = AsciiChar;
252 }
253
254 Length = 1;
255
256 Status = TerminalDevice->SerialIo->Write (
257 TerminalDevice->SerialIo,
258 &Length,
259 &GraphicChar
260 );
261
262 if (EFI_ERROR (Status)) {
263 goto OutputError;
264 }
265
266 break;
267
268 case TerminalTypeVtUtf8:
269 UnicodeToUtf8 (*WString, &Utf8Char, &ValidBytes);
270 Length = ValidBytes;
271 Status = TerminalDevice->SerialIo->Write (
272 TerminalDevice->SerialIo,
273 &Length,
274 (UINT8 *)&Utf8Char
275 );
276 if (EFI_ERROR (Status)) {
277 goto OutputError;
278 }
279
280 break;
281 }
282
283 //
284 // Update cursor position.
285 //
286 switch (*WString) {
287 case CHAR_BACKSPACE:
288 if (Mode->CursorColumn > 0) {
289 Mode->CursorColumn--;
290 }
291
292 break;
293
294 case CHAR_LINEFEED:
295 if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
296 Mode->CursorRow++;
297 }
298
299 break;
300
301 case CHAR_CARRIAGE_RETURN:
302 Mode->CursorColumn = 0;
303 break;
304
305 default:
306 if (Mode->CursorColumn < (INT32)(MaxColumn - 1)) {
307 Mode->CursorColumn++;
308 } else {
309 Mode->CursorColumn = 0;
310 if (Mode->CursorRow < (INT32)(MaxRow - 1)) {
311 Mode->CursorRow++;
312 }
313
314 if ((TerminalDevice->TerminalType == TerminalTypeTtyTerm) &&
315 !TerminalDevice->OutputEscChar)
316 {
317 //
318 // We've written the last character on the line. The
319 // terminal doesn't actually wrap its cursor until we print
320 // the next character, but the driver thinks it has wrapped
321 // already. Print CR LF to synchronize the terminal with
322 // the driver, but only if we're not in the middle of
323 // printing an escape sequence.
324 //
325 CrLfStr[0] = '\r';
326 CrLfStr[1] = '\n';
327
328 Length = sizeof (CrLfStr);
329
330 Status = TerminalDevice->SerialIo->Write (
331 TerminalDevice->SerialIo,
332 &Length,
333 CrLfStr
334 );
335
336 if (EFI_ERROR (Status)) {
337 goto OutputError;
338 }
339 }
340 }
341
342 break;
343 }
344 }
345
346 if (Warning) {
347 return EFI_WARN_UNKNOWN_GLYPH;
348 }
349
350 return EFI_SUCCESS;
351
352 OutputError:
353 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
354 EFI_ERROR_CODE | EFI_ERROR_MINOR,
355 (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_OUTPUT_ERROR),
356 TerminalDevice->DevicePath
357 );
358
359 return EFI_DEVICE_ERROR;
360 }
361
362 /**
363 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
364
365 If one of the characters in the *Wstring is
366 neither valid Unicode drawing characters,
367 not ASCII code, then this function will return
368 EFI_UNSUPPORTED.
369
370 @param This Indicates the calling context.
371 @param WString The Null-terminated Unicode string to be tested.
372
373 @retval EFI_SUCCESS The terminal is capable of rendering the output string.
374 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered.
375
376 **/
377 EFI_STATUS
378 EFIAPI
379 TerminalConOutTestString (
380 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
381 IN CHAR16 *WString
382 )
383 {
384 TERMINAL_DEV *TerminalDevice;
385 EFI_STATUS Status;
386
387 //
388 // get Terminal device data structure pointer.
389 //
390 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
391
392 switch (TerminalDevice->TerminalType) {
393 case TerminalTypePcAnsi:
394 case TerminalTypeVt100:
395 case TerminalTypeVt100Plus:
396 case TerminalTypeTtyTerm:
397 Status = AnsiTestString (TerminalDevice, WString);
398 break;
399
400 case TerminalTypeVtUtf8:
401 Status = VTUTF8TestString (TerminalDevice, WString);
402 break;
403
404 default:
405 Status = EFI_UNSUPPORTED;
406 break;
407 }
408
409 return Status;
410 }
411
412 /**
413 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
414
415 It returns information for an available text mode
416 that the terminal supports.
417
418 @param This Indicates the calling context.
419 @param ModeNumber The mode number to return information on.
420 @param Columns The returned columns of the requested mode.
421 @param Rows The returned rows of the requested mode.
422
423 @retval EFI_SUCCESS The requested mode information is returned.
424 @retval EFI_UNSUPPORTED The mode number is not valid.
425
426 **/
427 EFI_STATUS
428 EFIAPI
429 TerminalConOutQueryMode (
430 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
431 IN UINTN ModeNumber,
432 OUT UINTN *Columns,
433 OUT UINTN *Rows
434 )
435 {
436 TERMINAL_DEV *TerminalDevice;
437
438 if (ModeNumber >= (UINTN)This->Mode->MaxMode) {
439 return EFI_UNSUPPORTED;
440 }
441
442 //
443 // Get Terminal device data structure pointer.
444 //
445 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
446 *Columns = TerminalDevice->TerminalConsoleModeData[ModeNumber].Columns;
447 *Rows = TerminalDevice->TerminalConsoleModeData[ModeNumber].Rows;
448
449 return EFI_SUCCESS;
450 }
451
452 /**
453 Implements EFI_SIMPLE_TEXT_OUT.SetMode().
454
455 Set the terminal to a specified display mode.
456 In this driver, we only support mode 0.
457
458 @param This Indicates the calling context.
459 @param ModeNumber The text mode to set.
460
461 @retval EFI_SUCCESS The requested text mode is set.
462 @retval EFI_DEVICE_ERROR The requested text mode cannot be set
463 because of serial device error.
464 @retval EFI_UNSUPPORTED The text mode number is not valid.
465
466 **/
467 EFI_STATUS
468 EFIAPI
469 TerminalConOutSetMode (
470 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
471 IN UINTN ModeNumber
472 )
473 {
474 EFI_STATUS Status;
475 TERMINAL_DEV *TerminalDevice;
476
477 //
478 // get Terminal device data structure pointer.
479 //
480 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
481
482 if (ModeNumber >= (UINTN)This->Mode->MaxMode) {
483 return EFI_UNSUPPORTED;
484 }
485
486 //
487 // Set the current mode
488 //
489 This->Mode->Mode = (INT32)ModeNumber;
490
491 This->ClearScreen (This);
492
493 TerminalDevice->OutputEscChar = TRUE;
494 Status = This->OutputString (This, mSetModeString);
495 TerminalDevice->OutputEscChar = FALSE;
496
497 if (EFI_ERROR (Status)) {
498 return EFI_DEVICE_ERROR;
499 }
500
501 This->Mode->Mode = (INT32)ModeNumber;
502
503 Status = This->ClearScreen (This);
504 if (EFI_ERROR (Status)) {
505 return EFI_DEVICE_ERROR;
506 }
507
508 return EFI_SUCCESS;
509 }
510
511 /**
512 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
513
514 @param This Indicates the calling context.
515 @param Attribute The attribute to set. Only bit0..6 are valid, all other bits
516 are undefined and must be zero.
517
518 @retval EFI_SUCCESS The requested attribute is set.
519 @retval EFI_DEVICE_ERROR The requested attribute cannot be set due to serial port error.
520 @retval EFI_UNSUPPORTED The attribute requested is not defined by EFI spec.
521
522 **/
523 EFI_STATUS
524 EFIAPI
525 TerminalConOutSetAttribute (
526 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
527 IN UINTN Attribute
528 )
529 {
530 UINT8 ForegroundControl;
531 UINT8 BackgroundControl;
532 UINT8 BrightControl;
533 INT32 SavedColumn;
534 INT32 SavedRow;
535 EFI_STATUS Status;
536 TERMINAL_DEV *TerminalDevice;
537
538 SavedColumn = 0;
539 SavedRow = 0;
540
541 //
542 // get Terminal device data structure pointer.
543 //
544 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
545
546 //
547 // only the bit0..6 of the Attribute is valid
548 //
549 if ((Attribute | 0x7f) != 0x7f) {
550 return EFI_UNSUPPORTED;
551 }
552
553 //
554 // Skip outputting the command string for the same attribute
555 // It improves the terminal performance significantly
556 //
557 if (This->Mode->Attribute == (INT32)Attribute) {
558 return EFI_SUCCESS;
559 }
560
561 //
562 // convert Attribute value to terminal emulator
563 // understandable foreground color
564 //
565 switch (Attribute & 0x07) {
566 case EFI_BLACK:
567 ForegroundControl = 30;
568 break;
569
570 case EFI_BLUE:
571 ForegroundControl = 34;
572 break;
573
574 case EFI_GREEN:
575 ForegroundControl = 32;
576 break;
577
578 case EFI_CYAN:
579 ForegroundControl = 36;
580 break;
581
582 case EFI_RED:
583 ForegroundControl = 31;
584 break;
585
586 case EFI_MAGENTA:
587 ForegroundControl = 35;
588 break;
589
590 case EFI_BROWN:
591 ForegroundControl = 33;
592 break;
593
594 default:
595
596 case EFI_LIGHTGRAY:
597 ForegroundControl = 37;
598 break;
599 }
600
601 //
602 // bit4 of the Attribute indicates bright control
603 // of terminal emulator.
604 //
605 BrightControl = (UINT8)((Attribute >> 3) & 1);
606
607 //
608 // convert Attribute value to terminal emulator
609 // understandable background color.
610 //
611 switch ((Attribute >> 4) & 0x07) {
612 case EFI_BLACK:
613 BackgroundControl = 40;
614 break;
615
616 case EFI_BLUE:
617 BackgroundControl = 44;
618 break;
619
620 case EFI_GREEN:
621 BackgroundControl = 42;
622 break;
623
624 case EFI_CYAN:
625 BackgroundControl = 46;
626 break;
627
628 case EFI_RED:
629 BackgroundControl = 41;
630 break;
631
632 case EFI_MAGENTA:
633 BackgroundControl = 45;
634 break;
635
636 case EFI_BROWN:
637 BackgroundControl = 43;
638 break;
639
640 default:
641
642 case EFI_LIGHTGRAY:
643 BackgroundControl = 47;
644 break;
645 }
646
647 //
648 // terminal emulator's control sequence to set attributes
649 //
650 mSetAttributeString[BRIGHT_CONTROL_OFFSET] = (CHAR16)('0' + BrightControl);
651 mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 0] = (CHAR16)('0' + (ForegroundControl / 10));
652 mSetAttributeString[FOREGROUND_CONTROL_OFFSET + 1] = (CHAR16)('0' + (ForegroundControl % 10));
653 mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 0] = (CHAR16)('0' + (BackgroundControl / 10));
654 mSetAttributeString[BACKGROUND_CONTROL_OFFSET + 1] = (CHAR16)('0' + (BackgroundControl % 10));
655
656 //
657 // save current column and row
658 // for future scrolling back use.
659 //
660 SavedColumn = This->Mode->CursorColumn;
661 SavedRow = This->Mode->CursorRow;
662
663 TerminalDevice->OutputEscChar = TRUE;
664 Status = This->OutputString (This, mSetAttributeString);
665 TerminalDevice->OutputEscChar = FALSE;
666
667 if (EFI_ERROR (Status)) {
668 return EFI_DEVICE_ERROR;
669 }
670
671 //
672 // scroll back to saved cursor position.
673 //
674 This->Mode->CursorColumn = SavedColumn;
675 This->Mode->CursorRow = SavedRow;
676
677 This->Mode->Attribute = (INT32)Attribute;
678
679 return EFI_SUCCESS;
680 }
681
682 /**
683 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
684 It clears the ANSI terminal's display to the
685 currently selected background color.
686
687 @param This Indicates the calling context.
688
689 @retval EFI_SUCCESS The operation completed successfully.
690 @retval EFI_DEVICE_ERROR The terminal screen cannot be cleared due to serial port error.
691 @retval EFI_UNSUPPORTED The terminal is not in a valid display mode.
692
693 **/
694 EFI_STATUS
695 EFIAPI
696 TerminalConOutClearScreen (
697 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
698 )
699 {
700 EFI_STATUS Status;
701 TERMINAL_DEV *TerminalDevice;
702
703 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
704
705 //
706 // control sequence for clear screen request
707 //
708 TerminalDevice->OutputEscChar = TRUE;
709 Status = This->OutputString (This, mClearScreenString);
710 TerminalDevice->OutputEscChar = FALSE;
711
712 if (EFI_ERROR (Status)) {
713 return EFI_DEVICE_ERROR;
714 }
715
716 Status = This->SetCursorPosition (This, 0, 0);
717
718 return Status;
719 }
720
721 /**
722 Implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
723
724 @param This Indicates the calling context.
725 @param Column The row to set cursor to.
726 @param Row The column to set cursor to.
727
728 @retval EFI_SUCCESS The operation completed successfully.
729 @retval EFI_DEVICE_ERROR The request fails due to serial port error.
730 @retval EFI_UNSUPPORTED The terminal is not in a valid text mode, or the cursor position
731 is invalid for current mode.
732
733 **/
734 EFI_STATUS
735 EFIAPI
736 TerminalConOutSetCursorPosition (
737 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
738 IN UINTN Column,
739 IN UINTN Row
740 )
741 {
742 EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
743 UINTN MaxColumn;
744 UINTN MaxRow;
745 EFI_STATUS Status;
746 TERMINAL_DEV *TerminalDevice;
747 CHAR16 *String;
748
749 TerminalDevice = TERMINAL_CON_OUT_DEV_FROM_THIS (This);
750
751 //
752 // get current mode
753 //
754 Mode = This->Mode;
755
756 //
757 // get geometry of current mode
758 //
759 Status = This->QueryMode (
760 This,
761 Mode->Mode,
762 &MaxColumn,
763 &MaxRow
764 );
765 if (EFI_ERROR (Status)) {
766 return EFI_UNSUPPORTED;
767 }
768
769 if ((Column >= MaxColumn) || (Row >= MaxRow)) {
770 return EFI_UNSUPPORTED;
771 }
772
773 //
774 // control sequence to move the cursor
775 //
776 // Optimize cursor motion control sequences for TtyTerm. Move
777 // within the current line if possible, and don't output anyting if
778 // it isn't necessary.
779 //
780 if ((TerminalDevice->TerminalType == TerminalTypeTtyTerm) &&
781 ((UINTN)Mode->CursorRow == Row))
782 {
783 if ((UINTN)Mode->CursorColumn > Column) {
784 mCursorBackwardString[FW_BACK_OFFSET + 0] = (CHAR16)('0' + ((Mode->CursorColumn - Column) / 10));
785 mCursorBackwardString[FW_BACK_OFFSET + 1] = (CHAR16)('0' + ((Mode->CursorColumn - Column) % 10));
786 String = mCursorBackwardString;
787 } else if (Column > (UINTN)Mode->CursorColumn) {
788 mCursorForwardString[FW_BACK_OFFSET + 0] = (CHAR16)('0' + ((Column - Mode->CursorColumn) / 10));
789 mCursorForwardString[FW_BACK_OFFSET + 1] = (CHAR16)('0' + ((Column - Mode->CursorColumn) % 10));
790 String = mCursorForwardString;
791 } else {
792 String = L""; // No cursor motion necessary
793 }
794 } else {
795 mSetCursorPositionString[ROW_OFFSET + 0] = (CHAR16)('0' + ((Row + 1) / 10));
796 mSetCursorPositionString[ROW_OFFSET + 1] = (CHAR16)('0' + ((Row + 1) % 10));
797 mSetCursorPositionString[COLUMN_OFFSET + 0] = (CHAR16)('0' + ((Column + 1) / 10));
798 mSetCursorPositionString[COLUMN_OFFSET + 1] = (CHAR16)('0' + ((Column + 1) % 10));
799 String = mSetCursorPositionString;
800 }
801
802 TerminalDevice->OutputEscChar = TRUE;
803 Status = This->OutputString (This, String);
804 TerminalDevice->OutputEscChar = FALSE;
805
806 if (EFI_ERROR (Status)) {
807 return EFI_DEVICE_ERROR;
808 }
809
810 //
811 // update current cursor position
812 // in the Mode data structure.
813 //
814 Mode->CursorColumn = (INT32)Column;
815 Mode->CursorRow = (INT32)Row;
816
817 return EFI_SUCCESS;
818 }
819
820 /**
821 Implements SIMPLE_TEXT_OUTPUT.EnableCursor().
822
823 In this driver, the cursor cannot be hidden.
824
825 @param This Indicates the calling context.
826 @param Visible If TRUE, the cursor is set to be visible,
827 If FALSE, the cursor is set to be invisible.
828
829 @retval EFI_SUCCESS The request is valid.
830 @retval EFI_UNSUPPORTED The terminal does not support cursor hidden.
831
832 **/
833 EFI_STATUS
834 EFIAPI
835 TerminalConOutEnableCursor (
836 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
837 IN BOOLEAN Visible
838 )
839 {
840 if (!Visible) {
841 return EFI_UNSUPPORTED;
842 }
843
844 return EFI_SUCCESS;
845 }
846
847 /**
848 Detects if a Unicode char is for Box Drawing text graphics.
849
850 @param Graphic Unicode char to test.
851 @param PcAnsi Optional pointer to return PCANSI equivalent of
852 Graphic.
853 @param Ascii Optional pointer to return ASCII equivalent of
854 Graphic.
855
856 @retval TRUE If Graphic is a supported Unicode Box Drawing character.
857
858 **/
859 BOOLEAN
860 TerminalIsValidTextGraphics (
861 IN CHAR16 Graphic,
862 OUT CHAR8 *PcAnsi OPTIONAL,
863 OUT CHAR8 *Ascii OPTIONAL
864 )
865 {
866 UNICODE_TO_CHAR *Table;
867
868 if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) {
869 //
870 // Unicode drawing code charts are all in the 0x25xx range,
871 // arrows are 0x21xx
872 //
873 return FALSE;
874 }
875
876 for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) {
877 if (Graphic == Table->Unicode) {
878 if (PcAnsi != NULL) {
879 *PcAnsi = Table->PcAnsi;
880 }
881
882 if (Ascii != NULL) {
883 *Ascii = Table->Ascii;
884 }
885
886 return TRUE;
887 }
888 }
889
890 return FALSE;
891 }
892
893 /**
894 Detects if a valid ASCII char.
895
896 @param Ascii An ASCII character.
897
898 @retval TRUE If it is a valid ASCII character.
899 @retval FALSE If it is not a valid ASCII character.
900
901 **/
902 BOOLEAN
903 TerminalIsValidAscii (
904 IN CHAR16 Ascii
905 )
906 {
907 //
908 // valid ascii code lies in the extent of 0x20 ~ 0x7f
909 //
910 if ((Ascii >= 0x20) && (Ascii <= 0x7f)) {
911 return TRUE;
912 }
913
914 return FALSE;
915 }
916
917 /**
918 Detects if a valid EFI control character.
919
920 @param CharC An input EFI Control character.
921
922 @retval TRUE If it is a valid EFI control character.
923 @retval FALSE If it is not a valid EFI control character.
924
925 **/
926 BOOLEAN
927 TerminalIsValidEfiCntlChar (
928 IN CHAR16 CharC
929 )
930 {
931 //
932 // only support four control characters.
933 //
934 if ((CharC == CHAR_NULL) ||
935 (CharC == CHAR_BACKSPACE) ||
936 (CharC == CHAR_LINEFEED) ||
937 (CharC == CHAR_CARRIAGE_RETURN) ||
938 (CharC == CHAR_TAB)
939 )
940 {
941 return TRUE;
942 }
943
944 return FALSE;
945 }