Home | History | Annotate | Download | only in TerminalDxe
      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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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