1
2
3
4
5
6
7
8#include <common.h>
9#include <charset.h>
10#include <malloc.h>
11#include <time.h>
12#include <dm/device.h>
13#include <efi_loader.h>
14#include <env.h>
15#include <stdio_dev.h>
16#include <video_console.h>
17#include <linux/delay.h>
18
19#define EFI_COUT_MODE_2 2
20#define EFI_MAX_COUT_MODE 3
21
22struct cout_mode {
23 unsigned long columns;
24 unsigned long rows;
25 int present;
26};
27
28static struct cout_mode efi_cout_modes[] = {
29
30 {
31 .columns = 80,
32 .rows = 25,
33 .present = 1,
34 },
35
36 {
37 .columns = 80,
38 .rows = 50,
39 .present = 0,
40 },
41
42 {
43 .columns = 0,
44 .rows = 0,
45 .present = 0,
46 },
47};
48
49const efi_guid_t efi_guid_text_input_ex_protocol =
50 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
51const efi_guid_t efi_guid_text_input_protocol =
52 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
53const efi_guid_t efi_guid_text_output_protocol =
54 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
55
56#define cESC '\x1b'
57#define ESC "\x1b"
58
59
60static struct simple_text_output_mode efi_con_mode = {
61 .max_mode = 1,
62 .mode = 0,
63 .attribute = 0,
64 .cursor_column = 0,
65 .cursor_row = 0,
66 .cursor_visible = 1,
67};
68
69static int term_get_char(s32 *c)
70{
71 u64 timeout;
72
73
74 timeout = timer_get_us() + 100000;
75
76 while (!tstc())
77 if (timer_get_us() > timeout)
78 return 1;
79
80 *c = getchar();
81 return 0;
82}
83
84
85
86
87
88
89
90
91
92static int term_read_reply(int *n, int num, char end_char)
93{
94 s32 c;
95 int i = 0;
96
97 if (term_get_char(&c) || c != cESC)
98 return -1;
99
100 if (term_get_char(&c) || c != '[')
101 return -1;
102
103 n[0] = 0;
104 while (1) {
105 if (!term_get_char(&c)) {
106 if (c == ';') {
107 i++;
108 if (i >= num)
109 return -1;
110 n[i] = 0;
111 continue;
112 } else if (c == end_char) {
113 break;
114 } else if (c > '9' || c < '0') {
115 return -1;
116 }
117
118
119 n[i] *= 10;
120 n[i] += c - '0';
121 } else {
122 return -1;
123 }
124 }
125 if (i != num - 1)
126 return -1;
127
128 return 0;
129}
130
131
132
133
134
135
136
137
138
139
140
141
142static efi_status_t EFIAPI efi_cout_output_string(
143 struct efi_simple_text_output_protocol *this,
144 const u16 *string)
145{
146 struct simple_text_output_mode *con = &efi_con_mode;
147 struct cout_mode *mode = &efi_cout_modes[con->mode];
148 char *buf, *pos;
149 const u16 *p;
150 efi_status_t ret = EFI_SUCCESS;
151
152 EFI_ENTRY("%p, %p", this, string);
153
154 if (!this || !string) {
155 ret = EFI_INVALID_PARAMETER;
156 goto out;
157 }
158
159 buf = malloc(utf16_utf8_strlen(string) + 1);
160 if (!buf) {
161 ret = EFI_OUT_OF_RESOURCES;
162 goto out;
163 }
164 pos = buf;
165 utf16_utf8_strcpy(&pos, string);
166 fputs(stdout, buf);
167 free(buf);
168
169
170
171
172
173
174
175
176 for (p = string; *p; ++p) {
177 switch (*p) {
178 case '\b':
179 if (con->cursor_column)
180 con->cursor_column--;
181 break;
182 case '\n':
183 con->cursor_column = 0;
184 con->cursor_row++;
185 break;
186 case '\r':
187 con->cursor_column = 0;
188 break;
189 case 0xd800 ... 0xdbff:
190
191
192
193
194 break;
195 default:
196
197 if (*p > 0x1f)
198 con->cursor_column++;
199 break;
200 }
201 if (con->cursor_column >= mode->columns) {
202 con->cursor_column = 0;
203 con->cursor_row++;
204 }
205
206
207
208
209 if (con->cursor_row >= mode->rows && con->cursor_row)
210 con->cursor_row--;
211 }
212
213out:
214 return EFI_EXIT(ret);
215}
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231static efi_status_t EFIAPI efi_cout_test_string(
232 struct efi_simple_text_output_protocol *this,
233 const u16 *string)
234{
235 EFI_ENTRY("%p, %p", this, string);
236 return EFI_EXIT(EFI_SUCCESS);
237}
238
239
240
241
242
243
244
245
246
247
248static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
249{
250 if (!mode->present)
251 return false;
252
253 return (mode->rows == rows) && (mode->columns == cols);
254}
255
256
257
258
259
260
261
262
263
264
265
266static int query_console_serial(int *rows, int *cols)
267{
268 int ret = 0;
269 int n[2];
270
271
272 while (tstc())
273 getchar();
274
275
276
277
278
279
280
281
282
283
284 printf(ESC "7"
285 ESC "[r"
286 ESC "[999;999H"
287 ESC "[6n");
288
289
290 if (term_read_reply(n, 2, 'R')) {
291 ret = 1;
292 goto out;
293 }
294
295 *cols = n[1];
296 *rows = n[0];
297out:
298 printf(ESC "8");
299 return ret;
300}
301
302
303
304
305
306
307
308
309
310static int __maybe_unused query_vidconsole(int *rows, int *cols)
311{
312 const char *stdout_name = env_get("stdout");
313 struct stdio_dev *stdout_dev;
314 struct udevice *dev;
315 struct vidconsole_priv *priv;
316
317 if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
318 return -ENODEV;
319 stdout_dev = stdio_get_by_name("vidconsole");
320 if (!stdout_dev)
321 return -ENODEV;
322 dev = stdout_dev->priv;
323 if (!dev)
324 return -ENODEV;
325 priv = dev_get_uclass_priv(dev);
326 if (!priv)
327 return -ENODEV;
328 *rows = priv->rows;
329 *cols = priv->cols;
330 return 0;
331}
332
333
334
335
336
337
338
339
340static void query_console_size(void)
341{
342 int rows = 25, cols = 80;
343 int ret = -ENODEV;
344
345 if IS_ENABLED(CONFIG_DM_VIDEO)
346 ret = query_vidconsole(&rows, &cols);
347 if (ret)
348 ret = query_console_serial(&rows, &cols);
349 if (ret)
350 return;
351
352
353 if (cols >= 80 && rows >= 50) {
354 efi_cout_modes[1].present = 1;
355 efi_con_mode.max_mode = 2;
356 }
357
358
359
360
361
362 if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
363 !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
364 efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
365 efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
366 efi_cout_modes[EFI_COUT_MODE_2].present = 1;
367 efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
368 efi_con_mode.mode = EFI_COUT_MODE_2;
369 }
370}
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386static efi_status_t EFIAPI efi_cout_query_mode(
387 struct efi_simple_text_output_protocol *this,
388 unsigned long mode_number, unsigned long *columns,
389 unsigned long *rows)
390{
391 EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
392
393 if (mode_number >= efi_con_mode.max_mode)
394 return EFI_EXIT(EFI_UNSUPPORTED);
395
396 if (efi_cout_modes[mode_number].present != 1)
397 return EFI_EXIT(EFI_UNSUPPORTED);
398
399 if (columns)
400 *columns = efi_cout_modes[mode_number].columns;
401 if (rows)
402 *rows = efi_cout_modes[mode_number].rows;
403
404 return EFI_EXIT(EFI_SUCCESS);
405}
406
407static const struct {
408 unsigned int fg;
409 unsigned int bg;
410} color[] = {
411 { 30, 40 },
412 { 34, 44 },
413 { 32, 42 },
414 { 36, 46 },
415 { 31, 41 },
416 { 35, 45 },
417 { 33, 43 },
418 { 37, 47 },
419};
420
421
422
423
424
425
426
427
428
429
430
431
432static efi_status_t EFIAPI efi_cout_set_attribute(
433 struct efi_simple_text_output_protocol *this,
434 unsigned long attribute)
435{
436 unsigned int bold = EFI_ATTR_BOLD(attribute);
437 unsigned int fg = EFI_ATTR_FG(attribute);
438 unsigned int bg = EFI_ATTR_BG(attribute);
439
440 EFI_ENTRY("%p, %lx", this, attribute);
441
442 efi_con_mode.attribute = attribute;
443 if (attribute)
444 printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg);
445 else
446 printf(ESC"[0;37;40m");
447
448 return EFI_EXIT(EFI_SUCCESS);
449}
450
451
452
453
454
455
456
457
458
459
460
461static efi_status_t EFIAPI efi_cout_clear_screen(
462 struct efi_simple_text_output_protocol *this)
463{
464 EFI_ENTRY("%p", this);
465
466
467
468
469
470 printf(ESC "[2J" ESC "[1;1H");
471 efi_con_mode.cursor_column = 0;
472 efi_con_mode.cursor_row = 0;
473
474 return EFI_EXIT(EFI_SUCCESS);
475}
476
477
478
479
480
481
482
483
484
485
486
487
488static efi_status_t EFIAPI efi_cout_set_mode(
489 struct efi_simple_text_output_protocol *this,
490 unsigned long mode_number)
491{
492 EFI_ENTRY("%p, %ld", this, mode_number);
493
494 if (mode_number >= efi_con_mode.max_mode)
495 return EFI_EXIT(EFI_UNSUPPORTED);
496
497 if (!efi_cout_modes[mode_number].present)
498 return EFI_EXIT(EFI_UNSUPPORTED);
499
500 efi_con_mode.mode = mode_number;
501 EFI_CALL(efi_cout_clear_screen(this));
502
503 return EFI_EXIT(EFI_SUCCESS);
504}
505
506
507
508
509
510
511
512
513
514
515
516
517static efi_status_t EFIAPI efi_cout_reset(
518 struct efi_simple_text_output_protocol *this,
519 char extended_verification)
520{
521 EFI_ENTRY("%p, %d", this, extended_verification);
522
523
524 EFI_CALL(efi_cout_clear_screen(this));
525
526 efi_con_mode.attribute = 0x07;
527 printf(ESC "[0;37;40m");
528
529 return EFI_EXIT(EFI_SUCCESS);
530}
531
532
533
534
535
536
537
538
539
540
541
542
543
544static efi_status_t EFIAPI efi_cout_set_cursor_position(
545 struct efi_simple_text_output_protocol *this,
546 unsigned long column, unsigned long row)
547{
548 efi_status_t ret = EFI_SUCCESS;
549 struct simple_text_output_mode *con = &efi_con_mode;
550 struct cout_mode *mode = &efi_cout_modes[con->mode];
551
552 EFI_ENTRY("%p, %ld, %ld", this, column, row);
553
554
555 if (!this) {
556 ret = EFI_INVALID_PARAMETER;
557 goto out;
558 }
559 if (row >= mode->rows || column >= mode->columns) {
560 ret = EFI_UNSUPPORTED;
561 goto out;
562 }
563
564
565
566
567
568 printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
569 efi_con_mode.cursor_column = column;
570 efi_con_mode.cursor_row = row;
571out:
572 return EFI_EXIT(ret);
573}
574
575
576
577
578
579
580
581
582
583
584
585
586static efi_status_t EFIAPI efi_cout_enable_cursor(
587 struct efi_simple_text_output_protocol *this,
588 bool enable)
589{
590 EFI_ENTRY("%p, %d", this, enable);
591
592 printf(ESC"[?25%c", enable ? 'h' : 'l');
593 efi_con_mode.cursor_visible = !!enable;
594
595 return EFI_EXIT(EFI_SUCCESS);
596}
597
598struct efi_simple_text_output_protocol efi_con_out = {
599 .reset = efi_cout_reset,
600 .output_string = efi_cout_output_string,
601 .test_string = efi_cout_test_string,
602 .query_mode = efi_cout_query_mode,
603 .set_mode = efi_cout_set_mode,
604 .set_attribute = efi_cout_set_attribute,
605 .clear_screen = efi_cout_clear_screen,
606 .set_cursor_position = efi_cout_set_cursor_position,
607 .enable_cursor = efi_cout_enable_cursor,
608 .mode = (void*)&efi_con_mode,
609};
610
611
612
613
614
615
616
617
618struct efi_cin_notify_function {
619 struct list_head link;
620 struct efi_key_data key;
621 efi_status_t (EFIAPI *function)
622 (struct efi_key_data *key_data);
623};
624
625static bool key_available;
626static struct efi_key_data next_key;
627static LIST_HEAD(cin_notify_functions);
628
629
630
631
632
633
634
635void set_shift_mask(int mod, struct efi_key_state *key_state)
636{
637 key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
638 if (mod) {
639 --mod;
640 if (mod & 1)
641 key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
642 if (mod & 2)
643 key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
644 if (mod & 4)
645 key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
646 if (!mod || (mod & 8))
647 key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
648 }
649}
650
651
652
653
654
655
656
657
658
659static int analyze_modifiers(struct efi_key_state *key_state)
660{
661 int c, mod = 0, ret = 0;
662
663 c = getchar();
664
665 if (c != ';') {
666 ret = c;
667 if (c == '~')
668 goto out;
669 c = getchar();
670 }
671 for (;;) {
672 switch (c) {
673 case '0'...'9':
674 mod *= 10;
675 mod += c - '0';
676
677 case ';':
678 c = getchar();
679 break;
680 default:
681 goto out;
682 }
683 }
684out:
685 set_shift_mask(mod, key_state);
686 if (!ret)
687 ret = c;
688 return ret;
689}
690
691
692
693
694
695
696
697static efi_status_t efi_cin_read_key(struct efi_key_data *key)
698{
699 struct efi_input_key pressed_key = {
700 .scan_code = 0,
701 .unicode_char = 0,
702 };
703 s32 ch;
704
705 if (console_read_unicode(&ch))
706 return EFI_NOT_READY;
707
708 key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
709 key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
710
711
712 if (ch >= 0x10000)
713 ch = '?';
714
715 switch (ch) {
716 case 0x1b:
717
718
719
720
721
722
723 udelay(10000);
724 if (!tstc()) {
725 pressed_key.scan_code = 23;
726 break;
727 }
728
729
730
731
732 ch = getchar();
733 switch (ch) {
734 case cESC:
735 pressed_key.scan_code = 23;
736 break;
737 case 'O':
738 ch = getchar();
739
740 if (ch == 'F') {
741 pressed_key.scan_code = 6;
742 break;
743 } else if (ch < 'P') {
744 set_shift_mask(ch - '0', &key->key_state);
745 ch = getchar();
746 }
747 pressed_key.scan_code = ch - 'P' + 11;
748 break;
749 case '[':
750 ch = getchar();
751 switch (ch) {
752 case 'A'...'D':
753 pressed_key.scan_code = ch - 'A' + 1;
754 break;
755 case 'F':
756 pressed_key.scan_code = 6;
757 break;
758 case 'H':
759 pressed_key.scan_code = 5;
760 break;
761 case '1':
762 ch = analyze_modifiers(&key->key_state);
763 switch (ch) {
764 case '1'...'5':
765 pressed_key.scan_code = ch - '1' + 11;
766 break;
767 case '6'...'9':
768 pressed_key.scan_code = ch - '6' + 15;
769 break;
770 case 'A'...'D':
771 pressed_key.scan_code = ch - 'A' + 1;
772 break;
773 case 'F':
774 pressed_key.scan_code = 6;
775 break;
776 case 'H':
777 pressed_key.scan_code = 5;
778 break;
779 case '~':
780 pressed_key.scan_code = 5;
781 break;
782 }
783 break;
784 case '2':
785 ch = analyze_modifiers(&key->key_state);
786 switch (ch) {
787 case '0'...'1':
788 pressed_key.scan_code = ch - '0' + 19;
789 break;
790 case '3'...'4':
791 pressed_key.scan_code = ch - '3' + 21;
792 break;
793 case '~':
794 pressed_key.scan_code = 7;
795 break;
796 }
797 break;
798 case '3':
799 pressed_key.scan_code = 8;
800 analyze_modifiers(&key->key_state);
801 break;
802 case '5':
803 pressed_key.scan_code = 9;
804 analyze_modifiers(&key->key_state);
805 break;
806 case '6':
807 pressed_key.scan_code = 10;
808 analyze_modifiers(&key->key_state);
809 break;
810 }
811 break;
812 default:
813
814 set_shift_mask(3, &key->key_state);
815 }
816 break;
817 case 0x7f:
818
819 ch = 0x08;
820 }
821 if (pressed_key.scan_code) {
822 key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
823 } else {
824 pressed_key.unicode_char = ch;
825
826
827
828
829
830 if (ch >= 0x01 && ch <= 0x1f) {
831 key->key_state.key_shift_state |=
832 EFI_SHIFT_STATE_VALID;
833 switch (ch) {
834 case 0x01 ... 0x07:
835 case 0x0b ... 0x0c:
836 case 0x0e ... 0x1f:
837 key->key_state.key_shift_state |=
838 EFI_LEFT_CONTROL_PRESSED;
839 }
840 }
841 }
842 key->key = pressed_key;
843
844 return EFI_SUCCESS;
845}
846
847
848
849
850static void efi_cin_notify(void)
851{
852 struct efi_cin_notify_function *item;
853
854 list_for_each_entry(item, &cin_notify_functions, link) {
855 bool match = true;
856
857
858 if (item->key.key.unicode_char || item->key.key.scan_code) {
859 if (item->key.key.unicode_char !=
860 next_key.key.unicode_char ||
861 item->key.key.scan_code != next_key.key.scan_code)
862 match = false;
863 }
864 if (item->key.key_state.key_shift_state &&
865 item->key.key_state.key_shift_state !=
866 next_key.key_state.key_shift_state)
867 match = false;
868
869 if (match)
870
871 EFI_CALL(item->function(&next_key));
872 }
873}
874
875
876
877
878static void efi_cin_check(void)
879{
880 efi_status_t ret;
881
882 if (key_available) {
883 efi_signal_event(efi_con_in.wait_for_key);
884 return;
885 }
886
887 if (tstc()) {
888 ret = efi_cin_read_key(&next_key);
889 if (ret == EFI_SUCCESS) {
890 key_available = true;
891
892
893 efi_cin_notify();
894
895
896 if (key_available)
897 efi_signal_event(efi_con_in.wait_for_key);
898 }
899 }
900}
901
902
903
904
905static void efi_cin_empty_buffer(void)
906{
907 while (tstc())
908 getchar();
909 key_available = false;
910}
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926static efi_status_t EFIAPI efi_cin_reset_ex(
927 struct efi_simple_text_input_ex_protocol *this,
928 bool extended_verification)
929{
930 efi_status_t ret = EFI_SUCCESS;
931
932 EFI_ENTRY("%p, %d", this, extended_verification);
933
934
935 if (!this) {
936 ret = EFI_INVALID_PARAMETER;
937 goto out;
938 }
939
940 efi_cin_empty_buffer();
941out:
942 return EFI_EXIT(ret);
943}
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
959 struct efi_simple_text_input_ex_protocol *this,
960 struct efi_key_data *key_data)
961{
962 efi_status_t ret = EFI_SUCCESS;
963
964 EFI_ENTRY("%p, %p", this, key_data);
965
966
967 if (!this || !key_data) {
968 ret = EFI_INVALID_PARAMETER;
969 goto out;
970 }
971
972
973 efi_timer_check();
974
975
976 efi_cin_check();
977
978 if (!key_available) {
979 ret = EFI_NOT_READY;
980 goto out;
981 }
982
983
984
985
986 switch (next_key.key.unicode_char) {
987 case 0x01 ... 0x07:
988 case 0x0b ... 0x0c:
989 case 0x0e ... 0x1a:
990 if (!(next_key.key_state.key_toggle_state &
991 EFI_CAPS_LOCK_ACTIVE) ^
992 !(next_key.key_state.key_shift_state &
993 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)))
994 next_key.key.unicode_char += 0x40;
995 else
996 next_key.key.unicode_char += 0x60;
997 }
998 *key_data = next_key;
999 key_available = false;
1000 efi_con_in.wait_for_key->is_signaled = false;
1001
1002out:
1003 return EFI_EXIT(ret);
1004}
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019static efi_status_t EFIAPI efi_cin_set_state(
1020 struct efi_simple_text_input_ex_protocol *this,
1021 u8 *key_toggle_state)
1022{
1023 EFI_ENTRY("%p, %p", this, key_toggle_state);
1024
1025
1026
1027
1028
1029
1030
1031 return EFI_EXIT(EFI_UNSUPPORTED);
1032}
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049static efi_status_t EFIAPI efi_cin_register_key_notify(
1050 struct efi_simple_text_input_ex_protocol *this,
1051 struct efi_key_data *key_data,
1052 efi_status_t (EFIAPI *key_notify_function)(
1053 struct efi_key_data *key_data),
1054 void **notify_handle)
1055{
1056 efi_status_t ret = EFI_SUCCESS;
1057 struct efi_cin_notify_function *notify_function;
1058
1059 EFI_ENTRY("%p, %p, %p, %p",
1060 this, key_data, key_notify_function, notify_handle);
1061
1062
1063 if (!this || !key_data || !key_notify_function || !notify_handle) {
1064 ret = EFI_INVALID_PARAMETER;
1065 goto out;
1066 }
1067
1068 EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
1069 key_data->key.unicode_char,
1070 key_data->key.scan_code,
1071 key_data->key_state.key_shift_state,
1072 key_data->key_state.key_toggle_state);
1073
1074 notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
1075 if (!notify_function) {
1076 ret = EFI_OUT_OF_RESOURCES;
1077 goto out;
1078 }
1079 notify_function->key = *key_data;
1080 notify_function->function = key_notify_function;
1081 list_add_tail(¬ify_function->link, &cin_notify_functions);
1082 *notify_handle = notify_function;
1083out:
1084 return EFI_EXIT(ret);
1085}
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100static efi_status_t EFIAPI efi_cin_unregister_key_notify(
1101 struct efi_simple_text_input_ex_protocol *this,
1102 void *notification_handle)
1103{
1104 efi_status_t ret = EFI_INVALID_PARAMETER;
1105 struct efi_cin_notify_function *item, *notify_function =
1106 notification_handle;
1107
1108 EFI_ENTRY("%p, %p", this, notification_handle);
1109
1110
1111 if (!this || !notification_handle)
1112 goto out;
1113
1114 list_for_each_entry(item, &cin_notify_functions, link) {
1115 if (item == notify_function) {
1116 ret = EFI_SUCCESS;
1117 break;
1118 }
1119 }
1120 if (ret != EFI_SUCCESS)
1121 goto out;
1122
1123
1124 list_del(¬ify_function->link);
1125 free(notify_function);
1126out:
1127 return EFI_EXIT(ret);
1128}
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144static efi_status_t EFIAPI efi_cin_reset
1145 (struct efi_simple_text_input_protocol *this,
1146 bool extended_verification)
1147{
1148 efi_status_t ret = EFI_SUCCESS;
1149
1150 EFI_ENTRY("%p, %d", this, extended_verification);
1151
1152
1153 if (!this) {
1154 ret = EFI_INVALID_PARAMETER;
1155 goto out;
1156 }
1157
1158 efi_cin_empty_buffer();
1159out:
1160 return EFI_EXIT(ret);
1161}
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176static efi_status_t EFIAPI efi_cin_read_key_stroke
1177 (struct efi_simple_text_input_protocol *this,
1178 struct efi_input_key *key)
1179{
1180 efi_status_t ret = EFI_SUCCESS;
1181
1182 EFI_ENTRY("%p, %p", this, key);
1183
1184
1185 if (!this || !key) {
1186 ret = EFI_INVALID_PARAMETER;
1187 goto out;
1188 }
1189
1190
1191 efi_timer_check();
1192
1193
1194 efi_cin_check();
1195
1196 if (!key_available) {
1197 ret = EFI_NOT_READY;
1198 goto out;
1199 }
1200 *key = next_key.key;
1201 key_available = false;
1202 efi_con_in.wait_for_key->is_signaled = false;
1203out:
1204 return EFI_EXIT(ret);
1205}
1206
1207static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
1208 .reset = efi_cin_reset_ex,
1209 .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
1210 .wait_for_key_ex = NULL,
1211 .set_state = efi_cin_set_state,
1212 .register_key_notify = efi_cin_register_key_notify,
1213 .unregister_key_notify = efi_cin_unregister_key_notify,
1214};
1215
1216struct efi_simple_text_input_protocol efi_con_in = {
1217 .reset = efi_cin_reset,
1218 .read_key_stroke = efi_cin_read_key_stroke,
1219 .wait_for_key = NULL,
1220};
1221
1222static struct efi_event *console_timer_event;
1223
1224
1225
1226
1227
1228
1229
1230static void EFIAPI efi_console_timer_notify(struct efi_event *event,
1231 void *context)
1232{
1233 EFI_ENTRY("%p, %p", event, context);
1234 efi_cin_check();
1235 EFI_EXIT(EFI_SUCCESS);
1236}
1237
1238
1239
1240
1241
1242
1243
1244static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
1245{
1246 EFI_ENTRY("%p, %p", event, context);
1247 efi_cin_check();
1248 EFI_EXIT(EFI_SUCCESS);
1249}
1250
1251
1252
1253
1254
1255
1256
1257
1258efi_status_t efi_console_register(void)
1259{
1260 efi_status_t r;
1261 efi_handle_t console_output_handle;
1262 efi_handle_t console_input_handle;
1263
1264
1265 query_console_size();
1266
1267
1268 r = efi_create_handle(&console_output_handle);
1269 if (r != EFI_SUCCESS)
1270 goto out_of_memory;
1271
1272 r = efi_add_protocol(console_output_handle,
1273 &efi_guid_text_output_protocol, &efi_con_out);
1274 if (r != EFI_SUCCESS)
1275 goto out_of_memory;
1276 systab.con_out_handle = console_output_handle;
1277 systab.stderr_handle = console_output_handle;
1278
1279 r = efi_create_handle(&console_input_handle);
1280 if (r != EFI_SUCCESS)
1281 goto out_of_memory;
1282
1283 r = efi_add_protocol(console_input_handle,
1284 &efi_guid_text_input_protocol, &efi_con_in);
1285 if (r != EFI_SUCCESS)
1286 goto out_of_memory;
1287 systab.con_in_handle = console_input_handle;
1288 r = efi_add_protocol(console_input_handle,
1289 &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
1290 if (r != EFI_SUCCESS)
1291 goto out_of_memory;
1292
1293
1294 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
1295 NULL, NULL, &efi_con_in.wait_for_key);
1296 if (r != EFI_SUCCESS) {
1297 printf("ERROR: Failed to register WaitForKey event\n");
1298 return r;
1299 }
1300 efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
1301 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
1302 efi_console_timer_notify, NULL, NULL,
1303 &console_timer_event);
1304 if (r != EFI_SUCCESS) {
1305 printf("ERROR: Failed to register console event\n");
1306 return r;
1307 }
1308
1309 r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50);
1310 if (r != EFI_SUCCESS)
1311 printf("ERROR: Failed to set console timer\n");
1312 return r;
1313out_of_memory:
1314 printf("ERROR: Out of memory\n");
1315 return r;
1316}
1317