]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/boot/efi/libefi/efi_console.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / sys / boot / efi / libefi / efi_console.c
1 /*-
2  * Copyright (c) 2000 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <efi.h>
31 #include <efilib.h>
32
33 #include "bootstrap.h"
34
35 static SIMPLE_TEXT_OUTPUT_INTERFACE     *conout;
36 static SIMPLE_INPUT_INTERFACE           *conin;
37
38 #ifdef TERM_EMU
39 #define DEFAULT_FGCOLOR EFI_LIGHTGRAY
40 #define DEFAULT_BGCOLOR EFI_BLACK
41
42 #define MAXARGS 8
43 static int args[MAXARGS], argc;
44 static int fg_c, bg_c, curx, cury;
45 static int esc;
46
47 void get_pos(int *x, int *y);
48 void curs_move(int *_x, int *_y, int x, int y);
49 static void CL(int);
50 void HO(void);
51 void end_term(void);
52 #endif
53
54 static void efi_cons_probe(struct console *);
55 static int efi_cons_init(int);
56 void efi_cons_putchar(int);
57 int efi_cons_getchar(void);
58 void efi_cons_efiputchar(int);
59 int efi_cons_poll(void);
60
61 struct console efi_console = {
62         "efi",
63         "EFI console",
64         0,
65         efi_cons_probe,
66         efi_cons_init,
67         efi_cons_putchar,
68         efi_cons_getchar,
69         efi_cons_poll
70 };
71
72 #ifdef TERM_EMU
73
74 /* Get cursor position. */
75 void
76 get_pos(int *x, int *y)
77 {
78         *x = conout->Mode->CursorColumn;
79         *y = conout->Mode->CursorRow;
80 }
81
82 /* Move cursor to x rows and y cols (0-based). */
83 void
84 curs_move(int *_x, int *_y, int x, int y)
85 {
86         conout->SetCursorPosition(conout, x, y);
87         if (_x != NULL)
88                 *_x = conout->Mode->CursorColumn;
89         if (_y != NULL)
90                 *_y = conout->Mode->CursorRow;
91 }
92
93 /* Clear internal state of the terminal emulation code. */
94 void
95 end_term(void)
96 {
97         esc = 0;
98         argc = -1;
99 }
100
101 #endif
102
103 static void
104 efi_cons_probe(struct console *cp)
105 {
106         conout = ST->ConOut;
107         conin = ST->ConIn;
108         cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
109 }
110
111 static int
112 efi_cons_init(int arg)
113 {
114         conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
115             DEFAULT_BGCOLOR));
116 #ifdef TERM_EMU
117         end_term();
118         get_pos(&curx, &cury);
119         curs_move(&curx, &cury, curx, cury);
120         fg_c = DEFAULT_FGCOLOR;
121         bg_c = DEFAULT_BGCOLOR;
122 #endif
123         conout->EnableCursor(conout, TRUE);
124         return 0;
125 }
126
127 static void
128 efi_cons_rawputchar(int c)
129 {
130         int i;
131         UINTN x, y;
132         conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
133
134         if (c == '\t')
135                 /* XXX lame tab expansion */
136                 for (i = 0; i < 8; i++)
137                         efi_cons_rawputchar(' ');
138         else {
139 #ifndef TERM_EMU
140                 if (c == '\n')
141                         efi_cons_efiputchar('\r');
142                 else
143                         efi_cons_efiputchar(c);
144 #else
145                 switch (c) {
146                 case '\r':
147                         curx = 0;
148                         curs_move(&curx, &cury, curx, cury);
149                         return;
150                 case '\n':
151                         cury++;
152                         if (cury >= y) {
153                                 efi_cons_efiputchar('\n');
154                                 cury--;
155                         } else
156                                 curs_move(&curx, &cury, curx, cury);
157                         return;
158                 case '\b':
159                         if (curx > 0) {
160                                 curx--;
161                                 curs_move(&curx, &cury, curx, cury);
162                         }
163                         return;
164                 default:
165                         efi_cons_efiputchar(c);
166                         curx++;
167                         if (curx > x-1) {
168                                 curx = 0;
169                                 cury++;
170                         }
171                         if (cury > y-1) {
172                                 curx = 0;
173                                 cury--;
174                         }
175                 }
176                 curs_move(&curx, &cury, curx, cury);
177 #endif
178         }
179 }
180
181 /* Gracefully exit ESC-sequence processing in case of misunderstanding. */
182 static void
183 bail_out(int c)
184 {
185         char buf[16], *ch;
186         int i;
187
188         if (esc) {
189                 efi_cons_rawputchar('\033');
190                 if (esc != '\033')
191                         efi_cons_rawputchar(esc);
192                 for (i = 0; i <= argc; ++i) {
193                         sprintf(buf, "%d", args[i]);
194                         ch = buf;
195                         while (*ch)
196                                 efi_cons_rawputchar(*ch++);
197                 }
198         }
199         efi_cons_rawputchar(c);
200         end_term();
201 }
202
203 /* Clear display from current position to end of screen. */
204 static void
205 CD(void) {
206         int i;
207         UINTN x, y;
208
209         get_pos(&curx, &cury);
210         if (curx == 0 && cury == 0) {
211                 conout->ClearScreen(conout);
212                 end_term();
213                 return;
214         }
215
216         conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
217         CL(0);  /* clear current line from cursor to end */
218         for (i = cury + 1; i < y-1; i++) {
219                 curs_move(NULL, NULL, 0, i);
220                 CL(0);
221         }
222         curs_move(NULL, NULL, curx, cury);
223         end_term();
224 }
225
226 /*
227  * Absolute cursor move to args[0] rows and args[1] columns
228  * (the coordinates are 1-based).
229  */
230 static void
231 CM(void)
232 {
233         if (args[0] > 0)
234                 args[0]--;
235         if (args[1] > 0)
236                 args[1]--;
237         curs_move(&curx, &cury, args[1], args[0]);
238         end_term();
239 }
240
241 /* Home cursor (left top corner), also called from mode command. */
242 void
243 HO(void)
244 {
245         argc = 1;
246         args[0] = args[1] = 1;
247         CM();
248 }
249
250 /* Clear line from current position to end of line */
251 static void
252 CL(int direction)
253 {
254         int i, len;
255         UINTN x, y;
256         CHAR16 *line;
257
258         conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
259         switch (direction) {
260         case 0:         /* from cursor to end */
261                 len = x - curx + 1;
262                 break;
263         case 1:         /* from beginning to cursor */
264                 len = curx;
265                 break;
266         case 2:         /* entire line */
267                 len = x;
268                 break;
269         }
270
271         if (cury == y - 1)
272                 len--;
273
274         line = malloc(len * sizeof (CHAR16));
275         if (line == NULL) {
276                 printf("out of memory\n");
277                 return;
278         }
279         for (i = 0; i < len; i++)
280                 line[i] = ' ';
281         line[len-1] = 0;
282
283         if (direction != 0)
284                 curs_move(NULL, NULL, 0, cury);
285
286         conout->OutputString(conout, line);
287         /* restore cursor position */
288         curs_move(NULL, NULL, curx, cury);
289         free(line);
290         end_term();
291 }
292
293 static void
294 get_arg(int c)
295 {
296         if (argc < 0)
297                 argc = 0;
298         args[argc] *= 10;
299         args[argc] += c - '0';
300 }
301
302 /* Emulate basic capabilities of cons25 terminal */
303 static void
304 efi_term_emu(int c)
305 {
306         static int ansi_col[] = {
307                 0, 4, 2, 6, 1, 5, 3, 7
308         };
309         int t, i;
310
311         switch (esc) {
312         case 0:
313                 switch (c) {
314                 case '\033':
315                         esc = c;
316                         break;
317                 default:
318                         efi_cons_rawputchar(c);
319                         break;
320                 }
321                 break;
322         case '\033':
323                 switch (c) {
324                 case '[':
325                         esc = c;
326                         args[0] = 0;
327                         argc = -1;
328                         break;
329                 default:
330                         bail_out(c);
331                         break;
332                 }
333                 break;
334         case '[':
335                 switch (c) {
336                 case ';':
337                         if (argc < 0)
338                                 argc = 0;
339                         else if (argc + 1 >= MAXARGS)
340                                 bail_out(c);
341                         else
342                                 args[++argc] = 0;
343                         break;
344                 case 'H':               /* ho = \E[H */
345                         if (argc < 0)
346                                 HO();
347                         else if (argc == 1)
348                                 CM();
349                         else
350                                 bail_out(c);
351                         break;
352                 case 'J':               /* cd = \E[J */
353                         if (argc < 0)
354                                 CD();
355                         else
356                                 bail_out(c);
357                         break;
358                 case 'm':
359                         if (argc < 0) {
360                                 fg_c = DEFAULT_FGCOLOR;
361                                 bg_c = DEFAULT_BGCOLOR;
362                         }
363                         for (i = 0; i <= argc; ++i) {
364                                 switch (args[i]) {
365                                 case 0:         /* back to normal */
366                                         fg_c = DEFAULT_FGCOLOR;
367                                         bg_c = DEFAULT_BGCOLOR;
368                                         break;
369                                 case 1:         /* bold */
370                                         fg_c |= 0x8;
371                                         break;
372                                 case 4:         /* underline */
373                                 case 5:         /* blink */
374                                         bg_c |= 0x8;
375                                         break;
376                                 case 7:         /* reverse */
377                                         t = fg_c;
378                                         fg_c = bg_c;
379                                         bg_c = t;
380                                         break;
381                                 case 30: case 31: case 32: case 33:
382                                 case 34: case 35: case 36: case 37:
383                                         fg_c = ansi_col[args[i] - 30];
384                                         break;
385                                 case 39:        /* normal */
386                                         fg_c = DEFAULT_FGCOLOR;
387                                         break;
388                                 case 40: case 41: case 42: case 43:
389                                 case 44: case 45: case 46: case 47:
390                                         bg_c = ansi_col[args[i] - 40];
391                                         break;
392                                 case 49:        /* normal */
393                                         bg_c = DEFAULT_BGCOLOR;
394                                         break;
395                                 }
396                         }
397                         conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
398                         end_term();
399                         break;
400                 default:
401                         if (isdigit(c))
402                                 get_arg(c);
403                         else
404                                 bail_out(c);
405                         break;
406                 }
407                 break;
408         default:
409                 bail_out(c);
410                 break;
411         }
412 }
413
414 void
415 efi_cons_putchar(int c)
416 {
417 #ifdef TERM_EMU
418         efi_term_emu(c);
419 #else
420         efi_cons_rawputchar(c);
421 #endif
422 }
423
424 int
425 efi_cons_getchar()
426 {
427         EFI_INPUT_KEY key;
428         EFI_STATUS status;
429         UINTN junk;
430
431         /* Try to read a key stroke. We wait for one if none is pending. */
432         status = conin->ReadKeyStroke(conin, &key);
433         if (status == EFI_NOT_READY) {
434                 BS->WaitForEvent(1, &conin->WaitForKey, &junk);
435                 status = conin->ReadKeyStroke(conin, &key);
436         }
437         switch (key.ScanCode) {
438         case 0x17: /* ESC */
439                 return (0x1b);  /* esc */
440         }
441
442         /* this can return  */
443         return (key.UnicodeChar);
444 }
445
446 int
447 efi_cons_poll()
448 {
449         /* This can clear the signaled state. */
450         return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS);
451 }
452
453 /* Plain direct access to EFI OutputString(). */
454 void
455 efi_cons_efiputchar(int c)
456 {
457         CHAR16 buf[2];
458
459         /*
460          * translate box chars to unicode
461          */
462         switch (c) {
463         /* single frame */
464         case 0xb3: buf[0] = BOXDRAW_VERTICAL; break;
465         case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break;
466         case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break;
467         case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break;
468         case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break;
469         case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break;
470
471         /* double frame */
472         case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break;
473         case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break;
474         case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break;
475         case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break;
476         case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break;
477         case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break;
478
479         default:
480                 buf[0] = c;
481         }
482         buf[1] = 0;     /* terminate string */
483
484         conout->OutputString(conout, buf);
485 }