efi_console.c revision 293233
177943Sdfr/*- 277943Sdfr * Copyright (c) 2000 Doug Rabson 377943Sdfr * All rights reserved. 477943Sdfr * 577943Sdfr * Redistribution and use in source and binary forms, with or without 677943Sdfr * modification, are permitted provided that the following conditions 777943Sdfr * are met: 877943Sdfr * 1. Redistributions of source code must retain the above copyright 977943Sdfr * notice, this list of conditions and the following disclaimer. 1077943Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1177943Sdfr * notice, this list of conditions and the following disclaimer in the 1277943Sdfr * documentation and/or other materials provided with the distribution. 1377943Sdfr * 1477943Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1577943Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1677943Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1777943Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1877943Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1977943Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2077943Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2177943Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2277943Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2377943Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2477943Sdfr * SUCH DAMAGE. 2577943Sdfr */ 2677943Sdfr 27113038Sobrien#include <sys/cdefs.h> 28113038Sobrien__FBSDID("$FreeBSD: head/sys/boot/efi/libefi/efi_console.c 293233 2016-01-06 15:38:39Z emaste $"); 2978327Sobrien 3077943Sdfr#include <efi.h> 3177943Sdfr#include <efilib.h> 3277943Sdfr 3377943Sdfr#include "bootstrap.h" 3477943Sdfr 3577943Sdfrstatic SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 3677943Sdfrstatic SIMPLE_INPUT_INTERFACE *conin; 3777943Sdfr 38293233Semaste#ifdef TERM_EMU 39293233Semaste#define DEFAULT_FGCOLOR EFI_LIGHTGRAY 40293233Semaste#define DEFAULT_BGCOLOR EFI_BLACK 41293233Semaste 42293233Semaste#define MAXARGS 8 43293233Semastestatic int args[MAXARGS], argc; 44293233Semastestatic int fg_c, bg_c, curx, cury; 45293233Semastestatic int esc; 46293233Semaste 47293233Semastevoid get_pos(int *x, int *y); 48293233Semastevoid curs_move(int *_x, int *_y, int x, int y); 49293233Semastestatic void CL(int); 50293233Semaste#endif 51293233Semaste 52293233Semastestatic void efi_cons_probe(struct console *); 53293233Semastestatic int efi_cons_init(int); 54293233Semastevoid efi_cons_putchar(int); 55293233Semasteint efi_cons_getchar(void); 56293233Semastevoid efi_cons_efiputchar(int); 57293233Semasteint efi_cons_poll(void); 58293233Semaste 59293233Semastestruct console efi_console = { 60293233Semaste "efi", 61293233Semaste "EFI console", 62293233Semaste 0, 63293233Semaste efi_cons_probe, 64293233Semaste efi_cons_init, 65293233Semaste efi_cons_putchar, 66293233Semaste efi_cons_getchar, 67293233Semaste efi_cons_poll 68293233Semaste}; 69293233Semaste 70293233Semaste#ifdef TERM_EMU 71293233Semaste 72293233Semaste/* Get cursor position. */ 73293233Semastevoid 74293233Semasteget_pos(int *x, int *y) 75293233Semaste{ 76293233Semaste *x = conout->Mode->CursorColumn; 77293233Semaste *y = conout->Mode->CursorRow; 78293233Semaste} 79293233Semaste 80293233Semaste/* Move cursor to x rows and y cols (0-based). */ 81293233Semastevoid 82293233Semastecurs_move(int *_x, int *_y, int x, int y) 83293233Semaste{ 84293233Semaste conout->SetCursorPosition(conout, x, y); 85293233Semaste if (_x != NULL) 86293233Semaste *_x = conout->Mode->CursorColumn; 87293233Semaste if (_y != NULL) 88293233Semaste *_y = conout->Mode->CursorRow; 89293233Semaste} 90293233Semaste 91293233Semaste/* Clear internal state of the terminal emulation code. */ 92293233Semastevoid 93293233Semasteend_term(void) 94293233Semaste{ 95293233Semaste esc = 0; 96293233Semaste argc = -1; 97293233Semaste} 98293233Semaste 99293233Semaste#endif 100293233Semaste 10177943Sdfrstatic void 10277943Sdfrefi_cons_probe(struct console *cp) 10377943Sdfr{ 10477943Sdfr conout = ST->ConOut; 10577943Sdfr conin = ST->ConIn; 10677943Sdfr cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; 10777943Sdfr} 10877943Sdfr 10977943Sdfrstatic int 11077943Sdfrefi_cons_init(int arg) 11177943Sdfr{ 112293233Semaste conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR, 113293233Semaste DEFAULT_BGCOLOR)); 114293233Semaste#ifdef TERM_EMU 115293233Semaste end_term(); 116293233Semaste get_pos(&curx, &cury); 117293233Semaste curs_move(&curx, &cury, curx, cury); 118293233Semaste fg_c = DEFAULT_FGCOLOR; 119293233Semaste bg_c = DEFAULT_BGCOLOR; 120293233Semaste#endif 121293233Semaste conout->EnableCursor(conout, TRUE); 12277943Sdfr return 0; 12377943Sdfr} 12477943Sdfr 125293233Semastestatic void 126293233Semasteefi_cons_rawputchar(int c) 127293233Semaste{ 128293233Semaste int i; 129293233Semaste UINTN x, y; 130293233Semaste conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 131293233Semaste 132293233Semaste if (c == '\t') 133293233Semaste /* XXX lame tab expansion */ 134293233Semaste for (i = 0; i < 8; i++) 135293233Semaste efi_cons_rawputchar(' '); 136293233Semaste else { 137293233Semaste#ifndef TERM_EMU 138293233Semaste if (c == '\n') 139293233Semaste efi_cons_efiputchar('\r'); 140293233Semaste else 141293233Semaste efi_cons_efiputchar(c); 142293233Semaste#else 143293233Semaste switch (c) { 144293233Semaste case '\r': 145293233Semaste curx = 0; 146293233Semaste curs_move(&curx, &cury, curx, cury); 147293233Semaste return; 148293233Semaste case '\n': 149293233Semaste cury++; 150293233Semaste if (cury >= y) { 151293233Semaste efi_cons_efiputchar('\n'); 152293233Semaste cury--; 153293233Semaste } else 154293233Semaste curs_move(&curx, &cury, curx, cury); 155293233Semaste return; 156293233Semaste case '\b': 157293233Semaste if (curx > 0) { 158293233Semaste curx--; 159293233Semaste curs_move(&curx, &cury, curx, cury); 160293233Semaste } 161293233Semaste return; 162293233Semaste default: 163293233Semaste efi_cons_efiputchar(c); 164293233Semaste curx++; 165293233Semaste if (curx > x-1) { 166293233Semaste curx = 0; 167293233Semaste cury++; 168293233Semaste } 169293233Semaste if (cury > y-1) { 170293233Semaste curx = 0; 171293233Semaste cury--; 172293233Semaste } 173293233Semaste } 174293233Semaste curs_move(&curx, &cury, curx, cury); 175293233Semaste#endif 176293233Semaste } 177293233Semaste} 178293233Semaste 179293233Semaste/* Gracefully exit ESC-sequence processing in case of misunderstanding. */ 180293233Semastestatic void 181293233Semastebail_out(int c) 182293233Semaste{ 183293233Semaste char buf[16], *ch; 184293233Semaste int i; 185293233Semaste 186293233Semaste if (esc) { 187293233Semaste efi_cons_rawputchar('\033'); 188293233Semaste if (esc != '\033') 189293233Semaste efi_cons_rawputchar(esc); 190293233Semaste for (i = 0; i <= argc; ++i) { 191293233Semaste sprintf(buf, "%d", args[i]); 192293233Semaste ch = buf; 193293233Semaste while (*ch) 194293233Semaste efi_cons_rawputchar(*ch++); 195293233Semaste } 196293233Semaste } 197293233Semaste efi_cons_rawputchar(c); 198293233Semaste end_term(); 199293233Semaste} 200293233Semaste 201293233Semaste/* Clear display from current position to end of screen. */ 202293233Semastestatic void 203293233SemasteCD(void) { 204293233Semaste int i; 205293233Semaste UINTN x, y; 206293233Semaste 207293233Semaste get_pos(&curx, &cury); 208293233Semaste if (curx == 0 && cury == 0) { 209293233Semaste conout->ClearScreen(conout); 210293233Semaste end_term(); 211293233Semaste return; 212293233Semaste } 213293233Semaste 214293233Semaste conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 215293233Semaste CL(0); /* clear current line from cursor to end */ 216293233Semaste for (i = cury + 1; i < y-1; i++) { 217293233Semaste curs_move(NULL, NULL, 0, i); 218293233Semaste CL(0); 219293233Semaste } 220293233Semaste curs_move(NULL, NULL, curx, cury); 221293233Semaste end_term(); 222293233Semaste} 223293233Semaste 224293233Semaste/* 225293233Semaste * Absolute cursor move to args[0] rows and args[1] columns 226293233Semaste * (the coordinates are 1-based). 227293233Semaste */ 228293233Semastestatic void 229293233SemasteCM(void) 230293233Semaste{ 231293233Semaste if (args[0] > 0) 232293233Semaste args[0]--; 233293233Semaste if (args[1] > 0) 234293233Semaste args[1]--; 235293233Semaste curs_move(&curx, &cury, args[1], args[0]); 236293233Semaste end_term(); 237293233Semaste} 238293233Semaste 239293233Semaste/* Home cursor (left top corner), also called from mode command. */ 24077943Sdfrvoid 241293233SemasteHO(void) 24277943Sdfr{ 243293233Semaste argc = 1; 244293233Semaste args[0] = args[1] = 1; 245293233Semaste CM(); 246293233Semaste} 24777943Sdfr 248293233Semaste/* Clear line from current position to end of line */ 249293233Semastestatic void 250293233SemasteCL(int direction) 251293233Semaste{ 252293233Semaste int i, len; 253293233Semaste UINTN x, y; 254293233Semaste CHAR16 *line; 25577943Sdfr 256293233Semaste conout->QueryMode(conout, conout->Mode->Mode, &x, &y); 257293233Semaste switch (direction) { 258293233Semaste case 0: /* from cursor to end */ 259293233Semaste len = x - curx + 1; 260293233Semaste break; 261293233Semaste case 1: /* from beginning to cursor */ 262293233Semaste len = curx; 263293233Semaste break; 264293233Semaste case 2: /* entire line */ 265293233Semaste len = x; 266293233Semaste break; 267293233Semaste } 26877943Sdfr 269293233Semaste if (cury == y - 1) 270293233Semaste len--; 271293233Semaste 272293233Semaste line = malloc(len * sizeof (CHAR16)); 273293233Semaste if (line == NULL) { 274293233Semaste printf("out of memory\n"); 275293233Semaste return; 276293233Semaste } 277293233Semaste for (i = 0; i < len; i++) 278293233Semaste line[i] = ' '; 279293233Semaste line[len-1] = 0; 280293233Semaste 281293233Semaste if (direction != 0) 282293233Semaste curs_move(NULL, NULL, 0, cury); 283293233Semaste 284293233Semaste conout->OutputString(conout, line); 285293233Semaste /* restore cursor position */ 286293233Semaste curs_move(NULL, NULL, curx, cury); 287293233Semaste free(line); 288293233Semaste end_term(); 28977943Sdfr} 29077943Sdfr 291293233Semastestatic void 292293233Semasteget_arg(int c) 293293233Semaste{ 294293233Semaste if (argc < 0) 295293233Semaste argc = 0; 296293233Semaste args[argc] *= 10; 297293233Semaste args[argc] += c - '0'; 298293233Semaste} 299293233Semaste 300293233Semaste/* Emulate basic capabilities of cons25 terminal */ 301293233Semastestatic void 302293233Semasteefi_term_emu(int c) 303293233Semaste{ 304293233Semaste static int ansi_col[] = { 305293233Semaste 0, 4, 2, 6, 1, 5, 3, 7 306293233Semaste }; 307293233Semaste int t, i; 308293233Semaste 309293233Semaste switch (esc) { 310293233Semaste case 0: 311293233Semaste switch (c) { 312293233Semaste case '\033': 313293233Semaste esc = c; 314293233Semaste break; 315293233Semaste default: 316293233Semaste efi_cons_rawputchar(c); 317293233Semaste break; 318293233Semaste } 319293233Semaste break; 320293233Semaste case '\033': 321293233Semaste switch (c) { 322293233Semaste case '[': 323293233Semaste esc = c; 324293233Semaste args[0] = 0; 325293233Semaste argc = -1; 326293233Semaste break; 327293233Semaste default: 328293233Semaste bail_out(c); 329293233Semaste break; 330293233Semaste } 331293233Semaste break; 332293233Semaste case '[': 333293233Semaste switch (c) { 334293233Semaste case ';': 335293233Semaste if (argc < 0) 336293233Semaste argc = 0; 337293233Semaste else if (argc + 1 >= MAXARGS) 338293233Semaste bail_out(c); 339293233Semaste else 340293233Semaste args[++argc] = 0; 341293233Semaste break; 342293233Semaste case 'H': /* ho = \E[H */ 343293233Semaste if (argc < 0) 344293233Semaste HO(); 345293233Semaste else if (argc == 1) 346293233Semaste CM(); 347293233Semaste else 348293233Semaste bail_out(c); 349293233Semaste break; 350293233Semaste case 'J': /* cd = \E[J */ 351293233Semaste if (argc < 0) 352293233Semaste CD(); 353293233Semaste else 354293233Semaste bail_out(c); 355293233Semaste break; 356293233Semaste case 'm': 357293233Semaste if (argc < 0) { 358293233Semaste fg_c = DEFAULT_FGCOLOR; 359293233Semaste bg_c = DEFAULT_BGCOLOR; 360293233Semaste } 361293233Semaste for (i = 0; i <= argc; ++i) { 362293233Semaste switch (args[i]) { 363293233Semaste case 0: /* back to normal */ 364293233Semaste fg_c = DEFAULT_FGCOLOR; 365293233Semaste bg_c = DEFAULT_BGCOLOR; 366293233Semaste break; 367293233Semaste case 1: /* bold */ 368293233Semaste fg_c |= 0x8; 369293233Semaste break; 370293233Semaste case 4: /* underline */ 371293233Semaste case 5: /* blink */ 372293233Semaste bg_c |= 0x8; 373293233Semaste break; 374293233Semaste case 7: /* reverse */ 375293233Semaste t = fg_c; 376293233Semaste fg_c = bg_c; 377293233Semaste bg_c = t; 378293233Semaste break; 379293233Semaste case 30: case 31: case 32: case 33: 380293233Semaste case 34: case 35: case 36: case 37: 381293233Semaste fg_c = ansi_col[args[i] - 30]; 382293233Semaste break; 383293233Semaste case 39: /* normal */ 384293233Semaste fg_c = DEFAULT_FGCOLOR; 385293233Semaste break; 386293233Semaste case 40: case 41: case 42: case 43: 387293233Semaste case 44: case 45: case 46: case 47: 388293233Semaste bg_c = ansi_col[args[i] - 40]; 389293233Semaste break; 390293233Semaste case 49: /* normal */ 391293233Semaste bg_c = DEFAULT_BGCOLOR; 392293233Semaste break; 393293233Semaste } 394293233Semaste } 395293233Semaste conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c)); 396293233Semaste end_term(); 397293233Semaste break; 398293233Semaste default: 399293233Semaste if (isdigit(c)) 400293233Semaste get_arg(c); 401293233Semaste else 402293233Semaste bail_out(c); 403293233Semaste break; 404293233Semaste } 405293233Semaste break; 406293233Semaste default: 407293233Semaste bail_out(c); 408293233Semaste break; 409293233Semaste } 410293233Semaste} 411293233Semaste 412293233Semastevoid 413293233Semasteefi_cons_putchar(int c) 414293233Semaste{ 415293233Semaste#ifdef TERM_EMU 416293233Semaste efi_term_emu(c); 417293233Semaste#else 418293233Semaste efi_cons_rawputchar(c); 419293233Semaste#endif 420293233Semaste} 421293233Semaste 42277943Sdfrint 42377943Sdfrefi_cons_getchar() 42477943Sdfr{ 42577943Sdfr EFI_INPUT_KEY key; 426107682Smarcel EFI_STATUS status; 42777943Sdfr UINTN junk; 42877943Sdfr 429107682Smarcel /* Try to read a key stroke. We wait for one if none is pending. */ 430107682Smarcel status = conin->ReadKeyStroke(conin, &key); 431107682Smarcel if (status == EFI_NOT_READY) { 432107682Smarcel BS->WaitForEvent(1, &conin->WaitForKey, &junk); 433107682Smarcel status = conin->ReadKeyStroke(conin, &key); 434107682Smarcel } 435293233Semaste switch (key.ScanCode) { 436293233Semaste case 0x17: /* ESC */ 437293233Semaste return (0x1b); /* esc */ 438293233Semaste } 439293233Semaste 440293233Semaste /* this can return */ 441107682Smarcel return (key.UnicodeChar); 44277943Sdfr} 44377943Sdfr 44477943Sdfrint 44577943Sdfrefi_cons_poll() 44677943Sdfr{ 447107682Smarcel /* This can clear the signaled state. */ 448107682Smarcel return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); 44977943Sdfr} 45077943Sdfr 451293233Semaste/* Plain direct access to EFI OutputString(). */ 452293233Semastevoid 453293233Semasteefi_cons_efiputchar(int c) 454293233Semaste{ 455293233Semaste CHAR16 buf[2]; 456293233Semaste 457293233Semaste /* 458293233Semaste * translate box chars to unicode 459293233Semaste */ 460293233Semaste switch (c) { 461293233Semaste /* single frame */ 462293233Semaste case 0xb3: buf[0] = BOXDRAW_VERTICAL; break; 463293233Semaste case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break; 464293233Semaste case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break; 465293233Semaste case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break; 466293233Semaste case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break; 467293233Semaste case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break; 468293233Semaste 469293233Semaste /* double frame */ 470293233Semaste case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break; 471293233Semaste case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break; 472293233Semaste case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break; 473293233Semaste case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break; 474293233Semaste case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break; 475293233Semaste case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break; 476293233Semaste 477293233Semaste default: 478293233Semaste buf[0] = c; 479293233Semaste } 480293233Semaste buf[1] = 0; /* terminate string */ 481293233Semaste 482293233Semaste conout->OutputString(conout, buf); 483293233Semaste} 484