Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.9
      1 /* $NetBSD: cfb.c,v 1.9 1999/03/24 05:51:21 mrg 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: cfb.c,v 1.9 1999/03/24 05:51:21 mrg 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 #include <machine/autoconf.h>
     54 
     55 #include <dev/tc/tcvar.h>
     56 #include <dev/ic/bt459reg.h>
     57 
     58 #include <uvm/uvm_extern.h>
     59 
     60 /* XXX BUS'IFYING XXX */
     61 
     62 #if defined(pmax)
     63 #define	machine_btop(x) mips_btop(x)
     64 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
     65 #endif
     66 
     67 #if defined(__alpha__) || defined(alpha)
     68 /*
     69  * Digital UNIX never supports PMAG-BA
     70  */
     71 #define machine_btop(x) alpha_btop(x)
     72 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     73 #endif
     74 
     75 /*
     76  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     77  * obscure register layout such as 2nd and 3rd Bt459 registers are
     78  * adjacent each other in a word, i.e.,
     79  *	struct bt459triplet {
     80  * 		struct {
     81  *			u_int8_t u0;
     82  *			u_int8_t u1;
     83  *			u_int8_t u2;
     84  *			unsigned :8;
     85  *		} bt_lo;
     86  *		...
     87  * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
     88  */
     89 struct bt459reg {
     90         u_int32_t       bt_lo;
     91         u_int32_t       bt_hi;
     92         u_int32_t       bt_reg;
     93         u_int32_t       bt_cmap;
     94 };
     95 
     96 /* XXX XXX XXX */
     97 
     98 struct fb_devconfig {
     99 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    100 	paddr_t dc_paddr;		/* memory space physical base address */
    101 	vsize_t	dc_size;		/* size of slot memory */
    102 	int	dc_wid;			/* width of frame buffer */
    103 	int	dc_ht;			/* height of frame buffer */
    104 	int	dc_depth;		/* depth, bits per pixel */
    105 	int	dc_rowbytes;		/* bytes in a FB scan line */
    106 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    107 	struct raster	dc_raster;	/* raster description */
    108 	struct rcons	dc_rcons;	/* raster blitter control info */
    109 	int	    dc_blanked;		/* currently has video disabled */
    110 };
    111 
    112 struct hwcmap {
    113 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    114 	u_int8_t r[CMAP_SIZE];
    115 	u_int8_t g[CMAP_SIZE];
    116 	u_int8_t b[CMAP_SIZE];
    117 };
    118 
    119 struct hwcursor {
    120 	struct wsdisplay_curpos cc_pos;
    121 	struct wsdisplay_curpos cc_hot;
    122 	struct wsdisplay_curpos cc_size;
    123 #define	CURSOR_MAX_SIZE	64
    124 	u_int8_t cc_color[6];
    125 	u_int64_t cc_image[64 + 64];
    126 };
    127 
    128 struct cfb_softc {
    129 	struct device sc_dev;
    130 	struct fb_devconfig *sc_dc;	/* device configuration */
    131 	struct hwcmap sc_cmap;		/* software copy of colormap */
    132 	struct hwcursor sc_cursor;	/* software copy of cursor */
    133 	int sc_curenb;			/* cursor sprite enabled */
    134 	int sc_changed;			/* need update of colormap */
    135 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    136 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    137 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    138 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    139 #define	DATA_ALL_CHANGED	0x0f
    140 	int nscreens;
    141 	short magic_x, magic_y;		/* CX cursor location offset */
    142 #define	CX_MAGIC_X 220
    143 #define	CX_MAGIC_Y 35
    144 };
    145 
    146 #define	CX_FB_OFFSET	0x000000
    147 #define	CX_FB_SIZE	0x100000
    148 #define	CX_BT459_OFFSET	0x200000
    149 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
    150 
    151 int  cfbmatch __P((struct device *, struct cfdata *, void *));
    152 void cfbattach __P((struct device *, struct device *, void *));
    153 
    154 struct cfattach cfb_ca = {
    155 	sizeof(struct cfb_softc), cfbmatch, cfbattach,
    156 };
    157 
    158 void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    159 struct fb_devconfig cfb_console_dc;
    160 tc_addr_t cfb_consaddr;
    161 
    162 struct wsdisplay_emulops cfb_emulops = {
    163 	rcons_cursor,			/* could use hardware cursor; punt */
    164 	rcons_mapchar,
    165 	rcons_putchar,
    166 	rcons_copycols,
    167 	rcons_erasecols,
    168 	rcons_copyrows,
    169 	rcons_eraserows,
    170 	rcons_alloc_attr
    171 };
    172 
    173 struct wsscreen_descr cfb_stdscreen = {
    174 	"std", 0, 0,
    175 	&cfb_emulops,
    176 	0, 0,
    177 	0
    178 };
    179 
    180 const struct wsscreen_descr *_cfb_scrlist[] = {
    181 	&cfb_stdscreen,
    182 };
    183 
    184 struct wsscreen_list cfb_screenlist = {
    185 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
    186 };
    187 
    188 int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    189 int	cfbmmap __P((void *, off_t, int));
    190 
    191 int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    192 				      void **, int *, int *, long *));
    193 void	cfb_free_screen __P((void *, void *));
    194 void	cfb_show_screen __P((void *, void *));
    195 
    196 struct wsdisplay_accessops cfb_accessops = {
    197 	cfbioctl,
    198 	cfbmmap,
    199 	cfb_alloc_screen,
    200 	cfb_free_screen,
    201 	cfb_show_screen,
    202 	0 /* load_font */
    203 };
    204 
    205 int  cfb_cnattach __P((tc_addr_t));
    206 int  cfbintr __P((void *));
    207 void cfbinit __P((struct fb_devconfig *));
    208 
    209 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    210 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    211 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    212 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    213 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
    214 static void bt459_set_curpos __P((struct cfb_softc *));
    215 
    216 /* XXX XXX XXX */
    217 #define	BT459_SELECT(vdac, regno) do {		\
    218 	vdac->bt_lo = (regno) & 0x00ff;		\
    219 	vdac->bt_hi = ((regno)& 0x0f00) >> 8;	\
    220 	tc_wmb();				\
    221    } while (0)
    222 /* XXX XXX XXX */
    223 
    224 /*
    225  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    226  *   M M M M I I I I		M I M I M I M I
    227  *	[ before ]		   [ after ]
    228  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    229  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    230  */
    231 const static u_int8_t shuffle[256] = {
    232 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    233 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    234 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    235 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    236 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    237 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    238 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    239 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    240 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    241 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    242 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    243 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    244 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    245 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    246 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    247 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    248 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    249 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    250 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    251 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    252 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    253 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    254 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    255 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    256 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    257 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    258 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    259 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    260 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    261 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    262 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    263 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    264 };
    265 
    266 int
    267 cfbmatch(parent, match, aux)
    268 	struct device *parent;
    269 	struct cfdata *match;
    270 	void *aux;
    271 {
    272 	struct tc_attach_args *ta = aux;
    273 
    274 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    275 		return (0);
    276 
    277 	return (1);
    278 }
    279 
    280 void
    281 cfb_getdevconfig(dense_addr, dc)
    282 	tc_addr_t dense_addr;
    283 	struct fb_devconfig *dc;
    284 {
    285 	struct raster *rap;
    286 	struct rcons *rcp;
    287 	int i;
    288 
    289 	dc->dc_vaddr = dense_addr;
    290 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET);
    291 
    292 	dc->dc_wid = 1024;
    293 	dc->dc_ht = 864;
    294 	dc->dc_depth = 8;
    295 	dc->dc_rowbytes = 1024;
    296 	dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET;
    297 	dc->dc_blanked = 0;
    298 
    299 	/* initialize colormap and cursor resource */
    300 	cfbinit(dc);
    301 
    302 	/* clear the screen */
    303 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    304 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    305 
    306 	/* initialize the raster */
    307 	rap = &dc->dc_raster;
    308 	rap->width = dc->dc_wid;
    309 	rap->height = dc->dc_ht;
    310 	rap->depth = dc->dc_depth;
    311 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    312 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    313 
    314 	/* initialize the raster console blitter */
    315 	rcp = &dc->dc_rcons;
    316 	rcp->rc_sp = rap;
    317 	rcp->rc_crow = rcp->rc_ccol = -1;
    318 	rcp->rc_crowp = &rcp->rc_crow;
    319 	rcp->rc_ccolp = &rcp->rc_ccol;
    320 	rcons_init(rcp, 34, 80);
    321 
    322 	cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    323 	cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    324 }
    325 
    326 void
    327 cfbattach(parent, self, aux)
    328 	struct device *parent, *self;
    329 	void *aux;
    330 {
    331 	struct cfb_softc *sc = (struct cfb_softc *)self;
    332 	struct tc_attach_args *ta = aux;
    333 	struct wsemuldisplaydev_attach_args waa;
    334 	struct hwcmap *cm;
    335 	int console, i;
    336 
    337 	console = (ta->ta_addr == cfb_consaddr);
    338 	if (console) {
    339 		sc->sc_dc = &cfb_console_dc;
    340 		sc->nscreens = 1;
    341 	}
    342 	else {
    343 		sc->sc_dc = (struct fb_devconfig *)
    344 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    345 		cfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    346 	}
    347 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    348 	    sc->sc_dc->dc_depth);
    349 
    350 	cm = &sc->sc_cmap;
    351 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    352 	for (i = 1; i < CMAP_SIZE; i++) {
    353 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    354 	}
    355 	sc->magic_x = CX_MAGIC_X;
    356 	sc->magic_y = CX_MAGIC_Y;
    357 
    358 	/* Establish an interrupt handler, and clear any pending interrupts */
    359         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc);
    360 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
    361 
    362 	waa.console = console;
    363 	waa.scrdata = &cfb_screenlist;
    364 	waa.accessops = &cfb_accessops;
    365 	waa.accesscookie = sc;
    366 
    367 	config_found(self, &waa, wsemuldisplaydevprint);
    368 }
    369 
    370 int
    371 cfbioctl(v, cmd, data, flag, p)
    372 	void *v;
    373 	u_long cmd;
    374 	caddr_t data;
    375 	int flag;
    376 	struct proc *p;
    377 {
    378 	struct cfb_softc *sc = v;
    379 	struct fb_devconfig *dc = sc->sc_dc;
    380 	int turnoff;
    381 
    382 	switch (cmd) {
    383 	case WSDISPLAYIO_GTYPE:
    384 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
    385 		return (0);
    386 
    387 	case WSDISPLAYIO_GINFO:
    388 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    389 		wsd_fbip->height = sc->sc_dc->dc_ht;
    390 		wsd_fbip->width = sc->sc_dc->dc_wid;
    391 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    392 		wsd_fbip->cmsize = CMAP_SIZE;
    393 #undef fbt
    394 		return (0);
    395 
    396 	case WSDISPLAYIO_GETCMAP:
    397 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    398 
    399 	case WSDISPLAYIO_PUTCMAP:
    400 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    401 
    402 	case WSDISPLAYIO_SVIDEO:
    403 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    404 		if ((dc->dc_blanked == 0) ^ turnoff) {
    405 			dc->dc_blanked = turnoff;
    406 			/* XXX later XXX */
    407 		}
    408 		return (0);
    409 
    410 	case WSDISPLAYIO_GVIDEO:
    411 		*(u_int *)data = dc->dc_blanked ?
    412 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    413 		return (0);
    414 
    415 	case WSDISPLAYIO_GCURPOS:
    416 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    417 		return (0);
    418 
    419 	case WSDISPLAYIO_SCURPOS:
    420 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    421 		bt459_set_curpos(sc);
    422 		return (0);
    423 
    424 	case WSDISPLAYIO_GCURMAX:
    425 		((struct wsdisplay_curpos *)data)->x =
    426 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    427 		return (0);
    428 
    429 	case WSDISPLAYIO_GCURSOR:
    430 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    431 
    432 	case WSDISPLAYIO_SCURSOR:
    433 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    434 	}
    435 	return ENOTTY;
    436 }
    437 
    438 int
    439 cfbmmap(v, offset, prot)
    440 	void *v;
    441 	off_t offset;
    442 	int prot;
    443 {
    444 	struct cfb_softc *sc = v;
    445 
    446 	if (offset >= CX_FB_SIZE || offset < 0)
    447 		return (-1);
    448 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    449 }
    450 
    451 int
    452 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    453 	void *v;
    454 	const struct wsscreen_descr *type;
    455 	void **cookiep;
    456 	int *curxp, *curyp;
    457 	long *attrp;
    458 {
    459 	struct cfb_softc *sc = v;
    460 	long defattr;
    461 
    462 	if (sc->nscreens > 0)
    463 		return (ENOMEM);
    464 
    465 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    466 	*curxp = 0;
    467 	*curyp = 0;
    468 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    469 	*attrp = defattr;
    470 	sc->nscreens++;
    471 	return (0);
    472 }
    473 
    474 void
    475 cfb_free_screen(v, cookie)
    476 	void *v;
    477 	void *cookie;
    478 {
    479 	struct cfb_softc *sc = v;
    480 
    481 	if (sc->sc_dc == &cfb_console_dc)
    482 		panic("cfb_free_screen: console");
    483 
    484 	sc->nscreens--;
    485 }
    486 
    487 void
    488 cfb_show_screen(v, cookie)
    489 	void *v;
    490 	void *cookie;
    491 {
    492 }
    493 
    494 int
    495 cfb_cnattach(addr)
    496         tc_addr_t addr;
    497 {
    498         struct fb_devconfig *dcp = &cfb_console_dc;
    499         long defattr;
    500 
    501         cfb_getdevconfig(addr, dcp);
    502 
    503         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    504 
    505         wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
    506                            0, 0, defattr);
    507         cfb_consaddr = addr;
    508         return(0);
    509 }
    510 
    511 
    512 int
    513 cfbintr(arg)
    514 	void *arg;
    515 {
    516 	struct cfb_softc *sc = arg;
    517 	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    518 	struct bt459reg *vdac;
    519 	int v;
    520 
    521 	*(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
    522 	if (sc->sc_changed == 0)
    523 		return (1);
    524 
    525 	vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    526 	v = sc->sc_changed;
    527 	sc->sc_changed = 0;
    528 	if (v & DATA_ENB_CHANGED) {
    529 		BT459_SELECT(vdac, BT459_REG_CCR);
    530 		vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
    531 	}
    532 	if (v & DATA_CURCMAP_CHANGED) {
    533 		u_int8_t *cp = sc->sc_cursor.cc_color;
    534 
    535 		BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
    536 		vdac->bt_reg = cp[1];	tc_wmb();
    537 		vdac->bt_reg = cp[3];	tc_wmb();
    538 		vdac->bt_reg = cp[5];	tc_wmb();
    539 
    540 		vdac->bt_reg = cp[0];	tc_wmb();
    541 		vdac->bt_reg = cp[2];	tc_wmb();
    542 		vdac->bt_reg = cp[4];	tc_wmb();
    543 	}
    544 	if (v & DATA_CURSHAPE_CHANGED) {
    545 		u_int8_t *ip, *mp, img, msk;
    546 		u_int8_t u;
    547 		int bcnt;
    548 
    549 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    550 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    551 
    552 		bcnt = 0;
    553 		BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
    554 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    555 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    556 			/* pad right half 32 pixel when smaller than 33 */
    557 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    558 				vdac->bt_reg = 0; tc_wmb();
    559 				vdac->bt_reg = 0; tc_wmb();
    560 			}
    561 			else {
    562 				img = *ip++;
    563 				msk = *mp++;
    564 				img &= msk;	/* cookie off image */
    565 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    566 				vdac->bt_reg = shuffle[u];	tc_wmb();
    567 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    568 				vdac->bt_reg = shuffle[u];	tc_wmb();
    569 			}
    570 			bcnt += 2;
    571 		}
    572 		/* pad unoccupied scan lines */
    573 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    574 			vdac->bt_reg = 0; tc_wmb();
    575 			vdac->bt_reg = 0; tc_wmb();
    576 			bcnt += 2;
    577 		}
    578 	}
    579 	if (v & DATA_CMAP_CHANGED) {
    580 		struct hwcmap *cm = &sc->sc_cmap;
    581 		int index;
    582 
    583 		BT459_SELECT(vdac, 0);
    584 		for (index = 0; index < CMAP_SIZE; index++) {
    585 			vdac->bt_cmap = cm->r[index];	tc_wmb();
    586 			vdac->bt_cmap = cm->g[index];	tc_wmb();
    587 			vdac->bt_cmap = cm->b[index];	tc_wmb();
    588 		}
    589 	}
    590 	return (1);
    591 }
    592 
    593 void
    594 cfbinit(dc)
    595 	struct fb_devconfig *dc;
    596 {
    597 	caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
    598 	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    599 	int i;
    600 
    601 	BT459_SELECT(vdac, BT459_REG_COMMAND_0);
    602 	vdac->bt_reg = 0x40; /* CMD0 */	tc_wmb();
    603 	vdac->bt_reg = 0x0;  /* CMD1 */	tc_wmb();
    604 	vdac->bt_reg = 0xc0; /* CMD2 */	tc_wmb();
    605 	vdac->bt_reg = 0xff; /* PRM */	tc_wmb();
    606 	vdac->bt_reg = 0;    /* 205 */	tc_wmb();
    607 	vdac->bt_reg = 0x0;  /* PBM */	tc_wmb();
    608 	vdac->bt_reg = 0;    /* 207 */	tc_wmb();
    609 	vdac->bt_reg = 0x0;  /* ORM */	tc_wmb();
    610 	vdac->bt_reg = 0x0;  /* OBM */	tc_wmb();
    611 	vdac->bt_reg = 0x0;  /* ILV */	tc_wmb();
    612 	vdac->bt_reg = 0x0;  /* TEST */	tc_wmb();
    613 
    614 	BT459_SELECT(vdac, BT459_REG_CCR);
    615 	vdac->bt_reg = 0x0;	tc_wmb();
    616 	vdac->bt_reg = 0x0;	tc_wmb();
    617 	vdac->bt_reg = 0x0;	tc_wmb();
    618 	vdac->bt_reg = 0x0;	tc_wmb();
    619 	vdac->bt_reg = 0x0;	tc_wmb();
    620 	vdac->bt_reg = 0x0;	tc_wmb();
    621 	vdac->bt_reg = 0x0;	tc_wmb();
    622 	vdac->bt_reg = 0x0;	tc_wmb();
    623 	vdac->bt_reg = 0x0;	tc_wmb();
    624 	vdac->bt_reg = 0x0;	tc_wmb();
    625 	vdac->bt_reg = 0x0;	tc_wmb();
    626 	vdac->bt_reg = 0x0;	tc_wmb();
    627 	vdac->bt_reg = 0x0;	tc_wmb();
    628 
    629 	/* build sane colormap */
    630 	BT459_SELECT(vdac, 0);
    631 	vdac->bt_cmap = 0;	tc_wmb();
    632 	vdac->bt_cmap = 0;	tc_wmb();
    633 	vdac->bt_cmap = 0;	tc_wmb();
    634 	for (i = 1; i < CMAP_SIZE; i++) {
    635 		vdac->bt_cmap = 0xff;	tc_wmb();
    636 		vdac->bt_cmap = 0xff;	tc_wmb();
    637 		vdac->bt_cmap = 0xff;	tc_wmb();
    638 	}
    639 
    640 	/* clear out cursor image */
    641 	BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
    642 	for (i = 0; i < 1024; i++)
    643 		vdac->bt_reg = 0xff;	tc_wmb();
    644 
    645 	/*
    646 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    647 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    648 	 * image color.  CCOLOR_1 will be never used.
    649 	 */
    650 	BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
    651 	vdac->bt_reg = 0xff;	tc_wmb();
    652 	vdac->bt_reg = 0xff;	tc_wmb();
    653 	vdac->bt_reg = 0xff;	tc_wmb();
    654 
    655 	vdac->bt_reg = 0;	tc_wmb();
    656 	vdac->bt_reg = 0;	tc_wmb();
    657 	vdac->bt_reg = 0;	tc_wmb();
    658 
    659 	vdac->bt_reg = 0xff;	tc_wmb();
    660 	vdac->bt_reg = 0xff;	tc_wmb();
    661 	vdac->bt_reg = 0xff;	tc_wmb();
    662 }
    663 
    664 static int
    665 get_cmap(sc, p)
    666 	struct cfb_softc *sc;
    667 	struct wsdisplay_cmap *p;
    668 {
    669 	u_int index = p->index, count = p->count;
    670 
    671 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    672 		return (EINVAL);
    673 
    674 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    675 	    !uvm_useracc(p->green, count, B_WRITE) ||
    676 	    !uvm_useracc(p->blue, count, B_WRITE))
    677 		return (EFAULT);
    678 
    679 	copyout(&sc->sc_cmap.r[index], p->red, count);
    680 	copyout(&sc->sc_cmap.g[index], p->green, count);
    681 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    682 
    683 	return (0);
    684 }
    685 
    686 static int
    687 set_cmap(sc, p)
    688 	struct cfb_softc *sc;
    689 	struct wsdisplay_cmap *p;
    690 {
    691 	u_int index = p->index, count = p->count;
    692 
    693 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    694 		return (EINVAL);
    695 
    696 	if (!uvm_useracc(p->red, count, B_READ) ||
    697 	    !uvm_useracc(p->green, count, B_READ) ||
    698 	    !uvm_useracc(p->blue, count, B_READ))
    699 		return (EFAULT);
    700 
    701 	copyin(p->red, &sc->sc_cmap.r[index], count);
    702 	copyin(p->green, &sc->sc_cmap.g[index], count);
    703 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    704 
    705 	sc->sc_changed |= DATA_CMAP_CHANGED;
    706 
    707 	return (0);
    708 }
    709 
    710 static int
    711 set_cursor(sc, p)
    712 	struct cfb_softc *sc;
    713 	struct wsdisplay_cursor *p;
    714 {
    715 #define	cc (&sc->sc_cursor)
    716 	int v, index, count, icount;
    717 
    718 	v = p->which;
    719 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    720 		index = p->cmap.index;
    721 		count = p->cmap.count;
    722 		if (index >= 2 || (index + count) > 2)
    723 			return (EINVAL);
    724 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    725 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    726 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    727 			return (EFAULT);
    728 	}
    729 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    730 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    731 			return (EINVAL);
    732 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    733 		if (!uvm_useracc(p->image, icount, B_READ) ||
    734 		    !uvm_useracc(p->mask, icount, B_READ))
    735 			return (EFAULT);
    736 	}
    737 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    738 		if (v & WSDISPLAY_CURSOR_DOCUR)
    739 			cc->cc_hot = p->hot;
    740 		if (v & WSDISPLAY_CURSOR_DOPOS)
    741 			set_curpos(sc, &p->pos);
    742 		bt459_set_curpos(sc);
    743 	}
    744 
    745 	sc->sc_changed = 0;
    746 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    747 		sc->sc_curenb = p->enable;
    748 		sc->sc_changed |= DATA_ENB_CHANGED;
    749 	}
    750 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    751 		copyin(p->cmap.red, &cc->cc_color[index], count);
    752 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    753 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    754 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    755 	}
    756 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    757 		cc->cc_size = p->size;
    758 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    759 		copyin(p->image, cc->cc_image, icount);
    760 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    761 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    762 	}
    763 
    764 	return (0);
    765 #undef cc
    766 }
    767 
    768 static int
    769 get_cursor(sc, p)
    770 	struct cfb_softc *sc;
    771 	struct wsdisplay_cursor *p;
    772 {
    773 	return (ENOTTY); /* XXX */
    774 }
    775 
    776 static void
    777 set_curpos(sc, curpos)
    778 	struct cfb_softc *sc;
    779 	struct wsdisplay_curpos *curpos;
    780 {
    781 	struct fb_devconfig *dc = sc->sc_dc;
    782 	int x = curpos->x, y = curpos->y;
    783 
    784 	if (y < 0)
    785 		y = 0;
    786 	else if (y > dc->dc_ht)
    787 		y = dc->dc_ht;
    788 	if (x < 0)
    789 		x = 0;
    790 	else if (x > dc->dc_wid)
    791 		x = dc->dc_wid;
    792 	sc->sc_cursor.cc_pos.x = x;
    793 	sc->sc_cursor.cc_pos.y = y;
    794 }
    795 
    796 void
    797 bt459_set_curpos(sc)
    798 	struct cfb_softc *sc;
    799 {
    800 	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    801 	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    802 	int x, y, s;
    803 
    804 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    805 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    806 	x += sc->magic_x; y += sc->magic_y; /* magic offset of CX coordinate */
    807 
    808 	s = spltty();
    809 
    810 	BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
    811 	vdac->bt_reg = x;	tc_wmb();
    812 	vdac->bt_reg = x >> 8;	tc_wmb();
    813 	vdac->bt_reg = y;	tc_wmb();
    814 	vdac->bt_reg = y >> 8;	tc_wmb();
    815 
    816 	splx(s);
    817 }
    818