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