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