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