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