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