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 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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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