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