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