1 1.15 manu /* $NetBSD: eficons.c,v 1.15 2025/06/19 15:00:17 manu Exp $ */ 2 1.1 nonaka 3 1.1 nonaka /*- 4 1.1 nonaka * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org> 5 1.1 nonaka * All rights reserved. 6 1.1 nonaka * 7 1.1 nonaka * Redistribution and use in source and binary forms, with or without 8 1.1 nonaka * modification, are permitted provided that the following conditions 9 1.1 nonaka * are met: 10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 11 1.1 nonaka * notice, this list of conditions and the following disclaimer. 12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 14 1.1 nonaka * documentation and/or other materials provided with the distribution. 15 1.1 nonaka * 16 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 nonaka * SUCH DAMAGE. 27 1.1 nonaka */ 28 1.1 nonaka 29 1.14 rin #include <sys/param.h> 30 1.1 nonaka #include <sys/bitops.h> 31 1.1 nonaka #include <sys/stdint.h> 32 1.1 nonaka 33 1.13 rin #include <comio_direct.h> 34 1.13 rin 35 1.1 nonaka #include "efiboot.h" 36 1.1 nonaka 37 1.1 nonaka #include "bootinfo.h" 38 1.1 nonaka #include "vbe.h" 39 1.1 nonaka 40 1.8 jmcneill #ifndef DEFAULT_GOP_MODE 41 1.9 jmcneill #define DEFAULT_GOP_MODE "1024x768" 42 1.8 jmcneill #endif 43 1.10 jmcneill #define FALLBACK_GOP_MODE 0 44 1.8 jmcneill 45 1.4 nonaka extern struct x86_boot_params boot_params; 46 1.4 nonaka 47 1.1 nonaka struct btinfo_console btinfo_console; 48 1.1 nonaka 49 1.1 nonaka static EFI_GRAPHICS_OUTPUT_PROTOCOL *efi_gop; 50 1.1 nonaka static int efi_gop_mode = -1; 51 1.1 nonaka static CHAR16 keybuf[16]; 52 1.1 nonaka static int keybuf_read = 0; 53 1.1 nonaka static int keybuf_write = 0; 54 1.1 nonaka 55 1.5 nonaka static SERIAL_IO_INTERFACE *serios[4]; 56 1.5 nonaka static int default_comspeed = 57 1.5 nonaka #if defined(CONSPEED) 58 1.5 nonaka CONSPEED; 59 1.5 nonaka #else 60 1.5 nonaka 9600; 61 1.5 nonaka #endif 62 1.5 nonaka static u_char serbuf[16]; 63 1.5 nonaka static int serbuf_read = 0; 64 1.5 nonaka static int serbuf_write = 0; 65 1.5 nonaka 66 1.13 rin static int raw_com_addr = 0; 67 1.13 rin 68 1.1 nonaka static void eficons_init_video(void); 69 1.1 nonaka static void efi_switch_video_to_text_mode(void); 70 1.1 nonaka 71 1.5 nonaka static int efi_cons_getc(void); 72 1.5 nonaka static int efi_cons_putc(int); 73 1.5 nonaka static int efi_cons_iskey(int); 74 1.5 nonaka static int efi_cons_waitforinputevent(uint64_t); 75 1.5 nonaka 76 1.5 nonaka static void efi_com_probe(void); 77 1.5 nonaka static bool efi_valid_com(int); 78 1.5 nonaka static int efi_com_init(int, int); 79 1.5 nonaka static int efi_com_getc(void); 80 1.5 nonaka static int efi_com_putc(int); 81 1.5 nonaka static int efi_com_status(int); 82 1.5 nonaka static int efi_com_waitforinputevent(uint64_t); 83 1.5 nonaka 84 1.13 rin static int raw_com_init(int, int); 85 1.13 rin static int raw_com_getc(void); 86 1.13 rin static int raw_com_putc(int); 87 1.13 rin static int raw_com_status(int); 88 1.13 rin static int raw_com_waitforinputevent(uint64_t); 89 1.13 rin 90 1.8 jmcneill static int efi_find_gop_mode(char *); 91 1.8 jmcneill 92 1.5 nonaka static int iodev; 93 1.5 nonaka static int (*internal_getchar)(void) = efi_cons_getc; 94 1.5 nonaka static int (*internal_putchar)(int) = efi_cons_putc; 95 1.5 nonaka static int (*internal_iskey)(int) = efi_cons_iskey; 96 1.5 nonaka static int (*internal_waitforinputevent)(uint64_t) = efi_cons_waitforinputevent; 97 1.5 nonaka 98 1.4 nonaka static int 99 1.4 nonaka getcomaddr(int idx) 100 1.4 nonaka { 101 1.4 nonaka static const short comioport[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; 102 1.4 nonaka 103 1.4 nonaka if (idx < __arraycount(comioport)) 104 1.4 nonaka return comioport[idx]; 105 1.4 nonaka return 0; 106 1.4 nonaka } 107 1.4 nonaka 108 1.4 nonaka /* 109 1.4 nonaka * XXX only pass console parameters to kernel. 110 1.4 nonaka */ 111 1.4 nonaka void 112 1.7 manu efi_consinit(int dev, int ioport, int speed) 113 1.4 nonaka { 114 1.5 nonaka int i; 115 1.4 nonaka 116 1.5 nonaka btinfo_console.speed = default_comspeed; 117 1.4 nonaka 118 1.4 nonaka switch (dev) { 119 1.4 nonaka case CONSDEV_AUTO: 120 1.5 nonaka for (i = 0; i < __arraycount(serios); i++) { 121 1.5 nonaka iodev = CONSDEV_COM0 + i; 122 1.5 nonaka if (!efi_valid_com(iodev)) 123 1.5 nonaka continue; 124 1.5 nonaka btinfo_console.addr = getcomaddr(i); 125 1.5 nonaka 126 1.5 nonaka efi_cons_putc('0' + i); 127 1.5 nonaka efi_com_init(btinfo_console.addr, btinfo_console.speed); 128 1.5 nonaka /* check for: 129 1.5 nonaka * 1. successful output 130 1.5 nonaka * 2. optionally, keypress within 7s 131 1.5 nonaka */ 132 1.5 nonaka if (efi_com_putc(':') && 133 1.5 nonaka efi_com_putc('-') && 134 1.5 nonaka efi_com_putc('(') && 135 1.5 nonaka awaitkey(7, 0)) 136 1.5 nonaka goto ok; 137 1.5 nonaka } 138 1.4 nonaka goto nocom; 139 1.5 nonaka ok: 140 1.5 nonaka break; 141 1.4 nonaka 142 1.4 nonaka case CONSDEV_COM0: 143 1.4 nonaka case CONSDEV_COM1: 144 1.4 nonaka case CONSDEV_COM2: 145 1.4 nonaka case CONSDEV_COM3: 146 1.4 nonaka iodev = dev; 147 1.4 nonaka btinfo_console.addr = ioport; 148 1.13 rin if (btinfo_console.addr == 0) 149 1.4 nonaka btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); 150 1.4 nonaka if (speed != 0) 151 1.4 nonaka btinfo_console.speed = speed; 152 1.5 nonaka efi_com_init(btinfo_console.addr, btinfo_console.speed); 153 1.4 nonaka break; 154 1.4 nonaka 155 1.4 nonaka case CONSDEV_COM0KBD: 156 1.4 nonaka case CONSDEV_COM1KBD: 157 1.4 nonaka case CONSDEV_COM2KBD: 158 1.4 nonaka case CONSDEV_COM3KBD: 159 1.4 nonaka iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0; 160 1.5 nonaka btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); 161 1.5 nonaka 162 1.5 nonaka efi_cons_putc('0' + iodev - CONSDEV_COM0); 163 1.5 nonaka efi_com_init(btinfo_console.addr, btinfo_console.speed); 164 1.5 nonaka /* check for: 165 1.5 nonaka * 1. successful output 166 1.5 nonaka * 2. optionally, keypress within 7s 167 1.5 nonaka */ 168 1.5 nonaka if (efi_com_putc(':') && 169 1.5 nonaka efi_com_putc('-') && 170 1.5 nonaka efi_com_putc('(') && 171 1.5 nonaka awaitkey(7, 0)) 172 1.5 nonaka goto kbd; 173 1.5 nonaka /*FALLTHROUGH*/ 174 1.4 nonaka case CONSDEV_PC: 175 1.4 nonaka default: 176 1.4 nonaka nocom: 177 1.4 nonaka iodev = CONSDEV_PC; 178 1.5 nonaka internal_putchar = efi_cons_putc; 179 1.5 nonaka kbd: 180 1.5 nonaka internal_getchar = efi_cons_getc; 181 1.5 nonaka internal_iskey = efi_cons_iskey; 182 1.5 nonaka internal_waitforinputevent = efi_cons_waitforinputevent; 183 1.5 nonaka memset(keybuf, 0, sizeof(keybuf)); 184 1.5 nonaka keybuf_read = keybuf_write = 0; 185 1.4 nonaka break; 186 1.4 nonaka } 187 1.4 nonaka 188 1.4 nonaka strlcpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16); 189 1.4 nonaka } 190 1.4 nonaka 191 1.1 nonaka int 192 1.1 nonaka cninit(void) 193 1.1 nonaka { 194 1.1 nonaka 195 1.1 nonaka efi_switch_video_to_text_mode(); 196 1.1 nonaka eficons_init_video(); 197 1.5 nonaka efi_com_probe(); 198 1.1 nonaka 199 1.7 manu efi_consinit(boot_params.bp_consdev, boot_params.bp_consaddr, 200 1.4 nonaka boot_params.bp_conspeed); 201 1.1 nonaka 202 1.1 nonaka return 0; 203 1.1 nonaka } 204 1.1 nonaka 205 1.5 nonaka void 206 1.5 nonaka efi_cons_show(void) 207 1.5 nonaka { 208 1.5 nonaka const bool pc_is_console = strcmp(btinfo_console.devname, "pc") == 0; 209 1.5 nonaka const bool com_is_console = strcmp(btinfo_console.devname, "com") == 0; 210 1.5 nonaka bool first = true; 211 1.5 nonaka bool found = false; 212 1.5 nonaka int i; 213 1.5 nonaka 214 1.5 nonaka if (efi_gop != NULL) { 215 1.5 nonaka printf("pc"); 216 1.5 nonaka if (pc_is_console) 217 1.5 nonaka printf("*"); 218 1.5 nonaka first = false; 219 1.5 nonaka } 220 1.5 nonaka 221 1.5 nonaka for (i = 0; i < __arraycount(serios); i++) { 222 1.5 nonaka if (serios[i] != NULL) { 223 1.5 nonaka if (!first) 224 1.5 nonaka printf(" "); 225 1.5 nonaka first = false; 226 1.5 nonaka 227 1.5 nonaka printf("com%d", i); 228 1.5 nonaka if (com_is_console && 229 1.5 nonaka btinfo_console.addr == getcomaddr(i)) { 230 1.5 nonaka printf(",%d*", btinfo_console.speed); 231 1.5 nonaka found = true; 232 1.5 nonaka } 233 1.5 nonaka } 234 1.5 nonaka } 235 1.5 nonaka if (!found && com_is_console) { 236 1.5 nonaka if (!first) 237 1.5 nonaka printf(" "); 238 1.5 nonaka first = false; 239 1.5 nonaka 240 1.5 nonaka printf("com,0x%x,%d*", btinfo_console.addr, 241 1.5 nonaka btinfo_console.speed); 242 1.5 nonaka } 243 1.5 nonaka 244 1.5 nonaka printf("\n"); 245 1.5 nonaka } 246 1.5 nonaka 247 1.5 nonaka static int 248 1.5 nonaka efi_cons_getc(void) 249 1.1 nonaka { 250 1.1 nonaka EFI_STATUS status; 251 1.1 nonaka EFI_INPUT_KEY key; 252 1.1 nonaka int c; 253 1.1 nonaka 254 1.1 nonaka if (keybuf_read != keybuf_write) { 255 1.1 nonaka c = keybuf[keybuf_read]; 256 1.1 nonaka keybuf_read = (keybuf_read + 1) % __arraycount(keybuf); 257 1.1 nonaka return c; 258 1.1 nonaka } 259 1.1 nonaka 260 1.1 nonaka status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, 261 1.1 nonaka &key); 262 1.1 nonaka while (status == EFI_NOT_READY) { 263 1.1 nonaka WaitForSingleEvent(ST->ConIn->WaitForKey, 0); 264 1.1 nonaka status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, 265 1.1 nonaka ST->ConIn, &key); 266 1.1 nonaka } 267 1.1 nonaka return key.UnicodeChar; 268 1.1 nonaka } 269 1.1 nonaka 270 1.5 nonaka static int 271 1.5 nonaka efi_cons_putc(int c) 272 1.1 nonaka { 273 1.1 nonaka CHAR16 buf[2]; 274 1.1 nonaka 275 1.5 nonaka buf[0] = c; 276 1.1 nonaka buf[1] = 0; 277 1.1 nonaka Output(buf); 278 1.5 nonaka 279 1.5 nonaka return 1; 280 1.1 nonaka } 281 1.1 nonaka 282 1.1 nonaka /*ARGSUSED*/ 283 1.5 nonaka static int 284 1.5 nonaka efi_cons_iskey(int intr) 285 1.1 nonaka { 286 1.1 nonaka EFI_STATUS status; 287 1.1 nonaka EFI_INPUT_KEY key; 288 1.1 nonaka 289 1.1 nonaka if (keybuf_read != keybuf_write) 290 1.1 nonaka return 1; 291 1.1 nonaka 292 1.1 nonaka status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, 293 1.1 nonaka &key); 294 1.1 nonaka if (EFI_ERROR(status)) 295 1.1 nonaka return 0; 296 1.1 nonaka 297 1.1 nonaka keybuf[keybuf_write] = key.UnicodeChar; 298 1.1 nonaka keybuf_write = (keybuf_write + 1) % __arraycount(keybuf); 299 1.1 nonaka return 1; 300 1.1 nonaka } 301 1.1 nonaka 302 1.5 nonaka static int 303 1.5 nonaka efi_cons_waitforinputevent(uint64_t timeout) 304 1.5 nonaka { 305 1.5 nonaka EFI_STATUS status; 306 1.5 nonaka 307 1.5 nonaka status = WaitForSingleEvent(ST->ConIn->WaitForKey, timeout); 308 1.5 nonaka if (!EFI_ERROR(status)) 309 1.5 nonaka return 0; 310 1.5 nonaka if (status == EFI_TIMEOUT) 311 1.5 nonaka return ETIMEDOUT; 312 1.5 nonaka return EINVAL; 313 1.5 nonaka } 314 1.5 nonaka 315 1.5 nonaka int 316 1.5 nonaka getchar(void) 317 1.5 nonaka { 318 1.5 nonaka 319 1.5 nonaka return internal_getchar(); 320 1.5 nonaka } 321 1.5 nonaka 322 1.5 nonaka void 323 1.5 nonaka putchar(int c) 324 1.5 nonaka { 325 1.5 nonaka 326 1.5 nonaka if (c == '\n') 327 1.5 nonaka internal_putchar('\r'); 328 1.5 nonaka internal_putchar(c); 329 1.5 nonaka } 330 1.5 nonaka 331 1.5 nonaka int 332 1.5 nonaka iskey(int intr) 333 1.5 nonaka { 334 1.5 nonaka 335 1.5 nonaka return internal_iskey(intr); 336 1.5 nonaka } 337 1.5 nonaka 338 1.1 nonaka char 339 1.1 nonaka awaitkey(int timeout, int tell) 340 1.1 nonaka { 341 1.1 nonaka char c = 0; 342 1.1 nonaka 343 1.1 nonaka for (;;) { 344 1.6 jakllsch char numbuf[32]; 345 1.6 jakllsch int len; 346 1.6 jakllsch 347 1.5 nonaka if (tell && timeout) { 348 1.1 nonaka len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ", 349 1.1 nonaka timeout); 350 1.1 nonaka if (len > 0 && len < sizeof(numbuf)) { 351 1.1 nonaka char *p = numbuf; 352 1.1 nonaka 353 1.1 nonaka printf("%s", numbuf); 354 1.1 nonaka while (*p) 355 1.1 nonaka *p++ = '\b'; 356 1.1 nonaka } 357 1.1 nonaka } 358 1.1 nonaka if (iskey(1)) { 359 1.1 nonaka /* flush input buffer */ 360 1.1 nonaka while (iskey(0)) 361 1.1 nonaka c = getchar(); 362 1.1 nonaka if (c == 0) 363 1.1 nonaka c = -1; 364 1.12 kim if (tell && timeout) 365 1.12 kim printf("%s", numbuf); 366 1.12 kim break; 367 1.1 nonaka } 368 1.15 manu if (timeout--) { 369 1.15 manu /* 370 1.15 manu * UEFI spec 2.10 section 7.1.7 371 1.15 manu * EFI_BOOT_SERVICES.SetTimer() timeout in 100ns units 372 1.15 manu * but the implementation may be broken and faster: 373 1.15 manu * check date to make sure we are slow enough. 374 1.15 manu */ 375 1.15 manu EFI_TIME t1, t2; 376 1.15 manu 377 1.15 manu uefi_call_wrapper(RT->GetTime, 2, &t1, NULL); 378 1.15 manu do { 379 1.15 manu internal_waitforinputevent(10000000); /* 1s */ 380 1.15 manu uefi_call_wrapper(RT->GetTime, 2, &t2, NULL); 381 1.15 manu } while (t1.Year == t2.Year && 382 1.15 manu t1.Month == t2.Month && 383 1.15 manu t1.Day == t2.Day && 384 1.15 manu t1.Hour == t2.Hour && 385 1.15 manu t1.Minute == t2.Minute && 386 1.15 manu t1.Second == t2.Second); 387 1.15 manu } 388 1.1 nonaka else 389 1.1 nonaka break; 390 1.6 jakllsch if (tell) 391 1.6 jakllsch printf("%s", numbuf); 392 1.1 nonaka } 393 1.1 nonaka 394 1.1 nonaka if (tell) 395 1.1 nonaka printf("0 seconds. \n"); 396 1.1 nonaka 397 1.1 nonaka return c; 398 1.1 nonaka } 399 1.1 nonaka 400 1.1 nonaka void 401 1.1 nonaka clear_pc_screen(void) 402 1.1 nonaka { 403 1.1 nonaka 404 1.1 nonaka uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); 405 1.1 nonaka } 406 1.1 nonaka 407 1.1 nonaka static uint8_t 408 1.1 nonaka getdepth(const EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) 409 1.1 nonaka { 410 1.1 nonaka 411 1.1 nonaka switch (info->PixelFormat) { 412 1.1 nonaka case PixelBlueGreenRedReserved8BitPerColor: 413 1.1 nonaka case PixelRedGreenBlueReserved8BitPerColor: 414 1.1 nonaka return 32; 415 1.1 nonaka 416 1.1 nonaka case PixelBitMask: 417 1.1 nonaka return fls32(info->PixelInformation.RedMask 418 1.1 nonaka | info->PixelInformation.GreenMask 419 1.1 nonaka | info->PixelInformation.BlueMask 420 1.1 nonaka | info->PixelInformation.ReservedMask); 421 1.1 nonaka 422 1.1 nonaka case PixelBltOnly: 423 1.1 nonaka case PixelFormatMax: 424 1.1 nonaka return 0; 425 1.1 nonaka } 426 1.1 nonaka return 0; 427 1.1 nonaka } 428 1.1 nonaka 429 1.1 nonaka static void 430 1.1 nonaka setpixelformat(UINT32 mask, uint8_t *num, uint8_t *pos) 431 1.1 nonaka { 432 1.1 nonaka uint8_t n, p; 433 1.1 nonaka 434 1.1 nonaka n = popcount32(mask); 435 1.1 nonaka p = ffs32(mask); 436 1.1 nonaka if (p > 0) 437 1.1 nonaka p--; 438 1.1 nonaka 439 1.1 nonaka *num = n; 440 1.1 nonaka *pos = p; 441 1.1 nonaka } 442 1.1 nonaka 443 1.1 nonaka static void 444 1.1 nonaka bi_framebuffer(void) 445 1.1 nonaka { 446 1.1 nonaka EFI_STATUS status; 447 1.1 nonaka EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; 448 1.1 nonaka struct btinfo_framebuffer fb; 449 1.11 jmcneill INT32 bestmode; 450 1.8 jmcneill UINTN sz; 451 1.1 nonaka 452 1.8 jmcneill if (efi_gop == NULL) 453 1.8 jmcneill goto nofb; 454 1.1 nonaka 455 1.1 nonaka if (efi_gop_mode >= 0) { 456 1.1 nonaka bestmode = efi_gop_mode; 457 1.1 nonaka } else { 458 1.8 jmcneill /* If a mode has not been selected, choose a default */ 459 1.8 jmcneill bestmode = efi_find_gop_mode(DEFAULT_GOP_MODE); 460 1.10 jmcneill if (bestmode == -1) 461 1.10 jmcneill bestmode = FALLBACK_GOP_MODE; 462 1.8 jmcneill } 463 1.2 nonaka 464 1.8 jmcneill status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop, 465 1.8 jmcneill bestmode); 466 1.8 jmcneill if (EFI_ERROR(status) || efi_gop->Mode->Mode != bestmode) { 467 1.8 jmcneill printf("GOP setmode failed: %" PRIxMAX "\n", 468 1.8 jmcneill (uintmax_t)status); 469 1.8 jmcneill goto nofb; 470 1.8 jmcneill } 471 1.1 nonaka 472 1.8 jmcneill status = uefi_call_wrapper(efi_gop->QueryMode, 4, 473 1.8 jmcneill efi_gop, bestmode, &sz, &info); 474 1.8 jmcneill if (EFI_ERROR(status)) { 475 1.8 jmcneill printf("GOP querymode failed: %" PRIxMAX "\n", 476 1.8 jmcneill (uintmax_t)status); 477 1.8 jmcneill goto nofb; 478 1.1 nonaka } 479 1.1 nonaka 480 1.1 nonaka memset(&fb, 0, sizeof(fb)); 481 1.1 nonaka fb.physaddr = efi_gop->Mode->FrameBufferBase; 482 1.1 nonaka fb.flags = 0; 483 1.1 nonaka fb.width = info->HorizontalResolution; 484 1.1 nonaka fb.height = info->VerticalResolution; 485 1.1 nonaka fb.depth = getdepth(info); 486 1.1 nonaka fb.stride = info->PixelsPerScanLine * ((fb.depth + 7) / 8); 487 1.1 nonaka fb.vbemode = 0; /* XXX */ 488 1.1 nonaka 489 1.1 nonaka switch (info->PixelFormat) { 490 1.1 nonaka case PixelBlueGreenRedReserved8BitPerColor: 491 1.1 nonaka fb.rnum = 8; 492 1.1 nonaka fb.gnum = 8; 493 1.1 nonaka fb.bnum = 8; 494 1.1 nonaka fb.rpos = 16; 495 1.1 nonaka fb.gpos = 8; 496 1.1 nonaka fb.bpos = 0; 497 1.1 nonaka break; 498 1.1 nonaka 499 1.1 nonaka case PixelRedGreenBlueReserved8BitPerColor: 500 1.1 nonaka fb.rnum = 8; 501 1.1 nonaka fb.gnum = 8; 502 1.1 nonaka fb.bnum = 8; 503 1.1 nonaka fb.rpos = 0; 504 1.1 nonaka fb.gpos = 8; 505 1.1 nonaka fb.bpos = 16; 506 1.1 nonaka break; 507 1.1 nonaka 508 1.1 nonaka case PixelBitMask: 509 1.1 nonaka setpixelformat(info->PixelInformation.RedMask, 510 1.1 nonaka &fb.rnum, &fb.rpos); 511 1.1 nonaka setpixelformat(info->PixelInformation.GreenMask, 512 1.1 nonaka &fb.gnum, &fb.gpos); 513 1.1 nonaka setpixelformat(info->PixelInformation.BlueMask, 514 1.1 nonaka &fb.bnum, &fb.bpos); 515 1.1 nonaka break; 516 1.1 nonaka 517 1.1 nonaka case PixelBltOnly: 518 1.1 nonaka case PixelFormatMax: 519 1.5 nonaka panic("Error: invalid pixel format (%d)", info->PixelFormat); 520 1.1 nonaka break; 521 1.1 nonaka } 522 1.1 nonaka 523 1.1 nonaka framebuffer_configure(&fb); 524 1.8 jmcneill return; 525 1.8 jmcneill 526 1.8 jmcneill nofb: 527 1.8 jmcneill framebuffer_configure(NULL); 528 1.1 nonaka } 529 1.1 nonaka 530 1.1 nonaka int 531 1.1 nonaka vbe_commit(void) 532 1.1 nonaka { 533 1.1 nonaka 534 1.1 nonaka bi_framebuffer(); 535 1.1 nonaka return 0; 536 1.1 nonaka } 537 1.1 nonaka 538 1.1 nonaka static void 539 1.1 nonaka print_text_modes(void) 540 1.1 nonaka { 541 1.1 nonaka EFI_STATUS status; 542 1.1 nonaka UINTN cols, rows; 543 1.1 nonaka INT32 i, curmode; 544 1.1 nonaka 545 1.1 nonaka curmode = ST->ConOut->Mode->Mode; 546 1.1 nonaka for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) { 547 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, 548 1.1 nonaka ST->ConOut, i, &cols, &rows); 549 1.1 nonaka if (EFI_ERROR(status)) 550 1.1 nonaka continue; 551 1.5 nonaka printf("%c%d: %" PRIxMAX "x%" PRIxMAX "\n", 552 1.5 nonaka i == curmode ? '*' : ' ', i, (uintmax_t)cols, (uintmax_t)rows); 553 1.1 nonaka } 554 1.1 nonaka } 555 1.1 nonaka 556 1.1 nonaka static int 557 1.1 nonaka efi_find_text_mode(char *arg) 558 1.1 nonaka { 559 1.1 nonaka EFI_STATUS status; 560 1.1 nonaka UINTN cols, rows; 561 1.1 nonaka INT32 i; 562 1.1 nonaka char mode[32]; 563 1.1 nonaka 564 1.1 nonaka for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) { 565 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, 566 1.1 nonaka ST->ConOut, i, &cols, &rows); 567 1.1 nonaka if (EFI_ERROR(status)) 568 1.1 nonaka continue; 569 1.5 nonaka snprintf(mode, sizeof(mode), "%" PRIuMAX "x%" PRIuMAX, 570 1.5 nonaka (uintmax_t)cols, (uintmax_t)rows); 571 1.1 nonaka if (strcmp(arg, mode) == 0) 572 1.1 nonaka return i; 573 1.1 nonaka } 574 1.1 nonaka return -1; 575 1.1 nonaka } 576 1.1 nonaka 577 1.1 nonaka void 578 1.1 nonaka command_text(char *arg) 579 1.1 nonaka { 580 1.1 nonaka EFI_STATUS status; 581 1.1 nonaka INT32 modenum; 582 1.1 nonaka 583 1.1 nonaka if (*arg == '\0' || strcmp(arg, "list") == 0) { 584 1.1 nonaka print_text_modes(); 585 1.1 nonaka return; 586 1.1 nonaka } 587 1.1 nonaka 588 1.1 nonaka if (strchr(arg, 'x') != NULL) { 589 1.1 nonaka modenum = efi_find_text_mode(arg); 590 1.1 nonaka if (modenum == -1) { 591 1.1 nonaka printf("mode %s not supported by firmware\n", arg); 592 1.1 nonaka return; 593 1.1 nonaka } 594 1.1 nonaka } else { 595 1.1 nonaka modenum = strtoul(arg, NULL, 0); 596 1.1 nonaka } 597 1.1 nonaka 598 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, modenum); 599 1.1 nonaka if (!EFI_ERROR(status)) 600 1.1 nonaka return; 601 1.1 nonaka 602 1.1 nonaka printf("invalid flag, must be 'list', a display mode, " 603 1.1 nonaka "or a mode number\n"); 604 1.1 nonaka } 605 1.1 nonaka 606 1.1 nonaka static int 607 1.1 nonaka print_gop_modes(void) 608 1.1 nonaka { 609 1.1 nonaka EFI_STATUS status; 610 1.1 nonaka EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; 611 1.1 nonaka UINTN sz; 612 1.1 nonaka UINT32 i; 613 1.1 nonaka uint8_t depth; 614 1.1 nonaka 615 1.1 nonaka if (efi_gop == NULL) 616 1.1 nonaka return 1; 617 1.1 nonaka 618 1.1 nonaka for (i = 0; i < efi_gop->Mode->MaxMode; i++) { 619 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4, efi_gop, i, 620 1.1 nonaka &sz, &info); 621 1.1 nonaka if (EFI_ERROR(status) && status == EFI_NOT_STARTED) { 622 1.1 nonaka status = uefi_call_wrapper(efi_gop->SetMode, 2, 623 1.1 nonaka efi_gop, efi_gop->Mode->Mode); 624 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4, 625 1.1 nonaka efi_gop, i, &sz, &info); 626 1.1 nonaka } 627 1.1 nonaka if (EFI_ERROR(status)) 628 1.1 nonaka continue; 629 1.1 nonaka 630 1.5 nonaka printf("%c%d: %dx%d ", 631 1.1 nonaka memcmp(info, efi_gop->Mode->Info, sizeof(*info)) == 0 ? 632 1.1 nonaka '*' : ' ', 633 1.1 nonaka i, info->HorizontalResolution, info->VerticalResolution); 634 1.1 nonaka switch (info->PixelFormat) { 635 1.1 nonaka case PixelRedGreenBlueReserved8BitPerColor: 636 1.5 nonaka printf("RGBR"); 637 1.1 nonaka break; 638 1.1 nonaka case PixelBlueGreenRedReserved8BitPerColor: 639 1.5 nonaka printf("BGRR"); 640 1.1 nonaka break; 641 1.1 nonaka case PixelBitMask: 642 1.5 nonaka printf("R:%08x G:%08x B:%08x X:%08x", 643 1.1 nonaka info->PixelInformation.RedMask, 644 1.1 nonaka info->PixelInformation.GreenMask, 645 1.1 nonaka info->PixelInformation.BlueMask, 646 1.1 nonaka info->PixelInformation.ReservedMask); 647 1.1 nonaka break; 648 1.1 nonaka case PixelBltOnly: 649 1.5 nonaka printf("(blt only)"); 650 1.1 nonaka break; 651 1.1 nonaka default: 652 1.5 nonaka printf("(Invalid pixel format)"); 653 1.1 nonaka break; 654 1.1 nonaka } 655 1.5 nonaka printf(" pitch %d", info->PixelsPerScanLine); 656 1.1 nonaka depth = getdepth(info); 657 1.1 nonaka if (depth > 0) 658 1.5 nonaka printf(" bpp %d", depth); 659 1.5 nonaka printf("\n"); 660 1.1 nonaka } 661 1.1 nonaka 662 1.1 nonaka return 0; 663 1.1 nonaka } 664 1.1 nonaka 665 1.1 nonaka static int 666 1.1 nonaka efi_find_gop_mode(char *arg) 667 1.1 nonaka { 668 1.1 nonaka EFI_STATUS status; 669 1.1 nonaka EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; 670 1.1 nonaka UINTN sz; 671 1.1 nonaka UINT32 i; 672 1.1 nonaka char mode[32]; 673 1.1 nonaka uint8_t depth; 674 1.1 nonaka 675 1.1 nonaka for (i = 0; i < efi_gop->Mode->MaxMode; i++) { 676 1.1 nonaka status = uefi_call_wrapper(efi_gop->QueryMode, 4, efi_gop, i, 677 1.1 nonaka &sz, &info); 678 1.1 nonaka if (EFI_ERROR(status)) 679 1.1 nonaka continue; 680 1.1 nonaka 681 1.1 nonaka depth = getdepth(info); 682 1.1 nonaka if (depth == 0) 683 1.1 nonaka continue; 684 1.1 nonaka 685 1.1 nonaka snprintf(mode, sizeof(mode), "%lux%lux%u", 686 1.1 nonaka (long)info->HorizontalResolution, 687 1.8 jmcneill (long)info->VerticalResolution, 688 1.8 jmcneill depth); 689 1.8 jmcneill if (strcmp(arg, mode) == 0) 690 1.8 jmcneill return i; 691 1.8 jmcneill 692 1.8 jmcneill snprintf(mode, sizeof(mode), "%lux%lu", 693 1.1 nonaka (long)info->HorizontalResolution, 694 1.8 jmcneill (long)info->VerticalResolution); 695 1.1 nonaka if (strcmp(arg, mode) == 0) 696 1.1 nonaka return i; 697 1.1 nonaka } 698 1.1 nonaka return -1; 699 1.1 nonaka } 700 1.1 nonaka 701 1.1 nonaka void 702 1.1 nonaka command_gop(char *arg) 703 1.1 nonaka { 704 1.1 nonaka EFI_STATUS status; 705 1.1 nonaka INT32 modenum; 706 1.1 nonaka 707 1.1 nonaka if (efi_gop == NULL) { 708 1.1 nonaka printf("GOP not supported by firmware\n"); 709 1.1 nonaka return; 710 1.1 nonaka } 711 1.1 nonaka 712 1.1 nonaka if (*arg == '\0' || strcmp(arg, "list") == 0) { 713 1.1 nonaka print_gop_modes(); 714 1.1 nonaka return; 715 1.1 nonaka } 716 1.1 nonaka 717 1.1 nonaka if (strchr(arg, 'x') != NULL) { 718 1.1 nonaka modenum = efi_find_gop_mode(arg); 719 1.1 nonaka if (modenum == -1) { 720 1.1 nonaka printf("mode %s not supported by firmware\n", arg); 721 1.1 nonaka return; 722 1.1 nonaka } 723 1.1 nonaka } else { 724 1.1 nonaka modenum = strtoul(arg, NULL, 0); 725 1.1 nonaka } 726 1.1 nonaka 727 1.1 nonaka status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop, modenum); 728 1.1 nonaka if (!EFI_ERROR(status) && efi_gop->Mode->Mode == modenum) { 729 1.1 nonaka efi_gop_mode = modenum; 730 1.1 nonaka return; 731 1.1 nonaka } 732 1.1 nonaka 733 1.1 nonaka printf("invalid flag, must be 'list', a display mode, " 734 1.1 nonaka "or a mode number\n"); 735 1.1 nonaka } 736 1.1 nonaka 737 1.1 nonaka static void 738 1.1 nonaka eficons_init_video(void) 739 1.1 nonaka { 740 1.1 nonaka EFI_STATUS status; 741 1.3 nonaka UINTN cols, rows; 742 1.3 nonaka INT32 i, best, mode80x25, mode100x31; 743 1.1 nonaka 744 1.1 nonaka /* 745 1.1 nonaka * Setup text mode 746 1.1 nonaka */ 747 1.1 nonaka uefi_call_wrapper(ST->ConOut->Reset, 2, ST->ConOut, TRUE); 748 1.1 nonaka 749 1.3 nonaka mode80x25 = mode100x31 = -1; 750 1.1 nonaka for (i = 0; i < ST->ConOut->Mode->MaxMode; i++) { 751 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, 752 1.1 nonaka ST->ConOut, i, &cols, &rows); 753 1.1 nonaka if (EFI_ERROR(status)) 754 1.1 nonaka continue; 755 1.3 nonaka 756 1.3 nonaka if (mode80x25 < 0 && cols == 80 && rows == 25) 757 1.3 nonaka mode80x25 = i; 758 1.3 nonaka else if (mode100x31 < 0 && cols == 100 && rows == 31) 759 1.3 nonaka mode100x31 = i; 760 1.1 nonaka } 761 1.3 nonaka best = mode100x31 >= 0 ? mode100x31 : mode80x25 >= 0 ? mode80x25 : -1; 762 1.1 nonaka if (best >= 0) 763 1.1 nonaka uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, best); 764 1.1 nonaka uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE); 765 1.1 nonaka uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); 766 1.1 nonaka 767 1.1 nonaka LibLocateProtocol(&GraphicsOutputProtocol, (void **)&efi_gop); 768 1.1 nonaka } 769 1.1 nonaka 770 1.1 nonaka /* 771 1.1 nonaka * for Apple EFI 772 1.1 nonaka */ 773 1.1 nonaka #define CONSOLE_CONTROL_PROTOCOL \ 774 1.1 nonaka {0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21}} 775 1.1 nonaka static EFI_GUID ConsoleControlProtocol = CONSOLE_CONTROL_PROTOCOL; 776 1.1 nonaka 777 1.1 nonaka struct _EFI_CONSOLE_CONTROL_INTERFACE; 778 1.1 nonaka typedef struct _EFI_CONSOLE_CONTROL_INTERFACE EFI_CONSOLE_CONTROL_INTERFACE; 779 1.1 nonaka typedef enum { EfiConsoleControlScreenText } EFI_CONSOLE_CONTROL_SCREEN_MODE; 780 1.1 nonaka typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( 781 1.1 nonaka IN EFI_CONSOLE_CONTROL_INTERFACE *This, 782 1.1 nonaka IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode 783 1.1 nonaka ); 784 1.1 nonaka struct _EFI_CONSOLE_CONTROL_INTERFACE { 785 1.1 nonaka VOID *GetMode; 786 1.1 nonaka EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; 787 1.1 nonaka VOID *LockStdIn; 788 1.1 nonaka }; 789 1.1 nonaka 790 1.1 nonaka static void 791 1.1 nonaka efi_switch_video_to_text_mode(void) 792 1.1 nonaka { 793 1.1 nonaka EFI_STATUS status; 794 1.1 nonaka EFI_CONSOLE_CONTROL_INTERFACE *cci; 795 1.1 nonaka 796 1.1 nonaka /* Set up the console, so printf works. */ 797 1.1 nonaka status = LibLocateProtocol(&ConsoleControlProtocol, (void **)&cci); 798 1.1 nonaka if (!EFI_ERROR(status)) { 799 1.1 nonaka uefi_call_wrapper(cci->SetMode, 2, cci, 800 1.1 nonaka EfiConsoleControlScreenText); 801 1.1 nonaka } 802 1.1 nonaka } 803 1.5 nonaka 804 1.5 nonaka /* 805 1.5 nonaka * serial port 806 1.5 nonaka */ 807 1.5 nonaka static void 808 1.5 nonaka efi_com_probe(void) 809 1.5 nonaka { 810 1.5 nonaka EFI_STATUS status; 811 1.5 nonaka UINTN i, nhandles; 812 1.5 nonaka EFI_HANDLE *handles; 813 1.5 nonaka EFI_DEVICE_PATH *dp, *dp0; 814 1.5 nonaka EFI_DEV_PATH_PTR dpp; 815 1.5 nonaka SERIAL_IO_INTERFACE *serio; 816 1.5 nonaka int uid = -1; 817 1.5 nonaka 818 1.5 nonaka status = LibLocateHandle(ByProtocol, &SerialIoProtocol, NULL, 819 1.5 nonaka &nhandles, &handles); 820 1.5 nonaka if (EFI_ERROR(status)) 821 1.5 nonaka return; 822 1.5 nonaka 823 1.5 nonaka for (i = 0; i < nhandles; i++) { 824 1.5 nonaka /* 825 1.5 nonaka * Identify port number of the handle. This assumes ACPI 826 1.5 nonaka * UID 0-3 map to legacy COM[1-4] and they use the legacy 827 1.5 nonaka * port address. 828 1.5 nonaka */ 829 1.5 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 830 1.5 nonaka &DevicePathProtocol, (void **)&dp0); 831 1.5 nonaka if (EFI_ERROR(status)) 832 1.5 nonaka continue; 833 1.5 nonaka 834 1.5 nonaka for (uid = -1, dp = dp0; 835 1.5 nonaka !IsDevicePathEnd(dp); 836 1.5 nonaka dp = NextDevicePathNode(dp)) { 837 1.5 nonaka 838 1.5 nonaka if (DevicePathType(dp) == ACPI_DEVICE_PATH && 839 1.5 nonaka DevicePathSubType(dp) == ACPI_DP) { 840 1.5 nonaka dpp = (EFI_DEV_PATH_PTR)dp; 841 1.5 nonaka if (dpp.Acpi->HID == EISA_PNP_ID(0x0501)) { 842 1.5 nonaka uid = dpp.Acpi->UID; 843 1.5 nonaka break; 844 1.5 nonaka } 845 1.5 nonaka } 846 1.5 nonaka } 847 1.5 nonaka if (uid < 0 || __arraycount(serios) <= uid) 848 1.5 nonaka continue; 849 1.5 nonaka 850 1.5 nonaka /* Prepare SERIAL_IO_INTERFACE */ 851 1.5 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 852 1.5 nonaka &SerialIoProtocol, (void **)&serio); 853 1.5 nonaka if (EFI_ERROR(status)) 854 1.5 nonaka continue; 855 1.5 nonaka 856 1.5 nonaka serios[uid] = serio; 857 1.5 nonaka } 858 1.5 nonaka 859 1.5 nonaka FreePool(handles); 860 1.5 nonaka 861 1.5 nonaka } 862 1.5 nonaka 863 1.5 nonaka static bool 864 1.5 nonaka efi_valid_com(int dev) 865 1.5 nonaka { 866 1.5 nonaka int idx; 867 1.5 nonaka 868 1.5 nonaka switch (dev) { 869 1.5 nonaka default: 870 1.5 nonaka case CONSDEV_PC: 871 1.5 nonaka return false; 872 1.5 nonaka 873 1.5 nonaka case CONSDEV_COM0: 874 1.5 nonaka case CONSDEV_COM1: 875 1.5 nonaka case CONSDEV_COM2: 876 1.5 nonaka case CONSDEV_COM3: 877 1.5 nonaka idx = dev - CONSDEV_COM0; 878 1.5 nonaka break; 879 1.5 nonaka } 880 1.5 nonaka 881 1.5 nonaka return idx < __arraycount(serios) && 882 1.5 nonaka serios[idx] != NULL && 883 1.5 nonaka getcomaddr(idx) != 0; 884 1.5 nonaka } 885 1.5 nonaka 886 1.5 nonaka static int 887 1.5 nonaka efi_com_init(int addr, int speed) 888 1.5 nonaka { 889 1.5 nonaka EFI_STATUS status; 890 1.5 nonaka SERIAL_IO_INTERFACE *serio; 891 1.5 nonaka 892 1.5 nonaka if (speed <= 0) 893 1.5 nonaka return 0; 894 1.5 nonaka 895 1.5 nonaka if (!efi_valid_com(iodev)) 896 1.13 rin return raw_com_init(addr, speed); 897 1.5 nonaka 898 1.5 nonaka serio = serios[iodev - CONSDEV_COM0]; 899 1.5 nonaka 900 1.5 nonaka if (serio->Mode->BaudRate != btinfo_console.speed) { 901 1.5 nonaka status = uefi_call_wrapper(serio->SetAttributes, 7, serio, 902 1.5 nonaka speed, serio->Mode->ReceiveFifoDepth, 903 1.5 nonaka serio->Mode->Timeout, serio->Mode->Parity, 904 1.5 nonaka serio->Mode->DataBits, serio->Mode->StopBits); 905 1.5 nonaka if (EFI_ERROR(status)) { 906 1.5 nonaka printf("com%d: SetAttribute() failed with status=%" PRIxMAX 907 1.5 nonaka "\n", iodev - CONSDEV_COM0, (uintmax_t)status); 908 1.5 nonaka return 0; 909 1.5 nonaka } 910 1.5 nonaka } 911 1.5 nonaka 912 1.13 rin raw_com_addr = 0; 913 1.5 nonaka default_comspeed = speed; 914 1.5 nonaka internal_getchar = efi_com_getc; 915 1.5 nonaka internal_putchar = efi_com_putc; 916 1.5 nonaka internal_iskey = efi_com_status; 917 1.5 nonaka internal_waitforinputevent = efi_com_waitforinputevent; 918 1.5 nonaka memset(serbuf, 0, sizeof(serbuf)); 919 1.5 nonaka serbuf_read = serbuf_write = 0; 920 1.5 nonaka 921 1.5 nonaka return speed; 922 1.5 nonaka } 923 1.5 nonaka 924 1.5 nonaka static int 925 1.5 nonaka efi_com_getc(void) 926 1.5 nonaka { 927 1.5 nonaka EFI_STATUS status; 928 1.5 nonaka SERIAL_IO_INTERFACE *serio; 929 1.5 nonaka UINTN sz; 930 1.5 nonaka u_char c; 931 1.5 nonaka 932 1.5 nonaka if (!efi_valid_com(iodev)) 933 1.5 nonaka panic("Invalid serial port: iodev=%d", iodev); 934 1.5 nonaka 935 1.5 nonaka if (serbuf_read != serbuf_write) { 936 1.5 nonaka c = serbuf[serbuf_read]; 937 1.5 nonaka serbuf_read = (serbuf_read + 1) % __arraycount(serbuf); 938 1.5 nonaka return c; 939 1.5 nonaka } 940 1.5 nonaka 941 1.5 nonaka serio = serios[iodev - CONSDEV_COM0]; 942 1.5 nonaka 943 1.5 nonaka for (;;) { 944 1.5 nonaka sz = 1; 945 1.5 nonaka status = uefi_call_wrapper(serio->Read, 3, serio, &sz, &c); 946 1.5 nonaka if (!EFI_ERROR(status) && sz > 0) 947 1.5 nonaka break; 948 1.5 nonaka if (status != EFI_TIMEOUT && EFI_ERROR(status)) 949 1.5 nonaka panic("Error reading from serial status=%"PRIxMAX, 950 1.5 nonaka (uintmax_t)status); 951 1.5 nonaka } 952 1.5 nonaka return c; 953 1.5 nonaka } 954 1.5 nonaka 955 1.5 nonaka static int 956 1.5 nonaka efi_com_putc(int c) 957 1.5 nonaka { 958 1.5 nonaka EFI_STATUS status; 959 1.5 nonaka SERIAL_IO_INTERFACE *serio; 960 1.5 nonaka UINTN sz = 1; 961 1.5 nonaka u_char buf; 962 1.5 nonaka 963 1.5 nonaka if (!efi_valid_com(iodev)) 964 1.5 nonaka return 0; 965 1.5 nonaka 966 1.5 nonaka serio = serios[iodev - CONSDEV_COM0]; 967 1.5 nonaka buf = c; 968 1.5 nonaka status = uefi_call_wrapper(serio->Write, 3, serio, &sz, &buf); 969 1.5 nonaka if (EFI_ERROR(status) || sz < 1) 970 1.5 nonaka return 0; 971 1.5 nonaka return 1; 972 1.5 nonaka } 973 1.5 nonaka 974 1.5 nonaka /*ARGSUSED*/ 975 1.5 nonaka static int 976 1.5 nonaka efi_com_status(int intr) 977 1.5 nonaka { 978 1.5 nonaka EFI_STATUS status; 979 1.5 nonaka SERIAL_IO_INTERFACE *serio; 980 1.5 nonaka UINTN sz; 981 1.5 nonaka u_char c; 982 1.5 nonaka 983 1.5 nonaka if (!efi_valid_com(iodev)) 984 1.5 nonaka panic("Invalid serial port: iodev=%d", iodev); 985 1.5 nonaka 986 1.5 nonaka if (serbuf_read != serbuf_write) 987 1.5 nonaka return 1; 988 1.5 nonaka 989 1.5 nonaka serio = serios[iodev - CONSDEV_COM0]; 990 1.5 nonaka sz = 1; 991 1.5 nonaka status = uefi_call_wrapper(serio->Read, 3, serio, &sz, &c); 992 1.5 nonaka if (EFI_ERROR(status) || sz < 1) 993 1.5 nonaka return 0; 994 1.5 nonaka 995 1.5 nonaka serbuf[serbuf_write] = c; 996 1.5 nonaka serbuf_write = (serbuf_write + 1) % __arraycount(serbuf); 997 1.5 nonaka return 1; 998 1.5 nonaka } 999 1.5 nonaka 1000 1.5 nonaka static void 1001 1.5 nonaka efi_com_periodic_event(EFI_EVENT event, void *ctx) 1002 1.5 nonaka { 1003 1.5 nonaka EFI_EVENT timer = ctx; 1004 1.5 nonaka 1005 1.5 nonaka if (efi_com_status(0)) { 1006 1.5 nonaka uefi_call_wrapper(BS->SetTimer, 3, event, TimerCancel, 0); 1007 1.5 nonaka uefi_call_wrapper(BS->SignalEvent, 1, timer); 1008 1.5 nonaka } 1009 1.5 nonaka } 1010 1.5 nonaka 1011 1.5 nonaka static int 1012 1.5 nonaka efi_com_waitforinputevent(uint64_t timeout) 1013 1.5 nonaka { 1014 1.5 nonaka EFI_STATUS status; 1015 1.5 nonaka EFI_EVENT timer, periodic; 1016 1.5 nonaka 1017 1.5 nonaka status = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, 1018 1.5 nonaka &timer); 1019 1.5 nonaka if (EFI_ERROR(status)) 1020 1.5 nonaka return EINVAL; 1021 1.5 nonaka 1022 1.5 nonaka status = uefi_call_wrapper(BS->CreateEvent, 5, 1023 1.5 nonaka EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, efi_com_periodic_event, 1024 1.5 nonaka timer, &periodic); 1025 1.5 nonaka if (EFI_ERROR(status)) { 1026 1.5 nonaka uefi_call_wrapper(BS->CloseEvent, 1, timer); 1027 1.5 nonaka return EINVAL; 1028 1.5 nonaka } 1029 1.5 nonaka 1030 1.5 nonaka status = uefi_call_wrapper(BS->SetTimer, 3, periodic, TimerPeriodic, 1031 1.5 nonaka 1000000); /* 100ms */ 1032 1.5 nonaka if (EFI_ERROR(status)) { 1033 1.5 nonaka uefi_call_wrapper(BS->CloseEvent, 1, periodic); 1034 1.5 nonaka uefi_call_wrapper(BS->CloseEvent, 1, timer); 1035 1.5 nonaka return EINVAL; 1036 1.5 nonaka } 1037 1.5 nonaka status = WaitForSingleEvent(&timer, timeout); 1038 1.5 nonaka uefi_call_wrapper(BS->SetTimer, 3, periodic, TimerCancel, 0); 1039 1.5 nonaka uefi_call_wrapper(BS->CloseEvent, 1, periodic); 1040 1.5 nonaka uefi_call_wrapper(BS->CloseEvent, 1, timer); 1041 1.5 nonaka if (!EFI_ERROR(status)) 1042 1.5 nonaka return 0; 1043 1.5 nonaka if (status == EFI_TIMEOUT) 1044 1.5 nonaka return ETIMEDOUT; 1045 1.5 nonaka return EINVAL; 1046 1.5 nonaka } 1047 1.13 rin 1048 1.13 rin static int 1049 1.13 rin raw_com_init(int addr, int speed) 1050 1.13 rin { 1051 1.13 rin 1052 1.13 rin if (addr == 0 || speed <= 0) 1053 1.13 rin return 0; 1054 1.13 rin 1055 1.13 rin speed = cominit_d(addr, speed); 1056 1.13 rin 1057 1.13 rin raw_com_addr = addr; 1058 1.13 rin default_comspeed = speed; 1059 1.13 rin internal_getchar = raw_com_getc; 1060 1.13 rin internal_putchar = raw_com_putc; 1061 1.13 rin internal_iskey = raw_com_status; 1062 1.13 rin internal_waitforinputevent = raw_com_waitforinputevent; 1063 1.13 rin 1064 1.13 rin return speed; 1065 1.13 rin } 1066 1.13 rin 1067 1.13 rin static int 1068 1.13 rin raw_com_getc(void) 1069 1.13 rin { 1070 1.13 rin 1071 1.13 rin if (raw_com_addr == 0) 1072 1.13 rin panic("%s: Invalid serial port", __func__); 1073 1.13 rin return comgetc_d(raw_com_addr); 1074 1.13 rin } 1075 1.13 rin 1076 1.13 rin static int 1077 1.13 rin raw_com_putc(int c) 1078 1.13 rin { 1079 1.13 rin 1080 1.13 rin if (raw_com_addr == 0) 1081 1.13 rin panic("%s: Invalid serial port", __func__); 1082 1.13 rin return computc_d(c, raw_com_addr); 1083 1.13 rin } 1084 1.13 rin 1085 1.13 rin static int 1086 1.13 rin raw_com_status(int intr) 1087 1.13 rin { 1088 1.13 rin 1089 1.13 rin if (raw_com_addr == 0) 1090 1.13 rin panic("%s: Invalid serial port", __func__); 1091 1.13 rin return comstatus_d(raw_com_addr); 1092 1.13 rin } 1093 1.13 rin 1094 1.13 rin static int 1095 1.13 rin raw_com_waitforinputevent(uint64_t timeout /* in 0.1 usec */) 1096 1.13 rin { 1097 1.13 rin uint64_t ms; 1098 1.13 rin 1099 1.13 rin if (raw_com_addr == 0) 1100 1.13 rin panic("%s: Invalid serial port", __func__); 1101 1.13 rin 1102 1.13 rin for (ms = howmany(timeout, 10 * 1000); ms != 0; ms--) { 1103 1.13 rin if (raw_com_status(0)) 1104 1.13 rin return 0; 1105 1.13 rin uefi_call_wrapper(BS->Stall, 1, 1000); 1106 1.13 rin } 1107 1.13 rin return ETIMEDOUT; 1108 1.13 rin } 1109