Home | History | Annotate | Line # | Download | only in dev
      1  1.1  tsutsui /*	$NetBSD: fbbm.c,v 1.2 2026/09/20 11:52:56 tsutsui Exp $	*/
      2  1.1  tsutsui 
      3  1.1  tsutsui /*-
      4  1.1  tsutsui  * Copyright (c) 2026 Izumi Tsutsui.  All rights reserved.
      5  1.1  tsutsui  *
      6  1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
      7  1.1  tsutsui  * modification, are permitted provided that the following conditions
      8  1.1  tsutsui  * are met:
      9  1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
     10  1.1  tsutsui  *    notice, this list of conditions and the following disclaimer.
     11  1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
     14  1.1  tsutsui  *
     15  1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  1.1  tsutsui  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  1.1  tsutsui  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  1.1  tsutsui  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  1.1  tsutsui  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  1.1  tsutsui  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  1.1  tsutsui  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  1.1  tsutsui  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  1.1  tsutsui  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  1.1  tsutsui  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  1.1  tsutsui  */
     26  1.1  tsutsui 
     27  1.1  tsutsui #include <sys/cdefs.h>
     28  1.1  tsutsui __KERNEL_RCSID(0, "$NetBSD: fbbm.c,v 1.2 2026/09/20 11:52:56 tsutsui Exp $");
     29  1.1  tsutsui 
     30  1.1  tsutsui #include <sys/param.h>
     31  1.1  tsutsui #include <sys/device.h>
     32  1.1  tsutsui #include <sys/errno.h>
     33  1.1  tsutsui #include <sys/ioctl.h>
     34  1.1  tsutsui #include <sys/kmem.h>
     35  1.1  tsutsui #include <sys/systm.h>
     36  1.1  tsutsui 
     37  1.1  tsutsui #include <machine/bus.h>
     38  1.1  tsutsui 
     39  1.1  tsutsui #include <news68k/dev/hbvar.h>
     40  1.1  tsutsui #include <news68k/dev/nwb225reg.h>
     41  1.1  tsutsui 
     42  1.1  tsutsui #include <dev/wscons/wsconsio.h>
     43  1.1  tsutsui #include <dev/wscons/wsdisplayvar.h>
     44  1.1  tsutsui 
     45  1.1  tsutsui struct fbbm_devconfig {
     46  1.1  tsutsui 	bus_space_tag_t dc_bst;
     47  1.1  tsutsui 	bus_space_handle_t dc_rcont_bsh;
     48  1.1  tsutsui 	bus_space_handle_t dc_krom_bsh;
     49  1.1  tsutsui 
     50  1.1  tsutsui 	int dc_nplanes;
     51  1.1  tsutsui 	uint32_t dc_planemask;
     52  1.1  tsutsui 	int dc_dispver;
     53  1.1  tsutsui 
     54  1.1  tsutsui 	int dc_fbwidth;
     55  1.1  tsutsui 	int dc_fbheight;
     56  1.1  tsutsui 	int dc_width;
     57  1.1  tsutsui 	int dc_height;
     58  1.1  tsutsui 
     59  1.1  tsutsui 	int dc_fontwidth;
     60  1.1  tsutsui 	int dc_fontheight;
     61  1.1  tsutsui 	int dc_cellwidth;
     62  1.1  tsutsui 	int dc_cellheight;
     63  1.1  tsutsui 
     64  1.1  tsutsui 	int dc_ncols;
     65  1.1  tsutsui 	int dc_nrows;
     66  1.1  tsutsui 	int dc_xorigin;
     67  1.1  tsutsui 	int dc_yorigin;
     68  1.1  tsutsui 
     69  1.1  tsutsui 	int dc_cursoron;
     70  1.1  tsutsui 	int dc_cursorrow;
     71  1.1  tsutsui 	int dc_cursorcol;
     72  1.1  tsutsui 
     73  1.1  tsutsui 	struct wsscreen_descr dc_wsscrdescr;
     74  1.1  tsutsui };
     75  1.1  tsutsui 
     76  1.1  tsutsui struct fbbm_softc {
     77  1.1  tsutsui 	device_t sc_dev;
     78  1.1  tsutsui 	struct fbbm_devconfig *sc_dc;
     79  1.1  tsutsui 	int sc_nscreens;
     80  1.1  tsutsui 	int sc_wsmode;
     81  1.1  tsutsui 	const struct wsscreen_descr *sc_scrdescs[1];
     82  1.1  tsutsui 	struct wsscreen_list sc_scrlist;
     83  1.1  tsutsui };
     84  1.1  tsutsui 
     85  1.1  tsutsui /* autoconf functions and helpers */
     86  1.1  tsutsui static int fbbm_match(device_t, cfdata_t, void *);
     87  1.1  tsutsui static void fbbm_attach(device_t, device_t, void *);
     88  1.1  tsutsui 
     89  1.1  tsutsui static bool fbbm_console_initialized(void);
     90  1.1  tsutsui static int fbbm_probe(bus_space_tag_t, bus_addr_t);
     91  1.1  tsutsui 
     92  1.1  tsutsui /* bus_space mappings */
     93  1.1  tsutsui static int nwb225_map(struct fbbm_devconfig *, bus_space_tag_t, bus_addr_t);
     94  1.1  tsutsui static void nwb225_unmap(struct fbbm_devconfig *);
     95  1.1  tsutsui 
     96  1.1  tsutsui /* ROP helper functions */
     97  1.1  tsutsui static void nwb225_rop_reset(struct fbbm_devconfig *);
     98  1.1  tsutsui static int nwb225_rop_wait(struct fbbm_devconfig *);
     99  1.1  tsutsui static void nwb225_ctl_write(struct fbbm_devconfig *, uint16_t, uint16_t);
    100  1.1  tsutsui static void nwb225_rop_set_plane_mask(struct fbbm_devconfig *, uint32_t);
    101  1.1  tsutsui static void nwb225_rop_make_funcvec(struct fbbm_devconfig *, u_int,
    102  1.1  tsutsui     uint32_t, uint32_t, uint8_t *);
    103  1.1  tsutsui static void nwb225_rop_funcvec_constant_s(struct fbbm_devconfig *, uint8_t *,
    104  1.1  tsutsui     u_int);
    105  1.1  tsutsui static void nwb225_rop_set_funcvec(struct fbbm_devconfig *, const uint8_t *);
    106  1.1  tsutsui 
    107  1.1  tsutsui /* Hardware primitive ROP functions */
    108  1.1  tsutsui static int nwb225_rop_copy_rect(struct fbbm_devconfig *, int, int, int, int,
    109  1.1  tsutsui     int, int, u_int);
    110  1.1  tsutsui static int nwb225_rop_fill_rect(struct fbbm_devconfig *, int, int, int, int,
    111  1.1  tsutsui     uint32_t);
    112  1.1  tsutsui static int nwb225_rop_hwrite(struct fbbm_devconfig *, const uint16_t *, int,
    113  1.1  tsutsui     int, int, int, int, int, int, uint32_t, uint32_t);
    114  1.1  tsutsui 
    115  1.1  tsutsui /* ROM font functions */
    116  1.1  tsutsui static bus_size_t nwb225_krom_ascii_offset(u_int);
    117  1.1  tsutsui static void nwb225_krom_load_cell(struct fbbm_devconfig *, u_int,
    118  1.1  tsutsui     uint16_t *);
    119  1.1  tsutsui 
    120  1.1  tsutsui /* Initialization */
    121  1.1  tsutsui static int nwb225_init_hardware(struct fbbm_devconfig *);
    122  1.1  tsutsui 
    123  1.1  tsutsui static void fbbm_init_screen(struct fbbm_devconfig *);
    124  1.1  tsutsui static int fbbm_clear_screen(struct fbbm_devconfig *);
    125  1.1  tsutsui 
    126  1.1  tsutsui /* wsdisplay_emulops functions */
    127  1.1  tsutsui static void fbbm_cursor(void *, int, int, int);
    128  1.1  tsutsui static int fbbm_mapchar(void *, int, u_int *);
    129  1.1  tsutsui static void fbbm_putchar(void *, int, int, u_int, long);
    130  1.1  tsutsui static void fbbm_copycols(void *, int, int, int, int);
    131  1.1  tsutsui static void fbbm_erasecols(void *, int, int, int, long);
    132  1.1  tsutsui static void fbbm_copyrows(void *, int, int, int);
    133  1.1  tsutsui static void fbbm_eraserows(void *, int, int, long);
    134  1.1  tsutsui static int fbbm_allocattr(void *, int, int, int, long *);
    135  1.1  tsutsui 
    136  1.1  tsutsui /* wsdisplay_accessops functions */
    137  1.1  tsutsui static int fbbm_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    138  1.1  tsutsui static int fbbm_alloc_screen(void *, const struct wsscreen_descr *, void **,
    139  1.1  tsutsui     int *, int *, long *);
    140  1.1  tsutsui static void fbbm_free_screen(void *, void *);
    141  1.1  tsutsui static int fbbm_show_screen(void *, void *, int, void (*)(void *, int, int),
    142  1.1  tsutsui     void *);
    143  1.1  tsutsui 
    144  1.1  tsutsui /* cnattach function for early console */
    145  1.1  tsutsui int fbbm_cnattach(void);
    146  1.1  tsutsui 
    147  1.1  tsutsui CFATTACH_DECL_NEW(fbbm, sizeof(struct fbbm_softc),
    148  1.1  tsutsui     fbbm_match, fbbm_attach, NULL, NULL);
    149  1.1  tsutsui 
    150  1.1  tsutsui static struct fbbm_devconfig fbbm_console_dc;
    151  1.1  tsutsui 
    152  1.1  tsutsui static const struct wsdisplay_emulops fbbm_emulops = {
    153  1.1  tsutsui 	.cursor = fbbm_cursor,
    154  1.1  tsutsui 	.mapchar = fbbm_mapchar,
    155  1.1  tsutsui 	.putchar = fbbm_putchar,
    156  1.1  tsutsui 	.copycols = fbbm_copycols,
    157  1.1  tsutsui 	.erasecols = fbbm_erasecols,
    158  1.1  tsutsui 	.copyrows = fbbm_copyrows,
    159  1.1  tsutsui 	.eraserows = fbbm_eraserows,
    160  1.1  tsutsui 	.allocattr = fbbm_allocattr,
    161  1.1  tsutsui 	.replaceattr = NULL,
    162  1.1  tsutsui };
    163  1.1  tsutsui 
    164  1.1  tsutsui static const struct wsdisplay_accessops fbbm_accessops = {
    165  1.1  tsutsui 	.ioctl = fbbm_ioctl,
    166  1.1  tsutsui 	.mmap = NULL,
    167  1.1  tsutsui 	.alloc_screen = fbbm_alloc_screen,
    168  1.1  tsutsui 	.free_screen = fbbm_free_screen,
    169  1.1  tsutsui 	.show_screen = fbbm_show_screen,
    170  1.1  tsutsui 	.load_font = NULL,
    171  1.1  tsutsui 	.pollc = NULL,
    172  1.1  tsutsui 	.scroll = NULL,
    173  1.1  tsutsui };
    174  1.1  tsutsui 
    175  1.1  tsutsui /* Timeout count to check ROP op complete */
    176  1.1  tsutsui #define NWB225_WAIT_MAX		100000
    177  1.1  tsutsui 
    178  1.1  tsutsui /* Maximum number of planes of NWB-225 (4 or 8) */
    179  1.1  tsutsui #define NWB225_MAX_PLANES	8
    180  1.1  tsutsui 
    181  1.1  tsutsui /*
    182  1.1  tsutsui  * Software logical functions F(S,D).
    183  1.1  tsutsui  * These values index nwb225_fccnvtab[] and are not hardware function values.
    184  1.1  tsutsui  */
    185  1.1  tsutsui #define NWB225_ROP_LF_0		0x00
    186  1.1  tsutsui #define NWB225_ROP_LF_S		0x03
    187  1.1  tsutsui #define NWB225_ROP_LF_D		0x05
    188  1.1  tsutsui #define NWB225_ROP_LF_DI	0x0a
    189  1.1  tsutsui #define NWB225_ROP_LF_1		0x0f
    190  1.1  tsutsui 
    191  1.1  tsutsui /*
    192  1.1  tsutsui  * Logical FBBM function to 51X hardware function conversion table
    193  1.1  tsutsui  * taken from NEWS-OS fbbm_51x.o.
    194  1.1  tsutsui  */
    195  1.1  tsutsui static const uint8_t nwb225_fccnvtab[16] = {
    196  1.1  tsutsui 	0x03, 0x0b, 0x07, 0x0f,
    197  1.1  tsutsui 	0x02, 0x0a, 0x06, 0x0e,
    198  1.1  tsutsui 	0x01, 0x09, 0x05, 0x0d,
    199  1.1  tsutsui 	0x00, 0x08, 0x04, 0x0c,
    200  1.1  tsutsui };
    201  1.1  tsutsui 
    202  1.1  tsutsui /*
    203  1.1  tsutsui  * Fixed initialization values written by the NWS-1750 PROM and NEWS-OS
    204  1.1  tsutsui  * 51X setup.  Their individual timing/control semantics are intentionally
    205  1.1  tsutsui  * not inferred here.
    206  1.1  tsutsui  */
    207  1.1  tsutsui static const uint16_t nwb225_init_words[] = {
    208  1.1  tsutsui 	0x0400, 0x0002, 0x0005, 0x00d8,
    209  1.1  tsutsui 	0x0000, 0x0006, 0x0000,
    210  1.1  tsutsui };
    211  1.1  tsutsui 
    212  1.1  tsutsui /*
    213  1.1  tsutsui  * 4-bit component values taken from the NWS-1750 PROM NWB-225 module.
    214  1.1  tsutsui  * The PROM repeats this 16-entry table through all 256 palette indices
    215  1.1  tsutsui  * and writes each component after shifting it left by four bits.
    216  1.1  tsutsui  */
    217  1.1  tsutsui static const uint8_t nwb225_prom_palette[16][3] = {
    218  1.1  tsutsui 	{  0,  0,  0 },
    219  1.1  tsutsui 	{  0,  0,  4 },
    220  1.1  tsutsui 	{  0,  4,  0 },
    221  1.1  tsutsui 	{  0,  4,  4 },
    222  1.1  tsutsui 	{  4,  0,  0 },
    223  1.1  tsutsui 	{  4,  0,  4 },
    224  1.1  tsutsui 	{  4,  4,  0 },
    225  1.1  tsutsui 	{  4,  4,  4 },
    226  1.1  tsutsui 	{  8,  8,  8 },
    227  1.1  tsutsui 	{  0,  0, 15 },
    228  1.1  tsutsui 	{  0, 15,  0 },
    229  1.1  tsutsui 	{  0, 15, 15 },
    230  1.1  tsutsui 	{ 15,  0,  0 },
    231  1.1  tsutsui 	{ 15,  0, 15 },
    232  1.1  tsutsui 	{ 15, 15,  0 },
    233  1.1  tsutsui 	{ 15, 15, 15 },
    234  1.1  tsutsui };
    235  1.1  tsutsui 
    236  1.1  tsutsui static bool
    237  1.1  tsutsui fbbm_console_initialized(void)
    238  1.1  tsutsui {
    239  1.1  tsutsui 
    240  1.1  tsutsui 	/*
    241  1.1  tsutsui 	 * This is initialized in fbbm_init_screen() via
    242  1.1  tsutsui 	 * fbbm_cnattach() or fbbm_cnattach().
    243  1.1  tsutsui 	 */
    244  1.1  tsutsui 	return fbbm_console_dc.dc_wsscrdescr.textops == &fbbm_emulops;
    245  1.1  tsutsui }
    246  1.1  tsutsui 
    247  1.1  tsutsui static int
    248  1.1  tsutsui fbbm_probe(bus_space_tag_t bst, bus_addr_t rcont_addr)
    249  1.1  tsutsui {
    250  1.1  tsutsui 	bus_space_handle_t bsh;
    251  1.1  tsutsui 	int rv;
    252  1.1  tsutsui 
    253  1.1  tsutsui 	if (bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0, &bsh) != 0)
    254  1.1  tsutsui 		return 0;
    255  1.1  tsutsui 
    256  1.1  tsutsui 	/* NEWS-OS fb225_probe() used a byte-sized badaddr() at this base */
    257  1.1  tsutsui 	rv = news68k_bus_space_probe(bst, bsh, 0, 1);
    258  1.1  tsutsui 	bus_space_unmap(bst, bsh, NWB225_RCONT_SIZE);
    259  1.1  tsutsui 
    260  1.1  tsutsui 	return rv;
    261  1.1  tsutsui }
    262  1.1  tsutsui 
    263  1.1  tsutsui static int
    264  1.1  tsutsui fbbm_match(device_t parent, cfdata_t cf, void *aux)
    265  1.1  tsutsui {
    266  1.1  tsutsui 	struct hb_attach_args *ha = aux;
    267  1.1  tsutsui 
    268  1.1  tsutsui 	if (strcmp(ha->ha_name, "fbbm") != 0)
    269  1.1  tsutsui 		return 0;
    270  1.1  tsutsui 	if (ha->ha_address != NWB225_RCONT_BASE)
    271  1.1  tsutsui 		return 0;
    272  1.1  tsutsui 
    273  1.1  tsutsui 	return fbbm_probe(ha->ha_bust, ha->ha_address);
    274  1.1  tsutsui }
    275  1.1  tsutsui 
    276  1.1  tsutsui static void
    277  1.1  tsutsui fbbm_attach(device_t parent, device_t self, void *aux)
    278  1.1  tsutsui {
    279  1.1  tsutsui 	struct fbbm_softc *sc = device_private(self);
    280  1.1  tsutsui 	struct hb_attach_args *ha = aux;
    281  1.1  tsutsui 	struct fbbm_devconfig *dc;
    282  1.1  tsutsui 	struct wsemuldisplaydev_attach_args waa;
    283  1.1  tsutsui 	bool console;
    284  1.1  tsutsui 
    285  1.1  tsutsui 	sc->sc_dev = self;
    286  1.1  tsutsui 	console = fbbm_console_initialized();
    287  1.1  tsutsui 
    288  1.1  tsutsui 	if (console) {
    289  1.1  tsutsui 		dc = &fbbm_console_dc;
    290  1.1  tsutsui 		sc->sc_nscreens = 1;
    291  1.1  tsutsui 	} else {
    292  1.1  tsutsui 		dc = kmem_zalloc(sizeof(*dc), KM_SLEEP);
    293  1.1  tsutsui 		if (nwb225_map(dc, ha->ha_bust, ha->ha_address) != 0) {
    294  1.1  tsutsui 			aprint_error(": unable to map device registers");
    295  1.1  tsutsui 			goto out_free;
    296  1.1  tsutsui 		}
    297  1.1  tsutsui 
    298  1.1  tsutsui 		if (nwb225_init_hardware(dc) != 0) {
    299  1.1  tsutsui 			aprint_error(": controller initialization failed");
    300  1.1  tsutsui 			goto out_unmap;
    301  1.1  tsutsui 		}
    302  1.1  tsutsui 
    303  1.1  tsutsui 		fbbm_init_screen(dc);
    304  1.1  tsutsui 		if (fbbm_clear_screen(dc) != 0) {
    305  1.1  tsutsui 			aprint_error(": unable to clear text screen");
    306  1.1  tsutsui 			goto out_unmap;
    307  1.1  tsutsui 		}
    308  1.1  tsutsui 		sc->sc_nscreens = 0;
    309  1.1  tsutsui 	}
    310  1.1  tsutsui 
    311  1.1  tsutsui 	sc->sc_dc = dc;
    312  1.1  tsutsui 	sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
    313  1.1  tsutsui 	sc->sc_scrdescs[0] = &dc->dc_wsscrdescr;
    314  1.1  tsutsui 	sc->sc_scrlist.nscreens = __arraycount(sc->sc_scrdescs);
    315  1.1  tsutsui 	sc->sc_scrlist.screens = sc->sc_scrdescs;
    316  1.1  tsutsui 
    317  1.1  tsutsui 	aprint_normal(": NWB-225, %d x %d, %d planes, display version %d\n",
    318  1.1  tsutsui 	    dc->dc_width, dc->dc_height, dc->dc_nplanes, dc->dc_dispver);
    319  1.1  tsutsui 
    320  1.1  tsutsui 	waa.console = console;
    321  1.1  tsutsui 	waa.scrdata = &sc->sc_scrlist;
    322  1.1  tsutsui 	waa.accessops = &fbbm_accessops;
    323  1.1  tsutsui 	waa.accesscookie = sc;
    324  1.1  tsutsui 
    325  1.1  tsutsui 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
    326  1.1  tsutsui 	return;
    327  1.1  tsutsui 
    328  1.1  tsutsui  out_unmap:
    329  1.1  tsutsui 	nwb225_unmap(dc);
    330  1.1  tsutsui  out_free:
    331  1.1  tsutsui 	kmem_free(dc, sizeof(*dc));
    332  1.1  tsutsui }
    333  1.1  tsutsui 
    334  1.1  tsutsui static int
    335  1.1  tsutsui nwb225_map(struct fbbm_devconfig *dc, bus_space_tag_t bst,
    336  1.1  tsutsui     bus_addr_t rcont_addr)
    337  1.1  tsutsui {
    338  1.1  tsutsui 	int error;
    339  1.1  tsutsui 
    340  1.1  tsutsui 	dc->dc_bst = bst;
    341  1.1  tsutsui 
    342  1.1  tsutsui 	error = bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0,
    343  1.1  tsutsui 	    &dc->dc_rcont_bsh);
    344  1.1  tsutsui 	if (error != 0)
    345  1.1  tsutsui 		return error;
    346  1.1  tsutsui 
    347  1.1  tsutsui 	error = bus_space_map(bst, NWB225_KROM_BASE, NWB225_KROM_SIZE, 0,
    348  1.1  tsutsui 	    &dc->dc_krom_bsh);
    349  1.1  tsutsui 	if (error != 0) {
    350  1.1  tsutsui 		bus_space_unmap(bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
    351  1.1  tsutsui 		return error;
    352  1.1  tsutsui 	}
    353  1.1  tsutsui 
    354  1.1  tsutsui 	return 0;
    355  1.1  tsutsui }
    356  1.1  tsutsui 
    357  1.1  tsutsui static void
    358  1.1  tsutsui nwb225_unmap(struct fbbm_devconfig *dc)
    359  1.1  tsutsui {
    360  1.1  tsutsui 
    361  1.1  tsutsui 	bus_space_unmap(dc->dc_bst, dc->dc_krom_bsh, NWB225_KROM_SIZE);
    362  1.1  tsutsui 	bus_space_unmap(dc->dc_bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
    363  1.1  tsutsui }
    364  1.1  tsutsui 
    365  1.1  tsutsui static void
    366  1.1  tsutsui nwb225_rop_reset(struct fbbm_devconfig *dc)
    367  1.1  tsutsui {
    368  1.1  tsutsui 
    369  1.1  tsutsui 	/*
    370  1.1  tsutsui 	 * Both NEWS-OS fb51X_rop_reset() and the NWS-1750 PROM perform
    371  1.1  tsutsui 	 * this 0 -> 1 sequence.
    372  1.1  tsutsui 	 */
    373  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 0);
    374  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 1);
    375  1.1  tsutsui }
    376  1.1  tsutsui 
    377  1.1  tsutsui static int
    378  1.1  tsutsui nwb225_rop_wait(struct fbbm_devconfig *dc)
    379  1.1  tsutsui {
    380  1.1  tsutsui 	uint16_t status;
    381  1.1  tsutsui 	int i;
    382  1.1  tsutsui 
    383  1.1  tsutsui 	for (i = 0; i < NWB225_WAIT_MAX; i++) {
    384  1.1  tsutsui 		status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh,
    385  1.1  tsutsui 		    NWB225_STATUS);
    386  1.1  tsutsui 		if ((status & NWB225_STATUS_BUSY) == 0)
    387  1.1  tsutsui 			return 0;
    388  1.1  tsutsui 	}
    389  1.1  tsutsui 
    390  1.1  tsutsui 	/* Reset ROP engine on timeout as NEWS-OS does */
    391  1.1  tsutsui 	nwb225_rop_reset(dc);
    392  1.1  tsutsui 	return ETIMEDOUT;
    393  1.1  tsutsui }
    394  1.1  tsutsui 
    395  1.1  tsutsui static void
    396  1.1  tsutsui nwb225_ctl_write(struct fbbm_devconfig *dc, uint16_t selector, uint16_t value)
    397  1.1  tsutsui {
    398  1.1  tsutsui 
    399  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    400  1.1  tsutsui 	    NWB225_CTL_SELECT, selector);
    401  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    402  1.1  tsutsui 	    NWB225_CTL_DATA, value);
    403  1.1  tsutsui }
    404  1.1  tsutsui 
    405  1.1  tsutsui static void
    406  1.1  tsutsui nwb225_rop_set_plane_mask(struct fbbm_devconfig *dc, uint32_t planemask)
    407  1.1  tsutsui {
    408  1.1  tsutsui 	uint8_t disabled_planes;
    409  1.1  tsutsui 	uint16_t hwmask;
    410  1.1  tsutsui 
    411  1.1  tsutsui 	disabled_planes = (uint8_t)~planemask;
    412  1.1  tsutsui 	hwmask = (uint16_t)disabled_planes << NWB225_PLANE_CTRL_SHIFT;
    413  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    414  1.1  tsutsui 	    NWB225_PLANE_CTRL, hwmask);
    415  1.1  tsutsui }
    416  1.1  tsutsui 
    417  1.1  tsutsui static void
    418  1.1  tsutsui nwb225_rop_make_funcvec(struct fbbm_devconfig *dc, u_int logical_func,
    419  1.1  tsutsui     uint32_t src1, uint32_t src0, uint8_t *funcvec)
    420  1.1  tsutsui {
    421  1.1  tsutsui 	uint8_t f_s0_d, f_s1_d;
    422  1.1  tsutsui 	uint8_t func_by_srcmap[4];
    423  1.1  tsutsui 	uint8_t src1_bit, src0_bit, src_map;
    424  1.1  tsutsui 	int i;
    425  1.1  tsutsui 
    426  1.1  tsutsui 	KASSERT(logical_func <= 0x0f);
    427  1.1  tsutsui 	KASSERT(dc->dc_nplanes == 4 || dc->dc_nplanes == 8);
    428  1.1  tsutsui 
    429  1.1  tsutsui 	/* F(0,D) */
    430  1.1  tsutsui 	f_s0_d = (logical_func >> 2) & 0x03;
    431  1.1  tsutsui 	/* F(1,D) */
    432  1.1  tsutsui 	f_s1_d = logical_func & 0x03;
    433  1.1  tsutsui 
    434  1.1  tsutsui 	func_by_srcmap[0] = (f_s0_d << 2) | f_s0_d;
    435  1.1  tsutsui 	func_by_srcmap[1] = (f_s1_d << 2) | f_s0_d;
    436  1.1  tsutsui 	func_by_srcmap[2] = (f_s0_d << 2) | f_s1_d;
    437  1.1  tsutsui 	func_by_srcmap[3] = (f_s1_d << 2) | f_s1_d;
    438  1.1  tsutsui 
    439  1.1  tsutsui 	for (i = 0; i < dc->dc_nplanes; i++) {
    440  1.1  tsutsui 		src1_bit = src1 & 0x01;
    441  1.1  tsutsui 		src0_bit = src0 & 0x01;
    442  1.1  tsutsui 		src_map = (src1_bit << 1) | src0_bit;
    443  1.1  tsutsui 		funcvec[i] = func_by_srcmap[src_map];
    444  1.1  tsutsui 		src1 >>= 1;
    445  1.1  tsutsui 		src0 >>= 1;
    446  1.1  tsutsui 	}
    447  1.1  tsutsui }
    448  1.1  tsutsui 
    449  1.1  tsutsui static void
    450  1.1  tsutsui nwb225_rop_funcvec_constant_s(struct fbbm_devconfig *dc, uint8_t *funcvec,
    451  1.1  tsutsui     u_int s)
    452  1.1  tsutsui {
    453  1.1  tsutsui 	uint8_t logical_func, f_s0_d, f_s1_d, d_func, result;
    454  1.1  tsutsui 	int i;
    455  1.1  tsutsui 
    456  1.1  tsutsui 	KASSERT(dc->dc_nplanes == 4 || dc->dc_nplanes == 8);
    457  1.1  tsutsui 	KASSERT(s <= 1);
    458  1.1  tsutsui 
    459  1.1  tsutsui 	for (i = 0; i < dc->dc_nplanes; i++) {
    460  1.1  tsutsui 		logical_func = funcvec[i];
    461  1.1  tsutsui 		KASSERT(logical_func <= 0x0f);
    462  1.1  tsutsui 
    463  1.1  tsutsui 		/* F(0,D) */
    464  1.1  tsutsui 		f_s0_d = (logical_func >> 2) & 0x03;
    465  1.1  tsutsui 		/* F(1,D) */
    466  1.1  tsutsui 		f_s1_d = logical_func & 0x03;
    467  1.1  tsutsui 
    468  1.1  tsutsui 		d_func = (s == 0) ? f_s0_d : f_s1_d;
    469  1.1  tsutsui 		switch (d_func) {
    470  1.1  tsutsui 		case 0:
    471  1.1  tsutsui 			result = NWB225_ROP_LF_0;
    472  1.1  tsutsui 			break;
    473  1.1  tsutsui 		case 1:
    474  1.1  tsutsui 			result = NWB225_ROP_LF_D;
    475  1.1  tsutsui 			break;
    476  1.1  tsutsui 		case 2:
    477  1.1  tsutsui 			result = NWB225_ROP_LF_DI;
    478  1.1  tsutsui 			break;
    479  1.1  tsutsui 		case 3:
    480  1.1  tsutsui 			result = NWB225_ROP_LF_1;
    481  1.1  tsutsui 			break;
    482  1.1  tsutsui 		default:
    483  1.1  tsutsui 			KASSERT(false);
    484  1.1  tsutsui 			result = NWB225_ROP_LF_0;
    485  1.1  tsutsui 			break;
    486  1.1  tsutsui 		}
    487  1.1  tsutsui 		funcvec[i] = result;
    488  1.1  tsutsui 	}
    489  1.1  tsutsui }
    490  1.1  tsutsui 
    491  1.1  tsutsui static void
    492  1.1  tsutsui nwb225_rop_set_funcvec(struct fbbm_devconfig *dc, const uint8_t *funcvec)
    493  1.1  tsutsui {
    494  1.1  tsutsui 	uint8_t logical_func, hw_func;
    495  1.1  tsutsui 	int i;
    496  1.1  tsutsui 
    497  1.1  tsutsui 	for (i = 0; i < dc->dc_nplanes; i++) {
    498  1.1  tsutsui 		KASSERT(funcvec[i] <= 0x0f);
    499  1.1  tsutsui 		logical_func = funcvec[i];
    500  1.1  tsutsui 		hw_func = nwb225_fccnvtab[logical_func];
    501  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    502  1.1  tsutsui 		    NWB225_ROP_FUNC(i), hw_func);
    503  1.1  tsutsui 	}
    504  1.1  tsutsui }
    505  1.1  tsutsui 
    506  1.1  tsutsui static int
    507  1.1  tsutsui nwb225_rect_valid(struct fbbm_devconfig *dc, int x, int y, int width,
    508  1.1  tsutsui     int height)
    509  1.1  tsutsui {
    510  1.1  tsutsui 
    511  1.1  tsutsui 	if (x < 0 || y < 0 || width <= 0 || height <= 0)
    512  1.1  tsutsui 		return 0;
    513  1.1  tsutsui 	if (x >= dc->dc_fbwidth || y >= dc->dc_fbheight)
    514  1.1  tsutsui 		return 0;
    515  1.1  tsutsui 	if (width > dc->dc_fbwidth - x || height > dc->dc_fbheight - y)
    516  1.1  tsutsui 		return 0;
    517  1.1  tsutsui 
    518  1.1  tsutsui 	return 1;
    519  1.1  tsutsui }
    520  1.1  tsutsui 
    521  1.1  tsutsui static int
    522  1.1  tsutsui nwb225_rop_copy_rect(struct fbbm_devconfig *dc, int sx, int sy, int width,
    523  1.1  tsutsui     int height, int dx, int dy, u_int logical_func)
    524  1.1  tsutsui {
    525  1.1  tsutsui 	uint8_t funcvec[NWB225_MAX_PLANES];
    526  1.1  tsutsui 	bus_size_t copy_mode;
    527  1.1  tsutsui 	bool reverse_x, reverse_y;
    528  1.1  tsutsui 	int src_x, src_y, dst_x, dst_y, limit_x;
    529  1.1  tsutsui 	int error;
    530  1.1  tsutsui 
    531  1.1  tsutsui 	if (logical_func > 0x0f)
    532  1.1  tsutsui 		return EINVAL;
    533  1.1  tsutsui 
    534  1.1  tsutsui 	if (nwb225_rect_valid(dc, sx, sy, width, height) == 0 ||
    535  1.1  tsutsui 	    nwb225_rect_valid(dc, dx, dy, width, height) == 0)
    536  1.1  tsutsui 		return EINVAL;
    537  1.1  tsutsui 
    538  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    539  1.1  tsutsui 	if (__predict_false(error != 0))
    540  1.1  tsutsui 		return error;
    541  1.1  tsutsui 
    542  1.1  tsutsui 	nwb225_rop_make_funcvec(dc, logical_func, dc->dc_planemask, 0, funcvec);
    543  1.1  tsutsui 	nwb225_rop_set_funcvec(dc, funcvec);
    544  1.1  tsutsui 	nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
    545  1.1  tsutsui 
    546  1.1  tsutsui 	/* Wait again as NEWS-OS does */
    547  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    548  1.1  tsutsui 	if (__predict_false(error != 0))
    549  1.1  tsutsui 		return error;
    550  1.1  tsutsui 
    551  1.1  tsutsui 	reverse_x = (sx < dx);
    552  1.1  tsutsui 	reverse_y = (sy < dy);
    553  1.1  tsutsui 	src_x     = sx + (reverse_x ? width : 0);
    554  1.1  tsutsui 	dst_x     = dx + (reverse_x ? width : 0);
    555  1.1  tsutsui 	limit_x   = dx + (reverse_x ? 0 : width);
    556  1.1  tsutsui 	src_y     = sy + (reverse_y ? height - 1 : 0);
    557  1.1  tsutsui 	dst_y     = dy + (reverse_y ? height - 1 : 0);
    558  1.1  tsutsui 
    559  1.1  tsutsui 	if (reverse_x) {
    560  1.1  tsutsui 		if (reverse_y) {
    561  1.1  tsutsui 			copy_mode = NWB225_ROP_COPY_XR_YR;
    562  1.1  tsutsui 		} else {
    563  1.1  tsutsui 			copy_mode = NWB225_ROP_COPY_XR_YF;
    564  1.1  tsutsui 		}
    565  1.1  tsutsui 	} else {
    566  1.1  tsutsui 		if (reverse_y) {
    567  1.1  tsutsui 			copy_mode = NWB225_ROP_COPY_XF_YR;
    568  1.1  tsutsui 		} else {
    569  1.1  tsutsui 			copy_mode = NWB225_ROP_COPY_XF_YF;
    570  1.1  tsutsui 		}
    571  1.1  tsutsui 	}
    572  1.1  tsutsui 
    573  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    574  1.1  tsutsui 	    copy_mode, 0);
    575  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    576  1.1  tsutsui 	    NWB225_DST_ADDR(dst_y), dst_x);
    577  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    578  1.1  tsutsui 	    NWB225_SRC_ADDR(src_y) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, src_x);
    579  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    580  1.1  tsutsui 	    NWB225_ROP_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, limit_x);
    581  1.1  tsutsui 
    582  1.1  tsutsui 	/* Wait complete for polling ops */
    583  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    584  1.1  tsutsui 
    585  1.1  tsutsui 	return error;
    586  1.1  tsutsui }
    587  1.1  tsutsui 
    588  1.1  tsutsui static int
    589  1.1  tsutsui nwb225_rop_fill_rect(struct fbbm_devconfig *dc, int x, int y, int width,
    590  1.1  tsutsui     int height, uint32_t color)
    591  1.1  tsutsui {
    592  1.1  tsutsui 	uint8_t funcvec[NWB225_MAX_PLANES];
    593  1.1  tsutsui 	int error;
    594  1.1  tsutsui 
    595  1.1  tsutsui 	if (nwb225_rect_valid(dc, x, y, width, height) == 0)
    596  1.1  tsutsui 		return EINVAL;
    597  1.1  tsutsui 
    598  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    599  1.1  tsutsui 	if (__predict_false(error != 0))
    600  1.1  tsutsui 		return error;
    601  1.1  tsutsui 
    602  1.1  tsutsui 	color &= dc->dc_planemask;
    603  1.1  tsutsui 	nwb225_rop_make_funcvec(dc, NWB225_ROP_LF_S, color, 0, funcvec);
    604  1.1  tsutsui 	nwb225_rop_funcvec_constant_s(dc, funcvec, 1);
    605  1.1  tsutsui 	nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
    606  1.1  tsutsui 	nwb225_rop_set_funcvec(dc, funcvec);
    607  1.1  tsutsui 
    608  1.1  tsutsui 	/* Wait again as NEWS-OS does */
    609  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    610  1.1  tsutsui 	if (__predict_false(error != 0))
    611  1.1  tsutsui 		return error;
    612  1.1  tsutsui 
    613  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    614  1.1  tsutsui 	    NWB225_ROP_CONST_FILL, 0);
    615  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    616  1.1  tsutsui 	    NWB225_DST_ADDR(0), 0);
    617  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    618  1.1  tsutsui 	    NWB225_SRC_ADDR(0) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, 0);
    619  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    620  1.1  tsutsui 	    NWB225_DST_ADDR(y), x);
    621  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    622  1.1  tsutsui 	    NWB225_ROP_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, x + width);
    623  1.1  tsutsui 
    624  1.1  tsutsui 	/* Wait complete for polling ops */
    625  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    626  1.1  tsutsui 
    627  1.1  tsutsui 	return error;
    628  1.1  tsutsui }
    629  1.1  tsutsui 
    630  1.1  tsutsui static int
    631  1.1  tsutsui nwb225_rop_hwrite(struct fbbm_devconfig *dc, const uint16_t *src_words,
    632  1.1  tsutsui     int src_stride_words, int srcx, int srcy, int width, int height,
    633  1.1  tsutsui     int dx, int dy, uint32_t foreground, uint32_t background)
    634  1.1  tsutsui {
    635  1.1  tsutsui 	uint8_t funcvec[NWB225_MAX_PLANES];
    636  1.1  tsutsui 	int source_word_offset, source_bit_offset;
    637  1.1  tsutsui 	int row_words, row_skip_words, row, word;
    638  1.1  tsutsui 	const uint16_t *sp;
    639  1.1  tsutsui 	int error;
    640  1.1  tsutsui 
    641  1.1  tsutsui 	if (src_words == NULL || src_stride_words <= 0 || srcx < 0 || srcy < 0)
    642  1.1  tsutsui 		return EINVAL;
    643  1.1  tsutsui 
    644  1.1  tsutsui 	if (nwb225_rect_valid(dc, dx, dy, width, height) == 0)
    645  1.1  tsutsui 		return EINVAL;
    646  1.1  tsutsui 
    647  1.1  tsutsui 	source_word_offset = srcx / NWB225_HWRITE_BITS_PER_WORD;
    648  1.1  tsutsui 	source_bit_offset  = srcx % NWB225_HWRITE_BITS_PER_WORD;
    649  1.1  tsutsui 	row_words =
    650  1.1  tsutsui 	    howmany(source_bit_offset + width, NWB225_HWRITE_BITS_PER_WORD);
    651  1.1  tsutsui 	if (source_word_offset + row_words > src_stride_words)
    652  1.1  tsutsui 		return EINVAL;
    653  1.1  tsutsui 
    654  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    655  1.1  tsutsui 	if (__predict_false(error != 0))
    656  1.1  tsutsui 		return error;
    657  1.1  tsutsui 
    658  1.1  tsutsui 	foreground &= dc->dc_planemask;
    659  1.1  tsutsui 	background &= dc->dc_planemask;
    660  1.1  tsutsui 	nwb225_rop_make_funcvec(dc, NWB225_ROP_LF_S, foreground, background,
    661  1.1  tsutsui 	    funcvec);
    662  1.1  tsutsui 	nwb225_rop_set_funcvec(dc, funcvec);
    663  1.1  tsutsui 	nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
    664  1.1  tsutsui 
    665  1.1  tsutsui 	/* Wait again as NEWS-OS does */
    666  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    667  1.1  tsutsui 	if (__predict_false(error != 0))
    668  1.1  tsutsui 		return error;
    669  1.1  tsutsui 
    670  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    671  1.1  tsutsui 	    NWB225_DST_ADDR(dy), dx);
    672  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    673  1.1  tsutsui 	    NWB225_SRC_ADDR(0) | NWB225_ROP_ADDR_FLAG_SET_SHIFT,
    674  1.1  tsutsui 	    source_bit_offset);
    675  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    676  1.1  tsutsui 	    NWB225_HWRITE_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE,
    677  1.1  tsutsui 	    dx + width);
    678  1.1  tsutsui 
    679  1.1  tsutsui 	sp = src_words + (srcy * src_stride_words) + source_word_offset;
    680  1.1  tsutsui 	row_skip_words = src_stride_words - row_words;
    681  1.1  tsutsui 	for (row = 0; row < height; row++) {
    682  1.1  tsutsui 		for (word = 0; word < row_words; word++)
    683  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    684  1.1  tsutsui 			    NWB225_HWRITE_DATA, *sp++);
    685  1.1  tsutsui 		sp += row_skip_words;
    686  1.1  tsutsui 	}
    687  1.1  tsutsui 
    688  1.1  tsutsui 	/* Wait complete for polling ops */
    689  1.1  tsutsui 	error = nwb225_rop_wait(dc);
    690  1.1  tsutsui 
    691  1.1  tsutsui 	return error;
    692  1.1  tsutsui }
    693  1.1  tsutsui 
    694  1.1  tsutsui static bus_size_t
    695  1.1  tsutsui nwb225_krom_ascii_offset(u_int c)
    696  1.1  tsutsui {
    697  1.1  tsutsui 	u_int index;
    698  1.1  tsutsui 
    699  1.1  tsutsui 	index = c - NWB225_KROM_ASCII_FIRST;
    700  1.1  tsutsui 	return ((index & 0xe0) << 9) | ((index & 0x1f) << 7);
    701  1.1  tsutsui }
    702  1.1  tsutsui 
    703  1.1  tsutsui static void
    704  1.1  tsutsui nwb225_krom_load_cell(struct fbbm_devconfig *dc, u_int c, uint16_t *cell)
    705  1.1  tsutsui {
    706  1.1  tsutsui 	bus_size_t offset;
    707  1.1  tsutsui 	int row;
    708  1.1  tsutsui 
    709  1.1  tsutsui 	memset(cell, 0, NWB225_CELL_HEIGHT * sizeof(*cell));
    710  1.1  tsutsui 	offset = nwb225_krom_ascii_offset(c);
    711  1.1  tsutsui 
    712  1.1  tsutsui 	/*
    713  1.1  tsutsui 	 * The PROM renderer reads one 32-bit KROM row, keeps the upper word,
    714  1.1  tsutsui 	 * masks its low four bits, and places the 24 glyph rows after four
    715  1.1  tsutsui 	 * blank rows in the 16x30 cell.
    716  1.1  tsutsui 	 */
    717  1.1  tsutsui 	for (row = 0; row < NWB225_FONT_HEIGHT; row++)
    718  1.1  tsutsui 		cell[NWB225_GLYPH_YOFFSET + row] =
    719  1.1  tsutsui 		    bus_space_read_2(dc->dc_bst, dc->dc_krom_bsh,
    720  1.1  tsutsui 		    offset + row * NWB225_KROM_ROWBYTES) &
    721  1.1  tsutsui 		    NWB225_KROM_ASCII_MASK;
    722  1.1  tsutsui }
    723  1.1  tsutsui 
    724  1.1  tsutsui static int
    725  1.1  tsutsui nwb225_init_hardware(struct fbbm_devconfig *dc)
    726  1.1  tsutsui {
    727  1.1  tsutsui 	uint16_t status, value;
    728  1.1  tsutsui 	int i, component;
    729  1.1  tsutsui 
    730  1.1  tsutsui 	/*
    731  1.1  tsutsui 	 * Use the cold-init sequence used by the NWB-225 routine in the
    732  1.1  tsutsui 	 * NWS-1750 PROM. In particular, the second reset is intentional.
    733  1.1  tsutsui 	 * The serial console cold-boot experiment required the init block
    734  1.1  tsutsui 	 * followed by this reset before stable sync was established by CRTC.
    735  1.1  tsutsui 	 */
    736  1.1  tsutsui 	nwb225_rop_reset(dc);
    737  1.1  tsutsui 
    738  1.1  tsutsui 	for (i = 0; i < __arraycount(nwb225_init_words); i++)
    739  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    740  1.1  tsutsui 		    NWB225_INIT_BASE + i * sizeof(uint16_t),
    741  1.1  tsutsui 		    nwb225_init_words[i]);
    742  1.1  tsutsui 
    743  1.1  tsutsui 	status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS);
    744  1.1  tsutsui 	if ((status & NWB225_STATUS_4PLANE) != 0)
    745  1.1  tsutsui 		dc->dc_nplanes = 4;
    746  1.1  tsutsui 	else
    747  1.1  tsutsui 		dc->dc_nplanes = 8;
    748  1.1  tsutsui 	dc->dc_planemask = (1U << dc->dc_nplanes) - 1;
    749  1.1  tsutsui 	dc->dc_dispver =
    750  1.1  tsutsui 	    (status & NWB225_STATUS_DISPVER) >> NWB225_STATUS_DISPVER_SHIFT;
    751  1.1  tsutsui 
    752  1.1  tsutsui 	nwb225_ctl_write(dc, 4, dc->dc_planemask);
    753  1.1  tsutsui 	nwb225_ctl_write(dc, 5, 0);
    754  1.1  tsutsui 	nwb225_ctl_write(dc, 6, 0x40);
    755  1.1  tsutsui 	nwb225_ctl_write(dc, 7, 0);
    756  1.1  tsutsui 
    757  1.1  tsutsui 	nwb225_rop_reset(dc);
    758  1.1  tsutsui 
    759  1.1  tsutsui 	/* Complete the fixed PROM palette/control initialization */
    760  1.1  tsutsui 	for (i = 0; i < 256; i++) {
    761  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    762  1.1  tsutsui 		    NWB225_PAL_INDEX, i);
    763  1.1  tsutsui 		for (component = 0; component < 3; component++) {
    764  1.1  tsutsui 			value = nwb225_prom_palette[i & 0x0f][component] << 4;
    765  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
    766  1.1  tsutsui 			    NWB225_PAL_DATA, value);
    767  1.1  tsutsui 		}
    768  1.1  tsutsui 	}
    769  1.1  tsutsui 
    770  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_PLANE_CTRL, 0);
    771  1.1  tsutsui 
    772  1.1  tsutsui 	return nwb225_rop_wait(dc);
    773  1.1  tsutsui }
    774  1.1  tsutsui 
    775  1.1  tsutsui static void
    776  1.1  tsutsui fbbm_init_screen(struct fbbm_devconfig *dc)
    777  1.1  tsutsui {
    778  1.1  tsutsui 
    779  1.1  tsutsui 	dc->dc_fbwidth = NWB225_FB_WIDTH;
    780  1.1  tsutsui 	dc->dc_fbheight = NWB225_FB_HEIGHT;
    781  1.1  tsutsui 	dc->dc_width = NWB225_VIS_WIDTH;
    782  1.1  tsutsui 	dc->dc_height = NWB225_VIS_HEIGHT;
    783  1.1  tsutsui 
    784  1.1  tsutsui 	dc->dc_fontwidth = NWB225_FONT_WIDTH;
    785  1.1  tsutsui 	dc->dc_fontheight = NWB225_FONT_HEIGHT;
    786  1.1  tsutsui 	dc->dc_cellwidth = NWB225_CELL_WIDTH;
    787  1.1  tsutsui 	dc->dc_cellheight = NWB225_CELL_HEIGHT;
    788  1.1  tsutsui 
    789  1.1  tsutsui 	dc->dc_ncols = NWB225_TEXT_COLS;
    790  1.1  tsutsui 	dc->dc_nrows = NWB225_TEXT_ROWS;
    791  1.1  tsutsui 	dc->dc_xorigin = NWB225_TEXT_XORIGIN;
    792  1.1  tsutsui 	dc->dc_yorigin = NWB225_TEXT_YORIGIN;
    793  1.1  tsutsui 
    794  1.1  tsutsui 	dc->dc_wsscrdescr.name = "std";
    795  1.1  tsutsui 	dc->dc_wsscrdescr.ncols = dc->dc_ncols;
    796  1.1  tsutsui 	dc->dc_wsscrdescr.nrows = dc->dc_nrows;
    797  1.1  tsutsui 	dc->dc_wsscrdescr.textops = &fbbm_emulops;
    798  1.1  tsutsui 	dc->dc_wsscrdescr.fontwidth = dc->dc_cellwidth;
    799  1.1  tsutsui 	dc->dc_wsscrdescr.fontheight = dc->dc_cellheight;
    800  1.1  tsutsui 	dc->dc_wsscrdescr.capabilities = WSSCREEN_REVERSE;
    801  1.1  tsutsui 	dc->dc_wsscrdescr.modecookie = NULL;
    802  1.1  tsutsui 
    803  1.1  tsutsui 	dc->dc_cursoron = 0;
    804  1.1  tsutsui 	dc->dc_cursorrow = 0;
    805  1.1  tsutsui 	dc->dc_cursorcol = 0;
    806  1.1  tsutsui }
    807  1.1  tsutsui 
    808  1.1  tsutsui /*
    809  1.1  tsutsui  * Clear the visible display region.
    810  1.1  tsutsui  * Called from both normal attach and early cnattach.
    811  1.1  tsutsui  */
    812  1.1  tsutsui static int
    813  1.1  tsutsui fbbm_clear_screen(struct fbbm_devconfig *dc)
    814  1.1  tsutsui {
    815  1.1  tsutsui 
    816  1.1  tsutsui 	return nwb225_rop_fill_rect(dc, 0, 0, dc->dc_width, dc->dc_height, 0);
    817  1.1  tsutsui }
    818  1.1  tsutsui 
    819  1.1  tsutsui static uint32_t
    820  1.1  tsutsui fbbm_attr_background(struct fbbm_devconfig *dc, long attr)
    821  1.1  tsutsui {
    822  1.1  tsutsui 
    823  1.1  tsutsui 	return (attr & WSATTR_REVERSE) != 0 ? dc->dc_planemask : 0;
    824  1.1  tsutsui }
    825  1.1  tsutsui 
    826  1.1  tsutsui /*
    827  1.1  tsutsui  * wsdisplay_emulops functions
    828  1.1  tsutsui  */
    829  1.1  tsutsui static void
    830  1.1  tsutsui fbbm_cursor(void *cookie, int on, int row, int col)
    831  1.1  tsutsui {
    832  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
    833  1.1  tsutsui 	int x, y, error;
    834  1.1  tsutsui 
    835  1.1  tsutsui 	if (dc->dc_cursoron != 0) {
    836  1.1  tsutsui 		x = dc->dc_xorigin + dc->dc_cursorcol * dc->dc_cellwidth;
    837  1.1  tsutsui 		y = dc->dc_yorigin + dc->dc_cursorrow * dc->dc_cellheight;
    838  1.1  tsutsui 		error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
    839  1.1  tsutsui 		    dc->dc_cellheight, x, y, NWB225_ROP_LF_DI);
    840  1.1  tsutsui 		if (error != 0)
    841  1.1  tsutsui 			return;
    842  1.1  tsutsui 		dc->dc_cursoron = 0;
    843  1.1  tsutsui 	}
    844  1.1  tsutsui 
    845  1.1  tsutsui 	dc->dc_cursorrow = row;
    846  1.1  tsutsui 	dc->dc_cursorcol = col;
    847  1.1  tsutsui 	if (on == 0)
    848  1.1  tsutsui 		return;
    849  1.1  tsutsui 	if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols)
    850  1.1  tsutsui 		return;
    851  1.1  tsutsui 
    852  1.1  tsutsui 	x = dc->dc_xorigin + col * dc->dc_cellwidth;
    853  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
    854  1.1  tsutsui 	error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
    855  1.1  tsutsui 	    dc->dc_cellheight, x, y, NWB225_ROP_LF_DI);
    856  1.1  tsutsui 	if (error == 0)
    857  1.1  tsutsui 		dc->dc_cursoron = 1;
    858  1.1  tsutsui }
    859  1.1  tsutsui 
    860  1.1  tsutsui static int
    861  1.1  tsutsui fbbm_mapchar(void *cookie, int c, u_int *cp)
    862  1.1  tsutsui {
    863  1.1  tsutsui 
    864  1.1  tsutsui 	if (c < NWB225_KROM_ASCII_FIRST || c > NWB225_KROM_ASCII_LAST) {
    865  1.1  tsutsui 		*cp = ' ';
    866  1.1  tsutsui 		return 0;
    867  1.1  tsutsui 	}
    868  1.1  tsutsui 
    869  1.1  tsutsui 	*cp = c;
    870  1.1  tsutsui 	return 5;
    871  1.1  tsutsui }
    872  1.1  tsutsui 
    873  1.1  tsutsui static void
    874  1.1  tsutsui fbbm_putchar(void *cookie, int row, int col, u_int uc, long attr)
    875  1.1  tsutsui {
    876  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
    877  1.1  tsutsui 	uint16_t cell[NWB225_CELL_HEIGHT];
    878  1.1  tsutsui 	uint32_t foreground, background;
    879  1.1  tsutsui 	int x, y;
    880  1.1  tsutsui 
    881  1.1  tsutsui 	if (__predict_false(row < 0 || row >= dc->dc_nrows ||
    882  1.1  tsutsui 	    col < 0 || col >= dc->dc_ncols))
    883  1.1  tsutsui 		return;
    884  1.1  tsutsui 	if (uc < NWB225_KROM_ASCII_FIRST || uc > NWB225_KROM_ASCII_LAST)
    885  1.1  tsutsui 		uc = ' ';
    886  1.1  tsutsui 
    887  1.1  tsutsui 	nwb225_krom_load_cell(dc, uc, cell);
    888  1.1  tsutsui 	background = fbbm_attr_background(dc, attr);
    889  1.1  tsutsui 	foreground = (~background) & dc->dc_planemask;
    890  1.1  tsutsui 	x = dc->dc_xorigin + col * dc->dc_cellwidth;
    891  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
    892  1.1  tsutsui 
    893  1.1  tsutsui 	(void)nwb225_rop_hwrite(dc, cell, 1, 0, 0, dc->dc_cellwidth,
    894  1.1  tsutsui 	    dc->dc_cellheight, x, y, foreground, background);
    895  1.1  tsutsui }
    896  1.1  tsutsui 
    897  1.1  tsutsui static void
    898  1.1  tsutsui fbbm_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
    899  1.1  tsutsui {
    900  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
    901  1.1  tsutsui 	int sx, dx, y, width;
    902  1.1  tsutsui 
    903  1.1  tsutsui 	if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
    904  1.1  tsutsui 		return;
    905  1.1  tsutsui 	if (srccol < 0 || dstcol < 0 || srccol + ncols > dc->dc_ncols ||
    906  1.1  tsutsui 	    dstcol + ncols > dc->dc_ncols)
    907  1.1  tsutsui 		return;
    908  1.1  tsutsui 	if (srccol == dstcol)
    909  1.1  tsutsui 		return;
    910  1.1  tsutsui 
    911  1.1  tsutsui 	sx = dc->dc_xorigin + srccol * dc->dc_cellwidth;
    912  1.1  tsutsui 	dx = dc->dc_xorigin + dstcol * dc->dc_cellwidth;
    913  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
    914  1.1  tsutsui 	width = ncols * dc->dc_cellwidth;
    915  1.1  tsutsui 	(void)nwb225_rop_copy_rect(dc, sx, y, width, dc->dc_cellheight,
    916  1.1  tsutsui 	    dx, y, NWB225_ROP_LF_S);
    917  1.1  tsutsui }
    918  1.1  tsutsui 
    919  1.1  tsutsui static void
    920  1.1  tsutsui fbbm_erasecols(void *cookie, int row, int col, int ncols, long attr)
    921  1.1  tsutsui {
    922  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
    923  1.1  tsutsui 	uint32_t background;
    924  1.1  tsutsui 	int x, y, width;
    925  1.1  tsutsui 
    926  1.1  tsutsui 	if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
    927  1.1  tsutsui 		return;
    928  1.1  tsutsui 	if (col < 0 || col + ncols > dc->dc_ncols)
    929  1.1  tsutsui 		return;
    930  1.1  tsutsui 
    931  1.1  tsutsui 	x = dc->dc_xorigin + col * dc->dc_cellwidth;
    932  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
    933  1.1  tsutsui 	width = ncols * dc->dc_cellwidth;
    934  1.1  tsutsui 	background = fbbm_attr_background(dc, attr);
    935  1.1  tsutsui 	(void)nwb225_rop_fill_rect(dc, x, y, width, dc->dc_cellheight,
    936  1.1  tsutsui 	    background);
    937  1.1  tsutsui }
    938  1.1  tsutsui 
    939  1.1  tsutsui static void
    940  1.1  tsutsui fbbm_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
    941  1.1  tsutsui {
    942  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
    943  1.1  tsutsui 	int x, sy, dy, height;
    944  1.1  tsutsui 
    945  1.1  tsutsui 	if (nrows <= 0 || srcrow < 0 || dstrow < 0 ||
    946  1.1  tsutsui 	    srcrow + nrows > dc->dc_nrows || dstrow + nrows > dc->dc_nrows)
    947  1.1  tsutsui 		return;
    948  1.1  tsutsui 	if (srcrow == dstrow)
    949  1.1  tsutsui 		return;
    950  1.1  tsutsui 
    951  1.1  tsutsui 	x = dc->dc_xorigin;
    952  1.1  tsutsui 	sy = dc->dc_yorigin + srcrow * dc->dc_cellheight;
    953  1.1  tsutsui 	dy = dc->dc_yorigin + dstrow * dc->dc_cellheight;
    954  1.1  tsutsui 	height = nrows * dc->dc_cellheight;
    955  1.1  tsutsui 	(void)nwb225_rop_copy_rect(dc, x, sy,
    956  1.1  tsutsui 	    dc->dc_ncols * dc->dc_cellwidth, height, x, dy, NWB225_ROP_LF_S);
    957  1.1  tsutsui }
    958  1.1  tsutsui 
    959  1.1  tsutsui static void
    960  1.1  tsutsui fbbm_eraserows(void *cookie, int row, int nrows, long attr)
    961  1.1  tsutsui {
    962  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
    963  1.1  tsutsui 	uint32_t background;
    964  1.1  tsutsui 	int x, y, height;
    965  1.1  tsutsui 
    966  1.1  tsutsui 	if (nrows <= 0 || row < 0 || row + nrows > dc->dc_nrows)
    967  1.1  tsutsui 		return;
    968  1.1  tsutsui 
    969  1.1  tsutsui 	x = dc->dc_xorigin;
    970  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
    971  1.1  tsutsui 	height = nrows * dc->dc_cellheight;
    972  1.1  tsutsui 	background = fbbm_attr_background(dc, attr);
    973  1.1  tsutsui 	(void)nwb225_rop_fill_rect(dc, x, y,
    974  1.1  tsutsui 	    dc->dc_ncols * dc->dc_cellwidth, height, background);
    975  1.1  tsutsui }
    976  1.1  tsutsui 
    977  1.1  tsutsui static int
    978  1.1  tsutsui fbbm_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
    979  1.1  tsutsui {
    980  1.1  tsutsui 
    981  1.1  tsutsui 	if ((flags & ~WSATTR_REVERSE) != 0)
    982  1.1  tsutsui 		return EINVAL;
    983  1.1  tsutsui 
    984  1.1  tsutsui 	*attrp = flags & WSATTR_REVERSE;
    985  1.1  tsutsui 	return 0;
    986  1.1  tsutsui }
    987  1.1  tsutsui 
    988  1.1  tsutsui /*
    989  1.1  tsutsui  * wsdisplay_accessops functions
    990  1.1  tsutsui  */
    991  1.1  tsutsui static int
    992  1.1  tsutsui fbbm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    993  1.1  tsutsui {
    994  1.1  tsutsui 	struct fbbm_softc *sc = v;
    995  1.1  tsutsui 	struct fbbm_devconfig *dc = sc->sc_dc;
    996  1.1  tsutsui 	struct wsdisplay_fbinfo *fbinfo;
    997  1.1  tsutsui 
    998  1.1  tsutsui 	switch (cmd) {
    999  1.1  tsutsui 	case WSDISPLAYIO_GTYPE:
   1000  1.1  tsutsui 		*(u_int *)data = WSDISPLAY_TYPE_NWB225;
   1001  1.1  tsutsui 		return 0;
   1002  1.1  tsutsui 
   1003  1.1  tsutsui 	case WSDISPLAYIO_GINFO:
   1004  1.1  tsutsui 		fbinfo = data;
   1005  1.1  tsutsui 		fbinfo->height = dc->dc_height;
   1006  1.1  tsutsui 		fbinfo->width = dc->dc_width;
   1007  1.1  tsutsui 		fbinfo->depth = dc->dc_nplanes;
   1008  1.1  tsutsui 		fbinfo->cmsize = 0;
   1009  1.1  tsutsui 		return 0;
   1010  1.1  tsutsui 
   1011  1.1  tsutsui 	case WSDISPLAYIO_SMODE:
   1012  1.1  tsutsui 		sc->sc_wsmode = *(int *)data;
   1013  1.1  tsutsui 		return 0;
   1014  1.1  tsutsui 
   1015  1.1  tsutsui 	default:
   1016  1.1  tsutsui 		break;
   1017  1.1  tsutsui 	}
   1018  1.1  tsutsui 
   1019  1.1  tsutsui 	return EPASSTHROUGH;
   1020  1.1  tsutsui }
   1021  1.1  tsutsui 
   1022  1.1  tsutsui static int
   1023  1.1  tsutsui fbbm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
   1024  1.1  tsutsui     int *ccolp, int *crowp, long *attrp)
   1025  1.1  tsutsui {
   1026  1.1  tsutsui 	struct fbbm_softc *sc = v;
   1027  1.1  tsutsui 	struct fbbm_devconfig *dc = sc->sc_dc;
   1028  1.1  tsutsui 	long attr;
   1029  1.1  tsutsui 	int error;
   1030  1.1  tsutsui 
   1031  1.1  tsutsui 	KASSERT(type == &dc->dc_wsscrdescr);
   1032  1.1  tsutsui 
   1033  1.1  tsutsui 	if (sc->sc_nscreens != 0)
   1034  1.1  tsutsui 		return ENOMEM;
   1035  1.1  tsutsui 
   1036  1.1  tsutsui 	error = fbbm_allocattr(dc, 0, 0, 0, &attr);
   1037  1.1  tsutsui 	if (error != 0)
   1038  1.1  tsutsui 		return error;
   1039  1.1  tsutsui 
   1040  1.1  tsutsui 	*cookiep = dc;
   1041  1.1  tsutsui 	*ccolp = 0;
   1042  1.1  tsutsui 	*crowp = 0;
   1043  1.1  tsutsui 	*attrp = attr;
   1044  1.1  tsutsui 	sc->sc_nscreens = 1;
   1045  1.1  tsutsui 
   1046  1.1  tsutsui 	return 0;
   1047  1.1  tsutsui }
   1048  1.1  tsutsui 
   1049  1.1  tsutsui static void
   1050  1.1  tsutsui fbbm_free_screen(void *v, void *cookie)
   1051  1.1  tsutsui {
   1052  1.1  tsutsui 	struct fbbm_softc *sc = v;
   1053  1.1  tsutsui 
   1054  1.1  tsutsui 	KASSERT(sc->sc_nscreens == 1);
   1055  1.1  tsutsui 	KASSERT(cookie == sc->sc_dc);
   1056  1.1  tsutsui 	KASSERT(sc->sc_dc != &fbbm_console_dc);
   1057  1.1  tsutsui 	sc->sc_nscreens = 0;
   1058  1.1  tsutsui }
   1059  1.1  tsutsui 
   1060  1.1  tsutsui static int
   1061  1.1  tsutsui fbbm_show_screen(void *v, void *cookie, int waitok,
   1062  1.1  tsutsui     void (*cb)(void *, int, int), void *cbarg)
   1063  1.1  tsutsui {
   1064  1.1  tsutsui 
   1065  1.1  tsutsui 	return 0;
   1066  1.1  tsutsui }
   1067  1.1  tsutsui 
   1068  1.1  tsutsui int
   1069  1.1  tsutsui fbbm_cnattach(void)
   1070  1.1  tsutsui {
   1071  1.1  tsutsui 	struct fbbm_devconfig *dc;
   1072  1.1  tsutsui 	long attr;
   1073  1.1  tsutsui 
   1074  1.1  tsutsui 	if (fbbm_console_initialized())
   1075  1.1  tsutsui 		return 0;
   1076  1.1  tsutsui 
   1077  1.1  tsutsui 	dc = &fbbm_console_dc;
   1078  1.1  tsutsui 	memset(dc, 0, sizeof(*dc));
   1079  1.1  tsutsui 	if (fbbm_probe(NEWS68K_BUS_SPACE_EIO, NWB225_RCONT_BASE) == 0)
   1080  1.1  tsutsui 		return ENXIO;
   1081  1.1  tsutsui 
   1082  1.1  tsutsui 	if (nwb225_map(dc, NEWS68K_BUS_SPACE_EIO, NWB225_RCONT_BASE) != 0)
   1083  1.1  tsutsui 		goto out_clear;
   1084  1.1  tsutsui 
   1085  1.1  tsutsui 	if (nwb225_init_hardware(dc) != 0)
   1086  1.1  tsutsui 		goto out_unmap;
   1087  1.1  tsutsui 
   1088  1.1  tsutsui 	fbbm_init_screen(dc);
   1089  1.1  tsutsui 	if (fbbm_clear_screen(dc) != 0)
   1090  1.1  tsutsui 		goto out_unmap;
   1091  1.1  tsutsui 
   1092  1.1  tsutsui 	if (fbbm_allocattr(dc, 0, 0, 0, &attr))
   1093  1.1  tsutsui 		goto out_unmap;
   1094  1.1  tsutsui 
   1095  1.1  tsutsui 	wsdisplay_cnattach(&dc->dc_wsscrdescr, dc, 0, 0, attr);
   1096  1.1  tsutsui 	return 0;
   1097  1.1  tsutsui 
   1098  1.1  tsutsui  out_unmap:
   1099  1.1  tsutsui 	nwb225_unmap(dc);
   1100  1.1  tsutsui  out_clear:
   1101  1.1  tsutsui 	memset(dc, 0, sizeof(*dc));
   1102  1.1  tsutsui 	return 1;
   1103  1.1  tsutsui }
   1104