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