Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.21
      1 /* $NetBSD: cfb.c,v 1.21 2000/06/26 04:56:27 simonb 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.21 2000/06/26 04:56:27 simonb 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/wscons/wsconsio.h>
     50 #include <dev/wscons/wsdisplayvar.h>
     51 
     52 #include <dev/rasops/rasops.h>
     53 #include <dev/wsfont/wsfont.h>
     54 
     55 #include <dev/tc/tcvar.h>
     56 #include <dev/ic/bt459reg.h>
     57 
     58 #include <uvm/uvm_extern.h>
     59 
     60 #if defined(pmax)
     61 #define	machine_btop(x) mips_btop(x)
     62 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
     63 #endif
     64 
     65 #if defined(__alpha__) || defined(alpha)
     66 /*
     67  * Digital UNIX never supports PMAG-BA
     68  */
     69 #define machine_btop(x) alpha_btop(x)
     70 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     71 #endif
     72 
     73 /*
     74  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     75  * obscure register layout such as 2nd and 3rd Bt459 registers are
     76  * adjacent each other in a word, i.e.,
     77  *	struct bt459triplet {
     78  * 		struct {
     79  *			u_int8_t u0;
     80  *			u_int8_t u1;
     81  *			u_int8_t u2;
     82  *			unsigned :8;
     83  *		} bt_lo;
     84  *		...
     85  * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
     86  *
     87  * struct bt459reg {
     88  *         u_int32_t       bt_lo;
     89  *         u_int32_t       bt_hi;
     90  *         u_int32_t       bt_reg;
     91  *         u_int32_t       bt_cmap;
     92  * };
     93  *
     94  */
     95 
     96 /* Bt459 hardware registers */
     97 #define bt_lo	0
     98 #define bt_hi	1
     99 #define bt_reg	2
    100 #define bt_cmap 3
    101 
    102 #define REG(base, index)	*((u_int32_t *)(base) + (index))
    103 #define SELECT(vdac, regno) do {			\
    104 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
    105 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
    106 	tc_wmb();					\
    107    } while (0)
    108 
    109 struct fb_devconfig {
    110 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    111 	paddr_t dc_paddr;		/* memory space physical base address */
    112 	vsize_t	dc_size;		/* size of slot memory */
    113 	int	dc_wid;			/* width of frame buffer */
    114 	int	dc_ht;			/* height of frame buffer */
    115 	int	dc_depth;		/* depth, bits per pixel */
    116 	int	dc_rowbytes;		/* bytes in a FB scan line */
    117 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    118 	int	    dc_blanked;		/* currently has video disabled */
    119 
    120 	struct rasops_info rinfo;
    121 };
    122 
    123 struct hwcmap256 {
    124 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    125 	u_int8_t r[CMAP_SIZE];
    126 	u_int8_t g[CMAP_SIZE];
    127 	u_int8_t b[CMAP_SIZE];
    128 };
    129 
    130 struct hwcursor64 {
    131 	struct wsdisplay_curpos cc_pos;
    132 	struct wsdisplay_curpos cc_hot;
    133 	struct wsdisplay_curpos cc_size;
    134 	struct wsdisplay_curpos cc_magic;
    135 #define	CURSOR_MAX_SIZE	64
    136 	u_int8_t cc_color[6];
    137 	u_int64_t cc_image[64 + 64];
    138 };
    139 
    140 struct cfb_softc {
    141 	struct device sc_dev;
    142 	struct fb_devconfig *sc_dc;	/* device configuration */
    143 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    144 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    145 	int sc_curenb;			/* cursor sprite enabled */
    146 	int sc_changed;			/* need update of colormap */
    147 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    148 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    149 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    150 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    151 #define	DATA_ALL_CHANGED	0x0f
    152 	int nscreens;
    153 };
    154 
    155 #define	CX_MAGIC_X	220
    156 #define	CX_MAGIC_Y 	35
    157 
    158 #define	CX_FB_OFFSET	0x000000
    159 #define	CX_FB_SIZE	0x100000
    160 #define	CX_BT459_OFFSET	0x200000
    161 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
    162 
    163 static int  cfbmatch __P((struct device *, struct cfdata *, void *));
    164 static void cfbattach __P((struct device *, struct device *, void *));
    165 
    166 const struct cfattach cfb_ca = {
    167 	sizeof(struct cfb_softc), cfbmatch, cfbattach,
    168 };
    169 
    170 static void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    171 static struct fb_devconfig cfb_console_dc;
    172 static tc_addr_t cfb_consaddr;
    173 
    174 static struct wsscreen_descr cfb_stdscreen = {
    175 	"std", 0, 0,
    176 	0, /* textops */
    177 	0, 0,
    178 	WSSCREEN_REVERSE
    179 };
    180 
    181 static const struct wsscreen_descr *_cfb_scrlist[] = {
    182 	&cfb_stdscreen,
    183 };
    184 
    185 static const struct wsscreen_list cfb_screenlist = {
    186 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
    187 };
    188 
    189 static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    190 static paddr_t	cfbmmap __P((void *, off_t, int));
    191 
    192 static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    193 				      void **, int *, int *, long *));
    194 static void	cfb_free_screen __P((void *, void *));
    195 static int	cfb_show_screen __P((void *, void *, int,
    196 				     void (*) (void *, int, int), void *));
    197 
    198 static const struct wsdisplay_accessops cfb_accessops = {
    199 	cfbioctl,
    200 	cfbmmap,
    201 	cfb_alloc_screen,
    202 	cfb_free_screen,
    203 	cfb_show_screen,
    204 	0 /* load_font */
    205 };
    206 
    207 int  cfb_cnattach __P((tc_addr_t));
    208 static int  cfbintr __P((void *));
    209 static void cfbinit __P((struct fb_devconfig *));
    210 
    211 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    212 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    213 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    214 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    215 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
    216 static void bt459_set_curpos __P((struct cfb_softc *));
    217 
    218 /*
    219  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    220  *   M M M M I I I I		M I M I M I M I
    221  *	[ before ]		   [ after ]
    222  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    223  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    224  */
    225 static const u_int8_t shuffle[256] = {
    226 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    227 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    228 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    229 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    230 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    231 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    232 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    233 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    234 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    235 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    236 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    237 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    238 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    239 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    240 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    241 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    242 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    243 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    244 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    245 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    246 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    247 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    248 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    249 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    250 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    251 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    252 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    253 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    254 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    255 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    256 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    257 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    258 };
    259 
    260 static int
    261 cfbmatch(parent, match, aux)
    262 	struct device *parent;
    263 	struct cfdata *match;
    264 	void *aux;
    265 {
    266 	struct tc_attach_args *ta = aux;
    267 
    268 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    269 		return (0);
    270 
    271 	return (1);
    272 }
    273 
    274 static void
    275 cfb_getdevconfig(dense_addr, dc)
    276 	tc_addr_t dense_addr;
    277 	struct fb_devconfig *dc;
    278 {
    279 	int i, cookie;
    280 
    281 	dc->dc_vaddr = dense_addr;
    282 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET);
    283 
    284 	dc->dc_wid = 1024;
    285 	dc->dc_ht = 864;
    286 	dc->dc_depth = 8;
    287 	dc->dc_rowbytes = 1024;
    288 	dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET;
    289 	dc->dc_blanked = 0;
    290 
    291 	/* initialize colormap and cursor resource */
    292 	cfbinit(dc);
    293 
    294 	/* clear the screen */
    295 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    296 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    297 
    298 	dc->rinfo.ri_flg = RI_CENTER;
    299 	dc->rinfo.ri_depth = dc->dc_depth;
    300 	dc->rinfo.ri_bits = (void *)dc->dc_videobase;
    301 	dc->rinfo.ri_width = dc->dc_wid;
    302 	dc->rinfo.ri_height = dc->dc_ht;
    303 	dc->rinfo.ri_stride = dc->dc_rowbytes;
    304 
    305 	wsfont_init();
    306 	/* prefer 8 pixel wide font */
    307 	if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
    308 		cookie = wsfont_find(NULL, 0, 0, 0);
    309 	if (cookie <= 0) {
    310 		printf("cfb: font table is empty\n");
    311 		return;
    312 	}
    313 
    314 	if (wsfont_lock(cookie, &dc->rinfo.ri_font,
    315 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
    316 		printf("cfb: couldn't lock font\n");
    317 		return;
    318 	}
    319 	dc->rinfo.ri_wsfcookie = cookie;
    320 
    321 	rasops_init(&dc->rinfo, 34, 80);
    322 
    323 	/* XXX shouldn't be global */
    324 	cfb_stdscreen.nrows = dc->rinfo.ri_rows;
    325 	cfb_stdscreen.ncols = dc->rinfo.ri_cols;
    326 	cfb_stdscreen.textops = &dc->rinfo.ri_ops;
    327 	cfb_stdscreen.capabilities = dc->rinfo.ri_caps;
    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 	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 	memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256));
    354 
    355 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
    356 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
    357 
    358 	/* Establish an interrupt handler, and clear any pending interrupts */
    359 	tc_intr_establish(parent, ta->ta_cookie, 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 static 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 paddr_t
    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 static 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->rinfo; /* one and only for now */
    466 	*curxp = 0;
    467 	*curyp = 0;
    468 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
    469 	*attrp = defattr;
    470 	sc->nscreens++;
    471 	return (0);
    472 }
    473 
    474 static 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 static int
    488 cfb_show_screen(v, cookie, waitok, cb, cbarg)
    489 	void *v;
    490 	void *cookie;
    491 	int waitok;
    492 	void (*cb) __P((void *, int, int));
    493 	void *cbarg;
    494 {
    495 
    496 	return (0);
    497 }
    498 
    499 /* EXPORT */ int
    500 cfb_cnattach(addr)
    501 	tc_addr_t addr;
    502 {
    503 	struct fb_devconfig *dcp = &cfb_console_dc;
    504 	long defattr;
    505 
    506 	cfb_getdevconfig(addr, dcp);
    507 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
    508 	wsdisplay_cnattach(&cfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
    509 	cfb_consaddr = addr;
    510 	return(0);
    511 }
    512 
    513 static int
    514 cfbintr(arg)
    515 	void *arg;
    516 {
    517 	struct cfb_softc *sc = arg;
    518 	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    519 	struct bt459reg *vdac;
    520 	int v;
    521 
    522 	*(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
    523 	if (sc->sc_changed == 0)
    524 		return (1);
    525 
    526 	vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    527 	v = sc->sc_changed;
    528 	sc->sc_changed = 0;
    529 	if (v & DATA_ENB_CHANGED) {
    530 		SELECT(vdac, BT459_IREG_CCR);
    531 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
    532 	}
    533 	if (v & DATA_CURCMAP_CHANGED) {
    534 		u_int8_t *cp = sc->sc_cursor.cc_color;
    535 
    536 		SELECT(vdac, BT459_IREG_CCOLOR_2);
    537 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
    538 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
    539 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
    540 
    541 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
    542 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
    543 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
    544 	}
    545 	if (v & DATA_CURSHAPE_CHANGED) {
    546 		u_int8_t *ip, *mp, img, msk;
    547 		u_int8_t u;
    548 		int bcnt;
    549 
    550 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    551 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    552 
    553 		bcnt = 0;
    554 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
    555 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    556 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    557 			/* pad right half 32 pixel when smaller than 33 */
    558 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    559 				REG(vdac, bt_reg) = 0; tc_wmb();
    560 				REG(vdac, bt_reg) = 0; tc_wmb();
    561 			}
    562 			else {
    563 				img = *ip++;
    564 				msk = *mp++;
    565 				img &= msk;	/* cookie off image */
    566 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    567 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    568 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    569 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    570 			}
    571 			bcnt += 2;
    572 		}
    573 		/* pad unoccupied scan lines */
    574 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    575 			REG(vdac, bt_reg) = 0; tc_wmb();
    576 			REG(vdac, bt_reg) = 0; tc_wmb();
    577 			bcnt += 2;
    578 		}
    579 	}
    580 	if (v & DATA_CMAP_CHANGED) {
    581 		struct hwcmap256 *cm = &sc->sc_cmap;
    582 		int index;
    583 
    584 		SELECT(vdac, 0);
    585 		for (index = 0; index < CMAP_SIZE; index++) {
    586 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
    587 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
    588 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
    589 		}
    590 	}
    591 	return (1);
    592 }
    593 
    594 static void
    595 cfbinit(dc)
    596 	struct fb_devconfig *dc;
    597 {
    598 	caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
    599 	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    600 	int i;
    601 
    602 	SELECT(vdac, BT459_IREG_COMMAND_0);
    603 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
    604 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
    605 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
    606 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
    607 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
    608 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
    609 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
    610 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
    611 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
    612 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
    613 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
    614 
    615 	SELECT(vdac, BT459_IREG_CCR);
    616 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    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 
    630 	/* build sane colormap */
    631 	SELECT(vdac, 0);
    632 	for (i = 0; i < CMAP_SIZE; i++) {
    633 		REG(vdac, bt_cmap) = rasops_cmap[3 * i + 0];
    634 		tc_wmb();
    635 		REG(vdac, bt_cmap) = rasops_cmap[3 * i + 1];
    636 		tc_wmb();
    637 		REG(vdac, bt_cmap) = rasops_cmap[3 * i + 2];
    638 		tc_wmb();
    639 	}
    640 
    641 	/* clear out cursor image */
    642 	SELECT(vdac, BT459_IREG_CRAM_BASE);
    643 	for (i = 0; i < 1024; i++)
    644 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
    645 
    646 	/*
    647 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    648 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    649 	 * image color.  CCOLOR_1 will be never used.
    650 	 */
    651 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    652 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    653 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    654 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    655 
    656 	REG(vdac, bt_reg) = 0;	tc_wmb();
    657 	REG(vdac, bt_reg) = 0;	tc_wmb();
    658 	REG(vdac, bt_reg) = 0;	tc_wmb();
    659 
    660 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    661 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    662 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    663 }
    664 
    665 static int
    666 get_cmap(sc, p)
    667 	struct cfb_softc *sc;
    668 	struct wsdisplay_cmap *p;
    669 {
    670 	u_int index = p->index, count = p->count;
    671 
    672 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    673 		return (EINVAL);
    674 
    675 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    676 	    !uvm_useracc(p->green, count, B_WRITE) ||
    677 	    !uvm_useracc(p->blue, count, B_WRITE))
    678 		return (EFAULT);
    679 
    680 	copyout(&sc->sc_cmap.r[index], p->red, count);
    681 	copyout(&sc->sc_cmap.g[index], p->green, count);
    682 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    683 
    684 	return (0);
    685 }
    686 
    687 static int
    688 set_cmap(sc, p)
    689 	struct cfb_softc *sc;
    690 	struct wsdisplay_cmap *p;
    691 {
    692 	u_int index = p->index, count = p->count;
    693 
    694 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    695 		return (EINVAL);
    696 
    697 	if (!uvm_useracc(p->red, count, B_READ) ||
    698 	    !uvm_useracc(p->green, count, B_READ) ||
    699 	    !uvm_useracc(p->blue, count, B_READ))
    700 		return (EFAULT);
    701 
    702 	copyin(p->red, &sc->sc_cmap.r[index], count);
    703 	copyin(p->green, &sc->sc_cmap.g[index], count);
    704 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    705 
    706 	sc->sc_changed |= DATA_CMAP_CHANGED;
    707 
    708 	return (0);
    709 }
    710 
    711 static int
    712 set_cursor(sc, p)
    713 	struct cfb_softc *sc;
    714 	struct wsdisplay_cursor *p;
    715 {
    716 #define	cc (&sc->sc_cursor)
    717 	int v, index, count, icount;
    718 
    719 	v = p->which;
    720 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    721 		index = p->cmap.index;
    722 		count = p->cmap.count;
    723 		if (index >= 2 || (index + count) > 2)
    724 			return (EINVAL);
    725 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    726 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    727 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    728 			return (EFAULT);
    729 	}
    730 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    731 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    732 			return (EINVAL);
    733 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    734 		if (!uvm_useracc(p->image, icount, B_READ) ||
    735 		    !uvm_useracc(p->mask, icount, B_READ))
    736 			return (EFAULT);
    737 	}
    738 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    739 		if (v & WSDISPLAY_CURSOR_DOCUR)
    740 			cc->cc_hot = p->hot;
    741 		if (v & WSDISPLAY_CURSOR_DOPOS)
    742 			set_curpos(sc, &p->pos);
    743 		bt459_set_curpos(sc);
    744 	}
    745 
    746 	sc->sc_changed = 0;
    747 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    748 		sc->sc_curenb = p->enable;
    749 		sc->sc_changed |= DATA_ENB_CHANGED;
    750 	}
    751 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    752 		copyin(p->cmap.red, &cc->cc_color[index], count);
    753 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    754 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    755 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    756 	}
    757 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    758 		cc->cc_size = p->size;
    759 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    760 		copyin(p->image, cc->cc_image, icount);
    761 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    762 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    763 	}
    764 
    765 	return (0);
    766 #undef cc
    767 }
    768 
    769 static int
    770 get_cursor(sc, p)
    771 	struct cfb_softc *sc;
    772 	struct wsdisplay_cursor *p;
    773 {
    774 	return (ENOTTY); /* XXX */
    775 }
    776 
    777 static void
    778 set_curpos(sc, curpos)
    779 	struct cfb_softc *sc;
    780 	struct wsdisplay_curpos *curpos;
    781 {
    782 	struct fb_devconfig *dc = sc->sc_dc;
    783 	int x = curpos->x, y = curpos->y;
    784 
    785 	if (y < 0)
    786 		y = 0;
    787 	else if (y > dc->dc_ht)
    788 		y = dc->dc_ht;
    789 	if (x < 0)
    790 		x = 0;
    791 	else if (x > dc->dc_wid)
    792 		x = dc->dc_wid;
    793 	sc->sc_cursor.cc_pos.x = x;
    794 	sc->sc_cursor.cc_pos.y = y;
    795 }
    796 
    797 void
    798 bt459_set_curpos(sc)
    799 	struct cfb_softc *sc;
    800 {
    801 	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    802 	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    803 	int x, y, s;
    804 
    805 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    806 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    807 
    808 	x += sc->sc_cursor.cc_magic.x;
    809 	y += sc->sc_cursor.cc_magic.y;
    810 
    811 	s = spltty();
    812 
    813 	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
    814 	REG(vdac, bt_reg) = x;		tc_wmb();
    815 	REG(vdac, bt_reg) = x >> 8;	tc_wmb();
    816 	REG(vdac, bt_reg) = y;		tc_wmb();
    817 	REG(vdac, bt_reg) = y >> 8;	tc_wmb();
    818 
    819 	splx(s);
    820 }
    821