Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.1
      1 /* $NetBSD: sfb.c,v 1.1 1998/10/29 12:24:25 nisimura Exp $ */
      2 
      3 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
      4 
      5 __KERNEL_RCSID(0, "$NetBSD: sfb.c,v 1.1 1998/10/29 12:24:25 nisimura Exp $");
      6 
      7 #include <sys/param.h>
      8 #include <sys/systm.h>
      9 #include <sys/kernel.h>
     10 #include <sys/device.h>
     11 #include <sys/malloc.h>
     12 #include <sys/buf.h>
     13 #include <sys/ioctl.h>
     14 #include <vm/vm.h>
     15 
     16 #include <machine/bus.h>
     17 #include <machine/intr.h>
     18 
     19 #include <dev/rcons/raster.h>
     20 #include <dev/wscons/wsconsio.h>
     21 #include <dev/wscons/wscons_raster.h>
     22 #include <dev/wscons/wsdisplayvar.h>
     23 #include <machine/autoconf.h>
     24 
     25 #include <dev/tc/tcvar.h>
     26 #include <dev/ic/bt459reg.h>
     27 #include <machine/sfbreg.h>
     28 
     29 #include "opt_uvm.h"
     30 #if defined(UVM)
     31 #include <uvm/uvm_extern.h>
     32 #define useracc uvm_useracc
     33 #endif
     34 
     35 /* XXX BUS'IFYING XXX */
     36 
     37 #if defined(__pmax__)
     38 #define	machine_btop(x) mips_btop(x)
     39 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
     40 #endif
     41 
     42 #if defined(__alpha__) || defined(alpha)
     43 #define machine_btop(x) alpha_btop(x)
     44 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     45 #endif
     46 
     47 /* XXX XXX XXX */
     48 
     49 /*
     50  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     51  * weird register layout such as each of 2nd and 3rd Bt459 registers
     52  * is adjacent each other in a word, i.e.,
     53  *
     54  *	struct bt459triplet {
     55  * 		struct {
     56  *			u_int8_t u0;
     57  *			u_int8_t u1;
     58  *			u_int8_t u2;
     59  *			unsigned :8;
     60  *		} bt_lo;
     61  *		...
     62  *
     63  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
     64  */
     65 struct bt459reg {
     66         u_int32_t       bt_lo;
     67         u_int32_t       bt_hi;
     68         u_int32_t       bt_reg;
     69         u_int32_t       bt_cmap;
     70 };
     71 
     72 struct fb_devconfig {
     73 	vaddr_t dc_vaddr;		/* memory space virtual base address */
     74 	paddr_t dc_paddr;		/* memory space physical base address */
     75 	vsize_t dc_size;		/* size of slot memory */
     76 	int	dc_wid;			/* width of frame buffer */
     77 	int	dc_ht;			/* height of frame buffer */
     78 	int	dc_depth;		/* depth, bits per pixel */
     79 	int	dc_rowbytes;		/* bytes in a FB scan line */
     80 	vaddr_t	dc_videobase;		/* base of flat frame buffer */
     81 	struct raster	dc_raster;	/* raster description */
     82 	struct rcons	dc_rcons;	/* raster blitter control info */
     83 	int	    dc_blanked;		/* currently has video disabled */
     84 };
     85 
     86 struct hwcmap {
     87 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
     88 	u_int8_t r[CMAP_SIZE];
     89 	u_int8_t g[CMAP_SIZE];
     90 	u_int8_t b[CMAP_SIZE];
     91 };
     92 
     93 struct hwcursor {
     94 	struct wsdisplay_curpos cc_pos;
     95 	struct wsdisplay_curpos cc_hot;
     96 	struct wsdisplay_curpos cc_size;
     97 #define	CURSOR_MAX_SIZE	64
     98 	u_int8_t cc_color[6];
     99 	u_int64_t cc_image[64 + 64];
    100 };
    101 
    102 struct sfb_softc {
    103 	struct device sc_dev;
    104 	struct fb_devconfig *sc_dc;	/* device configuration */
    105 	struct hwcmap sc_cmap;		/* software copy of colormap */
    106 	struct hwcursor sc_cursor;	/* software copy of cursor */
    107 	int sc_curenb;			/* cursor sprite enabled */
    108 	int sc_changed;			/* need update of colormap */
    109 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    110 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    111 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    112 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    113 #define	DATA_ALL_CHANGED	0x0f
    114 	int nscreens;
    115 };
    116 
    117 int  sfbmatch __P((struct device *, struct cfdata *, void *));
    118 void sfbattach __P((struct device *, struct device *, void *));
    119 
    120 struct cfattach sfb_ca = {
    121 	sizeof(struct sfb_softc), sfbmatch, sfbattach,
    122 };
    123 
    124 void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    125 struct fb_devconfig sfb_console_dc;
    126 tc_addr_t sfb_consaddr;
    127 
    128 struct wsdisplay_emulops sfb_emulops = {
    129 	rcons_cursor,			/* could use hardware cursor; punt */
    130 	rcons_mapchar,
    131 	rcons_putchar,
    132 	rcons_copycols,
    133 	rcons_erasecols,
    134 	rcons_copyrows,
    135 	rcons_eraserows,
    136 	rcons_alloc_attr
    137 };
    138 
    139 struct wsscreen_descr sfb_stdscreen = {
    140 	"std", 0, 0,
    141 	&sfb_emulops,
    142 	0, 0,
    143 	0
    144 };
    145 
    146 const struct wsscreen_descr *_sfb_scrlist[] = {
    147 	&sfb_stdscreen,
    148 };
    149 
    150 struct wsscreen_list sfb_screenlist = {
    151 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
    152 };
    153 
    154 int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    155 int	sfbmmap __P((void *, off_t, int));
    156 
    157 int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    158 				      void **, int *, int *, long *));
    159 void	sfb_free_screen __P((void *, void *));
    160 void	sfb_show_screen __P((void *, void *));
    161 int	sfb_load_font __P((void *, void *, int, int, int, void *));
    162 
    163 struct wsdisplay_accessops sfb_accessops = {
    164 	sfbioctl,
    165 	sfbmmap,
    166 	sfb_alloc_screen,
    167 	sfb_free_screen,
    168 	sfb_show_screen,
    169 	sfb_load_font
    170 };
    171 
    172 int  sfb_cnattach __P((tc_addr_t));
    173 int  sfbintr __P((void *));
    174 void sfbinit __P((struct fb_devconfig *));
    175 
    176 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    177 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    178 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    179 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    180 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
    181 static void bt459_set_curpos __P((struct sfb_softc *));
    182 
    183 /* XXX XXX XXX */
    184 #define	BT459_SELECT(vdac, regno) do {		\
    185 	vdac->bt_lo = (regno) & 0x00ff;		\
    186 	vdac->bt_hi = ((regno)& 0xff00) >> 8 ;	\
    187 	tc_wmb();				\
    188    } while (0)
    189 /* XXX XXX XXX */
    190 
    191 int
    192 sfbmatch(parent, match, aux)
    193 	struct device *parent;
    194 	struct cfdata *match;
    195 	void *aux;
    196 {
    197 	struct tc_attach_args *ta = aux;
    198 
    199 	if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
    200 		return (0);
    201 
    202 	return (1);
    203 }
    204 
    205 void
    206 sfb_getdevconfig(dense_addr, dc)
    207 	tc_addr_t dense_addr;
    208 	struct fb_devconfig *dc;
    209 {
    210 	struct raster *rap;
    211 	struct rcons *rcp;
    212 	caddr_t sfbasic;
    213 	int i, hsetup, vsetup, vbase;
    214 
    215 	dc->dc_vaddr = dense_addr;
    216 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    217 
    218 	sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
    219 	hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
    220 	vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
    221 	vbase  = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) & 0x1ff;
    222 
    223 	dc->dc_wid = (hsetup & 0x1ff) << 2;
    224 	dc->dc_ht = (vsetup & 0x7ff);
    225 	dc->dc_depth = 8;
    226 	dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
    227 	dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
    228 	dc->dc_blanked = 0;
    229 
    230 	/* initialize colormap and cursor resource */
    231 	sfbinit(dc);
    232 
    233 	/* clear the screen */
    234 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    235 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    236 
    237 	/* initialize the raster */
    238 	rap = &dc->dc_raster;
    239 	rap->width = dc->dc_wid;
    240 	rap->height = dc->dc_ht;
    241 	rap->depth = dc->dc_depth;
    242 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    243 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    244 
    245 	/* initialize the raster console blitter */
    246 	rcp = &dc->dc_rcons;
    247 	rcp->rc_sp = rap;
    248 	rcp->rc_crow = rcp->rc_ccol = -1;
    249 	rcp->rc_crowp = &rcp->rc_crow;
    250 	rcp->rc_ccolp = &rcp->rc_ccol;
    251 	rcons_init(rcp, 34, 80);
    252 
    253 	sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    254 	sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    255 }
    256 
    257 void
    258 sfbattach(parent, self, aux)
    259 	struct device *parent, *self;
    260 	void *aux;
    261 {
    262 	struct sfb_softc *sc = (struct sfb_softc *)self;
    263 	struct tc_attach_args *ta = aux;
    264 	struct wsemuldisplaydev_attach_args waa;
    265 	struct hwcmap *cm;
    266 	caddr_t sfbasic;
    267 	int console, i;
    268 
    269 	console = (ta->ta_addr == sfb_consaddr);
    270 	if (console) {
    271 		sc->sc_dc = &sfb_console_dc;
    272 		sc->nscreens = 1;
    273 	}
    274 	else {
    275 		sc->sc_dc = (struct fb_devconfig *)
    276 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    277 		sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    278 	}
    279 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    280 	    sc->sc_dc->dc_depth);
    281 
    282 	cm = &sc->sc_cmap;
    283 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    284 	for (i = 1; i < CMAP_SIZE; i++) {
    285 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    286 	}
    287 
    288         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
    289 
    290 	sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
    291 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    292 	*(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
    293 
    294 	waa.console = console;
    295 	waa.scrdata = &sfb_screenlist;
    296 	waa.accessops = &sfb_accessops;
    297 	waa.accesscookie = sc;
    298 
    299 	config_found(self, &waa, wsemuldisplaydevprint);
    300 }
    301 
    302 int
    303 sfbioctl(v, cmd, data, flag, p)
    304 	void *v;
    305 	u_long cmd;
    306 	caddr_t data;
    307 	int flag;
    308 	struct proc *p;
    309 {
    310 	struct sfb_softc *sc = v;
    311 	struct fb_devconfig *dc = sc->sc_dc;
    312 	int turnoff;
    313 
    314 	switch (cmd) {
    315 	case WSDISPLAYIO_GTYPE:
    316 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
    317 		return (0);
    318 
    319 	case WSDISPLAYIO_GINFO:
    320 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    321 		wsd_fbip->height = sc->sc_dc->dc_ht;
    322 		wsd_fbip->width = sc->sc_dc->dc_wid;
    323 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    324 		wsd_fbip->cmsize = CMAP_SIZE;
    325 #undef fbt
    326 		return (0);
    327 
    328 	case WSDISPLAYIO_GETCMAP:
    329 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    330 
    331 	case WSDISPLAYIO_PUTCMAP:
    332 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    333 
    334 	case WSDISPLAYIO_SVIDEO:
    335 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    336 		if ((dc->dc_blanked == 0) ^ turnoff) {
    337 			/* sc->sc_changed |= DATA_ALL_CHANGED; */
    338 			dc->dc_blanked = turnoff;
    339 		}
    340 		return (0);
    341 
    342 	case WSDISPLAYIO_GVIDEO:
    343 		*(u_int *)data = dc->dc_blanked ?
    344 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    345 		return (0);
    346 
    347 	case WSDISPLAYIO_GCURPOS:
    348 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    349 		return (0);
    350 
    351 	case WSDISPLAYIO_SCURPOS:
    352 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    353 		bt459_set_curpos(sc);
    354 		return (0);
    355 
    356 	case WSDISPLAYIO_GCURMAX:
    357 		((struct wsdisplay_curpos *)data)->x =
    358 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    359 		return (0);
    360 
    361 	case WSDISPLAYIO_GCURSOR:
    362 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    363 
    364 	case WSDISPLAYIO_SCURSOR:
    365 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    366 	}
    367 	return ENOTTY;
    368 }
    369 
    370 int
    371 sfbmmap(v, offset, prot)
    372 	void *v;
    373 	off_t offset;
    374 	int prot;
    375 {
    376 	struct sfb_softc *sc = v;
    377 
    378 	if (offset > 0x1000000) /* XXX */
    379 		return (-1);
    380 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    381 }
    382 
    383 int
    384 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    385 	void *v;
    386 	const struct wsscreen_descr *type;
    387 	void **cookiep;
    388 	int *curxp, *curyp;
    389 	long *attrp;
    390 {
    391 	struct sfb_softc *sc = v;
    392 	long defattr;
    393 
    394 	if (sc->nscreens > 0)
    395 		return (ENOMEM);
    396 
    397 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    398 	*curxp = 0;
    399 	*curyp = 0;
    400 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    401 	*attrp = defattr;
    402 	sc->nscreens++;
    403 	return (0);
    404 }
    405 
    406 void
    407 sfb_free_screen(v, cookie)
    408 	void *v;
    409 	void *cookie;
    410 {
    411 	struct sfb_softc *sc = v;
    412 
    413 	if (sc->sc_dc == &sfb_console_dc)
    414 		panic("sfb_free_screen: console");
    415 
    416 	sc->nscreens--;
    417 }
    418 
    419 void
    420 sfb_show_screen(v, cookie)
    421 	void *v;
    422 	void *cookie;
    423 {
    424 }
    425 
    426 int
    427 sfb_load_font(v, cookie, first, num, stride, data)
    428 	void *v;
    429 	void *cookie;
    430 	int first, num, stride;
    431 	void *data;
    432 {
    433 	return (EINVAL);
    434 }
    435 
    436 int
    437 sfb_cnattach(addr)
    438         tc_addr_t addr;
    439 {
    440         struct fb_devconfig *dcp = &sfb_console_dc;
    441         long defattr;
    442 
    443         sfb_getdevconfig(addr, dcp);
    444 
    445         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    446 
    447         wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
    448                            0, 0, defattr);
    449         sfb_consaddr = addr;
    450         return(0);
    451 }
    452 
    453 
    454 int
    455 sfbintr(arg)
    456 	void *arg;
    457 {
    458 	struct sfb_softc *sc = arg;
    459 	caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    460 	caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
    461 	struct bt459reg *vdac;
    462 	int v;
    463 
    464 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    465 	/* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
    466 
    467 	if (sc->sc_changed == 0)
    468 		return (1);
    469 
    470 	vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
    471 	v = sc->sc_changed;
    472 	sc->sc_changed = 0;
    473 
    474 	if (v & DATA_ENB_CHANGED) {
    475 		BT459_SELECT(vdac, BT459_REG_CCR);
    476 		vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00; tc_wmb();
    477 	}
    478 	if (v & DATA_CURCMAP_CHANGED) {
    479 		u_int8_t *cp = sc->sc_cursor.cc_color;
    480 
    481 		BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
    482 		vdac->bt_reg = cp[1];	tc_wmb();
    483 		vdac->bt_reg = cp[3];	tc_wmb();
    484 		vdac->bt_reg = cp[5];	tc_wmb();
    485 
    486 		BT459_SELECT(vdac, BT459_REG_CCOLOR_3);
    487 		vdac->bt_reg = cp[0];	tc_wmb();
    488 		vdac->bt_reg = cp[2];	tc_wmb();
    489 		vdac->bt_reg = cp[4];	tc_wmb();
    490 	}
    491 	if (v & DATA_CURSHAPE_CHANGED) {
    492 		u_int8_t *bp;
    493 		int i;
    494 
    495 		bp = (u_int8_t *)&sc->sc_cursor.cc_image;
    496 		BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
    497 		for (i = 0; i < sizeof(sc->sc_cursor.cc_image); i++) {
    498 			vdac->bt_reg = *bp++;
    499 			tc_wmb();
    500 		}
    501 	}
    502 	if (v & DATA_CMAP_CHANGED) {
    503 		struct hwcmap *cm = &sc->sc_cmap;
    504 		int index;
    505 
    506 		BT459_SELECT(vdac, 0);
    507 		for (index = 0; index < CMAP_SIZE; index++) {
    508 			vdac->bt_cmap = cm->r[index];	tc_wmb();
    509 			vdac->bt_cmap = cm->g[index];	tc_wmb();
    510 			vdac->bt_cmap = cm->b[index];	tc_wmb();
    511 		}
    512 	}
    513 	return (1);
    514 }
    515 
    516 void
    517 sfbinit(dc)
    518 	struct fb_devconfig *dc;
    519 {
    520 	caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
    521 	struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
    522 	int i;
    523 
    524 	*(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
    525 	*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
    526 	*(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
    527 	*(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
    528 
    529 	*(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
    530 
    531 	BT459_SELECT(vdac, 0);
    532 	vdac->bt_cmap = 0;	tc_wmb();
    533 	vdac->bt_cmap = 0;	tc_wmb();
    534 	vdac->bt_cmap = 0;	tc_wmb();
    535 	for (i = 1; i < CMAP_SIZE; i++) {
    536 		vdac->bt_cmap = 0xff;	tc_wmb();
    537 		vdac->bt_cmap = 0xff;	tc_wmb();
    538 		vdac->bt_cmap = 0xff;	tc_wmb();
    539 	}
    540 
    541 	BT459_SELECT(vdac, BT459_REG_COMMAND_0);
    542 	vdac->bt_reg = 0x40; /* CMD0 */	tc_wmb();
    543 	vdac->bt_reg = 0x0;  /* CMD1 */	tc_wmb();
    544 	vdac->bt_reg = 0xc0; /* CMD2 */	tc_wmb();
    545 	vdac->bt_reg = 0xff; /* PRM */	tc_wmb();
    546 	vdac->bt_reg = 0;    /* 205 */	tc_wmb();
    547 	vdac->bt_reg = 0x0;  /* PBM */	tc_wmb();
    548 	vdac->bt_reg = 0;    /* 207 */	tc_wmb();
    549 	vdac->bt_reg = 0x0;  /* ORM */	tc_wmb();
    550 	vdac->bt_reg = 0x0;  /* OBM */	tc_wmb();
    551 	vdac->bt_reg = 0x0;  /* ILV */	tc_wmb();
    552 	vdac->bt_reg = 0x0;  /* TEST */	tc_wmb();
    553 
    554 	BT459_SELECT(vdac, BT459_REG_CCR);
    555 	vdac->bt_reg = 0x0;	tc_wmb();
    556 	vdac->bt_reg = 0x0;	tc_wmb();
    557 	vdac->bt_reg = 0x0;	tc_wmb();
    558 	vdac->bt_reg = 0x0;	tc_wmb();
    559 	vdac->bt_reg = 0x0;	tc_wmb();
    560 	vdac->bt_reg = 0x0;	tc_wmb();
    561 	vdac->bt_reg = 0x0;	tc_wmb();
    562 	vdac->bt_reg = 0x0;	tc_wmb();
    563 	vdac->bt_reg = 0x0;	tc_wmb();
    564 	vdac->bt_reg = 0x0;	tc_wmb();
    565 	vdac->bt_reg = 0x0;	tc_wmb();
    566 	vdac->bt_reg = 0x0;	tc_wmb();
    567 	vdac->bt_reg = 0x0;	tc_wmb();
    568 }
    569 
    570 static int
    571 get_cmap(sc, p)
    572 	struct sfb_softc *sc;
    573 	struct wsdisplay_cmap *p;
    574 {
    575 	u_int index = p->index, count = p->count;
    576 
    577 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    578 		return (EINVAL);
    579 
    580 	if (!useracc(p->red, count, B_WRITE) ||
    581 	    !useracc(p->green, count, B_WRITE) ||
    582 	    !useracc(p->blue, count, B_WRITE))
    583 		return (EFAULT);
    584 
    585 	copyout(&sc->sc_cmap.r[index], p->red, count);
    586 	copyout(&sc->sc_cmap.g[index], p->green, count);
    587 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    588 
    589 	return (0);
    590 }
    591 
    592 static int
    593 set_cmap(sc, p)
    594 	struct sfb_softc *sc;
    595 	struct wsdisplay_cmap *p;
    596 {
    597 	u_int index = p->index, count = p->count;
    598 
    599 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    600 		return (EINVAL);
    601 
    602 	if (!useracc(p->red, count, B_READ) ||
    603 	    !useracc(p->green, count, B_READ) ||
    604 	    !useracc(p->blue, count, B_READ))
    605 		return (EFAULT);
    606 
    607 	copyin(p->red, &sc->sc_cmap.r[index], count);
    608 	copyin(p->green, &sc->sc_cmap.g[index], count);
    609 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    610 
    611 	sc->sc_changed |= DATA_CMAP_CHANGED;
    612 
    613 	return (0);
    614 }
    615 
    616 static int
    617 set_cursor(sc, p)
    618 	struct sfb_softc *sc;
    619 	struct wsdisplay_cursor *p;
    620 {
    621 #define	cc (&sc->sc_cursor)
    622 	int v, index, count;
    623 
    624 	v = p->which;
    625 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    626 		index = p->cmap.index;
    627 		count = p->cmap.count;
    628 
    629 		if (index >= 2 || (index + count) > 2)
    630 			return (EINVAL);
    631 		if (!useracc(p->cmap.red, count, B_READ) ||
    632 		    !useracc(p->cmap.green, count, B_READ) ||
    633 		    !useracc(p->cmap.blue, count, B_READ))
    634 			return (EFAULT);
    635 	}
    636 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    637 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    638 			return (EINVAL);
    639 		count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
    640 		if (!useracc(p->image, count, B_READ) ||
    641 		    !useracc(p->mask, count, B_READ))
    642 			return (EFAULT);
    643 	}
    644 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    645 		if (v & WSDISPLAY_CURSOR_DOCUR)
    646 			cc->cc_hot = p->hot;
    647 		if (v & WSDISPLAY_CURSOR_DOPOS)
    648 			set_curpos(sc, &p->pos);
    649 		bt459_set_curpos(sc);
    650 	}
    651 
    652 	sc->sc_changed = 0;
    653 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    654 		sc->sc_curenb = p->enable;
    655 		sc->sc_changed |= DATA_ENB_CHANGED;
    656 	}
    657 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    658 		count = p->cmap.count;
    659 		copyin(p->cmap.red, &cc->cc_color[index], count);
    660 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    661 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    662 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    663 	}
    664 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    665 		cc->cc_size = p->size;
    666 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    667 		copyin(p->image, cc->cc_image, count);
    668 		copyin(p->mask, &cc->cc_image[CURSOR_MAX_SIZE], count);
    669 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    670 	}
    671 
    672 	return (0);
    673 #undef cc
    674 }
    675 
    676 static int
    677 get_cursor(sc, p)
    678 	struct sfb_softc *sc;
    679 	struct wsdisplay_cursor *p;
    680 {
    681 	return (ENOTTY); /* XXX */
    682 }
    683 
    684 static void
    685 set_curpos(sc, curpos)
    686 	struct sfb_softc *sc;
    687 	struct wsdisplay_curpos *curpos;
    688 {
    689 	struct fb_devconfig *dc = sc->sc_dc;
    690 	int x = curpos->x, y = curpos->y;
    691 
    692 	if (y < 0)
    693 		y = 0;
    694 	else if (y > dc->dc_ht - sc->sc_cursor.cc_size.y - 1)
    695 		y = dc->dc_ht - sc->sc_cursor.cc_size.y - 1;
    696 	if (x < 0)
    697 		x = 0;
    698 	else if (x > dc->dc_wid - sc->sc_cursor.cc_size.x - 1)
    699 		x = dc->dc_wid - sc->sc_cursor.cc_size.x - 1;
    700 	sc->sc_cursor.cc_pos.x = x;
    701 	sc->sc_cursor.cc_pos.y = y;
    702 }
    703 
    704 static void
    705 bt459_set_curpos(sc)
    706 	struct sfb_softc *sc;
    707 {
    708 	caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    709 	struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
    710 	int x = 219, y = 34; /* magic offset of HX coordinate */
    711 	int s;
    712 
    713 	x += sc->sc_cursor.cc_pos.x;
    714 	y += sc->sc_cursor.cc_pos.y;
    715 
    716 	s = spltty();
    717 
    718 	BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
    719 	vdac->bt_reg = x;	tc_wmb();
    720 	vdac->bt_reg = x >> 8;	tc_wmb();
    721 	vdac->bt_reg = y;	tc_wmb();
    722 	vdac->bt_reg = y >> 8;	tc_wmb();
    723 
    724 	splx(s);
    725 }
    726