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