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