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