Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.12
      1 /* $NetBSD: tfb.c,v 1.12 1999/05/07 08:00:31 nisimura 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.12 1999/05/07 08:00:31 nisimura 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 
     54 #include <dev/tc/tcvar.h>
     55 #include <dev/ic/bt463reg.h>
     56 #include <dev/ic/bt431reg.h>
     57 
     58 #include <uvm/uvm_extern.h>
     59 
     60 /* XXX BUS'IFYING XXX */
     61 
     62 #if defined(pmax)
     63 #define	machine_btop(x) mips_btop(x)
     64 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
     65 
     66 struct bt463reg {
     67 	u_int8_t	bt_lo;
     68 	unsigned : 24;
     69 	u_int8_t	bt_hi;
     70 	unsigned : 24;
     71 	u_int8_t	bt_reg;
     72 	unsigned : 24;
     73 	u_int8_t	bt_cmap;
     74 };
     75 
     76 /*
     77  * N.B. a pair of Bt431s are located adjascently.
     78  * 	struct bt431twin {
     79  *		struct {
     80  *			u_int8_t u0;	for sprite image
     81  *			u_int8_t u1;	for sprite mask
     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 #endif
     96 
     97 #if defined(__alpha__) || defined(alpha)
     98 #define machine_btop(x) alpha_btop(x)
     99 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
    100 
    101 struct bt463reg {
    102 	u_int32_t	bt_lo;
    103 	u_int32_t	bt_hi;
    104 	u_int32_t	bt_reg;
    105 	u_int32_t	bt_cmap;
    106 };
    107 
    108 struct bt431reg {
    109 	u_int32_t	bt_lo;
    110 	u_int32_t	bt_hi;
    111 	u_int32_t	bt_ram;
    112 	u_int32_t	bt_ctl;
    113 };
    114 #endif
    115 
    116 /* XXX XXX XXX */
    117 
    118 struct fb_devconfig {
    119 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    120 	paddr_t dc_paddr;		/* memory space physical base address */
    121 	vsize_t dc_size;		/* size of slot memory */
    122 	int	dc_wid;			/* width of frame buffer */
    123 	int	dc_ht;			/* height of frame buffer */
    124 	int	dc_depth;		/* depth, bits per pixel */
    125 	int	dc_rowbytes;		/* bytes in a FB scan line */
    126 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    127 	struct raster	dc_raster;	/* raster description */
    128 	struct rcons	dc_rcons;	/* raster blitter control info */
    129 	int	    dc_blanked;		/* currently has video disabled */
    130 };
    131 
    132 struct hwcmap256 {
    133 #define	CMAP_SIZE	256	/* R/G/B entries */
    134 	u_int8_t r[CMAP_SIZE];
    135 	u_int8_t g[CMAP_SIZE];
    136 	u_int8_t b[CMAP_SIZE];
    137 };
    138 
    139 struct hwcursor64 {
    140 	struct wsdisplay_curpos cc_pos;
    141 	struct wsdisplay_curpos cc_hot;
    142 	struct wsdisplay_curpos cc_size;
    143 	struct wsdisplay_curpos cc_magic;
    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 hwcmap256 sc_cmap;	/* software copy of colormap */
    153 	struct hwcursor64 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 };
    163 
    164 #define	TX_MAGIC_X	220
    165 #define	TX_MAGIC_Y	35
    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 hwcmap256 *cm;
    374 	int console;
    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 	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
    391 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
    392 
    393 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
    394 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
    395 
    396         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, tfbintr, sc);
    397 
    398 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
    399 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
    400 
    401 	waa.console = console;
    402 	waa.scrdata = &tfb_screenlist;
    403 	waa.accessops = &tfb_accessops;
    404 	waa.accesscookie = sc;
    405 
    406 	config_found(self, &waa, wsemuldisplaydevprint);
    407 }
    408 
    409 int
    410 tfbioctl(v, cmd, data, flag, p)
    411 	void *v;
    412 	u_long cmd;
    413 	caddr_t data;
    414 	int flag;
    415 	struct proc *p;
    416 {
    417 	struct tfb_softc *sc = v;
    418 	struct fb_devconfig *dc = sc->sc_dc;
    419 	int turnoff;
    420 
    421 	switch (cmd) {
    422 	case WSDISPLAYIO_GTYPE:
    423 		*(u_int *)data = /* WSDISPLAY_TYPE_TX */ 0x19980910;
    424 		return (0);
    425 
    426 	case WSDISPLAYIO_GINFO:
    427 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    428 		wsd_fbip->height = sc->sc_dc->dc_ht;
    429 		wsd_fbip->width = sc->sc_dc->dc_wid;
    430 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    431 		wsd_fbip->cmsize = CMAP_SIZE;
    432 #undef fbt
    433 		return (0);
    434 
    435 	case WSDISPLAYIO_GETCMAP:
    436 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    437 
    438 	case WSDISPLAYIO_PUTCMAP:
    439 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    440 
    441 	case WSDISPLAYIO_SVIDEO:
    442 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    443 		if ((dc->dc_blanked == 0) ^ turnoff) {
    444 			dc->dc_blanked = turnoff;
    445 			/* XXX later XXX */
    446 		}
    447 		return (0);
    448 
    449 	case WSDISPLAYIO_GVIDEO:
    450 		*(u_int *)data = dc->dc_blanked ?
    451 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    452 		return (0);
    453 
    454 	case WSDISPLAYIO_GCURPOS:
    455 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    456 		return (0);
    457 
    458 	case WSDISPLAYIO_SCURPOS:
    459 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    460 		bt431_set_curpos(sc);
    461 		return (0);
    462 
    463 	case WSDISPLAYIO_GCURMAX:
    464 		((struct wsdisplay_curpos *)data)->x =
    465 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    466 		return (0);
    467 
    468 	case WSDISPLAYIO_GCURSOR:
    469 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    470 
    471 	case WSDISPLAYIO_SCURSOR:
    472 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    473 	}
    474 	return (ENOTTY);
    475 }
    476 
    477 int
    478 tfbmmap(v, offset, prot)
    479 	void *v;
    480 	off_t offset;
    481 	int prot;
    482 {
    483 	struct tfb_softc *sc = v;
    484 
    485 	if (offset >= TX_8FB_SIZE || offset < 0)
    486 		return (-1);
    487 	return machine_btop(sc->sc_dc->dc_paddr + TX_8FB_OFFSET + offset);
    488 }
    489 
    490 int
    491 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    492 	void *v;
    493 	const struct wsscreen_descr *type;
    494 	void **cookiep;
    495 	int *curxp, *curyp;
    496 	long *attrp;
    497 {
    498 	struct tfb_softc *sc = v;
    499 	long defattr;
    500 
    501 	if (sc->nscreens > 0)
    502 		return (ENOMEM);
    503 
    504 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    505 	*curxp = 0;
    506 	*curyp = 0;
    507 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    508 	*attrp = defattr;
    509 	sc->nscreens++;
    510 	return (0);
    511 }
    512 
    513 void
    514 tfb_free_screen(v, cookie)
    515 	void *v;
    516 	void *cookie;
    517 {
    518 	struct tfb_softc *sc = v;
    519 
    520 	if (sc->sc_dc == &tfb_console_dc)
    521 		panic("tfb_free_screen: console");
    522 
    523 	sc->nscreens--;
    524 }
    525 
    526 void
    527 tfb_show_screen(v, cookie)
    528 	void *v;
    529 	void *cookie;
    530 {
    531 }
    532 
    533 int
    534 tfb_cnattach(addr)
    535         tc_addr_t addr;
    536 {
    537         struct fb_devconfig *dcp = &tfb_console_dc;
    538         long defattr;
    539 
    540         tfb_getdevconfig(addr, dcp);
    541 
    542         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    543 
    544         wsdisplay_cnattach(&tfb_stdscreen, &dcp->dc_rcons,
    545                            0, 0, defattr);
    546         tfb_consaddr = addr;
    547         return(0);
    548 }
    549 
    550 int
    551 tfbintr(arg)
    552 	void *arg;
    553 {
    554 	struct tfb_softc *sc = arg;
    555 	caddr_t tfbbase;
    556 	struct bt463reg *vdac;
    557 	struct bt431reg *curs;
    558 	int v;
    559 
    560 	if (sc->sc_changed == 0)
    561 		return (1);
    562 
    563 	tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    564 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    565 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
    566 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
    567 	v = sc->sc_changed;
    568 	sc->sc_changed = 0;
    569 	if (v & DATA_ENB_CHANGED) {
    570 		BT431_SELECT(curs, BT431_REG_COMMAND);
    571 		curs->bt_ctl = (sc->sc_curenb) ? 0x4444 : 0x0404;
    572 	}
    573 	if (v & DATA_CURCMAP_CHANGED) {
    574 		u_int8_t *cp = sc->sc_cursor.cc_color;
    575 
    576 		BT463_SELECT(vdac, BT463_IREG_CURSOR_COLOR_0);
    577 		vdac->bt_reg = cp[1]; tc_wmb();
    578 		vdac->bt_reg = cp[3]; tc_wmb();
    579 		vdac->bt_reg = cp[5]; tc_wmb();
    580 
    581 		vdac->bt_reg = cp[0]; tc_wmb();
    582 		vdac->bt_reg = cp[2]; tc_wmb();
    583 		vdac->bt_reg = cp[4]; tc_wmb();
    584 
    585 		vdac->bt_reg = cp[1]; tc_wmb();
    586 		vdac->bt_reg = cp[3]; tc_wmb();
    587 		vdac->bt_reg = cp[5]; tc_wmb();
    588 
    589 		vdac->bt_reg = cp[1]; tc_wmb();
    590 		vdac->bt_reg = cp[3]; tc_wmb();
    591 		vdac->bt_reg = cp[5]; tc_wmb();
    592 	}
    593 	if (v & DATA_CURSHAPE_CHANGED) {
    594 		u_int8_t *ip, *mp, img, msk;
    595 		int bcnt;
    596 
    597 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    598 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    599 
    600 		bcnt = 0;
    601 		BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
    602 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    603 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    604 			/* pad right half 32 pixel when smaller than 33 */
    605 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    606 				curs->bt_ram = 0;
    607 				tc_wmb();
    608 			}
    609 			else {
    610 				img = *ip++;
    611 				msk = *mp++;
    612 				img &= msk;	/* cookie off image */
    613 				curs->bt_ram = (flip[msk] << 8) | flip[img];
    614 				tc_wmb();
    615 			}
    616 			bcnt += 2;
    617 		}
    618 		/* pad unoccupied scan lines */
    619 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    620 			curs->bt_ram = 0;
    621 			tc_wmb();
    622 			bcnt += 2;
    623 		}
    624 	}
    625 	if (v & DATA_CMAP_CHANGED) {
    626 		struct hwcmap256 *cm = &sc->sc_cmap;
    627 		int index;
    628 
    629 		BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
    630 		for (index = 0; index < CMAP_SIZE; index++) {
    631 			vdac->bt_cmap = cm->r[index];
    632 			vdac->bt_cmap = cm->g[index];
    633 			vdac->bt_cmap = cm->b[index];
    634 		}
    635 	}
    636 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
    637 	return (1);
    638 }
    639 
    640 void
    641 tfbinit(dc)
    642 	struct fb_devconfig *dc;
    643 {
    644 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
    645 	struct bt463reg *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    646 	struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    647 	int i;
    648 
    649 	BT463_SELECT(vdac, BT463_IREG_COMMAND_0);
    650 	vdac->bt_reg = 0x40;	tc_wmb();
    651 	vdac->bt_reg = 0x46;	tc_wmb();
    652 	vdac->bt_reg = 0xc0;	tc_wmb();
    653 	vdac->bt_reg = 0;	tc_wmb();	/* !? 204 !? */
    654 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane  0:7  */
    655 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane  8:15 */
    656 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane 16:23 */
    657 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane 24:27 */
    658 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink  0:7  */
    659 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink  8:15 */
    660 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink 16:23 */
    661 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink 24:27 */
    662 	vdac->bt_reg = 0x00;	tc_wmb();
    663 
    664 	BT463_SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    665 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    666 		vdac->bt_reg = /* ??? */ 0;
    667 		vdac->bt_reg = /* ??? */ 0;
    668 		vdac->bt_reg = /* ??? */ 0;
    669 	}
    670 
    671 	BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
    672 	vdac->bt_cmap = 0;	tc_wmb();
    673 	vdac->bt_cmap = 0;	tc_wmb();
    674 	vdac->bt_cmap = 0;	tc_wmb();
    675 	for (i = 1; i < BT463_NCMAP_ENTRIES; i++) {
    676 		vdac->bt_cmap = 0xff;	tc_wmb();
    677 		vdac->bt_cmap = 0xff;	tc_wmb();
    678 		vdac->bt_cmap = 0xff;	tc_wmb();
    679 	}
    680 
    681 	BT431_SELECT(curs, BT431_REG_COMMAND);
    682 	curs->bt_ctl = 0x0404;	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 	curs->bt_ctl = 0;	tc_wmb();
    695 }
    696 
    697 static int
    698 get_cmap(sc, p)
    699 	struct tfb_softc *sc;
    700 	struct wsdisplay_cmap *p;
    701 {
    702 	u_int index = p->index, count = p->count;
    703 
    704 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    705 		return (EINVAL);
    706 
    707 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    708 	    !uvm_useracc(p->green, count, B_WRITE) ||
    709 	    !uvm_useracc(p->blue, count, B_WRITE))
    710 		return (EFAULT);
    711 
    712 	copyout(&sc->sc_cmap.r[index], p->red, count);
    713 	copyout(&sc->sc_cmap.g[index], p->green, count);
    714 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    715 
    716 	return (0);
    717 }
    718 
    719 static int
    720 set_cmap(sc, p)
    721 	struct tfb_softc *sc;
    722 	struct wsdisplay_cmap *p;
    723 {
    724 	u_int index = p->index, count = p->count;
    725 
    726 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    727 		return (EINVAL);
    728 
    729 	if (!uvm_useracc(p->red, count, B_READ) ||
    730 	    !uvm_useracc(p->green, count, B_READ) ||
    731 	    !uvm_useracc(p->blue, count, B_READ))
    732 		return (EFAULT);
    733 
    734 	copyin(p->red, &sc->sc_cmap.r[index], count);
    735 	copyin(p->green, &sc->sc_cmap.g[index], count);
    736 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    737 
    738 	sc->sc_changed |= DATA_CMAP_CHANGED;
    739 
    740 	return (0);
    741 }
    742 
    743 static int
    744 set_cursor(sc, p)
    745 	struct tfb_softc *sc;
    746 	struct wsdisplay_cursor *p;
    747 {
    748 #define	cc (&sc->sc_cursor)
    749 	int v, index, count, icount;
    750 
    751 	v = p->which;
    752 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    753 		index = p->cmap.index;
    754 		count = p->cmap.count;
    755 		if (index >= 2 || (index + count) > 2)
    756 			return (EINVAL);
    757 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    758 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    759 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    760 			return (EFAULT);
    761 	}
    762 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    763 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    764 			return (EINVAL);
    765 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    766 		if (!uvm_useracc(p->image, icount, B_READ) ||
    767 		    !uvm_useracc(p->mask, icount, B_READ))
    768 			return (EFAULT);
    769 	}
    770 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    771 		if (v & WSDISPLAY_CURSOR_DOCUR)
    772 			cc->cc_hot = p->hot;
    773 		if (v & WSDISPLAY_CURSOR_DOPOS)
    774 			set_curpos(sc, &p->pos);
    775 		bt431_set_curpos(sc);
    776 	}
    777 
    778 	sc->sc_changed = 0;
    779 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    780 		sc->sc_curenb = p->enable;
    781 		sc->sc_changed |= DATA_ENB_CHANGED;
    782 	}
    783 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    784 		copyin(p->cmap.red, &cc->cc_color[index], count);
    785 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    786 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    787 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    788 	}
    789 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    790 		cc->cc_size = p->size;
    791 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    792 		copyin(p->image, cc->cc_image, icount);
    793 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    794 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    795 	}
    796 
    797 	return (0);
    798 #undef cc
    799 }
    800 
    801 static int
    802 get_cursor(sc, p)
    803 	struct tfb_softc *sc;
    804 	struct wsdisplay_cursor *p;
    805 {
    806 	return (ENOTTY); /* XXX */
    807 }
    808 
    809 static void
    810 set_curpos(sc, curpos)
    811 	struct tfb_softc *sc;
    812 	struct wsdisplay_curpos *curpos;
    813 {
    814 	struct fb_devconfig *dc = sc->sc_dc;
    815 	int x = curpos->x, y = curpos->y;
    816 
    817 	if (y < 0)
    818 		y = 0;
    819 	else if (y > dc->dc_ht)
    820 		y = dc->dc_ht;
    821 	if (x < 0)
    822 		x = 0;
    823 	else if (x > dc->dc_wid)
    824 		x = dc->dc_wid;
    825 	sc->sc_cursor.cc_pos.x = x;
    826 	sc->sc_cursor.cc_pos.y = y;
    827 }
    828 
    829 static void
    830 bt431_set_curpos(sc)
    831 	struct tfb_softc *sc;
    832 {
    833 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    834 	struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    835 	u_int16_t twin;
    836 	int x, y, s;
    837 
    838 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    839 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    840 
    841 	x += sc->sc_cursor.cc_magic.x;
    842 	y += sc->sc_cursor.cc_magic.y;
    843 
    844 	s = spltty();
    845 
    846 	BT431_SELECT(curs, BT431_REG_CURSOR_X_LOW);
    847 	curs->bt_ctl = TWIN_LO(x);	tc_wmb();
    848 	curs->bt_ctl = TWIN_HI(x);	tc_wmb();
    849 	curs->bt_ctl = TWIN_LO(y);	tc_wmb();
    850 	curs->bt_ctl = TWIN_HI(y);	tc_wmb();
    851 
    852 	splx(s);
    853 }
    854