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