1ffedf5deSToomas Soome /*
2199767f8SToomas Soome  * Copyright (c) 2000 Doug Rabson
3199767f8SToomas Soome  * All rights reserved.
4199767f8SToomas Soome  *
5199767f8SToomas Soome  * Redistribution and use in source and binary forms, with or without
6199767f8SToomas Soome  * modification, are permitted provided that the following conditions
7199767f8SToomas Soome  * are met:
8199767f8SToomas Soome  * 1. Redistributions of source code must retain the above copyright
9199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer.
10199767f8SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12199767f8SToomas Soome  *    documentation and/or other materials provided with the distribution.
13199767f8SToomas Soome  *
14199767f8SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767f8SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767f8SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767f8SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767f8SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767f8SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767f8SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767f8SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767f8SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767f8SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767f8SToomas Soome  * SUCH DAMAGE.
25199767f8SToomas Soome  */
26199767f8SToomas Soome 
27199767f8SToomas Soome #include <sys/cdefs.h>
28199767f8SToomas Soome 
29199767f8SToomas Soome #include <efi.h>
30199767f8SToomas Soome #include <efilib.h>
31*f334afcfSToomas Soome #include <eficonsctl.h>
32*f334afcfSToomas Soome #include <Guid/ConsoleInDevice.h>
33*f334afcfSToomas Soome #include <Guid/ConsoleOutDevice.h>
34*f334afcfSToomas Soome #include <Guid/StandardErrorDevice.h>
35*f334afcfSToomas Soome #include <Protocol/GraphicsOutput.h>
36*f334afcfSToomas Soome #include <Protocol/UgaDraw.h>
37*f334afcfSToomas Soome #include <Protocol/SimpleTextIn.h>
38*f334afcfSToomas Soome #include <Protocol/SimpleTextInEx.h>
39*f334afcfSToomas Soome #include <Protocol/SimpleTextOut.h>
409890ff83SToomas Soome #include <sys/tem_impl.h>
419890ff83SToomas Soome #include <sys/multiboot2.h>
429890ff83SToomas Soome #include <machine/metadata.h>
439890ff83SToomas Soome #include <gfx_fb.h>
44199767f8SToomas Soome 
45199767f8SToomas Soome #include "bootstrap.h"
46199767f8SToomas Soome 
47*f334afcfSToomas Soome struct efi_fb			efifb;
48*f334afcfSToomas Soome EFI_GRAPHICS_OUTPUT_PROTOCOL	*gop;
49*f334afcfSToomas Soome EFI_UGA_DRAW_PROTOCOL		*uga;
50*f334afcfSToomas Soome 
51*f334afcfSToomas Soome EFI_GUID gEfiConsoleInDeviceGuid = EFI_CONSOLE_IN_DEVICE_GUID;
52*f334afcfSToomas Soome EFI_GUID gEfiConsoleOutDeviceGuid = EFI_CONSOLE_OUT_DEVICE_GUID;
53*f334afcfSToomas Soome EFI_GUID gEfiStandardErrorDeviceGuid = EFI_STANDARD_ERROR_DEVICE_GUID;
54*f334afcfSToomas Soome EFI_GUID gEfiConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
55*f334afcfSToomas Soome EFI_GUID gEfiSimpleTextInProtocolGuid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
56*f334afcfSToomas Soome EFI_GUID gEfiSimpleTextInputExProtocolGuid =
57*f334afcfSToomas Soome     EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
58*f334afcfSToomas Soome EFI_GUID gEfiSimpleTextOutProtocolGuid = EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
599890ff83SToomas Soome static EFI_CONSOLE_CONTROL_PROTOCOL	*console_control;
609890ff83SToomas Soome static EFI_CONSOLE_CONTROL_SCREEN_MODE	console_mode;
61199767f8SToomas Soome static SIMPLE_TEXT_OUTPUT_INTERFACE	*conout;
62199767f8SToomas Soome 
639890ff83SToomas Soome /* mode change callback and argument from tem */
649890ff83SToomas Soome static vis_modechg_cb_t modechg_cb;
659890ff83SToomas Soome static struct vis_modechg_arg *modechg_arg;
669890ff83SToomas Soome static tem_vt_state_t tem;
679890ff83SToomas Soome 
689890ff83SToomas Soome struct efi_console_data {
699890ff83SToomas Soome 	struct visual_ops			*ecd_visual_ops;
709890ff83SToomas Soome 	SIMPLE_INPUT_INTERFACE			*ecd_conin;
719890ff83SToomas Soome 	EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL	*ecd_coninex;
729890ff83SToomas Soome };
73199767f8SToomas Soome 
74199767f8SToomas Soome #define	KEYBUFSZ 10
75c6dd35daSToomas Soome static unsigned keybuf[KEYBUFSZ];	/* keybuf for extended codes */
769890ff83SToomas Soome 
77416f8d72SToomas Soome static int key_pending;
78ffedf5deSToomas Soome 
799890ff83SToomas Soome static const unsigned char solaris_color_to_efi_color[16] = {
809890ff83SToomas Soome 	EFI_WHITE,
819890ff83SToomas Soome 	EFI_BLACK,
829890ff83SToomas Soome 	EFI_BLUE,
839890ff83SToomas Soome 	EFI_GREEN,
849890ff83SToomas Soome 	EFI_CYAN,
859890ff83SToomas Soome 	EFI_RED,
869890ff83SToomas Soome 	EFI_MAGENTA,
879890ff83SToomas Soome 	EFI_BROWN,
889890ff83SToomas Soome 	EFI_LIGHTGRAY,
899890ff83SToomas Soome 	EFI_DARKGRAY,
909890ff83SToomas Soome 	EFI_LIGHTBLUE,
919890ff83SToomas Soome 	EFI_LIGHTGREEN,
929890ff83SToomas Soome 	EFI_LIGHTCYAN,
939890ff83SToomas Soome 	EFI_LIGHTRED,
949890ff83SToomas Soome 	EFI_LIGHTMAGENTA,
959890ff83SToomas Soome 	EFI_YELLOW
969890ff83SToomas Soome };
97199767f8SToomas Soome 
989890ff83SToomas Soome #define	DEFAULT_FGCOLOR	EFI_LIGHTGRAY
999890ff83SToomas Soome #define	DEFAULT_BGCOLOR	EFI_BLACK
1009890ff83SToomas Soome 
1019890ff83SToomas Soome extern int efi_find_framebuffer(struct efi_fb *efifb);
102199767f8SToomas Soome 
1039890ff83SToomas Soome static void efi_framebuffer_setup(void);
104199767f8SToomas Soome static void efi_cons_probe(struct console *);
105199767f8SToomas Soome static int efi_cons_init(struct console *, int);
1069890ff83SToomas Soome static void efi_cons_putchar(struct console *, int);
1079890ff83SToomas Soome static void efi_cons_efiputchar(int);
1089890ff83SToomas Soome static int efi_cons_getchar(struct console *);
1099890ff83SToomas Soome static int efi_cons_poll(struct console *);
1109890ff83SToomas Soome static int efi_cons_ioctl(struct console *cp, int cmd, void *data);
11180e47917SToomas Soome static void efi_cons_devinfo(struct console *);
1129890ff83SToomas Soome 
1139890ff83SToomas Soome static int efi_fb_devinit(struct vis_devinit *);
1149890ff83SToomas Soome static void efi_cons_cursor(struct vis_conscursor *);
1159890ff83SToomas Soome 
1169890ff83SToomas Soome static int efi_text_devinit(struct vis_devinit *);
1179890ff83SToomas Soome static int efi_text_cons_clear(struct vis_consclear *);
1189890ff83SToomas Soome static void efi_text_cons_copy(struct vis_conscopy *);
1199890ff83SToomas Soome static void efi_text_cons_display(struct vis_consdisplay *);
120199767f8SToomas Soome 
121199767f8SToomas Soome struct console efi_console = {
1229890ff83SToomas Soome 	.c_name = "text",
1239890ff83SToomas Soome 	.c_desc = "EFI console",
1249890ff83SToomas Soome 	.c_flags = C_WIDEOUT,
1259890ff83SToomas Soome 	.c_probe = efi_cons_probe,
1269890ff83SToomas Soome 	.c_init = efi_cons_init,
1279890ff83SToomas Soome 	.c_out = efi_cons_putchar,
1289890ff83SToomas Soome 	.c_in = efi_cons_getchar,
1299890ff83SToomas Soome 	.c_ready = efi_cons_poll,
1309890ff83SToomas Soome 	.c_ioctl = efi_cons_ioctl,
13180e47917SToomas Soome 	.c_devinfo = efi_cons_devinfo,
1329890ff83SToomas Soome 	.c_private = NULL
133199767f8SToomas Soome };
134199767f8SToomas Soome 
1359890ff83SToomas Soome static struct vis_identifier fb_ident = { "efi_fb" };
1369890ff83SToomas Soome static struct vis_identifier text_ident = { "efi_text" };
1379890ff83SToomas Soome 
1389890ff83SToomas Soome struct visual_ops fb_ops = {
1399890ff83SToomas Soome 	.ident = &fb_ident,
1409890ff83SToomas Soome 	.kdsetmode = NULL,
1419890ff83SToomas Soome 	.devinit = efi_fb_devinit,
1422d84dc94SToomas Soome 	.cons_copy = gfx_fb_cons_copy,
1432d84dc94SToomas Soome 	.cons_display = gfx_fb_cons_display,
1449890ff83SToomas Soome 	.cons_cursor = efi_cons_cursor,
1452d84dc94SToomas Soome 	.cons_clear = gfx_fb_cons_clear,
1469890ff83SToomas Soome 	.cons_put_cmap = NULL
1479890ff83SToomas Soome };
148199767f8SToomas Soome 
1499890ff83SToomas Soome struct visual_ops text_ops = {
1509890ff83SToomas Soome 	.ident = &text_ident,
1519890ff83SToomas Soome 	.kdsetmode = NULL,
1529890ff83SToomas Soome 	.devinit = efi_text_devinit,
1539890ff83SToomas Soome 	.cons_copy = efi_text_cons_copy,
1549890ff83SToomas Soome 	.cons_display = efi_text_cons_display,
1559890ff83SToomas Soome 	.cons_cursor = efi_cons_cursor,
1569890ff83SToomas Soome 	.cons_clear = efi_text_cons_clear,
1579890ff83SToomas Soome 	.cons_put_cmap = NULL
1589890ff83SToomas Soome };
1599890ff83SToomas Soome 
1609890ff83SToomas Soome /*
1619890ff83SToomas Soome  * platform specific functions for tem
1629890ff83SToomas Soome  */
1639890ff83SToomas Soome int
plat_stdout_is_framebuffer(void)1649890ff83SToomas Soome plat_stdout_is_framebuffer(void)
165199767f8SToomas Soome {
1669890ff83SToomas Soome 	return (console_mode == EfiConsoleControlScreenGraphics);
167199767f8SToomas Soome }
168199767f8SToomas Soome 
169199767f8SToomas Soome void
plat_tem_hide_prom_cursor(void)1709890ff83SToomas Soome plat_tem_hide_prom_cursor(void)
171199767f8SToomas Soome {
172190f051bSToomas Soome 	if (has_boot_services)
173190f051bSToomas Soome 		conout->EnableCursor(conout, FALSE);
1749890ff83SToomas Soome }
1759890ff83SToomas Soome 
1769890ff83SToomas Soome static void
plat_tem_display_prom_cursor(screen_pos_t row,screen_pos_t col)1779890ff83SToomas Soome plat_tem_display_prom_cursor(screen_pos_t row, screen_pos_t col)
1789890ff83SToomas Soome {
1799890ff83SToomas Soome 
180190f051bSToomas Soome 	if (has_boot_services) {
181190f051bSToomas Soome 		conout->SetCursorPosition(conout, col, row);
182190f051bSToomas Soome 		conout->EnableCursor(conout, TRUE);
183190f051bSToomas Soome 	}
184199767f8SToomas Soome }
185199767f8SToomas Soome 
186199767f8SToomas Soome void
plat_tem_get_prom_pos(uint32_t * row,uint32_t * col)1879890ff83SToomas Soome plat_tem_get_prom_pos(uint32_t *row, uint32_t *col)
188199767f8SToomas Soome {
1899890ff83SToomas Soome 	if (console_mode == EfiConsoleControlScreenText) {
1909890ff83SToomas Soome 		*col = (uint32_t)conout->Mode->CursorColumn;
1919890ff83SToomas Soome 		*row = (uint32_t)conout->Mode->CursorRow;
1929890ff83SToomas Soome 	} else {
1939890ff83SToomas Soome 		*col = 0;
1949890ff83SToomas Soome 		*row = 0;
1959890ff83SToomas Soome 	}
196199767f8SToomas Soome }
197199767f8SToomas Soome 
1989890ff83SToomas Soome /*
1999890ff83SToomas Soome  * plat_tem_get_prom_size() is supposed to return screen size
2009890ff83SToomas Soome  * in chars. Return real data for text mode and TEM defaults for graphical
2019890ff83SToomas Soome  * mode, so the tem can compute values based on default and font.
2029890ff83SToomas Soome  */
2039890ff83SToomas Soome void
plat_tem_get_prom_size(size_t * height,size_t * width)2049890ff83SToomas Soome plat_tem_get_prom_size(size_t *height, size_t *width)
2059890ff83SToomas Soome {
2069890ff83SToomas Soome 	UINTN cols, rows;
2079890ff83SToomas Soome 	if (console_mode == EfiConsoleControlScreenText) {
2089890ff83SToomas Soome 		(void) conout->QueryMode(conout, conout->Mode->Mode,
2099890ff83SToomas Soome 		    &cols, &rows);
2109890ff83SToomas Soome 		*height = (size_t)rows;
2119890ff83SToomas Soome 		*width = (size_t)cols;
2129890ff83SToomas Soome 	} else {
2139890ff83SToomas Soome 		*height = TEM_DEFAULT_ROWS;
2149890ff83SToomas Soome 		*width = TEM_DEFAULT_COLS;
2159890ff83SToomas Soome 	}
2169890ff83SToomas Soome }
217199767f8SToomas Soome 
2189890ff83SToomas Soome /*
2199890ff83SToomas Soome  * Callback to notify about console mode change.
2209890ff83SToomas Soome  * mode is value from enum EFI_CONSOLE_CONTROL_SCREEN_MODE.
2219890ff83SToomas Soome  */
2229890ff83SToomas Soome void
plat_cons_update_mode(int mode)2239890ff83SToomas Soome plat_cons_update_mode(int mode)
224199767f8SToomas Soome {
2259890ff83SToomas Soome 	UINTN cols, rows;
2269890ff83SToomas Soome 	struct vis_devinit devinit;
2279890ff83SToomas Soome 	struct efi_console_data *ecd = efi_console.c_private;
2289890ff83SToomas Soome 
2299890ff83SToomas Soome 	/* Make sure we have usable console. */
2309890ff83SToomas Soome 	if (efi_find_framebuffer(&efifb)) {
2319890ff83SToomas Soome 		console_mode = EfiConsoleControlScreenText;
2329890ff83SToomas Soome 	} else {
2339890ff83SToomas Soome 		efi_framebuffer_setup();
2349890ff83SToomas Soome 		if (mode != -1 && console_mode != mode)
2359890ff83SToomas Soome 			console_mode = mode;
2369890ff83SToomas Soome 	}
2379890ff83SToomas Soome 
2389890ff83SToomas Soome 	if (console_control != NULL)
239c6dd35daSToomas Soome 		(void) console_control->SetMode(console_control, console_mode);
2409890ff83SToomas Soome 
2419890ff83SToomas Soome 	/* some firmware enables the cursor when switching modes */
2429890ff83SToomas Soome 	conout->EnableCursor(conout, FALSE);
2439890ff83SToomas Soome 	if (console_mode == EfiConsoleControlScreenText) {
244c6dd35daSToomas Soome 		(void) conout->QueryMode(conout, conout->Mode->Mode,
2459890ff83SToomas Soome 		    &cols, &rows);
2469890ff83SToomas Soome 		devinit.version = VIS_CONS_REV;
2479890ff83SToomas Soome 		devinit.width = cols;
2489890ff83SToomas Soome 		devinit.height = rows;
2499890ff83SToomas Soome 		devinit.depth = 4;
2509890ff83SToomas Soome 		devinit.linebytes = cols;
2519890ff83SToomas Soome 		devinit.color_map = NULL;
2529890ff83SToomas Soome 		devinit.mode = VIS_TEXT;
2539890ff83SToomas Soome 		ecd->ecd_visual_ops = &text_ops;
2549890ff83SToomas Soome 	} else {
2559890ff83SToomas Soome 		devinit.version = VIS_CONS_REV;
2569890ff83SToomas Soome 		devinit.width = gfx_fb.framebuffer_common.framebuffer_width;
2579890ff83SToomas Soome 		devinit.height = gfx_fb.framebuffer_common.framebuffer_height;
2589890ff83SToomas Soome 		devinit.depth = gfx_fb.framebuffer_common.framebuffer_bpp;
2599890ff83SToomas Soome 		devinit.linebytes = gfx_fb.framebuffer_common.framebuffer_pitch;
2609890ff83SToomas Soome 		devinit.color_map = gfx_fb_color_map;
2619890ff83SToomas Soome 		devinit.mode = VIS_PIXEL;
2629890ff83SToomas Soome 		ecd->ecd_visual_ops = &fb_ops;
2639890ff83SToomas Soome 	}
2649890ff83SToomas Soome 
2659890ff83SToomas Soome 	modechg_cb(modechg_arg, &devinit);
266199767f8SToomas Soome }
267199767f8SToomas Soome 
268199767f8SToomas Soome static int
efi_fb_devinit(struct vis_devinit * data)2699890ff83SToomas Soome efi_fb_devinit(struct vis_devinit *data)
270199767f8SToomas Soome {
2719890ff83SToomas Soome 	if (console_mode != EfiConsoleControlScreenGraphics)
2729890ff83SToomas Soome 		return (1);
2739890ff83SToomas Soome 
2749890ff83SToomas Soome 	data->version = VIS_CONS_REV;
2759890ff83SToomas Soome 	data->width = gfx_fb.framebuffer_common.framebuffer_width;
2769890ff83SToomas Soome 	data->height = gfx_fb.framebuffer_common.framebuffer_height;
2779890ff83SToomas Soome 	data->depth = gfx_fb.framebuffer_common.framebuffer_bpp;
2789890ff83SToomas Soome 	data->linebytes = gfx_fb.framebuffer_common.framebuffer_pitch;
2799890ff83SToomas Soome 	data->color_map = gfx_fb_color_map;
2809890ff83SToomas Soome 	data->mode = VIS_PIXEL;
2819890ff83SToomas Soome 
2829890ff83SToomas Soome 	modechg_cb = data->modechg_cb;
2839890ff83SToomas Soome 	modechg_arg = data->modechg_arg;
2849890ff83SToomas Soome 
2859890ff83SToomas Soome 	return (0);
286199767f8SToomas Soome }
287199767f8SToomas Soome 
2889890ff83SToomas Soome static int
efi_text_devinit(struct vis_devinit * data)2899890ff83SToomas Soome efi_text_devinit(struct vis_devinit *data)
290199767f8SToomas Soome {
2919890ff83SToomas Soome 	UINTN cols, rows;
2929890ff83SToomas Soome 
2939890ff83SToomas Soome 	if (console_mode != EfiConsoleControlScreenText)
2949890ff83SToomas Soome 		return (1);
2959890ff83SToomas Soome 
296c6dd35daSToomas Soome 	(void) conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows);
2979890ff83SToomas Soome 	data->version = VIS_CONS_REV;
2989890ff83SToomas Soome 	data->width = cols;
2999890ff83SToomas Soome 	data->height = rows;
3009890ff83SToomas Soome 	data->depth = 4;
3019890ff83SToomas Soome 	data->linebytes = cols;
3029890ff83SToomas Soome 	data->color_map = NULL;
3039890ff83SToomas Soome 	data->mode = VIS_TEXT;
3049890ff83SToomas Soome 
3059890ff83SToomas Soome 	modechg_cb = data->modechg_cb;
3069890ff83SToomas Soome 	modechg_arg = data->modechg_arg;
3079890ff83SToomas Soome 
3089890ff83SToomas Soome 	return (0);
309199767f8SToomas Soome }
310199767f8SToomas Soome 
3119890ff83SToomas Soome static int
efi_text_cons_clear(struct vis_consclear * ca)3129890ff83SToomas Soome efi_text_cons_clear(struct vis_consclear *ca)
313199767f8SToomas Soome {
3149890ff83SToomas Soome 	EFI_STATUS st;
3159890ff83SToomas Soome 	UINTN attr = conout->Mode->Attribute & 0x0F;
3161b61d0d2SToomas Soome 	uint8_t bg;
317199767f8SToomas Soome 
318190f051bSToomas Soome 	if (!has_boot_services)
319190f051bSToomas Soome 		return (0);
320190f051bSToomas Soome 
321fa9eb222SToomas Soome 	bg = solaris_color_to_efi_color[ca->bg_color.four & 0xF] & 0x7;
3221b61d0d2SToomas Soome 
3231b61d0d2SToomas Soome 	attr = EFI_TEXT_ATTR(attr, bg);
3249890ff83SToomas Soome 	st = conout->SetAttribute(conout, attr);
3259890ff83SToomas Soome 	if (EFI_ERROR(st))
3269890ff83SToomas Soome 		return (1);
3279890ff83SToomas Soome 	st = conout->ClearScreen(conout);
3289890ff83SToomas Soome 	if (EFI_ERROR(st))
3299890ff83SToomas Soome 		return (1);
3309890ff83SToomas Soome 	return (0);
331199767f8SToomas Soome }
332199767f8SToomas Soome 
333199767f8SToomas Soome static void
efi_text_cons_copy(struct vis_conscopy * ma)3349890ff83SToomas Soome efi_text_cons_copy(struct vis_conscopy *ma)
3359890ff83SToomas Soome {
3369890ff83SToomas Soome 	UINTN col, row;
337199767f8SToomas Soome 
338190f051bSToomas Soome 	if (!has_boot_services)
339190f051bSToomas Soome 		return;
340190f051bSToomas Soome 
3419890ff83SToomas Soome 	col = 0;
3429890ff83SToomas Soome 	row = ma->e_row;
3439890ff83SToomas Soome 	conout->SetCursorPosition(conout, col, row);
344199767f8SToomas Soome 
3459890ff83SToomas Soome 	efi_cons_efiputchar('\n');
346199767f8SToomas Soome }
347199767f8SToomas Soome 
348199767f8SToomas Soome static void
efi_text_cons_display(struct vis_consdisplay * da)3499890ff83SToomas Soome efi_text_cons_display(struct vis_consdisplay *da)
350199767f8SToomas Soome {
3519890ff83SToomas Soome 	EFI_STATUS st;
3529890ff83SToomas Soome 	UINTN attr;
3539890ff83SToomas Soome 	UINTN row, col;
3549890ff83SToomas Soome 	tem_char_t *data;
3551b61d0d2SToomas Soome 	uint8_t fg, bg;
3569890ff83SToomas Soome 	int i;
357199767f8SToomas Soome 
358190f051bSToomas Soome 	if (!has_boot_services)
359190f051bSToomas Soome 		return;
360190f051bSToomas Soome 
361c6dd35daSToomas Soome 	(void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row);
3629890ff83SToomas Soome 
3639890ff83SToomas Soome 	/* reduce clear line on bottom row by one to prevent autoscroll */
3649890ff83SToomas Soome 	if (row - 1 == da->row && da->col == 0 && da->width == col)
3659890ff83SToomas Soome 		da->width--;
3669890ff83SToomas Soome 
3679890ff83SToomas Soome 	data = (tem_char_t *)da->data;
368fa9eb222SToomas Soome 	fg = solaris_color_to_efi_color[da->fg_color.four & 0xf];
369fa9eb222SToomas Soome 	bg = solaris_color_to_efi_color[da->bg_color.four & 0xf] & 0x7;
3701b61d0d2SToomas Soome 	attr = EFI_TEXT_ATTR(fg, bg);
3711b61d0d2SToomas Soome 
3729890ff83SToomas Soome 	st = conout->SetAttribute(conout, attr);
3739890ff83SToomas Soome 	if (EFI_ERROR(st))
3749890ff83SToomas Soome 		return;
3759890ff83SToomas Soome 	row = da->row;
3769890ff83SToomas Soome 	col = da->col;
3779890ff83SToomas Soome 	conout->SetCursorPosition(conout, col, row);
3789890ff83SToomas Soome 	for (i = 0; i < da->width; i++)
3799890ff83SToomas Soome 		efi_cons_efiputchar(data[i]);
380199767f8SToomas Soome }
381199767f8SToomas Soome 
efi_cons_cursor(struct vis_conscursor * cc)3829890ff83SToomas Soome static void efi_cons_cursor(struct vis_conscursor *cc)
383199767f8SToomas Soome {
3849890ff83SToomas Soome 	switch (cc->action) {
3859890ff83SToomas Soome 	case VIS_HIDE_CURSOR:
3869890ff83SToomas Soome 		if (plat_stdout_is_framebuffer())
3879890ff83SToomas Soome 			gfx_fb_display_cursor(cc);
3889890ff83SToomas Soome 		else
3899890ff83SToomas Soome 			plat_tem_hide_prom_cursor();
390199767f8SToomas Soome 		break;
3919890ff83SToomas Soome 	case VIS_DISPLAY_CURSOR:
3929890ff83SToomas Soome 		if (plat_stdout_is_framebuffer())
3939890ff83SToomas Soome 			gfx_fb_display_cursor(cc);
3949890ff83SToomas Soome 		else
3959890ff83SToomas Soome 			plat_tem_display_prom_cursor(cc->row, cc->col);
396199767f8SToomas Soome 		break;
3979890ff83SToomas Soome 	case VIS_GET_CURSOR: {	/* only used at startup */
3989890ff83SToomas Soome 		uint32_t row, col;
3999890ff83SToomas Soome 
400c6dd35daSToomas Soome 		row = col = 0;
4019890ff83SToomas Soome 		plat_tem_get_prom_pos(&row, &col);
4029890ff83SToomas Soome 		cc->row = row;
4039890ff83SToomas Soome 		cc->col = col;
4049890ff83SToomas Soome 		}
405199767f8SToomas Soome 		break;
406199767f8SToomas Soome 	}
4079890ff83SToomas Soome }
408199767f8SToomas Soome 
4099890ff83SToomas Soome static int
efi_cons_ioctl(struct console * cp,int cmd,void * data)4109890ff83SToomas Soome efi_cons_ioctl(struct console *cp, int cmd, void *data)
4119890ff83SToomas Soome {
4129890ff83SToomas Soome 	struct efi_console_data *ecd = cp->c_private;
4139890ff83SToomas Soome 	struct visual_ops *ops = ecd->ecd_visual_ops;
414199767f8SToomas Soome 
4159890ff83SToomas Soome 	switch (cmd) {
4169890ff83SToomas Soome 	case VIS_GETIDENTIFIER:
4179890ff83SToomas Soome 		memmove(data, ops->ident, sizeof (struct vis_identifier));
4189890ff83SToomas Soome 		break;
4199890ff83SToomas Soome 	case VIS_DEVINIT:
4209890ff83SToomas Soome 		return (ops->devinit(data));
4219890ff83SToomas Soome 	case VIS_CONSCLEAR:
4229890ff83SToomas Soome 		return (ops->cons_clear(data));
4239890ff83SToomas Soome 	case VIS_CONSCOPY:
4249890ff83SToomas Soome 		ops->cons_copy(data);
4259890ff83SToomas Soome 		break;
4269890ff83SToomas Soome 	case VIS_CONSDISPLAY:
4279890ff83SToomas Soome 		ops->cons_display(data);
4289890ff83SToomas Soome 		break;
4299890ff83SToomas Soome 	case VIS_CONSCURSOR:
4309890ff83SToomas Soome 		ops->cons_cursor(data);
4319890ff83SToomas Soome 		break;
4329890ff83SToomas Soome 	default:
4339890ff83SToomas Soome 		return (EINVAL);
434199767f8SToomas Soome 	}
4359890ff83SToomas Soome 	return (0);
436199767f8SToomas Soome }
437199767f8SToomas Soome 
438199767f8SToomas Soome static void
efi_framebuffer_setup(void)4399890ff83SToomas Soome efi_framebuffer_setup(void)
440199767f8SToomas Soome {
4419890ff83SToomas Soome 	int bpp, pos;
442554e720aSToomas Soome 	extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL *shadow_fb;
4439890ff83SToomas Soome 
4449890ff83SToomas Soome 	bpp = fls(efifb.fb_mask_red | efifb.fb_mask_green |
4459890ff83SToomas Soome 	    efifb.fb_mask_blue | efifb.fb_mask_reserved);
4469890ff83SToomas Soome 
447554e720aSToomas Soome 	if (shadow_fb != NULL)
448554e720aSToomas Soome 		free(shadow_fb);
449554e720aSToomas Soome 	shadow_fb = malloc(efifb.fb_width * efifb.fb_height *
450554e720aSToomas Soome 	    sizeof (*shadow_fb));
451554e720aSToomas Soome 
4529890ff83SToomas Soome 	gfx_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER;
4539890ff83SToomas Soome 	gfx_fb.framebuffer_common.mb_size = sizeof (gfx_fb);
4549890ff83SToomas Soome 	gfx_fb.framebuffer_common.framebuffer_addr = efifb.fb_addr;
4559890ff83SToomas Soome 	gfx_fb.framebuffer_common.framebuffer_width = efifb.fb_width;
4569890ff83SToomas Soome 	gfx_fb.framebuffer_common.framebuffer_height = efifb.fb_height;
4579890ff83SToomas Soome 	gfx_fb.framebuffer_common.framebuffer_bpp = bpp;
4589890ff83SToomas Soome 	gfx_fb.framebuffer_common.framebuffer_pitch =
4599890ff83SToomas Soome 	    efifb.fb_stride * (bpp >> 3);
4609890ff83SToomas Soome 	gfx_fb.framebuffer_common.framebuffer_type =
4619890ff83SToomas Soome 	    MULTIBOOT_FRAMEBUFFER_TYPE_RGB;
4629890ff83SToomas Soome 	gfx_fb.framebuffer_common.mb_reserved = 0;
4639890ff83SToomas Soome 
4649890ff83SToomas Soome 	pos = ffs(efifb.fb_mask_red);
4659890ff83SToomas Soome 	if (pos != 0)
4669890ff83SToomas Soome 		pos--;
4679890ff83SToomas Soome 	gfx_fb.u.fb2.framebuffer_red_mask_size = fls(efifb.fb_mask_red >> pos);
4689890ff83SToomas Soome 	gfx_fb.u.fb2.framebuffer_red_field_position = pos;
4699890ff83SToomas Soome 	pos = ffs(efifb.fb_mask_green);
4709890ff83SToomas Soome 	if (pos != 0)
4719890ff83SToomas Soome 		pos--;
4729890ff83SToomas Soome 	gfx_fb.u.fb2.framebuffer_green_mask_size =
4739890ff83SToomas Soome 	    fls(efifb.fb_mask_green >> pos);
4749890ff83SToomas Soome 	gfx_fb.u.fb2.framebuffer_green_field_position = pos;
4759890ff83SToomas Soome 	pos = ffs(efifb.fb_mask_blue);
4769890ff83SToomas Soome 	if (pos != 0)
4779890ff83SToomas Soome 		pos--;
4789890ff83SToomas Soome 	gfx_fb.u.fb2.framebuffer_blue_mask_size =
4799890ff83SToomas Soome 	    fls(efifb.fb_mask_blue >> pos);
4809890ff83SToomas Soome 	gfx_fb.u.fb2.framebuffer_blue_field_position = pos;
481199767f8SToomas Soome }
482199767f8SToomas Soome 
483199767f8SToomas Soome static void
efi_cons_probe(struct console * cp)4849890ff83SToomas Soome efi_cons_probe(struct console *cp)
485a1d63828SToomas Soome {
486a1d63828SToomas Soome 	cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
487a1d63828SToomas Soome }
488a1d63828SToomas Soome 
489a1d63828SToomas Soome static int
efi_cons_init(struct console * cp,int arg __unused)490a1d63828SToomas Soome efi_cons_init(struct console *cp, int arg __unused)
491199767f8SToomas Soome {
4929890ff83SToomas Soome 	struct efi_console_data *ecd;
493a1d63828SToomas Soome 	void *coninex;
4949890ff83SToomas Soome 	EFI_STATUS status;
4959890ff83SToomas Soome 	UINTN i, max_dim, best_mode, cols, rows;
4969890ff83SToomas Soome 
497a1d63828SToomas Soome 	if (cp->c_private != NULL)
498a1d63828SToomas Soome 		return (0);
499a1d63828SToomas Soome 
5009890ff83SToomas Soome 	ecd = calloc(1, sizeof (*ecd));
5019890ff83SToomas Soome 	/*
5029890ff83SToomas Soome 	 * As console probing is called very early, the only reason for
5039890ff83SToomas Soome 	 * out of memory can be that we just do not have enough memory.
5049890ff83SToomas Soome 	 */
5059890ff83SToomas Soome 	if (ecd == NULL)
5069890ff83SToomas Soome 		panic("efi_cons_probe: This system has not enough memory\n");
5079890ff83SToomas Soome 	cp->c_private = ecd;
5089890ff83SToomas Soome 
5099890ff83SToomas Soome 	ecd->ecd_conin = ST->ConIn;
510a1d63828SToomas Soome 	conout = ST->ConOut;
511a1d63828SToomas Soome 
512a1d63828SToomas Soome 	conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
513a1d63828SToomas Soome 	    DEFAULT_BGCOLOR));
514a1d63828SToomas Soome 	memset(keybuf, 0, KEYBUFSZ);
5159890ff83SToomas Soome 
516*f334afcfSToomas Soome 	status = BS->LocateProtocol(&gEfiConsoleControlProtocolGuid, NULL,
517c6dd35daSToomas Soome 	    (void **)&console_control);
5189890ff83SToomas Soome 	if (status == EFI_SUCCESS) {
5199890ff83SToomas Soome 		BOOLEAN GopUgaExists, StdInLocked;
5209890ff83SToomas Soome 		status = console_control->GetMode(console_control,
5219890ff83SToomas Soome 		    &console_mode, &GopUgaExists, &StdInLocked);
5229890ff83SToomas Soome 	} else {
5239890ff83SToomas Soome 		console_mode = EfiConsoleControlScreenText;
5249890ff83SToomas Soome 	}
5259890ff83SToomas Soome 
5269890ff83SToomas Soome 	max_dim = best_mode = 0;
527c6dd35daSToomas Soome 	for (i = 0; i <= conout->Mode->MaxMode; i++) {
5289890ff83SToomas Soome 		status = conout->QueryMode(conout, i, &cols, &rows);
5299890ff83SToomas Soome 		if (EFI_ERROR(status))
5309890ff83SToomas Soome 			continue;
5319890ff83SToomas Soome 		if (cols * rows > max_dim) {
5329890ff83SToomas Soome 			max_dim = cols * rows;
5339890ff83SToomas Soome 			best_mode = i;
534199767f8SToomas Soome 		}
535199767f8SToomas Soome 	}
5369890ff83SToomas Soome 	if (max_dim > 0)
5379890ff83SToomas Soome 		conout->SetMode(conout, best_mode);
5389890ff83SToomas Soome 	status = conout->QueryMode(conout, best_mode, &cols, &rows);
5399890ff83SToomas Soome 	if (EFI_ERROR(status)) {
5409890ff83SToomas Soome 		setenv("screen-#rows", "24", 1);
5419890ff83SToomas Soome 		setenv("screen-#cols", "80", 1);
5429890ff83SToomas Soome 	} else {
5439890ff83SToomas Soome 		char env[8];
5449890ff83SToomas Soome 		snprintf(env, sizeof (env), "%u", (unsigned)rows);
5459890ff83SToomas Soome 		setenv("screen-#rows", env, 1);
5469890ff83SToomas Soome 		snprintf(env, sizeof (env), "%u", (unsigned)cols);
5479890ff83SToomas Soome 		setenv("screen-#cols", env, 1);
5489890ff83SToomas Soome 	}
5499890ff83SToomas Soome 
5509890ff83SToomas Soome 	if (efi_find_framebuffer(&efifb)) {
5519890ff83SToomas Soome 		console_mode = EfiConsoleControlScreenText;
5529890ff83SToomas Soome 		ecd->ecd_visual_ops = &text_ops;
5539890ff83SToomas Soome 	} else {
5549890ff83SToomas Soome 		efi_framebuffer_setup();
5559890ff83SToomas Soome 		console_mode = EfiConsoleControlScreenGraphics;
5569890ff83SToomas Soome 		ecd->ecd_visual_ops = &fb_ops;
5579890ff83SToomas Soome 	}
5589890ff83SToomas Soome 
5599890ff83SToomas Soome 	if (console_control != NULL)
560c6dd35daSToomas Soome 		(void) console_control->SetMode(console_control, console_mode);
5619890ff83SToomas Soome 
5629890ff83SToomas Soome 	/* some firmware enables the cursor when switching modes */
5639890ff83SToomas Soome 	conout->EnableCursor(conout, FALSE);
5649890ff83SToomas Soome 
5659890ff83SToomas Soome 	coninex = NULL;
5669890ff83SToomas Soome 	/*
5679890ff83SToomas Soome 	 * Try to set up for SimpleTextInputEx protocol. If not available,
5689890ff83SToomas Soome 	 * we will use SimpleTextInput protocol.
5699890ff83SToomas Soome 	 */
570*f334afcfSToomas Soome 	status = BS->OpenProtocol(ST->ConsoleInHandle,
571*f334afcfSToomas Soome 	    &gEfiSimpleTextInputExProtocolGuid,
5729890ff83SToomas Soome 	    &coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
5739890ff83SToomas Soome 	if (status == EFI_SUCCESS)
5749890ff83SToomas Soome 		ecd->ecd_coninex = coninex;
5759890ff83SToomas Soome 
5762d84dc94SToomas Soome 	gfx_framework_init();
5779890ff83SToomas Soome 
578a1d63828SToomas Soome 	if (tem_info_init(cp) == 0 && tem == NULL) {
5799890ff83SToomas Soome 		tem = tem_init();
5809890ff83SToomas Soome 		if (tem != NULL)
5819890ff83SToomas Soome 			tem_activate(tem, B_TRUE);
5829890ff83SToomas Soome 	}
5839890ff83SToomas Soome 
5849890ff83SToomas Soome 	if (tem == NULL)
5859890ff83SToomas Soome 		panic("Failed to set up console terminal");
5869890ff83SToomas Soome 
5879890ff83SToomas Soome 	return (0);
5889890ff83SToomas Soome }
5899890ff83SToomas Soome 
5909890ff83SToomas Soome static void
efi_cons_putchar(struct console * cp __unused,int c)5919890ff83SToomas Soome efi_cons_putchar(struct console *cp __unused, int c)
5929890ff83SToomas Soome {
5939890ff83SToomas Soome 	uint8_t buf = c;
5949890ff83SToomas Soome 
5959890ff83SToomas Soome 	/* make sure we have some console output, support for panic() */
5969890ff83SToomas Soome 	if (tem == NULL)
5979890ff83SToomas Soome 		efi_cons_efiputchar(c);
5989890ff83SToomas Soome 	else
5999890ff83SToomas Soome 		tem_write(tem, &buf, sizeof (buf));
600199767f8SToomas Soome }
601199767f8SToomas Soome 
602416f8d72SToomas Soome static int
keybuf_getchar(void)603416f8d72SToomas Soome keybuf_getchar(void)
604199767f8SToomas Soome {
605416f8d72SToomas Soome 	int i, c = 0;
606199767f8SToomas Soome 
607199767f8SToomas Soome 	for (i = 0; i < KEYBUFSZ; i++) {
608199767f8SToomas Soome 		if (keybuf[i] != 0) {
609199767f8SToomas Soome 			c = keybuf[i];
610199767f8SToomas Soome 			keybuf[i] = 0;
611416f8d72SToomas Soome 			break;
612199767f8SToomas Soome 		}
613199767f8SToomas Soome 	}
614199767f8SToomas Soome 
615416f8d72SToomas Soome 	return (c);
616416f8d72SToomas Soome }
617ffedf5deSToomas Soome 
618416f8d72SToomas Soome static bool
keybuf_ischar(void)619416f8d72SToomas Soome keybuf_ischar(void)
620416f8d72SToomas Soome {
621416f8d72SToomas Soome 	int i;
622199767f8SToomas Soome 
623416f8d72SToomas Soome 	for (i = 0; i < KEYBUFSZ; i++) {
624416f8d72SToomas Soome 		if (keybuf[i] != 0)
625416f8d72SToomas Soome 			return (true);
626416f8d72SToomas Soome 	}
627416f8d72SToomas Soome 	return (false);
628416f8d72SToomas Soome }
629416f8d72SToomas Soome 
630416f8d72SToomas Soome /*
631416f8d72SToomas Soome  * We are not reading input before keybuf is empty, so we are safe
632416f8d72SToomas Soome  * just to fill keybuf from the beginning.
633416f8d72SToomas Soome  */
634416f8d72SToomas Soome static void
keybuf_inschar(EFI_INPUT_KEY * key)635416f8d72SToomas Soome keybuf_inschar(EFI_INPUT_KEY *key)
636416f8d72SToomas Soome {
637416f8d72SToomas Soome 
638416f8d72SToomas Soome 	switch (key->ScanCode) {
639169b638eSToomas Soome 	case SCAN_UP: /* UP */
640416f8d72SToomas Soome 		keybuf[0] = 0x1b;	/* esc */
641416f8d72SToomas Soome 		keybuf[1] = '[';
642416f8d72SToomas Soome 		keybuf[2] = 'A';
643416f8d72SToomas Soome 		break;
644169b638eSToomas Soome 	case SCAN_DOWN: /* DOWN */
645416f8d72SToomas Soome 		keybuf[0] = 0x1b;	/* esc */
646416f8d72SToomas Soome 		keybuf[1] = '[';
647416f8d72SToomas Soome 		keybuf[2] = 'B';
648416f8d72SToomas Soome 		break;
649169b638eSToomas Soome 	case SCAN_RIGHT: /* RIGHT */
650416f8d72SToomas Soome 		keybuf[0] = 0x1b;	/* esc */
651416f8d72SToomas Soome 		keybuf[1] = '[';
652416f8d72SToomas Soome 		keybuf[2] = 'C';
653416f8d72SToomas Soome 		break;
654169b638eSToomas Soome 	case SCAN_LEFT: /* LEFT */
655416f8d72SToomas Soome 		keybuf[0] = 0x1b;	/* esc */
656416f8d72SToomas Soome 		keybuf[1] = '[';
657416f8d72SToomas Soome 		keybuf[2] = 'D';
658416f8d72SToomas Soome 		break;
659169b638eSToomas Soome 	case SCAN_DELETE:
660169b638eSToomas Soome 		keybuf[0] = CHAR_BACKSPACE;
661169b638eSToomas Soome 		break;
662169b638eSToomas Soome 	case SCAN_ESC:
663416f8d72SToomas Soome 		keybuf[0] = 0x1b;	/* esc */
664416f8d72SToomas Soome 		break;
665416f8d72SToomas Soome 	default:
666416f8d72SToomas Soome 		keybuf[0] = key->UnicodeChar;
667416f8d72SToomas Soome 		break;
668199767f8SToomas Soome 	}
669416f8d72SToomas Soome }
670199767f8SToomas Soome 
671416f8d72SToomas Soome static bool
efi_readkey(SIMPLE_INPUT_INTERFACE * conin)6729890ff83SToomas Soome efi_readkey(SIMPLE_INPUT_INTERFACE *conin)
673416f8d72SToomas Soome {
674416f8d72SToomas Soome 	EFI_STATUS status;
675416f8d72SToomas Soome 	EFI_INPUT_KEY key;
676416f8d72SToomas Soome 
677416f8d72SToomas Soome 	status = conin->ReadKeyStroke(conin, &key);
678416f8d72SToomas Soome 	if (status == EFI_SUCCESS) {
679416f8d72SToomas Soome 		keybuf_inschar(&key);
680416f8d72SToomas Soome 		return (true);
681416f8d72SToomas Soome 	}
682416f8d72SToomas Soome 	return (false);
683199767f8SToomas Soome }
684199767f8SToomas Soome 
6859890ff83SToomas Soome static bool
efi_readkey_ex(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * coninex)6869890ff83SToomas Soome efi_readkey_ex(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex)
687199767f8SToomas Soome {
6889890ff83SToomas Soome 	EFI_STATUS status;
6899890ff83SToomas Soome 	EFI_INPUT_KEY *kp;
6909890ff83SToomas Soome 	EFI_KEY_DATA  key_data;
6919890ff83SToomas Soome 	uint32_t kss;
6929890ff83SToomas Soome 
6939890ff83SToomas Soome 	status = coninex->ReadKeyStrokeEx(coninex, &key_data);
6949890ff83SToomas Soome 	if (status == EFI_SUCCESS) {
6959890ff83SToomas Soome 		kss = key_data.KeyState.KeyShiftState;
6969890ff83SToomas Soome 		kp = &key_data.Key;
6979890ff83SToomas Soome 		if (kss & EFI_SHIFT_STATE_VALID) {
6989890ff83SToomas Soome 
6999890ff83SToomas Soome 			/*
7009890ff83SToomas Soome 			 * quick mapping to control chars, replace with
7019890ff83SToomas Soome 			 * map lookup later.
7029890ff83SToomas Soome 			 */
7039890ff83SToomas Soome 			if (kss & EFI_RIGHT_CONTROL_PRESSED ||
7049890ff83SToomas Soome 			    kss & EFI_LEFT_CONTROL_PRESSED) {
7059890ff83SToomas Soome 				if (kp->UnicodeChar >= 'a' &&
7069890ff83SToomas Soome 				    kp->UnicodeChar <= 'z') {
7079890ff83SToomas Soome 					kp->UnicodeChar -= 'a';
7089890ff83SToomas Soome 					kp->UnicodeChar++;
7099890ff83SToomas Soome 				}
7109890ff83SToomas Soome 			}
7119890ff83SToomas Soome 		}
712bf74bfd4SToomas Soome 		/*
713bf74bfd4SToomas Soome 		 * The shift state and/or toggle state may not be valid,
714bf74bfd4SToomas Soome 		 * but we still can have ScanCode or UnicodeChar.
715bf74bfd4SToomas Soome 		 */
716bf74bfd4SToomas Soome 		if (kp->ScanCode == 0 && kp->UnicodeChar == 0)
717bf74bfd4SToomas Soome 			return (false);
718bf74bfd4SToomas Soome 		keybuf_inschar(kp);
719bf74bfd4SToomas Soome 		return (true);
7209890ff83SToomas Soome 	}
7219890ff83SToomas Soome 	return (false);
7229890ff83SToomas Soome }
7239890ff83SToomas Soome 
7249890ff83SToomas Soome static int
efi_cons_getchar(struct console * cp)7259890ff83SToomas Soome efi_cons_getchar(struct console *cp)
7269890ff83SToomas Soome {
7279890ff83SToomas Soome 	struct efi_console_data *ecd;
728416f8d72SToomas Soome 	int c;
729199767f8SToomas Soome 
730416f8d72SToomas Soome 	if ((c = keybuf_getchar()) != 0)
731416f8d72SToomas Soome 		return (c);
732416f8d72SToomas Soome 
733190f051bSToomas Soome 	if (!has_boot_services)
734190f051bSToomas Soome 		return (-1);
735190f051bSToomas Soome 
7369890ff83SToomas Soome 	ecd = cp->c_private;
737416f8d72SToomas Soome 	key_pending = 0;
738416f8d72SToomas Soome 
7399890ff83SToomas Soome 	if (ecd->ecd_coninex == NULL) {
7409890ff83SToomas Soome 		if (efi_readkey(ecd->ecd_conin))
7419890ff83SToomas Soome 			return (keybuf_getchar());
7429890ff83SToomas Soome 	} else {
7439890ff83SToomas Soome 		if (efi_readkey_ex(ecd->ecd_coninex))
7449890ff83SToomas Soome 			return (keybuf_getchar());
7459890ff83SToomas Soome 	}
746416f8d72SToomas Soome 
747416f8d72SToomas Soome 	return (-1);
748416f8d72SToomas Soome }
749199767f8SToomas Soome 
7509890ff83SToomas Soome static int
efi_cons_poll(struct console * cp)7519890ff83SToomas Soome efi_cons_poll(struct console *cp)
752416f8d72SToomas Soome {
7539890ff83SToomas Soome 	struct efi_console_data *ecd;
7549890ff83SToomas Soome 	EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
7559890ff83SToomas Soome 	SIMPLE_INPUT_INTERFACE *conin;
7569890ff83SToomas Soome 	EFI_STATUS status;
7579890ff83SToomas Soome 
758416f8d72SToomas Soome 	if (keybuf_ischar() || key_pending)
759ffedf5deSToomas Soome 		return (1);
760ffedf5deSToomas Soome 
761190f051bSToomas Soome 	if (!has_boot_services)
762190f051bSToomas Soome 		return (0);
763190f051bSToomas Soome 
7649890ff83SToomas Soome 	ecd = cp->c_private;
7659890ff83SToomas Soome 	coninex = ecd->ecd_coninex;
7669890ff83SToomas Soome 	conin = ecd->ecd_conin;
767416f8d72SToomas Soome 	/*
768416f8d72SToomas Soome 	 * Some EFI implementation (u-boot for example) do not support
769416f8d72SToomas Soome 	 * WaitForKey().
770416f8d72SToomas Soome 	 * CheckEvent() can clear the signaled state.
771416f8d72SToomas Soome 	 */
7729890ff83SToomas Soome 	if (coninex != NULL) {
7739890ff83SToomas Soome 		if (coninex->WaitForKeyEx == NULL)
7749890ff83SToomas Soome 			key_pending = efi_readkey_ex(coninex);
7759890ff83SToomas Soome 		else {
7769890ff83SToomas Soome 			status = BS->CheckEvent(coninex->WaitForKeyEx);
7779890ff83SToomas Soome 			key_pending = status == EFI_SUCCESS;
7789890ff83SToomas Soome 		}
7799890ff83SToomas Soome 	} else {
7809890ff83SToomas Soome 		if (conin->WaitForKey == NULL)
7819890ff83SToomas Soome 			key_pending = efi_readkey(conin);
7829890ff83SToomas Soome 		else {
7839890ff83SToomas Soome 			status = BS->CheckEvent(conin->WaitForKey);
7849890ff83SToomas Soome 			key_pending = status == EFI_SUCCESS;
7859890ff83SToomas Soome 		}
7869890ff83SToomas Soome 	}
787ffedf5deSToomas Soome 
788416f8d72SToomas Soome 	return (key_pending);
789199767f8SToomas Soome }
790199767f8SToomas Soome 
791199767f8SToomas Soome /* Plain direct access to EFI OutputString(). */
792199767f8SToomas Soome void
efi_cons_efiputchar(int c)793199767f8SToomas Soome efi_cons_efiputchar(int c)
794199767f8SToomas Soome {
795199767f8SToomas Soome 	CHAR16 buf[2];
7969890ff83SToomas Soome 	EFI_STATUS status;
797199767f8SToomas Soome 
7989890ff83SToomas Soome 	buf[0] = c;
799c6dd35daSToomas Soome 	buf[1] = 0;	/* terminate string */
800199767f8SToomas Soome 
8019890ff83SToomas Soome 	status = conout->TestString(conout, buf);
8029890ff83SToomas Soome 	if (EFI_ERROR(status))
8039890ff83SToomas Soome 		buf[0] = '?';
804199767f8SToomas Soome 	conout->OutputString(conout, buf);
805199767f8SToomas Soome }
80680e47917SToomas Soome 
80780e47917SToomas Soome static void
efi_cons_devinfo_print(EFI_HANDLE handle)80880e47917SToomas Soome efi_cons_devinfo_print(EFI_HANDLE handle)
80980e47917SToomas Soome {
81080e47917SToomas Soome 	EFI_DEVICE_PATH *dp;
81180e47917SToomas Soome 	CHAR16 *text;
81280e47917SToomas Soome 
81380e47917SToomas Soome 	dp = efi_lookup_devpath(handle);
81480e47917SToomas Soome 	if (dp == NULL)
81580e47917SToomas Soome 		return;
81680e47917SToomas Soome 
81780e47917SToomas Soome 	text = efi_devpath_name(dp);
81880e47917SToomas Soome 	if (text == NULL)
81980e47917SToomas Soome 		return;
82080e47917SToomas Soome 
82180e47917SToomas Soome 	printf("\t%S", text);
82280e47917SToomas Soome 	efi_free_devpath_name(text);
82380e47917SToomas Soome }
82480e47917SToomas Soome 
82580e47917SToomas Soome static void
efi_cons_devinfo(struct console * cp __unused)82680e47917SToomas Soome efi_cons_devinfo(struct console *cp __unused)
82780e47917SToomas Soome {
82880e47917SToomas Soome 	EFI_HANDLE *handles;
82969764de3SToomas Soome 	uint_t nhandles;
83080e47917SToomas Soome 	EFI_STATUS status;
83180e47917SToomas Soome 
83280e47917SToomas Soome 	if (gop != NULL)
833*f334afcfSToomas Soome 		status = efi_get_protocol_handles(
834*f334afcfSToomas Soome 		    &gEfiGraphicsOutputProtocolGuid, &nhandles, &handles);
83580e47917SToomas Soome 	else
836*f334afcfSToomas Soome 		status = efi_get_protocol_handles(&gEfiUgaDrawProtocolGuid,
837*f334afcfSToomas Soome 		    &nhandles, &handles);
83880e47917SToomas Soome 
83980e47917SToomas Soome 	if (EFI_ERROR(status))
84080e47917SToomas Soome 		return;
84180e47917SToomas Soome 
84269764de3SToomas Soome 	for (uint_t i = 0; i < nhandles; i++)
84380e47917SToomas Soome 		efi_cons_devinfo_print(handles[i]);
84480e47917SToomas Soome 
84569764de3SToomas Soome 	free(handles);
84680e47917SToomas Soome }
847