Home | History | Annotate | Line # | Download | only in ee
      1 /*	$NetBSD: gsfb.c,v 1.24 2021/08/07 16:19:02 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by UCHIYAMA Yasushi.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: gsfb.c,v 1.24 2021/08/07 16:19:02 thorpej Exp $");
     34 
     35 #include "debug_playstation2.h"
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 
     40 #include <machine/autoconf.h>
     41 
     42 #include <dev/cons.h>
     43 
     44 #include <dev/wscons/wsconsio.h>
     45 #include <dev/wscons/wsdisplayvar.h>
     46 #include <dev/wscons/wscons_callbacks.h>
     47 
     48 #include <dev/wsfont/wsfont.h>
     49 
     50 #include <playstation2/ee/eevar.h>
     51 #include <playstation2/ee/gsvar.h>
     52 #include <playstation2/ee/gsreg.h>
     53 #include <playstation2/ee/dmacvar.h>
     54 #include <playstation2/ee/dmacreg.h>
     55 
     56 #ifdef DEBUG
     57 #define STATIC
     58 #else
     59 #define STATIC	static
     60 #endif
     61 
     62 struct gsfb_softc {
     63 	device_t sc_dev;
     64 	const struct wsscreen_descr *sc_screen;
     65 	struct wsdisplay_font *sc_font;
     66 	bool sc_is_console;
     67 };
     68 
     69 static int gsfb_is_console;
     70 static struct gsfb_softc gsfb_console_softc;
     71 
     72 STATIC void gsfb_dma_kick(paddr_t, size_t);
     73 STATIC void gsfb_font_expand_psmct32(const struct wsdisplay_font *, u_int,
     74     long, u_int32_t *);
     75 STATIC inline void gsfb_set_cursor_pos(u_int32_t *, int, int, int, int);
     76 
     77 #define ATTR_FG_GET(a)	(((a )>> 24) & 0xf)
     78 #define ATTR_BG_GET(a)	(((a )>> 16) & 0xf)
     79 #define ATTR_FG_SET(x)	(((x) << 24) & 0x0f000000)
     80 #define ATTR_BG_SET(x)	(((x) << 16) & 0x000f0000)
     81 
     82 STATIC const u_int32_t gsfb_ansi_psmct32[] = {
     83 	0x80000000, /* black */
     84 	0x800000aa, /* red */
     85 	0x8000aa00, /* green */
     86 	0x8000aaaa, /* brown */
     87 	0x80aa0000, /* blue */
     88 	0x80aa00aa, /* magenta */
     89 	0x80aaaa00, /* cyan */
     90 	0x80aaaaaa, /* white */
     91 	0x80000000, /* black */
     92 	0x800000ff, /* red */
     93 	0x8000ff00, /* green */
     94 	0x8000ffff, /* brown */
     95 	0x80ff0000, /* blue */
     96 	0x80ff00ff, /* magenta */
     97 	0x80ffff00, /* cyan */
     98 	0x80ffffff, /* black */
     99 };
    100 
    101 #define TRXPOS_DXY(f, x, y)						\
    102 ({									\
    103 	f[9] = ((x) & 0x000007ff) | (((y) << 16) & 0x07ff0000);		\
    104 })
    105 
    106 #define TRXPOS_SY_DY(f, sy, dy)						\
    107 ({									\
    108 	f[8] = (((sy) << 16) & 0x07ff0000);				\
    109 	f[9] = (((dy) << 16) & 0x07ff0000);				\
    110 })
    111 
    112 #define TRXPOS_DXY_SXY(f, dx, dy, sx, sy)				\
    113 ({									\
    114 	f[8] = ((((sy) << 16) & 0x07ff0000) | ((sx) & 0x000007ff));	\
    115 	f[9] = ((((dy) << 16) & 0x07ff0000) | ((dx) & 0x000007ff));	\
    116 })
    117 
    118 STATIC u_int32_t gsfb_scroll_cmd_640x16[] __attribute__((__aligned__(16))) = {
    119         0x00008004, 0x10000000, 0x0000000e, 0x00000000,
    120         0x000a0000, 0x000a0000, 0x00000050, 0x00000000,
    121         0x07ff0000, 0x07ff0000, 0x00000051, 0x00000000,
    122         0x00000280, 0x00000010, 0x00000052, 0x00000000,
    123         0x00000002, 0x00000000, 0x00000053, 0x00000000,
    124 };
    125 
    126 STATIC u_int32_t gsfb_cursor_cmd[] __attribute__((__aligned__(16))) = {
    127 	0x00008007, 0x10000000, 0x0000000e, 0x00000000,
    128 	0x00000001, 0x00000000, 0x0000001a, 0x00000000,
    129         0x000000a4, 0x00000080, 0x00000042, 0x00000000,
    130 	0x00000046, 0x00000000, 0x00000000, 0x00000000,
    131 	0x80ffffff, 0x00000000, 0x00000001, 0x00000000,
    132 	0x00000000, 0x00000000, 0x0000000d, 0x00000000,
    133 	0x80ffffff, 0x00000000, 0x00000001, 0x00000000,
    134 	0x00000000, 0x00000000, 0x00000005, 0x00000000,
    135 };
    136 
    137 STATIC u_int32_t gsfb_copy_cmd_8x16[] __attribute__((__aligned__(16))) = {
    138         0x00008004, 0x10000000, 0x0000000e, 0x00000000,
    139         0x000a0000, 0x000a0000, 0x00000050, 0x00000000,
    140         0x07ff07ff, 0x07ff07ff, 0x00000051, 0x00000000,
    141         0x00000008, 0x00000010, 0x00000052, 0x00000000,
    142         0x00000002, 0x00000000, 0x00000053, 0x00000000,
    143 };
    144 
    145 STATIC u_int32_t gsfb_init_cmd_640x480[] __attribute__((__aligned__(16))) = {
    146 	0x00008008, 0x10000000, 0x0000000e, 0x00000000,
    147 	0x000a0000, 0x00000000, 0x0000004c, 0x00000000,
    148 	0x00000096, 0x00000000, 0x0000004e, 0x00000000,
    149 	0x02800000, 0x01e00000, 0x00000040, 0x00000000,
    150 	0x00000006, 0x00000000, 0x00000000, 0x00000000,
    151 	0x80000000, 0x00000000, 0x00000001, 0x00000000,
    152 	0x00000000, 0x00000000, 0x0000000d, 0x00000000,
    153 	0x80000000, 0x00000000, 0x00000001, 0x00000000,
    154 	0x1e002800, 0x00000000, 0x00000005, 0x00000000,
    155 };
    156 
    157 STATIC u_int32_t gsfb_load_cmd_8x16_psmct32[(6 + 32) * 4]
    158 	__attribute__((__aligned__(16))) = {
    159 	/* GIF tag + GS command */
    160         0x00000004, 0x10000000, 0x0000000e, 0x00000000,
    161         0x00000000, 0x000a0000, 0x00000050, 0x00000000,
    162         0x00000000, 0x00000000, 0x00000051, 0x00000000,
    163         0x00000008, 0x00000016, 0x00000052, 0x00000000,
    164         0x00000000, 0x00000000, 0x00000053, 0x00000000,
    165         0x00008020, 0x08000000, 0x00000000, 0x00000000,
    166 	/* Load area */
    167 #define FONT_SCRATCH_BASE	(6 * 4)
    168 };
    169 
    170 #ifdef GSFB_DEBUG_MONITOR
    171 #include <machine/stdarg.h>
    172 STATIC const struct _gsfb_debug_window {
    173 	int start, nrow, attr;
    174 } _gsfb_debug_window[3] = {
    175 	{ 24, 2 , ATTR_BG_SET(WSCOL_BROWN) | ATTR_FG_SET(WSCOL_BLUE) },
    176 	{ 26, 2 , ATTR_BG_SET(WSCOL_CYAN) | ATTR_FG_SET(WSCOL_BLUE) },
    177 	{ 28, 2 , ATTR_BG_SET(WSCOL_WHITE) | ATTR_FG_SET(WSCOL_BLUE) },
    178 };
    179 STATIC char _gsfb_debug_buf[80 * 2];
    180 #endif /* GSFB_DEBUG_MONITOR */
    181 
    182 STATIC int gsfb_match(device_t, cfdata_t, void *);
    183 STATIC void gsfb_attach(device_t, device_t, void *);
    184 
    185 CFATTACH_DECL_NEW(gsfb, sizeof(struct gsfb_softc),
    186     gsfb_match, gsfb_attach, NULL, NULL);
    187 
    188 STATIC void gsfb_hwinit(void);
    189 STATIC int gsfb_swinit(struct gsfb_softc*);
    190 
    191 /* console */
    192 void gsfbcnprobe(struct consdev *);
    193 void gsfbcninit(struct consdev *);
    194 
    195 /* emul ops */
    196 STATIC void _gsfb_cursor(void *, int, int, int);
    197 STATIC int _gsfb_mapchar(void *, int, unsigned int *);
    198 STATIC void _gsfb_putchar(void *, int, int, u_int, long);
    199 STATIC void _gsfb_copycols(void *, int, int, int, int);
    200 STATIC void _gsfb_erasecols(void *, int, int, int, long);
    201 STATIC void _gsfb_copyrows(void *, int, int, int);
    202 STATIC void _gsfb_eraserows(void *, int, int, long);
    203 STATIC int _gsfb_allocattr(void *, int, int, int, long *);
    204 
    205 /* access ops */
    206 STATIC int _gsfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    207 STATIC paddr_t _gsfb_mmap(void *, void *, off_t, int);
    208 STATIC int _gsfb_alloc_screen(void *, const struct wsscreen_descr *, void **,
    209     int *, int *, long *);
    210 STATIC void _gsfb_free_screen(void *, void *);
    211 STATIC int _gsfb_show_screen(void *, void *, int, void (*)(void *, int, int),
    212     void *);
    213 STATIC void _gsfb_pollc(void *, int);
    214 
    215 /*
    216  * wsdisplay attach args
    217  *   std: screen size 640 x 480, font size 8 x 16
    218  */
    219 #define GSFB_STD_SCREEN_WIDTH		640
    220 #define GSFB_STD_SCREEN_HEIGHT		480
    221 #define GSFB_STD_FONT_WIDTH		8
    222 #define GSFB_STD_FONT_HEIGHT		16
    223 const struct wsdisplay_emulops _gsfb_emulops = {
    224 	.cursor		= _gsfb_cursor,
    225 	.mapchar	= _gsfb_mapchar,
    226 	.putchar	= _gsfb_putchar,
    227 	.copycols	= _gsfb_copycols,
    228 	.erasecols	= _gsfb_erasecols,
    229 	.copyrows	= _gsfb_copyrows,
    230 	.eraserows	= _gsfb_eraserows,
    231 	.allocattr	= _gsfb_allocattr
    232 };
    233 
    234 const struct wsscreen_descr _gsfb_std_screen = {
    235 	.name		= "std",
    236 	.ncols		= 80,
    237 #ifdef GSFB_DEBUG_MONITOR
    238 	.nrows		= 24,
    239 #else
    240 	.nrows		= 30,
    241 #endif
    242 	.textops	= &_gsfb_emulops,
    243 	.fontwidth	= 8,
    244 	.fontheight	= 16,
    245 	.capabilities	= WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
    246 	WSSCREEN_WSCOLORS
    247 };
    248 
    249 const struct wsscreen_descr *_gsfb_screen_table[] = {
    250 	&_gsfb_std_screen,
    251 };
    252 
    253 struct wsscreen_list _gsfb_screen_list = {
    254 	.nscreens	= sizeof(_gsfb_screen_table) /
    255 	sizeof(_gsfb_screen_table[0]),
    256 	.screens	= _gsfb_screen_table
    257 };
    258 
    259 struct wsdisplay_accessops _gsfb_accessops = {
    260 	.ioctl		= _gsfb_ioctl,
    261 	.mmap		= _gsfb_mmap,
    262 	.alloc_screen	= _gsfb_alloc_screen,
    263 	.free_screen	= _gsfb_free_screen,
    264 	.show_screen	= _gsfb_show_screen,
    265 	.load_font	= 0,
    266 	.pollc		= _gsfb_pollc
    267 };
    268 
    269 int
    270 gsfb_match(device_t parent, cfdata_t cf, void *aux)
    271 {
    272 	extern struct cfdriver gsfb_cd;
    273 	struct mainbus_attach_args *ma = aux;
    274 
    275 	if (strcmp(ma->ma_name, gsfb_cd.cd_name) != 0)
    276 		return (0);
    277 
    278 	return 1;
    279 }
    280 
    281 void
    282 gsfb_attach(device_t parent, device_t self, void *aux)
    283 {
    284 	struct wsemuldisplaydev_attach_args wa;
    285 	struct gsfb_softc *sc = device_private(self);
    286 
    287 	if (gsfb_is_console) {
    288 		memcpy(sc, &gsfb_console_softc, sizeof(gsfb_console_softc));
    289 		sc->sc_is_console = true;
    290 	}
    291 	sc->sc_dev = self;
    292 
    293 	if (!sc->sc_is_console && !gsfb_swinit(sc) != 0)
    294 		return;
    295 
    296 	printf("\n");
    297 
    298 	wa.console	= sc->sc_is_console;
    299 	wa.scrdata	= &_gsfb_screen_list;
    300 	wa.accessops	= &_gsfb_accessops;
    301 	wa.accesscookie	= sc;
    302 
    303 	config_found(self, &wa, wsdisplaydevprint, CFARGS_NONE);
    304 }
    305 
    306 /*
    307  * console
    308  */
    309 void
    310 gsfbcnprobe(struct consdev *cndev)
    311 {
    312 
    313 	cndev->cn_pri = CN_INTERNAL;
    314 }
    315 
    316 void
    317 gsfbcninit(struct consdev *cndev)
    318 {
    319 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_init_cmd_640x480);
    320 	u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    321 	long defattr =  ATTR_BG_SET(WS_DEFAULT_BG) | ATTR_FG_SET(WS_DEFAULT_FG);
    322 
    323 	gsfb_is_console = 1;
    324 
    325 	gsfb_hwinit();
    326 	gsfb_swinit(&gsfb_console_softc);
    327 
    328 	/* Set the screen to the default background color at boot */
    329 	buf[28] = gsfb_ansi_psmct32[ATTR_BG_GET(defattr)];
    330 	gsfb_dma_kick(paddr, sizeof gsfb_init_cmd_640x480);
    331 #ifdef GSFB_DEBUG_MONITOR
    332 	{
    333 		const struct _gsfb_debug_window *win;
    334 		int i;
    335 
    336 		for (i = 0; i < 3; i++) {
    337 			win = &_gsfb_debug_window[i];
    338 			_gsfb_eraserows(0, win->start, win->nrow, win->attr);
    339 		}
    340 	}
    341 #endif /* GSFB_DEBUG_MONITOR */
    342 
    343 	wsdisplay_cnattach(&_gsfb_std_screen, &gsfb_console_softc, 0, 0,
    344 	    defattr);
    345 }
    346 
    347 void
    348 gsfb_hwinit(void)
    349 {
    350 	/*
    351 	  gs_init(VESA_1A) hang up on SCPH-50000.
    352 	  use bootloader's setting.
    353 	  EN1 | CRTMOD | MMOD | AMOD | ALP(all 1.0)
    354 	*/
    355 	_reg_write_8(GS_S_PMODE_REG, 0xffa5);
    356 
    357 	dmac_init();
    358 
    359 	/* reset GIF channel DMA */
    360 	_reg_write_4(D2_QWC_REG, 0);
    361 	_reg_write_4(D2_MADR_REG, 0);
    362 	_reg_write_4(D2_TADR_REG, 0);
    363 	_reg_write_4(D2_CHCR_REG, 0);
    364 }
    365 
    366 int
    367 gsfb_swinit(struct gsfb_softc *sc)
    368 {
    369 	int font;
    370 
    371 	wsfont_init();
    372 	font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
    373 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    374 	if (font < 0)
    375 		return (1);
    376 
    377 	if (wsfont_lock(font, &sc->sc_font))
    378 		return (1);
    379 
    380 	sc->sc_screen = &_gsfb_std_screen;
    381 
    382 	return (0);
    383 }
    384 
    385 /*
    386  * wsdisplay
    387  */
    388 void
    389 _gsfb_cursor(void *cookie, int on, int row, int col)
    390 {
    391 	struct gsfb_softc *sc = cookie;
    392 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_cursor_cmd);
    393 	u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    394 	struct wsdisplay_font *font = sc->sc_font;
    395 
    396 	gsfb_set_cursor_pos(buf, col, row, font->fontwidth, font->fontheight);
    397 
    398 	gsfb_dma_kick(paddr, sizeof gsfb_cursor_cmd);
    399 }
    400 
    401 inline void
    402 gsfb_set_cursor_pos(u_int32_t *p, int x, int y, int w, int h)
    403 {
    404 
    405 	x *= w;
    406 	y *= h;
    407 	p[20] = ((x << 4) & 0xffff) | ((y << 20) & 0xffff0000);
    408 	p[28] = (((x + w) << 4) & 0xffff) | (((y + h) << 20) & 0xffff0000);
    409 }
    410 
    411 int
    412 _gsfb_mapchar(void *cookie, int c, unsigned int *cp)
    413 {
    414 	struct gsfb_softc *sc = cookie;
    415 	struct wsdisplay_font *font = sc->sc_font;
    416 
    417 	if (font->encoding != WSDISPLAY_FONTENC_ISO)
    418 		if ((c = wsfont_map_unichar(font, c)) < 0)
    419 			goto nomap;
    420 
    421 	if (c < font->firstchar || c >= font->firstchar + font->numchars)
    422 			goto nomap;
    423 
    424 	*cp = c;
    425 	return (5);
    426 
    427  nomap:
    428 	*cp = ' ';
    429 	return (0);
    430 }
    431 
    432 void
    433 _gsfb_putchar(void *cookie, int row, int col, u_int uc, long attr)
    434 {
    435 	struct gsfb_softc *sc = cookie;
    436 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_load_cmd_8x16_psmct32);
    437 	u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    438 	struct wsdisplay_font *font = sc->sc_font;
    439 
    440 	/* copy font data to DMA region */
    441 	gsfb_font_expand_psmct32(font, uc, attr, &buf[FONT_SCRATCH_BASE]);
    442 
    443 	/* set destination position */
    444 	TRXPOS_DXY(buf, col * font->fontwidth, row * font->fontheight);
    445 
    446 	/* kick to GIF */
    447 	gsfb_dma_kick(paddr, sizeof gsfb_load_cmd_8x16_psmct32);
    448 }
    449 
    450 void
    451 _gsfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
    452 {
    453 	struct gsfb_softc *sc = cookie;
    454 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_copy_cmd_8x16);
    455 	u_int32_t *cmd = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    456 	int y = sc->sc_font->fontheight * row;
    457 	int w = sc->sc_font->fontwidth;
    458 	int i;
    459 
    460 	if (dstcol > srccol) {
    461 		for (i = ncols - 1; i >= 0; i--) {
    462 			TRXPOS_DXY_SXY(cmd, (dstcol + i) * w, y, (srccol + i) * w, y);
    463 			gsfb_dma_kick(paddr, sizeof gsfb_copy_cmd_8x16);
    464 		}
    465 	} else {
    466 		for (i = 0; i < ncols; i++) {
    467 			TRXPOS_DXY_SXY(cmd, (dstcol + i) * w, y, (srccol + i) * w, y);
    468 			gsfb_dma_kick(paddr, sizeof gsfb_copy_cmd_8x16);
    469 		}
    470 	}
    471 }
    472 
    473 void
    474 _gsfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
    475 {
    476 	int i;
    477 
    478 	for (i = 0; i < ncols; i++)
    479 		_gsfb_putchar(cookie, row, startcol + i, ' ', attr);
    480 }
    481 
    482 void
    483 _gsfb_copyrows(void *cookie, int src, int dst, int num)
    484 {
    485 	struct gsfb_softc *sc = cookie;
    486 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_scroll_cmd_640x16);
    487 	u_int32_t *cmd = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    488 	int i;
    489 	int h = sc->sc_font->fontheight;
    490 
    491 	if (dst > src) {
    492 		for (i = num - 1; i >= 0; i--) {
    493 			TRXPOS_SY_DY(cmd, (src + i) * h, (dst  + i) * h);
    494 			gsfb_dma_kick(paddr, sizeof gsfb_scroll_cmd_640x16);
    495 		}
    496 	} else {
    497 		for (i = 0; i < num; i++) {
    498 			TRXPOS_SY_DY(cmd, (src + i) * h, (dst  + i) * h);
    499 			gsfb_dma_kick(paddr, sizeof gsfb_scroll_cmd_640x16);
    500 		}
    501 	}
    502 }
    503 
    504 void
    505 _gsfb_eraserows(void *cookie, int row, int nrow, long attr)
    506 {
    507 	struct gsfb_softc *sc = cookie;
    508 	int i, j;
    509 
    510 	for (j = 0; j < nrow; j++)
    511 		for (i = 0; i < sc->sc_screen->ncols; i++)
    512 			_gsfb_putchar(cookie, row + j, i, ' ', attr);
    513 }
    514 
    515 int
    516 _gsfb_allocattr(void *cookie, int fg, int bg, int flags, long *attr)
    517 {
    518 
    519 	if ((flags & WSATTR_BLINK) != 0)
    520 		return (EINVAL);
    521 
    522 	if ((flags & WSATTR_WSCOLORS) == 0) {
    523 		fg = WS_DEFAULT_FG;
    524 		bg = WS_DEFAULT_BG;
    525 	}
    526 
    527 	if ((flags & WSATTR_HILIT) != 0)
    528 		fg += 8;
    529 
    530 	flags = (flags & WSATTR_UNDERLINE) ? 1 : 0;
    531 
    532 
    533 	*attr = ATTR_BG_SET(bg) | ATTR_FG_SET(fg) | flags;
    534 
    535 	return (0);
    536 }
    537 
    538 int
    539 _gsfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    540 	struct lwp *l)
    541 {
    542 
    543 	return (EPASSTHROUGH); /* Inappropriate ioctl for device */
    544 }
    545 
    546 paddr_t
    547 _gsfb_mmap(void *v, void *vs, off_t offset, int prot)
    548 {
    549 
    550 	return (-1); /* can't mmap */
    551 }
    552 
    553 int
    554 _gsfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    555     int *curxp, int *curyp, long *attrp)
    556 {
    557 
    558 	*attrp = ATTR_BG_SET(WS_DEFAULT_BG) | ATTR_FG_SET(WS_DEFAULT_FG);
    559 
    560 	return (0);
    561 }
    562 
    563 void
    564 _gsfb_free_screen(void *v, void *cookie)
    565 {
    566 }
    567 
    568 int
    569 _gsfb_show_screen(void *v, void *cookie, int waitok,
    570     void (*cb)(void *, int, int), void *cbarg)
    571 {
    572 
    573 	return (0);
    574 }
    575 
    576 void
    577 _gsfb_pollc(void *v, int on)
    578 {
    579 
    580 }
    581 
    582 /*
    583  * font expansion
    584  *   PSMCT32 only
    585  */
    586 void
    587 gsfb_font_expand_psmct32(const struct wsdisplay_font *font, u_int c, long attr,
    588     u_int32_t *buf)
    589 {
    590 	u_int32_t fg, bg;
    591 	u_int8_t *bitmap;
    592 	int i, j;
    593 
    594 	KDASSERT(((u_int32_t)buf & 15) == 0);
    595 
    596 	fg = gsfb_ansi_psmct32[ATTR_FG_GET(attr)];
    597 	bg = gsfb_ansi_psmct32[ATTR_BG_GET(attr)];
    598 
    599 	bitmap = (u_int8_t *)font->data + (c - font->firstchar) *
    600 	    font->fontheight * font->stride;
    601 	for (i = 0; i < font->fontheight; i++, bitmap++) {
    602 		u_int32_t b = *bitmap;
    603 		for (j = 0; j < font->fontwidth; j++, b <<= 1)
    604 			*buf++ = (b & 0x80) ? fg : bg;
    605 	}
    606 }
    607 
    608 void
    609 gsfb_dma_kick(paddr_t addr, size_t size)
    610 {
    611 	/* Wait for previous DMA request complete */
    612 	while (_reg_read_4(D2_QWC_REG))
    613 		;
    614 
    615 	/* Wait until GS FIFO empty */
    616 	while ((_reg_read_8(GS_S_CSR_REG) & (3 << 14)) != (1 << 14))
    617 		;
    618 
    619 	/* wait for DMA complete */
    620 	dmac_bus_poll(D_CH2_GIF);
    621 
    622 	/* transfer addr */
    623 	_reg_write_4(D2_MADR_REG, addr);
    624 	/* transfer data size (unit qword) */
    625 	_reg_write_4(D2_QWC_REG, bytetoqwc(size));
    626 
    627 	/* kick DMA (normal-mode) */
    628 	dmac_chcr_write(D_CH2_GIF, D_CHCR_STR);
    629 }
    630 
    631 #ifdef GSFB_DEBUG_MONITOR
    632 void
    633 __gsfb_print(int window, const char *fmt, ...)
    634 {
    635 	const struct _gsfb_debug_window *win;
    636 	int i, s, x, y, n, a;
    637 	u_int c;
    638 	va_list ap;
    639 
    640 	if (!gsfb.initialized)
    641 		return;
    642 
    643 	s = _intr_suspend();
    644 	win = &_gsfb_debug_window[window];
    645 	x = 0;
    646 	y = win->start;
    647 	n = win->nrow * 80;
    648 	a = win->attr;
    649 
    650 	va_start(ap, fmt);
    651 	vsnprintf(_gsfb_debug_buf, n, fmt, ap);
    652 	va_end(ap);
    653 
    654 	_gsfb_eraserows(0, y, win->nrow, a);
    655 
    656 	for (i = 0; i < n &&
    657 	    (c = (u_int)_gsfb_debug_buf[i] & 0x7f) != 0; i++) {
    658 		if (c == '\n')
    659 			x = 0, y++;
    660 		else
    661 			_gsfb_putchar(0, y, x++, c, a);
    662 	}
    663 
    664 	_intr_resume(s);
    665 }
    666 
    667 void
    668 __gsfb_print_hex(int a0, int a1, int a2, int a3)
    669 {
    670 	__gsfb_print(2, "a0=%08x a1=%08x a2=%08x a3=%08x",
    671 	    a0, a1, a2, a3);
    672 }
    673 #endif /* GSFB_DEBUG_MONITOR */
    674