Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.53.16.3
      1 /* $NetBSD: tfb.c,v 1.53.16.3 2009/01/17 13:29:09 mjf Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Tohru Nishimura.
      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: tfb.c,v 1.53.16.3 2009/01/17 13:29:09 mjf Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/kernel.h>
     38 #include <sys/device.h>
     39 #include <sys/malloc.h>
     40 #include <sys/buf.h>
     41 #include <sys/ioctl.h>
     42 
     43 #include <sys/bus.h>
     44 #include <sys/intr.h>
     45 
     46 #include <dev/wscons/wsconsio.h>
     47 #include <dev/wscons/wsdisplayvar.h>
     48 
     49 #include <dev/rasops/rasops.h>
     50 #include <dev/wsfont/wsfont.h>
     51 
     52 #include <dev/tc/tcvar.h>
     53 #include <dev/ic/bt463reg.h>
     54 #include <dev/ic/bt431reg.h>
     55 
     56 #include <uvm/uvm_extern.h>
     57 
     58 #if defined(pmax)
     59 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
     60 #endif
     61 
     62 #if defined(alpha)
     63 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
     64 #endif
     65 
     66 /*
     67  * struct bt463reg {
     68  * 	u_int8_t	bt_lo;
     69  * 	unsigned : 24;
     70  * 	u_int8_t	bt_hi;
     71  * 	unsigned : 24;
     72  * 	u_int8_t	bt_reg;
     73  * 	unsigned : 24;
     74  * 	u_int8_t	bt_cmap;
     75  * };
     76  *
     77  * N.B. a pair of Bt431s are located adjascently.
     78  * 	struct bt431twin {
     79  *		struct {
     80  *			u_int8_t u0;	for sprite mask
     81  *			u_int8_t u1;	for sprite image
     82  *			unsigned :16;
     83  *		} bt_lo;
     84  *		...
     85  *
     86  * struct bt431reg {
     87  * 	u_int16_t	bt_lo;
     88  * 	unsigned : 16;
     89  * 	u_int16_t	bt_hi;
     90  * 	unsigned : 16;
     91  * 	u_int16_t	bt_ram;
     92  * 	unsigned : 16;
     93  * 	u_int16_t	bt_ctl;
     94  * };
     95  */
     96 
     97 /* Bt463 hardware registers, memory-mapped in 32bit stride */
     98 #define	bt_lo	0x0
     99 #define	bt_hi	0x4
    100 #define	bt_reg	0x8
    101 #define	bt_cmap	0xc
    102 
    103 /* Bt431 hardware registers, memory-mapped in 32bit stride */
    104 #define	bt_ram	0x8
    105 #define	bt_ctl	0xc
    106 
    107 #define	REGWRITE32(p,i,v) do {					\
    108 	*(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb();	\
    109     } while (0)
    110 
    111 #define	SELECT463(p,r) do {					\
    112 	REGWRITE32((p), bt_lo, 0xff & (r));			\
    113 	REGWRITE32((p), bt_hi, 0xff & ((r)>>8));		\
    114    } while (0)
    115 
    116 #define	TWIN(x)	   ((x) | ((x) << 8))
    117 #define	TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin)
    118 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8))
    119 
    120 #define	SELECT431(p,r) do {					\
    121 	REGWRITE32((p), bt_lo, TWIN(r));			\
    122 	REGWRITE32((p), bt_hi, 0);				\
    123    } while (0)
    124 
    125 struct hwcmap256 {
    126 #define	CMAP_SIZE	256	/* R/G/B entries */
    127 	u_int8_t r[CMAP_SIZE];
    128 	u_int8_t g[CMAP_SIZE];
    129 	u_int8_t b[CMAP_SIZE];
    130 };
    131 
    132 struct hwcursor64 {
    133 	struct wsdisplay_curpos cc_pos;
    134 	struct wsdisplay_curpos cc_hot;
    135 	struct wsdisplay_curpos cc_size;
    136 	struct wsdisplay_curpos cc_magic;
    137 #define	CURSOR_MAX_SIZE	64
    138 	u_int8_t cc_color[6];
    139 	u_int64_t cc_image[CURSOR_MAX_SIZE];
    140 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
    141 };
    142 
    143 struct tfb_softc {
    144 	vaddr_t sc_vaddr;
    145 	size_t sc_size;
    146 	struct rasops_info *sc_ri;
    147 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    148 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    149 	int sc_blanked;			/* video visibility disabled */
    150 	int sc_curenb;			/* cursor sprite enabled */
    151 	int sc_changed;			/* need update of hardware */
    152 #define	WSDISPLAY_CMAP_DOLUT	0x20
    153 	int nscreens;
    154 };
    155 
    156 #define	TX_MAGIC_X	360
    157 #define	TX_MAGIC_Y	36
    158 
    159 #define	TX_BT463_OFFSET	0x040000
    160 #define	TX_BT431_OFFSET	0x040010
    161 #define	TX_CONTROL	0x040030
    162 #define	TX_MAP_REGISTER	0x040030
    163 #define	TX_PIP_OFFSET	0x0800c0
    164 #define	TX_SELECTION	0x100000
    165 #define	TX_8BPP_OFFSET	0x200000
    166 #define	TX_8BPP_SIZE	0x200000
    167 #define	TX_24BPP_OFFSET	0x400000
    168 #define	TX_24BPP_SIZE	0x600000
    169 #define	TX_VIDEO_ENABLE	0xa00000
    170 
    171 #define	TX_CTL_VIDEO_ON	0x80
    172 #define	TX_CTL_INT_ENA	0x40
    173 #define	TX_CTL_INT_PEND	0x20
    174 #define	TX_CTL_SEG_ENA	0x10
    175 #define	TX_CTL_SEG	0x0f
    176 
    177 static int  tfbmatch(device_t, cfdata_t, void *);
    178 static void tfbattach(device_t, device_t, void *);
    179 
    180 CFATTACH_DECL_NEW(tfb, sizeof(struct tfb_softc),
    181     tfbmatch, tfbattach, NULL, NULL);
    182 
    183 static void tfb_common_init(struct rasops_info *);
    184 static void tfb_cmap_init(struct tfb_softc *);
    185 static struct rasops_info tfb_console_ri;
    186 static tc_addr_t tfb_consaddr;
    187 
    188 static struct wsscreen_descr tfb_stdscreen = {
    189 	"std", 0, 0,
    190 	0, /* textops */
    191 	0, 0,
    192 	WSSCREEN_REVERSE
    193 };
    194 
    195 static const struct wsscreen_descr *_tfb_scrlist[] = {
    196 	&tfb_stdscreen,
    197 };
    198 
    199 static const struct wsscreen_list tfb_screenlist = {
    200 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
    201 };
    202 
    203 static int	tfbioctl(void *, void *, u_long, void *, int, struct lwp *);
    204 static paddr_t	tfbmmap(void *, void *, off_t, int);
    205 
    206 static int	tfb_alloc_screen(void *, const struct wsscreen_descr *,
    207 				      void **, int *, int *, long *);
    208 static void	tfb_free_screen(void *, void *);
    209 static int	tfb_show_screen(void *, void *, int,
    210 				     void (*) (void *, int, int), void *);
    211 
    212 static const struct wsdisplay_accessops tfb_accessops = {
    213 	tfbioctl,
    214 	tfbmmap,
    215 	tfb_alloc_screen,
    216 	tfb_free_screen,
    217 	tfb_show_screen,
    218 	0 /* load_font */
    219 };
    220 
    221 int  tfb_cnattach(tc_addr_t);
    222 static int  tfbintr(void *);
    223 static void tfbhwinit(void *);
    224 
    225 static int  get_cmap(struct tfb_softc *, struct wsdisplay_cmap *);
    226 static int  set_cmap(struct tfb_softc *, struct wsdisplay_cmap *);
    227 static int  set_cursor(struct tfb_softc *, struct wsdisplay_cursor *);
    228 static int  get_cursor(struct tfb_softc *, struct wsdisplay_cursor *);
    229 static void set_curpos(struct tfb_softc *, struct wsdisplay_curpos *);
    230 
    231 /* bit order reverse */
    232 static const u_int8_t flip[256] = {
    233 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    234 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    235 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    236 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    237 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    238 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    239 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    240 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    241 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    242 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    243 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    244 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    245 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    246 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    247 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    248 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    249 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    250 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    251 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    252 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    253 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    254 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    255 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    256 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    257 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    258 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    259 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    260 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    261 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    262 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    263 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    264 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    265 };
    266 
    267 static int
    268 tfbmatch(device_t parent, cfdata_t match, void *aux)
    269 {
    270 	struct tc_attach_args *ta = aux;
    271 
    272 	if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
    273 	    && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    274 		return (0);
    275 
    276 	return (1);
    277 }
    278 
    279 
    280 static void
    281 tfbattach(device_t parent, device_t self, void *aux)
    282 {
    283 	struct tfb_softc *sc = device_private(self);
    284 	struct tc_attach_args *ta = aux;
    285 	struct rasops_info *ri;
    286 	struct wsemuldisplaydev_attach_args waa;
    287 	int console;
    288 
    289 	console = (ta->ta_addr == tfb_consaddr);
    290 	if (console) {
    291 		sc->sc_ri = ri = &tfb_console_ri;
    292 		sc->nscreens = 1;
    293 	}
    294 	else {
    295 		ri = malloc(sizeof(struct rasops_info),
    296 			M_DEVBUF, M_NOWAIT|M_ZERO);
    297 		if (ri == NULL) {
    298 			printf(": can't alloc memory\n");
    299 			return;
    300 		}
    301 
    302 		ri->ri_hw = (void *)ta->ta_addr;
    303 		tfb_common_init(ri);
    304 		sc->sc_ri = ri;
    305 	}
    306 	printf(": %dx%d, 8,24bpp\n", ri->ri_width, ri->ri_height);
    307 
    308 	tfb_cmap_init(sc);
    309 
    310 	sc->sc_vaddr = ta->ta_addr;
    311 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
    312 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
    313 	sc->sc_blanked = sc->sc_curenb = 0;
    314 
    315 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
    316 
    317 	*(u_int8_t *)((char *)ri->ri_hw + TX_CONTROL) &= ~0x40;
    318 	*(u_int8_t *)((char *)ri->ri_hw + TX_CONTROL) |= 0x40;
    319 
    320 	waa.console = console;
    321 	waa.scrdata = &tfb_screenlist;
    322 	waa.accessops = &tfb_accessops;
    323 	waa.accesscookie = sc;
    324 
    325 	config_found(self, &waa, wsemuldisplaydevprint);
    326 }
    327 
    328 static void
    329 tfb_common_init(struct rasops_info *ri)
    330 {
    331 	char *base;
    332 	int cookie;
    333 
    334 	base = (void *)ri->ri_hw;
    335 
    336 	/* initialize colormap and cursor hardware */
    337 	tfbhwinit(base);
    338 
    339 	ri->ri_flg = RI_CENTER;
    340 	ri->ri_depth = 8;
    341 	ri->ri_width = 1280;
    342 	ri->ri_height = 1024;
    343 	ri->ri_stride = 1280;
    344 	ri->ri_bits = base + TX_8BPP_OFFSET;
    345 
    346 	/* clear the screen */
    347 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    348 
    349 	wsfont_init();
    350 	/* prefer 12 pixel wide font */
    351 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
    352 	    WSDISPLAY_FONTORDER_L2R);
    353 	if (cookie <= 0)
    354 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
    355 		    WSDISPLAY_FONTORDER_L2R);
    356 	if (cookie <= 0) {
    357 		printf("tfb: font table is empty\n");
    358 		return;
    359 	}
    360 
    361 	if (wsfont_lock(cookie, &ri->ri_font)) {
    362 		printf("tfb: couldn't lock font\n");
    363 		return;
    364 	}
    365 	ri->ri_wsfcookie = cookie;
    366 
    367 	rasops_init(ri, 34, 80);
    368 
    369 	/* XXX shouldn't be global */
    370 	tfb_stdscreen.nrows = ri->ri_rows;
    371 	tfb_stdscreen.ncols = ri->ri_cols;
    372 	tfb_stdscreen.textops = &ri->ri_ops;
    373 	tfb_stdscreen.capabilities = ri->ri_caps;
    374 }
    375 
    376 static void
    377 tfb_cmap_init(struct tfb_softc *sc)
    378 {
    379 	struct hwcmap256 *cm;
    380 	const u_int8_t *p;
    381 	int index;
    382 
    383 	cm = &sc->sc_cmap;
    384 	p = rasops_cmap;
    385 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    386 		cm->r[index] = p[0];
    387 		cm->g[index] = p[1];
    388 		cm->b[index] = p[2];
    389 	}
    390 }
    391 
    392 static int
    393 tfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    394 {
    395 	struct tfb_softc *sc = v;
    396 	struct rasops_info *ri = sc->sc_ri;
    397 	int turnoff, s;
    398 
    399 	switch (cmd) {
    400 	case WSDISPLAYIO_GTYPE:
    401 		*(u_int *)data = WSDISPLAY_TYPE_TX;
    402 		return (0);
    403 
    404 	case WSDISPLAYIO_GINFO:
    405 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    406 		wsd_fbip->height = ri->ri_height;
    407 		wsd_fbip->width = ri->ri_width;
    408 		wsd_fbip->depth = ri->ri_depth;
    409 		wsd_fbip->cmsize = CMAP_SIZE;
    410 #undef fbt
    411 		return (0);
    412 
    413 	case WSDISPLAYIO_GETCMAP:
    414 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    415 
    416 	case WSDISPLAYIO_PUTCMAP:
    417 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    418 
    419 	case WSDISPLAYIO_SVIDEO:
    420 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    421 		if (sc->sc_blanked != turnoff) {
    422 			sc->sc_blanked = turnoff;
    423 #if 0	/* XXX later XXX */
    424 	To turn off;
    425 	- clear the MSB of TX control register; &= ~0x80,
    426 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
    427 #endif	/* XXX XXX XXX */
    428 		}
    429 		return (0);
    430 
    431 	case WSDISPLAYIO_GVIDEO:
    432 		*(u_int *)data = sc->sc_blanked ?
    433 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    434 		return (0);
    435 
    436 	case WSDISPLAYIO_GCURPOS:
    437 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    438 		return (0);
    439 
    440 	case WSDISPLAYIO_SCURPOS:
    441 		s = spltty();
    442 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    443 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    444 		splx(s);
    445 		return (0);
    446 
    447 	case WSDISPLAYIO_GCURMAX:
    448 		((struct wsdisplay_curpos *)data)->x =
    449 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    450 		return (0);
    451 
    452 	case WSDISPLAYIO_GCURSOR:
    453 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    454 
    455 	case WSDISPLAYIO_SCURSOR:
    456 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    457 
    458 	case WSDISPLAYIO_SMODE:
    459 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    460 			s = spltty();
    461 			tfb_cmap_init(sc);
    462 			sc->sc_curenb = 0;
    463 			sc->sc_blanked = 0;
    464 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
    465 			    WSDISPLAY_CMAP_DOLUT);
    466 			splx(s);
    467 		}
    468 		return (0);
    469 	}
    470 	return (EPASSTHROUGH);
    471 }
    472 
    473 static paddr_t
    474 tfbmmap(void *v, void *vs, off_t offset, int prot)
    475 {
    476 	struct tfb_softc *sc = v;
    477 
    478 	if (offset >= TX_8BPP_SIZE || offset < 0) /* XXX 24bpp XXX */
    479 		return (-1);
    480 	return machine_btop(sc->sc_vaddr + TX_8BPP_OFFSET + offset);
    481 }
    482 
    483 static int
    484 tfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    485     int *curxp, int *curyp, long *attrp)
    486 {
    487 	struct tfb_softc *sc = v;
    488 	struct rasops_info *ri = sc->sc_ri;
    489 	long defattr;
    490 
    491 	if (sc->nscreens > 0)
    492 		return (ENOMEM);
    493 
    494 	*cookiep = ri; /* one and only for now */
    495 	*curxp = 0;
    496 	*curyp = 0;
    497 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    498 	*attrp = defattr;
    499 	sc->nscreens++;
    500 	return (0);
    501 }
    502 
    503 static void
    504 tfb_free_screen(void *v, void *cookie)
    505 {
    506 	struct tfb_softc *sc = v;
    507 
    508 	if (sc->sc_ri == &tfb_console_ri)
    509 		panic("tfb_free_screen: console");
    510 
    511 	sc->nscreens--;
    512 }
    513 
    514 static int
    515 tfb_show_screen(void *v, void *cookie, int waitok,
    516     void (*cb)(void *, int, int), void *cbarg)
    517 {
    518 
    519 	return (0);
    520 }
    521 
    522 /* EXPORT */ int
    523 tfb_cnattach(tc_addr_t addr)
    524 {
    525 	struct rasops_info *ri;
    526 	long defattr;
    527 
    528 	ri = &tfb_console_ri;
    529 	ri->ri_hw = (void *)addr;
    530 	tfb_common_init(ri);
    531 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    532 	wsdisplay_cnattach(&tfb_stdscreen, ri, 0, 0, defattr);
    533 	tfb_consaddr = addr;
    534 	return (0);
    535 }
    536 
    537 static int
    538 tfbintr(void *arg)
    539 {
    540 	struct tfb_softc *sc = arg;
    541 	char *base, *vdac, *curs;
    542 	int v;
    543 
    544 	base = (void *)sc->sc_ri->ri_hw;
    545 	*(u_int8_t *)(base + TX_CONTROL) &= ~0x40;
    546 	if (sc->sc_changed == 0)
    547 		goto done;
    548 
    549 	vdac = base + TX_BT463_OFFSET;
    550 	curs = base + TX_BT431_OFFSET;
    551 	v = sc->sc_changed;
    552 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    553 		int onoff;
    554 
    555 		onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
    556 		SELECT431(curs, BT431_REG_COMMAND);
    557 		REGWRITE32(curs, bt_ctl, onoff);
    558 	}
    559 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    560 		int x, y;
    561 		u_int32_t twin;
    562 
    563 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    564 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    565 
    566 		x += sc->sc_cursor.cc_magic.x;
    567 		y += sc->sc_cursor.cc_magic.y;
    568 
    569 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    570 		REGWRITE32(curs, bt_ctl, TWIN_LO(x));
    571 		REGWRITE32(curs, bt_ctl, TWIN_HI(x));
    572 		REGWRITE32(curs, bt_ctl, TWIN_LO(y));
    573 		REGWRITE32(curs, bt_ctl, TWIN_HI(y));
    574 	}
    575 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    576 		u_int8_t *cp = sc->sc_cursor.cc_color;
    577 
    578 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
    579 		REGWRITE32(vdac, bt_reg, cp[1]);
    580 		REGWRITE32(vdac, bt_reg, cp[3]);
    581 		REGWRITE32(vdac, bt_reg, cp[5]);
    582 
    583 		REGWRITE32(vdac, bt_reg, cp[0]);
    584 		REGWRITE32(vdac, bt_reg, cp[2]);
    585 		REGWRITE32(vdac, bt_reg, cp[4]);
    586 
    587 		REGWRITE32(vdac, bt_reg, cp[1]);
    588 		REGWRITE32(vdac, bt_reg, cp[3]);
    589 		REGWRITE32(vdac, bt_reg, cp[5]);
    590 
    591 		REGWRITE32(vdac, bt_reg, cp[1]);
    592 		REGWRITE32(vdac, bt_reg, cp[3]);
    593 		REGWRITE32(vdac, bt_reg, cp[5]);
    594 	}
    595 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    596 		u_int8_t *ip, *mp, img, msk;
    597 		int bcnt;
    598 
    599 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    600 		mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    601 		bcnt = 0;
    602 		SELECT431(curs, BT431_REG_CRAM_BASE);
    603 
    604 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    605 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    606 			/* pad right half 32 pixel when smaller than 33 */
    607 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    608 				REGWRITE32(curs, bt_ram, 0);
    609 			}
    610 			else {
    611 				int half;
    612 				img = *ip++;
    613 				msk = *mp++;
    614 				img &= msk;	/* cookie off image */
    615 				half = (flip[img] << 8) | flip[msk];
    616 				REGWRITE32(curs, bt_ram, half);
    617 			}
    618 			bcnt += 2;
    619 		}
    620 		/* pad unoccupied scan lines */
    621 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    622 			REGWRITE32(curs, bt_ram, 0);
    623 			bcnt += 2;
    624 		}
    625 	}
    626 	if (v & WSDISPLAY_CMAP_DOLUT) {
    627 		struct hwcmap256 *cm = &sc->sc_cmap;
    628 		int index;
    629 
    630 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    631 		for (index = 0; index < CMAP_SIZE; index++) {
    632 			REGWRITE32(vdac, bt_cmap, cm->r[index]);
    633 			REGWRITE32(vdac, bt_cmap, cm->g[index]);
    634 			REGWRITE32(vdac, bt_cmap, cm->b[index]);
    635 		}
    636 	}
    637 	sc->sc_changed = 0;
    638 done:
    639 	*(u_int8_t *)(base + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
    640 	*(u_int8_t *)(base + TX_CONTROL) |= 0x40;
    641 	return (1);
    642 }
    643 
    644 static void
    645 tfbhwinit(void *tfbbase)
    646 {
    647 	char *vdac, *curs;
    648 	const u_int8_t *p;
    649 	int i;
    650 
    651 	vdac = (char *)tfbbase + TX_BT463_OFFSET;
    652 	curs = (char *)tfbbase + TX_BT431_OFFSET;
    653 	SELECT463(vdac, BT463_IREG_COMMAND_0);
    654 	REGWRITE32(vdac, bt_reg, 0x40);	/* CMD 0 */
    655 	REGWRITE32(vdac, bt_reg, 0x46);	/* CMD 1 */
    656 	REGWRITE32(vdac, bt_reg, 0xc0);	/* CMD 2 */
    657 	REGWRITE32(vdac, bt_reg, 0);	/* !? 204 !? */
    658 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane  0:7  */
    659 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane  8:15 */
    660 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane 16:23 */
    661 	REGWRITE32(vdac, bt_reg, 0xff);	/* plane 24:27 */
    662 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink  0:7  */
    663 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink  8:15 */
    664 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink 16:23 */
    665 	REGWRITE32(vdac, bt_reg, 0x00);	/* blink 24:27 */
    666 	REGWRITE32(vdac, bt_reg, 0x00);
    667 
    668 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
    669   {
    670 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
    671 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    672 	};
    673 
    674 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    675 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    676 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
    677 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
    678 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
    679 	}
    680   }
    681 #endif
    682 
    683 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    684 	p = rasops_cmap;
    685 	for (i = 0; i < 256; i++, p += 3) {
    686 		REGWRITE32(vdac, bt_cmap, p[0]);
    687 		REGWRITE32(vdac, bt_cmap, p[1]);
    688 		REGWRITE32(vdac, bt_cmap, p[2]);
    689 	}
    690 
    691 	/* !? Eeeh !? */
    692 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
    693 	for (i = 0; i < 256; i++) {
    694 		REGWRITE32(vdac, bt_cmap, i);
    695 		REGWRITE32(vdac, bt_cmap, i);
    696 		REGWRITE32(vdac, bt_cmap, i);
    697 	}
    698 
    699 	SELECT431(curs, BT431_REG_COMMAND);
    700 	REGWRITE32(curs, bt_ctl, 0x0404);
    701 	REGWRITE32(curs, bt_ctl, 0); /* XLO */
    702 	REGWRITE32(curs, bt_ctl, 0); /* XHI */
    703 	REGWRITE32(curs, bt_ctl, 0); /* YLO */
    704 	REGWRITE32(curs, bt_ctl, 0); /* YHI */
    705 	REGWRITE32(curs, bt_ctl, 0); /* XWLO */
    706 	REGWRITE32(curs, bt_ctl, 0); /* XWHI */
    707 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
    708 	REGWRITE32(curs, bt_ctl, 0); /* WYLO */
    709 	REGWRITE32(curs, bt_ctl, 0); /* WWLO */
    710 	REGWRITE32(curs, bt_ctl, 0); /* WWHI */
    711 	REGWRITE32(curs, bt_ctl, 0); /* WHLO */
    712 	REGWRITE32(curs, bt_ctl, 0); /* WHHI */
    713 
    714 	SELECT431(curs, BT431_REG_CRAM_BASE);
    715 	for (i = 0; i < 512; i++) {
    716 		REGWRITE32(curs, bt_ram, 0);
    717 	}
    718 }
    719 
    720 static int
    721 get_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
    722 {
    723 	u_int index = p->index, count = p->count;
    724 	int error;
    725 
    726 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    727 		return (EINVAL);
    728 
    729 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
    730 	if (error)
    731 		return error;
    732 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
    733 	if (error)
    734 		return error;
    735 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
    736 	return error;
    737 }
    738 
    739 static int
    740 set_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
    741 {
    742 	struct hwcmap256 cmap;
    743 	u_int index = p->index, count = p->count;
    744 	int error, s;
    745 
    746 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    747 		return (EINVAL);
    748 
    749 	error = copyin(p->red, &cmap.r[index], count);
    750 	if (error)
    751 		return error;
    752 	error = copyin(p->green, &cmap.g[index], count);
    753 	if (error)
    754 		return error;
    755 	error = copyin(p->blue, &cmap.b[index], count);
    756 	if (error)
    757 		return error;
    758 	s = spltty();
    759 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
    760 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
    761 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
    762 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    763 	splx(s);
    764 	return (0);
    765 }
    766 
    767 static int
    768 set_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
    769 {
    770 #define	cc (&sc->sc_cursor)
    771 	u_int v, index = 0, count = 0, icount = 0;
    772 	uint8_t r[2], g[2], b[2], image[512], mask[512];
    773 	int error, s;
    774 
    775 	v = p->which;
    776 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    777 		index = p->cmap.index;
    778 		count = p->cmap.count;
    779 		if (index >= 2 || (index + count) > 2)
    780 			return (EINVAL);
    781 		error = copyin(p->cmap.red, &r[index], count);
    782 		if (error)
    783 			return error;
    784 		error = copyin(p->cmap.green, &g[index], count);
    785 		if (error)
    786 			return error;
    787 		error = copyin(p->cmap.blue, &b[index], count);
    788 		if (error)
    789 			return error;
    790 	}
    791 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    792 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    793 			return (EINVAL);
    794 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    795 		error = copyin(p->image, image, icount);
    796 		if (error)
    797 			return error;
    798 		error = copyin(p->mask, mask, icount);
    799 		if (error)
    800 			return error;
    801 	}
    802 
    803 	s = spltty();
    804 	if (v & WSDISPLAY_CURSOR_DOCUR)
    805 		sc->sc_curenb = p->enable;
    806 	if (v & WSDISPLAY_CURSOR_DOPOS)
    807 		set_curpos(sc, &p->pos);
    808 	if (v & WSDISPLAY_CURSOR_DOHOT)
    809 		cc->cc_hot = p->hot;
    810 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    811 		memcpy(&cc->cc_color[index], &r[index], count);
    812 		memcpy(&cc->cc_color[index + 2], &g[index], count);
    813 		memcpy(&cc->cc_color[index + 4], &b[index], count);
    814 	}
    815 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    816 		cc->cc_size = p->size;
    817 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    818 		memcpy(cc->cc_image, image, icount);
    819 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    820 		memcpy(cc->cc_mask, mask, icount);
    821 	}
    822 	sc->sc_changed |= v;
    823 	splx(s);
    824 
    825 	return (0);
    826 #undef cc
    827 }
    828 
    829 static int
    830 get_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
    831 {
    832 	return (EPASSTHROUGH); /* XXX */
    833 }
    834 
    835 static void
    836 set_curpos(struct tfb_softc *sc, struct wsdisplay_curpos *curpos)
    837 {
    838 	struct rasops_info *ri = sc->sc_ri;
    839 	int x = curpos->x, y = curpos->y;
    840 
    841 	if (y < 0)
    842 		y = 0;
    843 	else if (y > ri->ri_height)
    844 		y = ri->ri_height;
    845 	if (x < 0)
    846 		x = 0;
    847 	else if (x > ri->ri_width)
    848 		x = ri->ri_width;
    849 	sc->sc_cursor.cc_pos.x = x;
    850 	sc->sc_cursor.cc_pos.y = y;
    851 }
    852