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