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