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