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