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