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