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