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