xref: /openbsd/sys/dev/fdt/simplefb.c (revision e0f76f79)
1*e0f76f79Skettenis /*	$OpenBSD: simplefb.c,v 1.20 2023/04/16 11:34:32 kettenis Exp $	*/
26fd46d03Skettenis /*
36fd46d03Skettenis  * Copyright (c) 2016 Mark Kettenis
46fd46d03Skettenis  *
56fd46d03Skettenis  * Permission to use, copy, modify, and distribute this software for any
66fd46d03Skettenis  * purpose with or without fee is hereby granted, provided that the above
76fd46d03Skettenis  * copyright notice and this permission notice appear in all copies.
86fd46d03Skettenis  *
96fd46d03Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106fd46d03Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116fd46d03Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126fd46d03Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136fd46d03Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146fd46d03Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156fd46d03Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166fd46d03Skettenis  */
176fd46d03Skettenis 
186fd46d03Skettenis #include <sys/param.h>
196fd46d03Skettenis #include <sys/systm.h>
206fd46d03Skettenis #include <sys/device.h>
216fd46d03Skettenis 
228186ecd8Skettenis #include <uvm/uvm_extern.h>
238186ecd8Skettenis 
246fd46d03Skettenis #include <machine/bus.h>
256fd46d03Skettenis #include <machine/fdt.h>
266fd46d03Skettenis 
276fd46d03Skettenis #include <dev/ofw/openfirm.h>
286fd46d03Skettenis #include <dev/ofw/fdt.h>
296fd46d03Skettenis 
306fd46d03Skettenis #include <dev/wscons/wsconsio.h>
316fd46d03Skettenis #include <dev/wscons/wsdisplayvar.h>
326fd46d03Skettenis #include <dev/rasops/rasops.h>
336fd46d03Skettenis 
3462b18b30Skettenis #define SIMPLEFB_WIDTH	160
3562b18b30Skettenis #define SIMPLEFB_HEIGHT	50
3662b18b30Skettenis 
376fd46d03Skettenis struct simplefb_format {
386fd46d03Skettenis 	const char *format;
396fd46d03Skettenis 	int depth;
406fd46d03Skettenis 	int rpos, rnum;
416fd46d03Skettenis 	int gpos, gnum;
426fd46d03Skettenis 	int bpos, bnum;
436fd46d03Skettenis };
446fd46d03Skettenis 
456fd46d03Skettenis /*
464b1a56afSjsg  * Supported pixel formats.  Layout omitted when it matches the
476fd46d03Skettenis  * rasops defaults.
486fd46d03Skettenis  */
49c39c0495Skn const struct simplefb_format simplefb_formats[] = {
506fd46d03Skettenis 	{ "r5g6b5", 16 },
516fd46d03Skettenis 	{ "x1r5g5b5", 15 },
526fd46d03Skettenis 	{ "a1r5g5b5", 15 },
536fd46d03Skettenis 	{ "r8g8b8", 24 },
5462b18b30Skettenis 	{ "x8r8g8b8", 32, 16, 8, 8, 8, 0, 8 },
5562b18b30Skettenis 	{ "a8r8g8b8", 32, 16, 8, 8, 8, 0, 8 },
5662b18b30Skettenis 	{ "x8b8g8r8", 32 },
570af672a9Skettenis 	{ "a8b8g8r8", 32 },
580af672a9Skettenis 	{ "x2r10g10b10", 32, 20, 10, 10, 10, 0, 10 },
590af672a9Skettenis 	{ "a2r10g10b10", 32, 20, 10, 10, 10, 0, 10 },
606fd46d03Skettenis };
616fd46d03Skettenis 
626fd46d03Skettenis struct simplefb_softc {
636fd46d03Skettenis 	struct device		sc_dev;
646fd46d03Skettenis 	bus_space_tag_t		sc_iot;
656fd46d03Skettenis 	bus_space_handle_t	sc_ioh;
666fd46d03Skettenis 
676fd46d03Skettenis 	struct rasops_info	sc_ri;
686fd46d03Skettenis 	struct wsscreen_descr	sc_wsd;
696fd46d03Skettenis 	struct wsscreen_list	sc_wsl;
706fd46d03Skettenis 	struct wsscreen_descr	*sc_scrlist[1];
716fd46d03Skettenis 
726fd46d03Skettenis 	struct simplefb_format	*sc_format;
736fd46d03Skettenis 	paddr_t			sc_paddr;
746fd46d03Skettenis 	psize_t			sc_psize;
756fd46d03Skettenis };
766fd46d03Skettenis 
77f2edca47Stobhe void (*simplefb_burn_hook)(u_int) = NULL;
78f2edca47Stobhe 
7962b18b30Skettenis struct rasops_info simplefb_ri;
8062b18b30Skettenis struct wsscreen_descr simplefb_wsd = { "std" };
8162b18b30Skettenis struct wsdisplay_charcell simplefb_bs[SIMPLEFB_WIDTH * SIMPLEFB_HEIGHT];
8262b18b30Skettenis 
836fd46d03Skettenis int	simplefb_match(struct device *, void *, void *);
846fd46d03Skettenis void	simplefb_attach(struct device *, struct device *, void *);
856fd46d03Skettenis 
869fdf0c62Smpi const struct cfattach simplefb_ca = {
876fd46d03Skettenis 	sizeof(struct simplefb_softc), simplefb_match, simplefb_attach
886fd46d03Skettenis };
896fd46d03Skettenis 
906fd46d03Skettenis struct cfdriver simplefb_cd = {
916fd46d03Skettenis 	NULL, "simplefb", DV_DULL
926fd46d03Skettenis };
936fd46d03Skettenis 
9462b18b30Skettenis const char *simplefb_init(int, struct rasops_info *);
9562b18b30Skettenis 
966fd46d03Skettenis int	simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *);
976fd46d03Skettenis paddr_t	simplefb_wsmmap(void *, off_t, int);
986fd46d03Skettenis int	simplefb_alloc_screen(void *, const struct wsscreen_descr *,
99e0c3e559Sjsg 	    void **, int *, int *, uint32_t *);
100f2edca47Stobhe void	simplefb_burn_screen(void *, u_int, u_int);
1016fd46d03Skettenis 
1026fd46d03Skettenis struct wsdisplay_accessops simplefb_accessops = {
1036fd46d03Skettenis 	.ioctl = simplefb_wsioctl,
1046fd46d03Skettenis 	.mmap = simplefb_wsmmap,
1056fd46d03Skettenis 	.alloc_screen = simplefb_alloc_screen,
1066fd46d03Skettenis 	.free_screen = rasops_free_screen,
1076fd46d03Skettenis 	.show_screen = rasops_show_screen,
1086fd46d03Skettenis 	.getchar = rasops_getchar,
1096fd46d03Skettenis 	.load_font = rasops_load_font,
1106fd46d03Skettenis 	.list_font = rasops_list_font,
111f2edca47Stobhe 	.scrollback = rasops_scrollback,
112f2edca47Stobhe 	.burn_screen = simplefb_burn_screen,
1136fd46d03Skettenis };
1146fd46d03Skettenis 
1156fd46d03Skettenis int
simplefb_match(struct device * parent,void * match,void * aux)1166fd46d03Skettenis simplefb_match(struct device *parent, void *match, void *aux)
1176fd46d03Skettenis {
1186fd46d03Skettenis 	struct fdt_attach_args *faa = aux;
1196fd46d03Skettenis 
12067e2424dSpatrick 	/* Don't attach if it has no address space. */
12167e2424dSpatrick 	if (faa->fa_nreg < 1 || faa->fa_reg[0].size == 0)
12267e2424dSpatrick 		return 0;
12367e2424dSpatrick 
1242723123cSkettenis 	/* Don't attach if another driver already claimed our framebuffer. */
12567e2424dSpatrick 	if (rasops_check_framebuffer(faa->fa_reg[0].addr))
1262723123cSkettenis 		return 0;
1272723123cSkettenis 
1286fd46d03Skettenis 	return OF_is_compatible(faa->fa_node, "simple-framebuffer");
1296fd46d03Skettenis }
1306fd46d03Skettenis 
1316fd46d03Skettenis void
simplefb_attach(struct device * parent,struct device * self,void * aux)1326fd46d03Skettenis simplefb_attach(struct device *parent, struct device *self, void *aux)
1336fd46d03Skettenis {
1346fd46d03Skettenis 	struct simplefb_softc *sc = (struct simplefb_softc *)self;
1356fd46d03Skettenis 	struct fdt_attach_args *faa = aux;
1366fd46d03Skettenis 	struct rasops_info *ri = &sc->sc_ri;
1376fd46d03Skettenis 	struct wsemuldisplaydev_attach_args waa;
13862b18b30Skettenis 	const char *format;
13962b18b30Skettenis 	int console = 0;
140e0c3e559Sjsg 	uint32_t defattr;
1416fd46d03Skettenis 
14262b18b30Skettenis 	format = simplefb_init(faa->fa_node, ri);
14362b18b30Skettenis 	if (format) {
1446fd46d03Skettenis 		printf(": unsupported format \"%s\"\n", format);
1456fd46d03Skettenis 		return;
1466fd46d03Skettenis 	}
1476fd46d03Skettenis 
14862b18b30Skettenis 	if (faa->fa_node == stdout_node)
14962b18b30Skettenis 		console = 1;
15062b18b30Skettenis 
1516fd46d03Skettenis 	sc->sc_iot = faa->fa_iot;
1526fd46d03Skettenis 	sc->sc_paddr = faa->fa_reg[0].addr;
1536fd46d03Skettenis 	sc->sc_psize = faa->fa_reg[0].size;
1546fd46d03Skettenis 	if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize,
15562b18b30Skettenis 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh)) {
15662b18b30Skettenis 		printf(": can't map framebuffer\n");
15762b18b30Skettenis 		return;
15862b18b30Skettenis 	}
1596fd46d03Skettenis 
1606fd46d03Skettenis 	ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
1616fd46d03Skettenis 	ri->ri_hw = sc;
1626fd46d03Skettenis 
16362b18b30Skettenis 	if (console) {
16462b18b30Skettenis 		/* Preserve contents. */
16562b18b30Skettenis 		ri->ri_bs = simplefb_bs;
16662b18b30Skettenis 		ri->ri_flg &= ~RI_CLEAR;
16762b18b30Skettenis 	}
16862b18b30Skettenis 
169f3d31b3eSfcambus 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
1706fd46d03Skettenis 
17162b18b30Skettenis 	ri->ri_flg |= RI_VCONS;
17262b18b30Skettenis 	rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH);
1736fd46d03Skettenis 
1746fd46d03Skettenis 	strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
1756fd46d03Skettenis 	sc->sc_wsd.capabilities = ri->ri_caps;
1766fd46d03Skettenis 	sc->sc_wsd.nrows = ri->ri_rows;
1776fd46d03Skettenis 	sc->sc_wsd.ncols = ri->ri_cols;
1786fd46d03Skettenis 	sc->sc_wsd.textops = &ri->ri_ops;
1796fd46d03Skettenis 	sc->sc_wsd.fontwidth = ri->ri_font->fontwidth;
1806fd46d03Skettenis 	sc->sc_wsd.fontheight = ri->ri_font->fontheight;
1816fd46d03Skettenis 
1826fd46d03Skettenis 	sc->sc_scrlist[0] = &sc->sc_wsd;
1836fd46d03Skettenis 	sc->sc_wsl.nscreens = 1;
1846fd46d03Skettenis 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
1856fd46d03Skettenis 
18662b18b30Skettenis 	if (console) {
187fc223b23Sjsg 		ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr);
18862b18b30Skettenis 		wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active,
18962b18b30Skettenis 		    simplefb_ri.ri_ccol, simplefb_ri.ri_crow, defattr);
19062b18b30Skettenis 	}
19162b18b30Skettenis 
1926fd46d03Skettenis 	memset(&waa, 0, sizeof(waa));
1936fd46d03Skettenis 	waa.scrdata = &sc->sc_wsl;
1946fd46d03Skettenis 	waa.accessops = &simplefb_accessops;
1956fd46d03Skettenis 	waa.accesscookie = ri;
19662b18b30Skettenis 	waa.console = console;
1976fd46d03Skettenis 
1986fd46d03Skettenis 	config_found_sm(self, &waa, wsemuldisplaydevprint,
1996fd46d03Skettenis 	    wsemuldisplaydevsubmatch);
2006fd46d03Skettenis }
2016fd46d03Skettenis 
20262b18b30Skettenis const char *
simplefb_init(int node,struct rasops_info * ri)20362b18b30Skettenis simplefb_init(int node, struct rasops_info *ri)
20462b18b30Skettenis {
205c39c0495Skn 	const struct simplefb_format *fmt = NULL;
20662b18b30Skettenis 	static char format[16];
20762b18b30Skettenis 	int i;
20862b18b30Skettenis 
20962b18b30Skettenis 	format[0] = 0;
21062b18b30Skettenis 	OF_getprop(node, "format", format, sizeof(format));
21162b18b30Skettenis 	format[sizeof(format) - 1] = 0;
21262b18b30Skettenis 
21362b18b30Skettenis 	for (i = 0; i < nitems(simplefb_formats); i++) {
21462b18b30Skettenis 		if (strcmp(format, simplefb_formats[i].format) == 0) {
21562b18b30Skettenis 			fmt = &simplefb_formats[i];
21662b18b30Skettenis 			break;
21762b18b30Skettenis 		}
21862b18b30Skettenis 	}
21962b18b30Skettenis 	if (fmt == NULL)
22062b18b30Skettenis 		return format;
22162b18b30Skettenis 
22262b18b30Skettenis 	ri->ri_width = OF_getpropint(node, "width", 0);
22362b18b30Skettenis 	ri->ri_height = OF_getpropint(node, "height", 0);
22462b18b30Skettenis 	ri->ri_stride = OF_getpropint(node, "stride", 0);
22562b18b30Skettenis 	ri->ri_depth = fmt->depth;
22662b18b30Skettenis 	ri->ri_rpos = fmt->rpos;
22762b18b30Skettenis 	ri->ri_rnum = fmt->rnum;
22862b18b30Skettenis 	ri->ri_gpos = fmt->gpos;
22962b18b30Skettenis 	ri->ri_gnum = fmt->gnum;
23062b18b30Skettenis 	ri->ri_bpos = fmt->bpos;
23162b18b30Skettenis 	ri->ri_bnum = fmt->bnum;
23262b18b30Skettenis 	ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR | RI_WRONLY;
23362b18b30Skettenis 
23462b18b30Skettenis 	return NULL;
23562b18b30Skettenis }
23662b18b30Skettenis 
2376fd46d03Skettenis int
simplefb_wsioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)2386fd46d03Skettenis simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
2396fd46d03Skettenis {
2406fd46d03Skettenis 	struct rasops_info *ri = v;
24163294167Skettenis 	struct simplefb_softc *sc = ri->ri_hw;
2428cd7757eSkettenis 	struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
2436fd46d03Skettenis 	struct wsdisplay_fbinfo	*wdf;
2446fd46d03Skettenis 
2456fd46d03Skettenis 	switch (cmd) {
2468cd7757eSkettenis 	case WSDISPLAYIO_GETPARAM:
2478cd7757eSkettenis 		if (ws_get_param)
2488cd7757eSkettenis 			return ws_get_param(dp);
2498cd7757eSkettenis 		return -1;
2508cd7757eSkettenis 	case WSDISPLAYIO_SETPARAM:
2518cd7757eSkettenis 		if (ws_set_param)
2528cd7757eSkettenis 			return ws_set_param(dp);
2538cd7757eSkettenis 		return -1;
2546fd46d03Skettenis 	case WSDISPLAYIO_GTYPE:
2557321c2f6Sjsg 		*(u_int *)data = WSDISPLAY_TYPE_EFIFB;
2566fd46d03Skettenis 		return 0;
2576fd46d03Skettenis 	case WSDISPLAYIO_GINFO:
2586fd46d03Skettenis 		wdf = (struct wsdisplay_fbinfo *)data;
2596fd46d03Skettenis 		wdf->width = ri->ri_width;
2606fd46d03Skettenis 		wdf->height = ri->ri_height;
2616fd46d03Skettenis 		wdf->depth = ri->ri_depth;
26263294167Skettenis 		wdf->stride = ri->ri_stride;
26363294167Skettenis 		wdf->offset = sc->sc_paddr & PAGE_MASK;
2646fd46d03Skettenis 		wdf->cmsize = 0;	/* color map is unavailable */
2656fd46d03Skettenis 		break;
2666fd46d03Skettenis 	case WSDISPLAYIO_LINEBYTES:
2676fd46d03Skettenis 		*(u_int *)data = ri->ri_stride;
2686fd46d03Skettenis 		break;
2696fd46d03Skettenis 	case WSDISPLAYIO_SMODE:
2706fd46d03Skettenis 		break;
2716fd46d03Skettenis 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
2726fd46d03Skettenis 		switch (ri->ri_depth) {
2736fd46d03Skettenis 		case 32:
2745e550f18Skettenis 			if (ri->ri_rnum == 10)
2755e550f18Skettenis 				*(u_int *)data = WSDISPLAYIO_DEPTH_30;
2765e550f18Skettenis 			else
2776fd46d03Skettenis 				*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
2786fd46d03Skettenis 			break;
2796fd46d03Skettenis 		case 24:
2806fd46d03Skettenis 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_24;
2816fd46d03Skettenis 			break;
2826fd46d03Skettenis 		case 16:
2836fd46d03Skettenis 			*(u_int *)data = WSDISPLAYIO_DEPTH_16;
2846fd46d03Skettenis 			break;
2856fd46d03Skettenis 		case 15:
2866fd46d03Skettenis 			*(u_int *)data = WSDISPLAYIO_DEPTH_15;
2876fd46d03Skettenis 			break;
2886fd46d03Skettenis 		default:
2896fd46d03Skettenis 			return -1;
2906fd46d03Skettenis 		}
2916fd46d03Skettenis 		break;
292*e0f76f79Skettenis 	case WSDISPLAYIO_GVIDEO:
293*e0f76f79Skettenis 	case WSDISPLAYIO_SVIDEO:
294*e0f76f79Skettenis 		break;
2956fd46d03Skettenis 	default:
2966fd46d03Skettenis 		return -1;
2976fd46d03Skettenis 	}
2986fd46d03Skettenis 
2996fd46d03Skettenis 	return 0;
3006fd46d03Skettenis }
3016fd46d03Skettenis 
3026fd46d03Skettenis paddr_t
simplefb_wsmmap(void * v,off_t off,int prot)3036fd46d03Skettenis simplefb_wsmmap(void *v, off_t off, int prot)
3046fd46d03Skettenis {
3056fd46d03Skettenis 	struct rasops_info *ri = v;
3066fd46d03Skettenis 	struct simplefb_softc *sc = ri->ri_hw;
3076fd46d03Skettenis 
308ec0359a7Skettenis 	if (off < 0 || off >= (sc->sc_psize + (sc->sc_paddr & PAGE_MASK)))
3096fd46d03Skettenis 		return -1;
3106fd46d03Skettenis 
311ec0359a7Skettenis 	return (((sc->sc_paddr & ~PAGE_MASK) + off) | PMAP_NOCACHE);
3126fd46d03Skettenis }
3136fd46d03Skettenis 
3146fd46d03Skettenis int
simplefb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,uint32_t * attrp)3156fd46d03Skettenis simplefb_alloc_screen(void *v, const struct wsscreen_descr *type,
316e0c3e559Sjsg     void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
3176fd46d03Skettenis {
3186fd46d03Skettenis 	return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp);
3196fd46d03Skettenis }
32062b18b30Skettenis 
321f2edca47Stobhe void
simplefb_burn_screen(void * v,u_int on,u_int flags)322f2edca47Stobhe simplefb_burn_screen(void *v, u_int on, u_int flags)
323f2edca47Stobhe {
324f2edca47Stobhe 	if (simplefb_burn_hook != NULL)
325f2edca47Stobhe 		simplefb_burn_hook(on);
326f2edca47Stobhe }
327f2edca47Stobhe 
32862b18b30Skettenis #include "ukbd.h"
32962b18b30Skettenis 
33062b18b30Skettenis #if NUKBD > 0
33162b18b30Skettenis #include <dev/usb/ukbdvar.h>
33262b18b30Skettenis #endif
33362b18b30Skettenis 
33462b18b30Skettenis void
simplefb_init_cons(bus_space_tag_t iot)33562b18b30Skettenis simplefb_init_cons(bus_space_tag_t iot)
33662b18b30Skettenis {
33762b18b30Skettenis 	struct rasops_info *ri = &simplefb_ri;
33862b18b30Skettenis 	bus_space_handle_t ioh;
33962b18b30Skettenis 	struct fdt_reg reg;
34062b18b30Skettenis 	void *node;
341e0c3e559Sjsg 	uint32_t defattr = 0;
34262b18b30Skettenis 
34362b18b30Skettenis 	node = fdt_find_cons("simple-framebuffer");
34462b18b30Skettenis 	if (node == NULL)
34562b18b30Skettenis 		return;
34662b18b30Skettenis 
34762b18b30Skettenis 	if (fdt_get_reg(node, 0, &reg))
34862b18b30Skettenis 		return;
34962b18b30Skettenis 
35062b18b30Skettenis 	if (bus_space_map(iot, reg.addr, reg.size,
35162b18b30Skettenis 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh))
35262b18b30Skettenis 		return;
35362b18b30Skettenis 
35462b18b30Skettenis 	ri->ri_bits = bus_space_vaddr(iot, ioh);
35562b18b30Skettenis 
35662b18b30Skettenis 	if (simplefb_init(stdout_node, ri))
35762b18b30Skettenis 		return;
35862b18b30Skettenis 
35962b18b30Skettenis 	ri->ri_bs = simplefb_bs;
36062b18b30Skettenis 	rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH);
36162b18b30Skettenis 
36262b18b30Skettenis 	simplefb_wsd.capabilities = ri->ri_caps;
36362b18b30Skettenis 	simplefb_wsd.ncols = ri->ri_cols;
36462b18b30Skettenis 	simplefb_wsd.nrows = ri->ri_rows;
36562b18b30Skettenis 	simplefb_wsd.textops = &ri->ri_ops;
36662b18b30Skettenis 	simplefb_wsd.fontwidth = ri->ri_font->fontwidth;
36762b18b30Skettenis 	simplefb_wsd.fontheight = ri->ri_font->fontheight;
36862b18b30Skettenis 
369fc223b23Sjsg 	ri->ri_ops.pack_attr(ri, 0, 0, 0, &defattr);
37062b18b30Skettenis 	wsdisplay_cnattach(&simplefb_wsd, ri, 0, 0, defattr);
37162b18b30Skettenis 
37262b18b30Skettenis #if NUKBD > 0
37362b18b30Skettenis 	/* Allow USB keyboards to become the console input device. */
37462b18b30Skettenis 	ukbd_cnattach();
37562b18b30Skettenis #endif
37662b18b30Skettenis }
377