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