Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.2
      1 /* $NetBSD: tfb.c,v 1.2 1998/10/30 00:53:12 nisimura Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996, 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.2 1998/10/30 00:53:12 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 /* it's really painful to manipulate 'twined' registers... */
    105 struct bt431reg {
    106 	u_int32_t	bt_lo;
    107 	u_int32_t	bt_hi;
    108 	u_int32_t	bt_ram;
    109 	u_int32_t	bt_ctl;
    110 };
    111 #endif
    112 
    113 /* XXX XXX XXX */
    114 
    115 struct fb_devconfig {
    116 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    117 	paddr_t dc_paddr;		/* memory space physical base address */
    118 	vsize_t dc_size;		/* size of slot memory */
    119 	int	dc_wid;			/* width of frame buffer */
    120 	int	dc_ht;			/* height of frame buffer */
    121 	int	dc_depth;		/* depth, bits per pixel */
    122 	int	dc_rowbytes;		/* bytes in a FB scan line */
    123 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    124 	struct raster	dc_raster;	/* raster description */
    125 	struct rcons	dc_rcons;	/* raster blitter control info */
    126 	int	    dc_blanked;		/* currently has video disabled */
    127 };
    128 
    129 struct hwcmap {
    130 #define	CMAP_SIZE	256	/* R/G/B entries */
    131 	u_int8_t r[CMAP_SIZE];
    132 	u_int8_t g[CMAP_SIZE];
    133 	u_int8_t b[CMAP_SIZE];
    134 };
    135 
    136 struct hwcursor {
    137 	struct wsdisplay_curpos cc_pos;
    138 	struct wsdisplay_curpos cc_hot;
    139 	struct wsdisplay_curpos cc_size;
    140 #define	CURSOR_MAX_SIZE	64
    141 	u_int8_t cc_color[6];
    142 	u_int64_t cc_image[64 + 64];
    143 };
    144 
    145 struct tfb_softc {
    146 	struct device sc_dev;
    147 	struct fb_devconfig *sc_dc;	/* device configuration */
    148 	struct hwcmap sc_cmap;		/* software copy of colormap */
    149 	struct hwcursor sc_cursor;	/* software copy of cursor */
    150 	int sc_curenb;			/* cursor sprite enabled */
    151 	int sc_changed;			/* need update of colormap */
    152 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    153 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    154 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    155 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    156 #define	DATA_ALL_CHANGED	0x0f
    157 	int nscreens;
    158 };
    159 
    160 int  tfbmatch __P((struct device *, struct cfdata *, void *));
    161 void tfbattach __P((struct device *, struct device *, void *));
    162 
    163 struct cfattach tfb_ca = {
    164 	sizeof(struct tfb_softc), tfbmatch, tfbattach,
    165 };
    166 
    167 void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    168 struct fb_devconfig tfb_console_dc;
    169 tc_addr_t tfb_consaddr;
    170 
    171 struct wsdisplay_emulops tfb_emulops = {
    172 	rcons_cursor,			/* could use hardware cursor; punt */
    173 	rcons_mapchar,
    174 	rcons_putchar,
    175 	rcons_copycols,
    176 	rcons_erasecols,
    177 	rcons_copyrows,
    178 	rcons_eraserows,
    179 	rcons_alloc_attr
    180 };
    181 
    182 struct wsscreen_descr tfb_stdscreen = {
    183 	"std", 0, 0,
    184 	&tfb_emulops,
    185 	0, 0,
    186 	0
    187 };
    188 
    189 const struct wsscreen_descr *_tfb_scrlist[] = {
    190 	&tfb_stdscreen,
    191 };
    192 
    193 struct wsscreen_list tfb_screenlist = {
    194 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
    195 };
    196 
    197 int	tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    198 int	tfbmmap __P((void *, off_t, int));
    199 
    200 int	tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    201 				      void **, int *, int *, long *));
    202 void	tfb_free_screen __P((void *, void *));
    203 void	tfb_show_screen __P((void *, void *));
    204 int	tfb_load_font __P((void *, void *, int, int, int, void *));
    205 
    206 struct wsdisplay_accessops tfb_accessops = {
    207 	tfbioctl,
    208 	tfbmmap,
    209 	tfb_alloc_screen,
    210 	tfb_free_screen,
    211 	tfb_show_screen,
    212 	tfb_load_font
    213 };
    214 
    215 int  tfb_cnattach __P((tc_addr_t));
    216 int  tfbintr __P((void *));
    217 void tfbinit __P((struct fb_devconfig *));
    218 
    219 static int  get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    220 static int  set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    221 static int  set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    222 static int  get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    223 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
    224 static void bt431_set_curpos __P((struct tfb_softc *));
    225 
    226 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
    227 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
    228 
    229 /* XXX XXX XXX */
    230 #define	BT431_SELECT(curs, regno) do {	\
    231 	u_int16_t twin;			\
    232 	curs->bt_lo = TWIN_LO(regno);	\
    233 	curs->bt_hi = TWIN_HI(regno);	\
    234 	tc_wmb();			\
    235    } while (0)
    236 
    237 #define	BT463_SELECT(vdac, regno) do {		\
    238 	vdac->bt_lo = (regno) & 0x00ff;		\
    239 	vdac->bt_hi = ((regno)& 0xff00) >> 8;	\
    240 	tc_wmb();				\
    241    } while (0)
    242 /* XXX XXX XXX */
    243 
    244 #define	TX_BT463_OFFSET	0x040000
    245 #define	TX_BT431_OFFSET	0x040010
    246 #define	TX_CONTROL	0x040030
    247 #define	TX_MAP_REGISTER	0x040030
    248 #define	TX_PIP_OFFSET	0x0800c0
    249 #define	TX_SELECTION	0x100000
    250 #define	TX_8FB_OFFSET	0x200000
    251 #define	TX_8FB_SIZE	0x100000
    252 #define	TX_24FB_OFFSET	0x400000
    253 #define	TX_24FB_SIZE	0x400000
    254 #define	TX_VIDEO_ENABLE	0xa00000
    255 
    256 #define TX_CTL_VIDEO_ON	0x80
    257 #define TX_CTL_INT_ENA	0x40
    258 #define TX_CTL_INT_PEND	0x20
    259 #define TX_CTL_SEG_ENA	0x10
    260 #define TX_CTL_SEG	0x0f
    261 
    262 
    263 int
    264 tfbmatch(parent, match, aux)
    265 	struct device *parent;
    266 	struct cfdata *match;
    267 	void *aux;
    268 {
    269 	struct tc_attach_args *ta = aux;
    270 
    271 	if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
    272 	    && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    273 		return (0);
    274 
    275 	return (1);
    276 }
    277 
    278 void
    279 tfb_getdevconfig(dense_addr, dc)
    280 	tc_addr_t dense_addr;
    281 	struct fb_devconfig *dc;
    282 {
    283 	struct raster *rap;
    284 	struct rcons *rcp;
    285 	int i;
    286 
    287 	dc->dc_vaddr = dense_addr;
    288 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    289 
    290 	dc->dc_wid = 1280;
    291 	dc->dc_ht = 1024;
    292 	dc->dc_depth = 8;
    293 	dc->dc_rowbytes = 1280;
    294 	dc->dc_videobase = dc->dc_vaddr + TX_8FB_OFFSET;
    295 	dc->dc_blanked = 0;
    296 
    297 	/* initialize colormap and cursor resource */
    298 	tfbinit(dc);
    299 
    300 	/* clear the screen */
    301 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    302 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    303 
    304 	/* initialize the raster */
    305 	rap = &dc->dc_raster;
    306 	rap->width = dc->dc_wid;
    307 	rap->height = dc->dc_ht;
    308 	rap->depth = dc->dc_depth;
    309 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    310 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    311 
    312 	/* initialize the raster console blitter */
    313 	rcp = &dc->dc_rcons;
    314 	rcp->rc_sp = rap;
    315 	rcp->rc_crow = rcp->rc_ccol = -1;
    316 	rcp->rc_crowp = &rcp->rc_crow;
    317 	rcp->rc_ccolp = &rcp->rc_ccol;
    318 	rcons_init(rcp, 34, 80);
    319 
    320 	tfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    321 	tfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    322 }
    323 
    324 void
    325 tfbattach(parent, self, aux)
    326 	struct device *parent, *self;
    327 	void *aux;
    328 {
    329 	struct tfb_softc *sc = (struct tfb_softc *)self;
    330 	struct tc_attach_args *ta = aux;
    331 	struct wsemuldisplaydev_attach_args waa;
    332 	struct hwcmap *cm;
    333 	int console, i;
    334 
    335 	console = (ta->ta_addr == tfb_consaddr);
    336 	if (console) {
    337 		sc->sc_dc = &tfb_console_dc;
    338 		sc->nscreens = 1;
    339 	}
    340 	else {
    341 		sc->sc_dc = (struct fb_devconfig *)
    342 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    343 		tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    344 	}
    345 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    346 	    sc->sc_dc->dc_depth);
    347 
    348 	cm = &sc->sc_cmap;
    349 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    350 	for (i = 1; i < CMAP_SIZE; i++) {
    351 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    352 	}
    353 
    354         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, tfbintr, sc);
    355 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
    356 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
    357 
    358 	waa.console = console;
    359 	waa.scrdata = &tfb_screenlist;
    360 	waa.accessops = &tfb_accessops;
    361 	waa.accesscookie = sc;
    362 
    363 	config_found(self, &waa, wsemuldisplaydevprint);
    364 }
    365 
    366 int
    367 tfbioctl(v, cmd, data, flag, p)
    368 	void *v;
    369 	u_long cmd;
    370 	caddr_t data;
    371 	int flag;
    372 	struct proc *p;
    373 {
    374 	struct tfb_softc *sc = v;
    375 	struct fb_devconfig *dc = sc->sc_dc;
    376 	int turnoff;
    377 
    378 	switch (cmd) {
    379 	case WSDISPLAYIO_GTYPE:
    380 		*(u_int *)data = /* WSDISPLAY_TYPE_TX */ 0x19980910;
    381 		return (0);
    382 
    383 	case WSDISPLAYIO_GINFO:
    384 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    385 		wsd_fbip->height = sc->sc_dc->dc_ht;
    386 		wsd_fbip->width = sc->sc_dc->dc_wid;
    387 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    388 		wsd_fbip->cmsize = CMAP_SIZE;
    389 #undef fbt
    390 		return (0);
    391 
    392 	case WSDISPLAYIO_GETCMAP:
    393 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    394 
    395 	case WSDISPLAYIO_PUTCMAP:
    396 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    397 
    398 	case WSDISPLAYIO_SVIDEO:
    399 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    400 		if ((dc->dc_blanked == 0) ^ turnoff) {
    401 			/* sc->sc_changed |= DATA_ALL_CHANGED; */
    402 			dc->dc_blanked = turnoff;
    403 		}
    404 		return (0);
    405 
    406 	case WSDISPLAYIO_GVIDEO:
    407 		*(u_int *)data = dc->dc_blanked ?
    408 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    409 		return (0);
    410 
    411 	case WSDISPLAYIO_GCURPOS:
    412 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    413 		return (0);
    414 
    415 	case WSDISPLAYIO_SCURPOS:
    416 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    417 		bt431_set_curpos(sc);
    418 		return (0);
    419 
    420 	case WSDISPLAYIO_GCURMAX:
    421 		((struct wsdisplay_curpos *)data)->x =
    422 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    423 		return (0);
    424 
    425 	case WSDISPLAYIO_GCURSOR:
    426 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    427 
    428 	case WSDISPLAYIO_SCURSOR:
    429 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    430 	}
    431 	return ENOTTY;
    432 }
    433 
    434 int
    435 tfbmmap(v, offset, prot)
    436 	void *v;
    437 	off_t offset;
    438 	int prot;
    439 {
    440 	struct tfb_softc *sc = v;
    441 
    442 	if (offset > TX_8FB_SIZE) /* XXX */
    443 		return (-1);
    444 	return machine_btop(sc->sc_dc->dc_paddr + TX_8FB_OFFSET + offset);
    445 }
    446 
    447 int
    448 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    449 	void *v;
    450 	const struct wsscreen_descr *type;
    451 	void **cookiep;
    452 	int *curxp, *curyp;
    453 	long *attrp;
    454 {
    455 	struct tfb_softc *sc = v;
    456 	long defattr;
    457 
    458 	if (sc->nscreens > 0)
    459 		return (ENOMEM);
    460 
    461 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    462 	*curxp = 0;
    463 	*curyp = 0;
    464 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    465 	*attrp = defattr;
    466 	sc->nscreens++;
    467 	return (0);
    468 }
    469 
    470 void
    471 tfb_free_screen(v, cookie)
    472 	void *v;
    473 	void *cookie;
    474 {
    475 	struct tfb_softc *sc = v;
    476 
    477 	if (sc->sc_dc == &tfb_console_dc)
    478 		panic("tfb_free_screen: console");
    479 
    480 	sc->nscreens--;
    481 }
    482 
    483 void
    484 tfb_show_screen(v, cookie)
    485 	void *v;
    486 	void *cookie;
    487 {
    488 }
    489 
    490 int
    491 tfb_load_font(v, cookie, first, num, stride, data)
    492 	void *v;
    493 	void *cookie;
    494 	int first, num, stride;
    495 	void *data;
    496 {
    497 	return (EINVAL);
    498 }
    499 
    500 int
    501 tfb_cnattach(addr)
    502         tc_addr_t addr;
    503 {
    504         struct fb_devconfig *dcp = &tfb_console_dc;
    505         long defattr;
    506 
    507         tfb_getdevconfig(addr, dcp);
    508 
    509         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    510 
    511         wsdisplay_cnattach(&tfb_stdscreen, &dcp->dc_rcons,
    512                            0, 0, defattr);
    513         tfb_consaddr = addr;
    514         return(0);
    515 }
    516 
    517 
    518 int
    519 tfbintr(arg)
    520 	void *arg;
    521 {
    522 	struct tfb_softc *sc = arg;
    523 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    524 	struct bt463reg *vdac;
    525 	struct bt431reg *curs;
    526 	int v;
    527 
    528 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
    529 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
    530 	if (sc->sc_changed == 0)
    531 		return (1);
    532 
    533 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    534 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
    535 	v = sc->sc_changed;
    536 	sc->sc_changed = 0;
    537 	if (v & DATA_ENB_CHANGED) {
    538 		BT431_SELECT(curs, BT431_REG_COMMAND);
    539 		curs->bt_ctl = (sc->sc_curenb) ? 0x4444 : 0x0404;
    540 	}
    541 	if (v & DATA_CURCMAP_CHANGED) {
    542 		u_int8_t *cp = sc->sc_cursor.cc_color;
    543 
    544 		BT463_SELECT(vdac, BT463_IREG_CURSOR_COLOR_0);
    545 		vdac->bt_reg = cp[1]; tc_wmb();
    546 		vdac->bt_reg = cp[3]; tc_wmb();
    547 		vdac->bt_reg = cp[5]; tc_wmb();
    548 
    549 		vdac->bt_reg = cp[0]; tc_wmb();
    550 		vdac->bt_reg = cp[2]; tc_wmb();
    551 		vdac->bt_reg = cp[4]; tc_wmb();
    552 
    553 		vdac->bt_reg = cp[1]; tc_wmb();
    554 		vdac->bt_reg = cp[3]; tc_wmb();
    555 		vdac->bt_reg = cp[5]; tc_wmb();
    556 
    557 		vdac->bt_reg = cp[1]; tc_wmb();
    558 		vdac->bt_reg = cp[3]; tc_wmb();
    559 		vdac->bt_reg = cp[5]; tc_wmb();
    560 	}
    561 	if (v & DATA_CURSHAPE_CHANGED) {
    562 		u_int8_t *bp1, *bp2;
    563 		u_int16_t twin;
    564 		int index;
    565 
    566 		bp1 = (u_int8_t *)&sc->sc_cursor.cc_image;
    567 		bp2 = (u_int8_t *)(&sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    568 
    569 		BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
    570 		for (index = 0;
    571 		    index < sizeof(sc->sc_cursor.cc_image)/sizeof(u_int16_t);
    572 		    index++) {
    573 			twin = *bp1++ | (*bp2++ << 8);
    574 			curs->bt_ram = twin;
    575 			tc_wmb();
    576 		}
    577 	}
    578 	if (v & DATA_CMAP_CHANGED) {
    579 		struct hwcmap *cm = &sc->sc_cmap;
    580 		int index;
    581 
    582 		BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
    583 		for (index = 0; index < CMAP_SIZE; index++) {
    584 			vdac->bt_cmap = cm->r[index];
    585 			vdac->bt_cmap = cm->g[index];
    586 			vdac->bt_cmap = cm->b[index];
    587 		}
    588 	}
    589 	return (1);
    590 }
    591 
    592 void
    593 tfbinit(dc)
    594 	struct fb_devconfig *dc;
    595 {
    596 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
    597 	struct bt463reg *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    598 	struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    599 	int i;
    600 
    601 	BT463_SELECT(vdac, BT463_IREG_COMMAND_0);
    602 	vdac->bt_reg = 0x40;	tc_wmb();
    603 	vdac->bt_reg = 0x46;	tc_wmb();
    604 	vdac->bt_reg = 0xc0;	tc_wmb();
    605 	vdac->bt_reg = 0;	tc_wmb();	/* !? 204 !? */
    606 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane  0:7  */
    607 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane  8:15 */
    608 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane 16:23 */
    609 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane 24:27 */
    610 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink  0:7  */
    611 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink  8:15 */
    612 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink 16:23 */
    613 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink 24:27 */
    614 	vdac->bt_reg = 0x00;	tc_wmb();
    615 
    616 	/* bt463_load_wid(vdac, 0, 16, -1); */
    617 
    618 	BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
    619 	vdac->bt_cmap = 0;	tc_wmb();
    620 	vdac->bt_cmap = 0;	tc_wmb();
    621 	vdac->bt_cmap = 0;	tc_wmb();
    622 	for (i = 1; i < CMAP_SIZE; i++) {
    623 		vdac->bt_cmap = 0xff;	tc_wmb();
    624 		vdac->bt_cmap = 0xff;	tc_wmb();
    625 		vdac->bt_cmap = 0xff;	tc_wmb();
    626 	}
    627 
    628 	BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM+0x100);
    629 	for (i = 0; i < CMAP_SIZE; i++) {
    630 		vdac->bt_cmap = 0;	tc_wmb();
    631 		vdac->bt_cmap = 0;	tc_wmb();
    632 		vdac->bt_cmap = 0;	tc_wmb();
    633 	}
    634 
    635 	BT431_SELECT(curs, BT431_REG_COMMAND);
    636 	curs->bt_ctl = 0x0404;	tc_wmb();
    637 	curs->bt_ctl = 0;	tc_wmb();
    638 	curs->bt_ctl = 0;	tc_wmb();
    639 	curs->bt_ctl = 0;	tc_wmb();
    640 	curs->bt_ctl = 0;	tc_wmb();
    641 	curs->bt_ctl = 0;	tc_wmb();
    642 	curs->bt_ctl = 0;	tc_wmb();
    643 	curs->bt_ctl = 0;	tc_wmb();
    644 	curs->bt_ctl = 0;	tc_wmb();
    645 	curs->bt_ctl = 0;	tc_wmb();
    646 	curs->bt_ctl = 0;	tc_wmb();
    647 	curs->bt_ctl = 0;	tc_wmb();
    648 	curs->bt_ctl = 0;	tc_wmb();
    649 }
    650 
    651 static int
    652 get_cmap(sc, p)
    653 	struct tfb_softc *sc;
    654 	struct wsdisplay_cmap *p;
    655 {
    656 	u_int index = p->index, count = p->count;
    657 
    658 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    659 		return (EINVAL);
    660 
    661 	if (!useracc(p->red, count, B_WRITE) ||
    662 	    !useracc(p->green, count, B_WRITE) ||
    663 	    !useracc(p->blue, count, B_WRITE))
    664 		return (EFAULT);
    665 
    666 	copyout(&sc->sc_cmap.r[index], p->red, count);
    667 	copyout(&sc->sc_cmap.g[index], p->green, count);
    668 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    669 
    670 	return (0);
    671 }
    672 
    673 static int
    674 set_cmap(sc, p)
    675 	struct tfb_softc *sc;
    676 	struct wsdisplay_cmap *p;
    677 {
    678 	u_int index = p->index, count = p->count;
    679 
    680 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    681 		return (EINVAL);
    682 
    683 	if (!useracc(p->red, count, B_READ) ||
    684 	    !useracc(p->green, count, B_READ) ||
    685 	    !useracc(p->blue, count, B_READ))
    686 		return (EFAULT);
    687 
    688 	copyin(p->red, &sc->sc_cmap.r[index], count);
    689 	copyin(p->green, &sc->sc_cmap.g[index], count);
    690 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    691 
    692 	sc->sc_changed |= DATA_CMAP_CHANGED;
    693 
    694 	return (0);
    695 }
    696 
    697 static int
    698 set_cursor(sc, p)
    699 	struct tfb_softc *sc;
    700 	struct wsdisplay_cursor *p;
    701 {
    702 #define	cc (&sc->sc_cursor)
    703 	int v, index, count;
    704 
    705 	v = p->which;
    706 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    707 		index = p->cmap.index;
    708 		count = p->cmap.count;
    709 		if (index >= 2 || (index + count) > 2)
    710 			return (EINVAL);
    711 		if (!useracc(p->cmap.red, count, B_READ) ||
    712 		    !useracc(p->cmap.green, count, B_READ) ||
    713 		    !useracc(p->cmap.blue, count, B_READ))
    714 			return (EFAULT);
    715 	}
    716 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    717 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    718 			return (EINVAL);
    719 		count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
    720 		if (!useracc(p->image, count, B_READ) ||
    721 		    !useracc(p->mask, count, B_READ))
    722 			return (EFAULT);
    723 	}
    724 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    725 		if (v & WSDISPLAY_CURSOR_DOCUR)
    726 			cc->cc_hot = p->hot;
    727 		if (v & WSDISPLAY_CURSOR_DOPOS)
    728 			set_curpos(sc, &p->pos);
    729 		bt431_set_curpos(sc);
    730 	}
    731 
    732 	sc->sc_changed = 0;
    733 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    734 		sc->sc_curenb = p->enable;
    735 		sc->sc_changed |= DATA_ENB_CHANGED;
    736 	}
    737 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    738 		count = p->cmap.count;
    739 		copyin(p->cmap.red, &cc->cc_color[index], count);
    740 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    741 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    742 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    743 	}
    744 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    745 		cc->cc_size = p->size;
    746 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    747 		copyin(p->image, (caddr_t)cc->cc_image, count);
    748 		copyin(p->mask, (caddr_t)(cc->cc_image+CURSOR_MAX_SIZE), count);
    749 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    750 	}
    751 
    752 	return (0);
    753 #undef cc
    754 }
    755 
    756 static int
    757 get_cursor(sc, p)
    758 	struct tfb_softc *sc;
    759 	struct wsdisplay_cursor *p;
    760 {
    761 	return (ENOTTY); /* XXX */
    762 }
    763 
    764 static void
    765 set_curpos(sc, curpos)
    766 	struct tfb_softc *sc;
    767 	struct wsdisplay_curpos *curpos;
    768 {
    769 	struct fb_devconfig *dc = sc->sc_dc;
    770 	int x = curpos->x, y = curpos->y;
    771 
    772 	if (y < 0)
    773 		y = 0;
    774 	else if (y > dc->dc_ht - sc->sc_cursor.cc_size.y - 1)
    775 		y = dc->dc_ht - sc->sc_cursor.cc_size.y - 1;
    776 	if (x < 0)
    777 		x = 0;
    778 	else if (x > dc->dc_wid - sc->sc_cursor.cc_size.x - 1)
    779 		x = dc->dc_wid - sc->sc_cursor.cc_size.x - 1;
    780 	sc->sc_cursor.cc_pos.x = x;
    781 	sc->sc_cursor.cc_pos.y = y;
    782 }
    783 
    784 static void
    785 bt431_set_curpos(sc)
    786 	struct tfb_softc *sc;
    787 {
    788 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    789 	struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    790 	int x = 220, y = 35; /* magic offset of TX coordinate */
    791 	u_int16_t twin;
    792 	int s;
    793 
    794 	x += sc->sc_cursor.cc_pos.x;
    795 	y += sc->sc_cursor.cc_pos.y;
    796 
    797 	s = spltty();
    798 
    799 	BT431_SELECT(curs, BT431_REG_CURSOR_X_LOW);
    800 	curs->bt_ctl = TWIN_LO(x);
    801 	curs->bt_ctl = TWIN_HI(x);
    802 	curs->bt_ctl = TWIN_LO(y);
    803 	curs->bt_ctl = TWIN_HI(y);
    804 
    805 	splx(s);
    806 }
    807