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