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