Home | History | Annotate | Download | only in SimpleTextInOutSerial
      1 /** @file
      2   Simple Console that sits on a SerialLib.
      3 
      4   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      5 
      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 /*
     17   Symbols used in table below
     18 ===========================
     19   ESC = 0x1B
     20   CSI = 0x9B
     21   DEL = 0x7f
     22   ^   = CTRL
     23 
     24 +=========+======+===========+==========+==========+
     25 |         | EFI  | UEFI 2.0  |          |          |
     26 |         | Scan |           |  VT100+  |          |
     27 |   KEY   | Code |  PC ANSI  |  VTUTF8  |   VT100  |
     28 +=========+======+===========+==========+==========+
     29 | NULL    | 0x00 |           |          |          |
     30 | UP      | 0x01 | ESC [ A   | ESC [ A  | ESC [ A  |
     31 | DOWN    | 0x02 | ESC [ B   | ESC [ B  | ESC [ B  |
     32 | RIGHT   | 0x03 | ESC [ C   | ESC [ C  | ESC [ C  |
     33 | LEFT    | 0x04 | ESC [ D   | ESC [ D  | ESC [ D  |
     34 | HOME    | 0x05 | ESC [ H   | ESC h    | ESC [ H  |
     35 | END     | 0x06 | ESC [ F   | ESC k    | ESC [ K  |
     36 | INSERT  | 0x07 | ESC [ @   | ESC +    | ESC [ @  |
     37 |         |      | ESC [ L   |          | ESC [ L  |
     38 | DELETE  | 0x08 | ESC [ X   | ESC -    | ESC [ P  |
     39 | PG UP   | 0x09 | ESC [ I   | ESC ?    | ESC [ V  |
     40 |         |      |           |          | ESC [ ?  |
     41 | PG DOWN | 0x0A | ESC [ G   | ESC /    | ESC [ U  |
     42 |         |      |           |          | ESC [ /  |
     43 | F1      | 0x0B | ESC [ M   | ESC 1    | ESC O P  |
     44 | F2      | 0x0C | ESC [ N   | ESC 2    | ESC O Q  |
     45 | F3      | 0x0D | ESC [ O   | ESC 3    | ESC O w  |
     46 | F4      | 0x0E | ESC [ P   | ESC 4    | ESC O x  |
     47 | F5      | 0x0F | ESC [ Q   | ESC 5    | ESC O t  |
     48 | F6      | 0x10 | ESC [ R   | ESC 6    | ESC O u  |
     49 | F7      | 0x11 | ESC [ S   | ESC 7    | ESC O q  |
     50 | F8      | 0x12 | ESC [ T   | ESC 8    | ESC O r  |
     51 | F9      | 0x13 | ESC [ U   | ESC 9    | ESC O p  |
     52 | F10     | 0x14 | ESC [ V   | ESC 0    | ESC O M  |
     53 | Escape  | 0x17 | ESC       | ESC      | ESC      |
     54 | F11     | 0x15 |           | ESC !    |          |
     55 | F12     | 0x16 |           | ESC @    |          |
     56 +=========+======+===========+==========+==========+
     57 
     58 */
     59 
     60 #include <PiDxe.h>
     61 #include <Library/UefiLib.h>
     62 #include <Library/UefiBootServicesTableLib.h>
     63 #include <Library/BaseLib.h>
     64 #include <Library/MemoryAllocationLib.h>
     65 #include <Library/DebugLib.h>
     66 #include <Library/SerialPortLib.h>
     67 #include <Library/PcdLib.h>
     68 
     69 #include <Protocol/SerialIo.h>
     70 #include <Protocol/SimpleTextIn.h>
     71 #include <Protocol/SimpleTextOut.h>
     72 #include <Protocol/DevicePath.h>
     73 
     74 
     75 #define MODE0_COLUMN_COUNT        80
     76 #define MODE0_ROW_COUNT           25
     77 
     78 
     79 EFI_STATUS
     80 EFIAPI
     81 TextInReset(
     82   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
     83   IN BOOLEAN                        ExtendedVerification
     84   );
     85 
     86 
     87 EFI_STATUS
     88 EFIAPI
     89 ReadKeyStroke(
     90   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
     91   OUT EFI_INPUT_KEY                 *Key
     92   );
     93 
     94 
     95 EFI_STATUS
     96 EFIAPI
     97 TextOutReset(
     98   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
     99   IN BOOLEAN                          ExtendedVerification
    100   );
    101 
    102 CHAR8 *
    103 EFIAPI
    104 SafeUnicodeStrToAsciiStr (
    105   IN      CONST CHAR16                *Source,
    106   OUT     CHAR8                       *Destination
    107   );
    108 
    109 EFI_STATUS
    110 EFIAPI
    111 OutputString (
    112   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    113   IN CHAR16                           *String
    114   );
    115 
    116 
    117 EFI_STATUS
    118 EFIAPI
    119 TestString (
    120   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    121   IN CHAR16                           *String
    122   );
    123 
    124 
    125 EFI_STATUS
    126 EFIAPI
    127 QueryMode (
    128   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    129   IN UINTN                            ModeNumber,
    130   OUT UINTN                           *Columns,
    131   OUT UINTN                           *Rows
    132   );
    133 
    134 
    135 EFI_STATUS
    136 EFIAPI
    137 SetMode(
    138   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    139   IN UINTN                            ModeNumber
    140   );
    141 
    142 
    143 EFI_STATUS
    144 EFIAPI
    145 SetAttribute(
    146   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    147   IN UINTN                            Attribute
    148   );
    149 
    150 
    151 EFI_STATUS
    152 EFIAPI
    153 ClearScreen (
    154   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This
    155   );
    156 
    157 
    158 EFI_STATUS
    159 EFIAPI
    160 SetCursorPosition (
    161   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    162   IN UINTN                            Column,
    163   IN UINTN                            Row
    164   );
    165 
    166 
    167 EFI_STATUS
    168 EFIAPI
    169 EnableCursor (
    170   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    171   IN BOOLEAN                          Enable
    172   );
    173 
    174 
    175  EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = {
    176   TextInReset,
    177   ReadKeyStroke,
    178   NULL
    179 };
    180 
    181  EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = {
    182   1,
    183   0,
    184   EFI_TEXT_ATTR( EFI_LIGHTGRAY, EFI_BLACK ),
    185   0,
    186   0,
    187   TRUE
    188 };
    189 
    190 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = {
    191   TextOutReset,
    192   OutputString,
    193   TestString,
    194   QueryMode,
    195   SetMode,
    196   SetAttribute,
    197   ClearScreen,
    198   SetCursorPosition,
    199   EnableCursor,
    200   &mSimpleTextOutMode
    201 };
    202 
    203 EFI_HANDLE           mInstallHandle = NULL;
    204 
    205 typedef struct {
    206   VENDOR_DEVICE_PATH        Guid;
    207   UART_DEVICE_PATH          Uart;
    208   EFI_DEVICE_PATH_PROTOCOL  End;
    209 } SIMPLE_TEXT_OUT_DEVICE_PATH;
    210 
    211 SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = {
    212   {
    213     { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} },
    214     EFI_CALLER_ID_GUID
    215   },
    216   {
    217     { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} },
    218     0,        // Reserved
    219     FixedPcdGet64 (PcdUartDefaultBaudRate),   // BaudRate
    220     FixedPcdGet8 (PcdUartDefaultDataBits),    // DataBits
    221     FixedPcdGet8 (PcdUartDefaultParity),      // Parity (N)
    222     FixedPcdGet8 (PcdUartDefaultStopBits)     // StopBits
    223   },
    224   { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} }
    225 };
    226 
    227 
    228 
    229 
    230 BOOLEAN
    231 TextOutIsValidAscii (
    232   IN CHAR16       Ascii
    233   )
    234 {
    235   //
    236   // valid ASCII code lies in the extent of 0x20 - 0x7F
    237   //
    238   if ((Ascii >= 0x20) && (Ascii <= 0x7F)) {
    239     return TRUE;
    240   }
    241 
    242   return FALSE;
    243 }
    244 
    245 
    246 BOOLEAN
    247 TextOutIsValidEfiCntlChar (
    248   IN CHAR16       Char
    249   )
    250 {
    251   //
    252   // only support four control characters.
    253   //
    254   if (Char == CHAR_NULL ||
    255       Char == CHAR_BACKSPACE ||
    256       Char == CHAR_LINEFEED ||
    257       Char == CHAR_CARRIAGE_RETURN ||
    258       Char == CHAR_TAB ) {
    259     return TRUE;
    260   }
    261 
    262   return FALSE;
    263 }
    264 
    265 
    266 VOID
    267 EFIAPI
    268 WaitForKeyEvent (
    269   IN EFI_EVENT          Event,
    270   IN VOID               *Context
    271   )
    272 {
    273   if (SerialPortPoll ())  {
    274     gBS->SignalEvent (Event);
    275   }
    276 }
    277 
    278 
    279 EFI_STATUS
    280 EFIAPI
    281 TextInReset (
    282   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
    283   IN BOOLEAN                        ExtendedVerification
    284   )
    285 {
    286   return EFI_SUCCESS;
    287 }
    288 
    289 
    290 EFI_STATUS
    291 EFIAPI
    292 ReadKeyStroke (
    293   IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
    294   OUT EFI_INPUT_KEY                 *Key
    295   )
    296 {
    297   CHAR8             Char;
    298 
    299   if (!SerialPortPoll ()) {
    300     return EFI_NOT_READY;
    301   }
    302 
    303   SerialPortRead ((UINT8 *)&Char, 1);
    304 
    305   //
    306   // Check for ESC sequence. This code is not techincally correct VT100 code.
    307   // An illegal ESC sequence represents an ESC and the characters that follow.
    308   // This code will eat one or two chars after an escape. This is done to
    309   // prevent some complex FIFOing of the data. It is good enough to get
    310   // the arrow and delete keys working
    311   //
    312   Key->UnicodeChar = 0;
    313   Key->ScanCode    = SCAN_NULL;
    314   if (Char == 0x1b) {
    315     SerialPortRead ((UINT8 *)&Char, 1);
    316     if (Char == '[') {
    317       SerialPortRead ((UINT8 *)&Char, 1);
    318       switch (Char) {
    319       case 'A':
    320         Key->ScanCode = SCAN_UP;
    321         break;
    322       case 'B':
    323         Key->ScanCode = SCAN_DOWN;
    324         break;
    325       case 'C':
    326         Key->ScanCode = SCAN_RIGHT;
    327         break;
    328       case 'D':
    329         Key->ScanCode = SCAN_LEFT;
    330         break;
    331       case 'H':
    332         Key->ScanCode = SCAN_HOME;
    333         break;
    334       case 'K':
    335       case 'F': // PC ANSI
    336         Key->ScanCode = SCAN_END;
    337         break;
    338       case '@':
    339       case 'L':
    340         Key->ScanCode = SCAN_INSERT;
    341         break;
    342       case 'P':
    343       case 'X': // PC ANSI
    344         Key->ScanCode = SCAN_DELETE;
    345         break;
    346       case 'U':
    347       case '/':
    348       case 'G': // PC ANSI
    349         Key->ScanCode = SCAN_PAGE_DOWN;
    350         break;
    351       case 'V':
    352       case '?':
    353       case 'I': // PC ANSI
    354         Key->ScanCode = SCAN_PAGE_UP;
    355         break;
    356 
    357       // PCANSI that does not conflict with VT100
    358       case 'M':
    359         Key->ScanCode = SCAN_F1;
    360         break;
    361       case 'N':
    362         Key->ScanCode = SCAN_F2;
    363         break;
    364       case 'O':
    365         Key->ScanCode = SCAN_F3;
    366         break;
    367       case 'Q':
    368         Key->ScanCode = SCAN_F5;
    369         break;
    370       case 'R':
    371         Key->ScanCode = SCAN_F6;
    372         break;
    373       case 'S':
    374         Key->ScanCode = SCAN_F7;
    375         break;
    376       case 'T':
    377         Key->ScanCode = SCAN_F8;
    378         break;
    379 
    380       default:
    381         Key->UnicodeChar = Char;
    382         break;
    383       }
    384     } else if (Char == '0') {
    385       SerialPortRead ((UINT8 *)&Char, 1);
    386       switch (Char) {
    387       case 'P':
    388         Key->ScanCode = SCAN_F1;
    389         break;
    390       case 'Q':
    391         Key->ScanCode = SCAN_F2;
    392         break;
    393       case 'w':
    394         Key->ScanCode = SCAN_F3;
    395         break;
    396       case 'x':
    397         Key->ScanCode = SCAN_F4;
    398         break;
    399       case 't':
    400         Key->ScanCode = SCAN_F5;
    401         break;
    402       case 'u':
    403         Key->ScanCode = SCAN_F6;
    404         break;
    405       case 'q':
    406         Key->ScanCode = SCAN_F7;
    407         break;
    408       case 'r':
    409         Key->ScanCode = SCAN_F8;
    410         break;
    411       case 'p':
    412         Key->ScanCode = SCAN_F9;
    413         break;
    414       case 'm':
    415         Key->ScanCode = SCAN_F10;
    416         break;
    417       default :
    418         break;
    419       }
    420     }
    421   } else if (Char < ' ') {
    422     if ((Char == CHAR_BACKSPACE) ||
    423         (Char == CHAR_TAB)       ||
    424         (Char == CHAR_LINEFEED)  ||
    425         (Char == CHAR_CARRIAGE_RETURN)) {
    426       // Only let through EFI required control characters
    427       Key->UnicodeChar = (CHAR16)Char;
    428     }
    429   } else if (Char == 0x7f) {
    430     Key->ScanCode = SCAN_DELETE;
    431   } else {
    432     Key->UnicodeChar = (CHAR16)Char;
    433   }
    434 
    435   return EFI_SUCCESS;
    436 }
    437 
    438 
    439 EFI_STATUS
    440 EFIAPI
    441 TextOutReset (
    442   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    443   IN BOOLEAN                          ExtendedVerification
    444   )
    445 {
    446   EFI_STATUS            Status;
    447 
    448   This->SetAttribute(
    449         This,
    450         EFI_TEXT_ATTR(This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK)
    451         );
    452 
    453   Status = This->SetMode (This, 0);
    454 
    455   return Status;
    456 }
    457 
    458 CHAR8 *
    459 EFIAPI
    460 SafeUnicodeStrToAsciiStr (
    461   IN      CONST CHAR16                *Source,
    462   OUT     CHAR8                       *Destination
    463   )
    464 {
    465   CHAR8                               *ReturnValue;
    466 
    467   ASSERT (Destination != NULL);
    468 
    469   //
    470   // ASSERT if Source is long than PcdMaximumUnicodeStringLength.
    471   // Length tests are performed inside StrLen().
    472   //
    473   ASSERT (StrSize (Source) != 0);
    474 
    475   //
    476   // Source and Destination should not overlap
    477   //
    478   ASSERT ((UINTN) ((CHAR16 *) Destination -  Source) > StrLen (Source));
    479   ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source));
    480 
    481 
    482   ReturnValue = Destination;
    483   while (*Source != '\0') {
    484     //
    485     // If any non-ascii characters in Source then replace it with '?'.
    486     //
    487     if (*Source < 0x80) {
    488       *Destination = (CHAR8) *Source;
    489     } else {
    490       *Destination = '?';
    491 
    492       //Surrogate pair check.
    493       if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) {
    494         Source++;
    495       }
    496     }
    497 
    498     Destination++;
    499     Source++;
    500   }
    501 
    502   *Destination = '\0';
    503 
    504   //
    505   // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength.
    506   // Length tests are performed inside AsciiStrLen().
    507   //
    508   ASSERT (AsciiStrSize (ReturnValue) != 0);
    509 
    510   return ReturnValue;
    511 }
    512 
    513 EFI_STATUS
    514 EFIAPI
    515 OutputString (
    516   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    517   IN CHAR16                           *String
    518   )
    519 {
    520   UINTN                       Size;
    521   CHAR8*                      OutputString;
    522   EFI_STATUS                  Status;
    523   EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
    524   UINTN                       MaxColumn;
    525   UINTN                       MaxRow;
    526 
    527   Size = StrLen(String) + 1;
    528   OutputString = AllocatePool(Size);
    529 
    530   //If there is any non-ascii characters in String buffer then replace it with '?'
    531   //Eventually, UnicodeStrToAsciiStr API should be fixed.
    532   SafeUnicodeStrToAsciiStr(String, OutputString);
    533   SerialPortWrite ((UINT8 *)OutputString, Size - 1);
    534 
    535   //
    536   // Parse each character of the string to output
    537   // to update the cursor position information
    538   //
    539   Mode = This->Mode;
    540 
    541   Status = This->QueryMode (
    542                    This,
    543                    Mode->Mode,
    544                    &MaxColumn,
    545                    &MaxRow
    546                    );
    547   if (EFI_ERROR (Status)) {
    548     return Status;
    549   }
    550 
    551   for (; *String != CHAR_NULL; String++) {
    552 
    553     switch (*String) {
    554     case CHAR_BACKSPACE:
    555       if (Mode->CursorColumn > 0) {
    556         Mode->CursorColumn--;
    557       }
    558       break;
    559 
    560     case CHAR_LINEFEED:
    561       if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
    562         Mode->CursorRow++;
    563       }
    564       break;
    565 
    566     case CHAR_CARRIAGE_RETURN:
    567       Mode->CursorColumn = 0;
    568       break;
    569 
    570     default:
    571       if (Mode->CursorColumn >= (INT32) (MaxColumn - 1)) {
    572         // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED
    573         // CHAR_LINEFEED
    574         if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
    575           Mode->CursorRow++;
    576         }
    577         // CHAR_CARIAGE_RETURN
    578         Mode->CursorColumn = 0;
    579       } else {
    580         Mode->CursorColumn++;
    581       }
    582       break;
    583     }
    584   }
    585 
    586   FreePool(OutputString);
    587 
    588   return EFI_SUCCESS;
    589 }
    590 
    591 
    592 EFI_STATUS
    593 EFIAPI
    594 TestString (
    595   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    596   IN CHAR16                           *String
    597   )
    598 {
    599   CHAR8           Character;
    600 
    601   for ( ; *String != CHAR_NULL; String++) {
    602     Character = (CHAR8)*String;
    603     if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) {
    604       return EFI_UNSUPPORTED;
    605     }
    606   }
    607 
    608   return EFI_SUCCESS;
    609 }
    610 
    611 
    612 EFI_STATUS
    613 EFIAPI
    614 QueryMode (
    615   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    616   IN UINTN                            ModeNumber,
    617   OUT UINTN                          *Columns,
    618   OUT UINTN                          *Rows
    619   )
    620 {
    621   if (This->Mode->MaxMode > 1) {
    622     return EFI_DEVICE_ERROR;
    623   }
    624 
    625   if (ModeNumber == 0) {
    626     *Columns  = MODE0_COLUMN_COUNT;
    627     *Rows     = MODE0_ROW_COUNT;
    628     return EFI_SUCCESS;
    629   }
    630 
    631   return EFI_UNSUPPORTED;
    632 }
    633 
    634 
    635 EFI_STATUS
    636 EFIAPI
    637 SetMode (
    638   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
    639   IN UINTN                              ModeNumber
    640   )
    641 {
    642   if (ModeNumber != 0) {
    643     return EFI_UNSUPPORTED;
    644   }
    645 
    646   This->Mode->Mode = 0;
    647   This->ClearScreen (This);
    648   return EFI_SUCCESS;
    649 }
    650 
    651 
    652 EFI_STATUS
    653 EFIAPI
    654 SetAttribute(
    655   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
    656   IN UINTN                              Attribute
    657   )
    658 {
    659   This->Mode->Attribute = (INT32)Attribute;
    660   return EFI_SUCCESS;
    661 }
    662 
    663 
    664 EFI_STATUS
    665 EFIAPI
    666 ClearScreen (
    667   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This
    668   )
    669 {
    670   EFI_STATUS    Status;
    671 
    672   Status = This->SetCursorPosition (This, 0, 0);
    673   return Status;
    674 }
    675 
    676 
    677 EFI_STATUS
    678 EFIAPI
    679 SetCursorPosition (
    680   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This,
    681   IN UINTN                              Column,
    682   IN UINTN                              Row
    683   )
    684 {
    685   EFI_SIMPLE_TEXT_OUTPUT_MODE       *Mode;
    686   EFI_STATUS                        Status;
    687   UINTN                             MaxColumn;
    688   UINTN                             MaxRow;
    689 
    690   Mode = This->Mode;
    691 
    692   Status = This->QueryMode(
    693                   This,
    694                   Mode->Mode,
    695                   &MaxColumn,
    696                   &MaxRow
    697                   );
    698   if (EFI_ERROR(Status)) {
    699     return EFI_UNSUPPORTED;
    700   }
    701 
    702   if ((Column >= MaxColumn) || (Row >= MaxRow)) {
    703     return EFI_UNSUPPORTED;
    704   }
    705 
    706   Mode->CursorColumn = (INT32)Column;
    707   Mode->CursorRow = (INT32)Row;
    708 
    709   return EFI_SUCCESS;
    710 }
    711 
    712 
    713 EFI_STATUS
    714 EFIAPI
    715 EnableCursor (
    716   IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
    717   IN BOOLEAN                          Enable
    718   )
    719 {
    720   if (!Enable) {
    721     return EFI_UNSUPPORTED;
    722   }
    723 
    724   return EFI_SUCCESS;
    725 }
    726 
    727 
    728 EFI_STATUS
    729 EFIAPI
    730 SimpleTextInOutEntryPoint (
    731   IN EFI_HANDLE         ImageHandle,
    732   IN EFI_SYSTEM_TABLE   *SystemTable
    733   )
    734 {
    735   EFI_STATUS            Status;
    736 
    737   Status = gBS->CreateEvent (
    738                   EVT_NOTIFY_WAIT,
    739                   TPL_NOTIFY,
    740                   WaitForKeyEvent,
    741                   NULL,
    742                   &mSimpleTextIn.WaitForKey
    743                   );
    744   ASSERT_EFI_ERROR (Status);
    745 
    746   Status = gBS->InstallMultipleProtocolInterfaces(
    747                   &mInstallHandle,
    748                   &gEfiSimpleTextInProtocolGuid,   &mSimpleTextIn,
    749                   &gEfiSimpleTextOutProtocolGuid,  &mSimpleTextOut,
    750                   &gEfiDevicePathProtocolGuid,     &mDevicePath,
    751                   NULL
    752                   );
    753   if (!EFI_ERROR (Status)) {
    754     gST->ConOut = &mSimpleTextOut;
    755     gST->ConIn = &mSimpleTextIn;
    756   }
    757 
    758   return Status;
    759 }
    760