Home | History | Annotate | Line # | Download | only in tc
mfb.c revision 1.26
      1 /* $NetBSD: mfb.c,v 1.26 2001/01/16 05:32:16 nisimura Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1998, 1999 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: mfb.c,v 1.26 2001/01/16 05:32:16 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 
     45 #include <machine/bus.h>
     46 #include <machine/intr.h>
     47 
     48 #include <dev/wscons/wsconsio.h>
     49 #include <dev/wscons/wsdisplayvar.h>
     50 
     51 #include <dev/rasops/rasops.h>
     52 #include <dev/wsfont/wsfont.h>
     53 
     54 #include <dev/tc/tcvar.h>
     55 #include <dev/ic/bt431reg.h>
     56 
     57 #include <uvm/uvm_extern.h>
     58 
     59 #if defined(pmax)
     60 #define	machine_btop(x) mips_btop(x)
     61 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
     62 
     63 #define	BYTE(base, index)	*((u_int8_t *)(base) + ((index)<<2))
     64 #define	HALF(base, index)	*((u_int16_t *)(base) + ((index)<<1))
     65 #endif
     66 
     67 #if defined(__alpha__) || defined(alpha)
     68 #define machine_btop(x) alpha_btop(x)
     69 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     70 
     71 #define	BYTE(base, index)	*((u_int32_t *)(base) + (index))
     72 #define	HALF(base, index)	*((u_int32_t *)(base) + (index))
     73 #endif
     74 
     75 /* Bt455 hardware registers */
     76 #define	bt_reg	0
     77 #define	bt_cmap	1
     78 #define	bt_clr	2
     79 #define	bt_ovly	3
     80 
     81 /* Bt431 hardware registers */
     82 #define	bt_lo	0
     83 #define	bt_hi	1
     84 #define	bt_ram	2
     85 #define	bt_ctl	3
     86 
     87 #define SELECT455(vdac, regno) do {	\
     88 	BYTE(vdac, bt_reg) = (regno);	\
     89 	BYTE(vdac, bt_clr) = 0;		\
     90 	tc_wmb();			\
     91    } while (0)
     92 
     93 #define	TWIN(x)    ((x)|((x) << 8))
     94 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
     95 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
     96 
     97 #define	SELECT431(curs, regno) do {	\
     98 	HALF(curs, bt_lo) = TWIN(regno);\
     99 	HALF(curs, bt_hi) = 0;		\
    100 	tc_wmb();			\
    101    } while (0)
    102 
    103 
    104 struct fb_devconfig {
    105 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    106 	paddr_t dc_paddr;		/* memory space physical base address */
    107 	vsize_t dc_size;		/* size of slot memory */
    108 	int	dc_wid;			/* width of frame buffer */
    109 	int	dc_ht;			/* height of frame buffer */
    110 	int	dc_depth;		/* depth, bits per pixel */
    111 	int	dc_rowbytes;		/* bytes in a FB scan line */
    112 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    113 	int	    dc_blanked;		/* currently has video disabled */
    114 
    115 	struct rasops_info rinfo;
    116 };
    117 
    118 struct hwcursor64 {
    119 	struct wsdisplay_curpos cc_pos;
    120 	struct wsdisplay_curpos cc_hot;
    121 	struct wsdisplay_curpos cc_size;
    122 	struct wsdisplay_curpos cc_magic;
    123 #define	CURSOR_MAX_SIZE	64
    124 	u_int8_t cc_color[6];
    125 	u_int64_t cc_image[64 + 64];
    126 };
    127 
    128 struct mfb_softc {
    129 	struct device sc_dev;
    130 	struct fb_devconfig *sc_dc;	/* device configuration */
    131 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    132 	int sc_curenb;			/* cursor sprite enabled */
    133 	int sc_changed;			/* need update of hardware */
    134 	int nscreens;
    135 };
    136 
    137 #define	MX_MAGIC_X	360
    138 #define	MX_MAGIC_Y	36
    139 
    140 #define	MX_FB_OFFSET	0x200000
    141 #define	MX_FB_SIZE	0x200000
    142 #define	MX_BT455_OFFSET	0x100000
    143 #define	MX_BT431_OFFSET	0x180000
    144 #define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
    145 
    146 static int  mfbmatch __P((struct device *, struct cfdata *, void *));
    147 static void mfbattach __P((struct device *, struct device *, void *));
    148 
    149 const struct cfattach mfb_ca = {
    150 	sizeof(struct mfb_softc), mfbmatch, mfbattach,
    151 };
    152 
    153 static void mfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    154 static struct fb_devconfig mfb_console_dc;
    155 static tc_addr_t mfb_consaddr;
    156 
    157 static struct wsscreen_descr mfb_stdscreen = {
    158 	"std", 0, 0,
    159 	0, /* textops */
    160 	0, 0,
    161 	WSSCREEN_REVERSE
    162 };
    163 
    164 static const struct wsscreen_descr *_mfb_scrlist[] = {
    165 	&mfb_stdscreen,
    166 };
    167 
    168 static const struct wsscreen_list mfb_screenlist = {
    169 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
    170 };
    171 
    172 static int	mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    173 static paddr_t	mfbmmap __P((void *, off_t, int));
    174 
    175 static int	mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    176 				      void **, int *, int *, long *));
    177 static void	mfb_free_screen __P((void *, void *));
    178 static int	mfb_show_screen __P((void *, void *, int,
    179 				     void (*) (void *, int, int), void *));
    180 
    181 static const struct wsdisplay_accessops mfb_accessops = {
    182 	mfbioctl,
    183 	mfbmmap,
    184 	mfb_alloc_screen,
    185 	mfb_free_screen,
    186 	mfb_show_screen,
    187 	0 /* load_font */
    188 };
    189 
    190 int  mfb_cnattach __P((tc_addr_t));
    191 static int  mfbintr __P((void *));
    192 static void mfbinit __P((struct fb_devconfig *));
    193 
    194 static int  set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
    195 static int  get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
    196 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
    197 
    198 /* bit order reverse */
    199 static const u_int8_t flip[256] = {
    200 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    201 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    202 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    203 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    204 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    205 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    206 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    207 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    208 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    209 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    210 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    211 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    212 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    213 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    214 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    215 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    216 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    217 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    218 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    219 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    220 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    221 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    222 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    223 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    224 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    225 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    226 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    227 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    228 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    229 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    230 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    231 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    232 };
    233 
    234 static int
    235 mfbmatch(parent, match, aux)
    236 	struct device *parent;
    237 	struct cfdata *match;
    238 	void *aux;
    239 {
    240 	struct tc_attach_args *ta = aux;
    241 
    242 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    243 		return (0);
    244 
    245 	return (1);
    246 }
    247 
    248 static void
    249 mfb_getdevconfig(dense_addr, dc)
    250 	tc_addr_t dense_addr;
    251 	struct fb_devconfig *dc;
    252 {
    253 	int i, cookie;
    254 
    255 	dc->dc_vaddr = dense_addr;
    256 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET);
    257 
    258 	dc->dc_wid = 1280;
    259 	dc->dc_ht = 1024;
    260 	dc->dc_depth = 8;
    261 	dc->dc_rowbytes = 2048;
    262 	dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET;
    263 	dc->dc_blanked = 0;
    264 
    265 	/* initialize colormap and cursor resource */
    266 	mfbinit(dc);
    267 
    268 	/* clear the screen */
    269 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    270 		*(u_int32_t *)(dc->dc_videobase + i) = 0;
    271 
    272 	dc->rinfo.ri_flg = RI_CENTER;
    273 	dc->rinfo.ri_depth = dc->dc_depth;
    274 	dc->rinfo.ri_bits = (void *)dc->dc_videobase;
    275 	dc->rinfo.ri_width = dc->dc_wid;
    276 	dc->rinfo.ri_height = dc->dc_ht;
    277 	dc->rinfo.ri_stride = dc->dc_rowbytes;
    278 
    279 	wsfont_init();
    280 	/* prefer 8 pixel wide font */
    281 	if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
    282 		cookie = wsfont_find(NULL, 0, 0, 0);
    283 	if (cookie <= 0) {
    284 		printf("mfb: font table is empty\n");
    285 		return;
    286 	}
    287 
    288 	if (wsfont_lock(cookie, &dc->rinfo.ri_font,
    289 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
    290 		printf("mfb: couldn't lock font\n");
    291 		return;
    292 	}
    293 	dc->rinfo.ri_wsfcookie = cookie;
    294 
    295 	rasops_init(&dc->rinfo, 34, 80);
    296 
    297 	/* XXX shouldn't be global */
    298 	mfb_stdscreen.nrows = dc->rinfo.ri_rows;
    299 	mfb_stdscreen.ncols = dc->rinfo.ri_cols;
    300 	mfb_stdscreen.textops = &dc->rinfo.ri_ops;
    301 	mfb_stdscreen.capabilities = dc->rinfo.ri_caps;
    302 }
    303 
    304 static void
    305 mfbattach(parent, self, aux)
    306 	struct device *parent, *self;
    307 	void *aux;
    308 {
    309 	struct mfb_softc *sc = (struct mfb_softc *)self;
    310 	struct tc_attach_args *ta = aux;
    311 	struct wsemuldisplaydev_attach_args waa;
    312 	caddr_t mfbbase;
    313 	int console;
    314 	volatile register int junk;
    315 
    316 	console = (ta->ta_addr == mfb_consaddr);
    317 	if (console) {
    318 		sc->sc_dc = &mfb_console_dc;
    319 		sc->nscreens = 1;
    320 	}
    321 	else {
    322 		sc->sc_dc = (struct fb_devconfig *)
    323 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    324 		mfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    325 	}
    326 	printf(": %d x %d, 1bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
    327 
    328 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
    329 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
    330 
    331 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
    332 
    333 	mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    334 	*(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0;
    335 	junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
    336 	*(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 1;
    337 
    338 	waa.console = console;
    339 	waa.scrdata = &mfb_screenlist;
    340 	waa.accessops = &mfb_accessops;
    341 	waa.accesscookie = sc;
    342 
    343 	config_found(self, &waa, wsemuldisplaydevprint);
    344 }
    345 
    346 static int
    347 mfbioctl(v, cmd, data, flag, p)
    348 	void *v;
    349 	u_long cmd;
    350 	caddr_t data;
    351 	int flag;
    352 	struct proc *p;
    353 {
    354 	struct mfb_softc *sc = v;
    355 	struct fb_devconfig *dc = sc->sc_dc;
    356 	int turnoff;
    357 
    358 	switch (cmd) {
    359 	case WSDISPLAYIO_GTYPE:
    360 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
    361 		return (0);
    362 
    363 	case WSDISPLAYIO_GINFO:
    364 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    365 		wsd_fbip->height = sc->sc_dc->dc_ht;
    366 		wsd_fbip->width = sc->sc_dc->dc_wid;
    367 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    368 		wsd_fbip->cmsize = 0;
    369 #undef fbt
    370 		return (0);
    371 
    372 	case WSDISPLAYIO_GETCMAP:
    373 	case WSDISPLAYIO_PUTCMAP:
    374 		return (ENOTTY);
    375 
    376 	case WSDISPLAYIO_SVIDEO:
    377 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    378 		if ((dc->dc_blanked == 0) ^ turnoff) {
    379 			dc->dc_blanked = turnoff;
    380 #if 0	/* XXX later XXX */
    381 	To turn off,
    382 	- assign Bt455 cmap[1].green with value 0 (black),
    383 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
    384 #endif	/* XXX XXX XXX */
    385 		}
    386 		return (0);
    387 
    388 	case WSDISPLAYIO_GVIDEO:
    389 		*(u_int *)data = dc->dc_blanked ?
    390 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    391 		return (0);
    392 
    393 	case WSDISPLAYIO_GCURPOS:
    394 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    395 		return (0);
    396 
    397 	case WSDISPLAYIO_SCURPOS:
    398 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    399 		sc->sc_changed = WSDISPLAY_CURSOR_DOPOS;
    400 		return (0);
    401 
    402 	case WSDISPLAYIO_GCURMAX:
    403 		((struct wsdisplay_curpos *)data)->x =
    404 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    405 		return (0);
    406 
    407 	case WSDISPLAYIO_GCURSOR:
    408 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    409 
    410 	case WSDISPLAYIO_SCURSOR:
    411 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    412 	}
    413 	return (ENOTTY);
    414 }
    415 
    416 static paddr_t
    417 mfbmmap(v, offset, prot)
    418 	void *v;
    419 	off_t offset;
    420 	int prot;
    421 {
    422 	struct mfb_softc *sc = v;
    423 
    424 	if (offset >= MX_FB_SIZE || offset < 0)
    425 		return (-1);
    426 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    427 }
    428 
    429 static int
    430 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    431 	void *v;
    432 	const struct wsscreen_descr *type;
    433 	void **cookiep;
    434 	int *curxp, *curyp;
    435 	long *attrp;
    436 {
    437 	struct mfb_softc *sc = v;
    438 	long defattr;
    439 
    440 	if (sc->nscreens > 0)
    441 		return (ENOMEM);
    442 
    443 	*cookiep = &sc->sc_dc->rinfo; /* one and only for now */
    444 	*curxp = 0;
    445 	*curyp = 0;
    446 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
    447 	*attrp = defattr;
    448 	sc->nscreens++;
    449 	return (0);
    450 }
    451 
    452 static void
    453 mfb_free_screen(v, cookie)
    454 	void *v;
    455 	void *cookie;
    456 {
    457 	struct mfb_softc *sc = v;
    458 
    459 	if (sc->sc_dc == &mfb_console_dc)
    460 		panic("mfb_free_screen: console");
    461 
    462 	sc->nscreens--;
    463 }
    464 
    465 static int
    466 mfb_show_screen(v, cookie, waitok, cb, cbarg)
    467 	void *v;
    468 	void *cookie;
    469 	int waitok;
    470 	void (*cb) __P((void *, int, int));
    471 	void *cbarg;
    472 {
    473 
    474 	return (0);
    475 }
    476 
    477 /* EXPORT */ int
    478 mfb_cnattach(addr)
    479 	tc_addr_t addr;
    480 {
    481 	struct fb_devconfig *dcp = &mfb_console_dc;
    482 	long defattr;
    483 
    484 	mfb_getdevconfig(addr, dcp);
    485 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
    486 	wsdisplay_cnattach(&mfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
    487 	mfb_consaddr = addr;
    488 	return (0);
    489 }
    490 
    491 static int
    492 mfbintr(arg)
    493 	void *arg;
    494 {
    495 	struct mfb_softc *sc = arg;
    496 	caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    497 	void *vdac, *curs;
    498 	int v;
    499 	volatile register int junk;
    500 
    501 	junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
    502 #if 0
    503 	*(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0;
    504 #endif
    505 	if (sc->sc_changed == 0)
    506 		return (1);
    507 
    508 	vdac = (void *)(mfbbase + MX_BT455_OFFSET);
    509 	curs = (void *)(mfbbase + MX_BT431_OFFSET);
    510 	v = sc->sc_changed;
    511 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    512 		SELECT431(curs, BT431_REG_COMMAND);
    513 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
    514 	}
    515 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    516 		int x, y;
    517 		u_int16_t twin;
    518 
    519 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    520 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    521 
    522 		x += sc->sc_cursor.cc_magic.x;
    523 		y += sc->sc_cursor.cc_magic.y;
    524 
    525 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    526 		HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
    527 		HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
    528 		HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
    529 		HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
    530 	}
    531 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    532 		u_int8_t *cp = sc->sc_cursor.cc_color;
    533 
    534 		SELECT455(vdac, 8);
    535 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    536 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
    537 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    538 
    539 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    540 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
    541 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    542 
    543 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
    544 		BYTE(vdac, bt_ovly) = cp[0];	tc_wmb();
    545 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
    546 	}
    547 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    548 		u_int8_t *ip, *mp, img, msk;
    549 		int bcnt;
    550 
    551 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    552 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    553 		bcnt = 0;
    554 		SELECT431(curs, BT431_REG_CRAM_BASE);
    555 
    556 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    557 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    558 			/* pad right half 32 pixel when smaller than 33 */
    559 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    560 				HALF(curs, bt_ram) = 0;
    561 				tc_wmb();
    562 			}
    563 			else {
    564 				img = *ip++;
    565 				msk = *mp++;
    566 				img &= msk;	/* cookie off image */
    567 				HALF(curs, bt_ram)
    568 				    = (flip[msk] << 8) | flip[img];
    569 				tc_wmb();
    570 			}
    571 			bcnt += 2;
    572 		}
    573 		/* pad unoccupied scan lines */
    574 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    575 			HALF(curs, bt_ram) = 0;
    576 			tc_wmb();
    577 			bcnt += 2;
    578 		}
    579 	}
    580 	sc->sc_changed = 0;
    581 	return (1);
    582 }
    583 
    584 static void
    585 mfbinit(dc)
    586 	struct fb_devconfig *dc;
    587 {
    588 	caddr_t mfbbase = (caddr_t)dc->dc_vaddr;
    589 	void *vdac = (void *)(mfbbase + MX_BT455_OFFSET);
    590 	void *curs = (void *)(mfbbase + MX_BT431_OFFSET);
    591 	int i;
    592 
    593 	SELECT431(curs, BT431_REG_COMMAND);
    594 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
    595 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
    596 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
    597 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
    598 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
    599 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
    600 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
    601 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    602 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    603 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
    604 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
    605 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
    606 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
    607 
    608 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
    609 	SELECT455(vdac, 0);
    610 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
    611 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
    612 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    613 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    614 	BYTE(vdac, bt_cmap) = 0xff;		tc_wmb();
    615 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    616 	for (i = 2; i < 16; i++) {
    617 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    618 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    619 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
    620 	}
    621 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
    622 	BYTE(vdac, bt_ovly) = 0xff;	tc_wmb();
    623 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
    624 
    625 	SELECT431(curs, BT431_REG_CRAM_BASE);
    626 	for (i = 0; i < 512; i++) {
    627 		HALF(curs, bt_ram) = 0;	tc_wmb();
    628 	}
    629 }
    630 
    631 static int
    632 set_cursor(sc, p)
    633 	struct mfb_softc *sc;
    634 	struct wsdisplay_cursor *p;
    635 {
    636 #define	cc (&sc->sc_cursor)
    637 	int v, count, index;
    638 
    639 	v = p->which;
    640 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    641 		index = p->cmap.index;
    642 		count = p->cmap.count;
    643 		if (index >= 2 || (index + count) > 2)
    644 			return (EINVAL);
    645 		if (!uvm_useracc(p->cmap.red, count, B_READ))
    646 			return (EFAULT);
    647 	}
    648 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    649 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    650 			return (EINVAL);
    651 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    652 		if (!uvm_useracc(p->image, count, B_READ) ||
    653 		    !uvm_useracc(p->mask, count, B_READ))
    654 			return (EFAULT);
    655 	}
    656 
    657 	if (v & WSDISPLAY_CURSOR_DOCUR)
    658 		sc->sc_curenb = p->enable;
    659 	if (v & WSDISPLAY_CURSOR_DOPOS)
    660 		set_curpos(sc, &p->pos);
    661 	if (v & WSDISPLAY_CURSOR_DOHOT)
    662 		cc->cc_hot = p->hot;
    663 	if (v & WSDISPLAY_CURSOR_DOCMAP)
    664 		copyin(p->cmap.red, &cc->cc_color[index], count);
    665 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    666 		cc->cc_size = p->size;
    667 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    668 		copyin(p->image, cc->cc_image, count);
    669 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
    670 	}
    671 	sc->sc_changed = v;
    672 
    673 	return (0);
    674 #undef cc
    675 }
    676 
    677 static int
    678 get_cursor(sc, p)
    679 	struct mfb_softc *sc;
    680 	struct wsdisplay_cursor *p;
    681 {
    682 	return (ENOTTY); /* XXX */
    683 }
    684 
    685 static void
    686 set_curpos(sc, curpos)
    687 	struct mfb_softc *sc;
    688 	struct wsdisplay_curpos *curpos;
    689 {
    690 	struct fb_devconfig *dc = sc->sc_dc;
    691 	int x = curpos->x, y = curpos->y;
    692 
    693 	if (y < 0)
    694 		y = 0;
    695 	else if (y > dc->dc_ht)
    696 		y = dc->dc_ht;
    697 	if (x < 0)
    698 		x = 0;
    699 	else if (x > dc->dc_wid)
    700 		x = dc->dc_wid;
    701 	sc->sc_cursor.cc_pos.x = x;
    702 	sc->sc_cursor.cc_pos.y = y;
    703 }
    704