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