Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.6
      1 /* $NetBSD: cfb.c,v 1.6 1999/01/11 21:35:55 drochner 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.6 1999/01/11 21:35:55 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 #include <machine/autoconf.h>
     54 
     55 #include <dev/tc/tcvar.h>
     56 #include <dev/ic/bt459reg.h>
     57 
     58 #include "opt_uvm.h"
     59 #if defined(UVM)
     60 #include <uvm/uvm_extern.h>
     61 #define useracc uvm_useracc
     62 #endif
     63 
     64 /* XXX BUS'IFYING XXX */
     65 
     66 #if defined(__pmax__)
     67 #define	machine_btop(x) mips_btop(x)
     68 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
     69 #endif
     70 
     71 #if defined(__alpha__) || defined(alpha)
     72 /*
     73  * Digital UNIX never supports PMAG-BA
     74  */
     75 #define machine_btop(x) alpha_btop(x)
     76 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
     77 #endif
     78 
     79 /*
     80  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     81  * obscure register layout such as 2nd and 3rd Bt459 registers are
     82  * adjacent each other in a word, i.e.,
     83  *	struct bt459triplet {
     84  * 		struct {
     85  *			u_int8_t u0;
     86  *			u_int8_t u1;
     87  *			u_int8_t u2;
     88  *			unsigned :8;
     89  *		} bt_lo;
     90  *		...
     91  * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
     92  */
     93 struct bt459reg {
     94         u_int32_t       bt_lo;
     95         u_int32_t       bt_hi;
     96         u_int32_t       bt_reg;
     97         u_int32_t       bt_cmap;
     98 };
     99 
    100 /* XXX XXX XXX */
    101 
    102 struct fb_devconfig {
    103 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    104 	paddr_t dc_paddr;		/* memory space physical base address */
    105 	vsize_t	dc_size;		/* size of slot memory */
    106 	int	dc_wid;			/* width of frame buffer */
    107 	int	dc_ht;			/* height of frame buffer */
    108 	int	dc_depth;		/* depth, bits per pixel */
    109 	int	dc_rowbytes;		/* bytes in a FB scan line */
    110 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    111 	struct raster	dc_raster;	/* raster description */
    112 	struct rcons	dc_rcons;	/* raster blitter control info */
    113 	int	    dc_blanked;		/* currently has video disabled */
    114 };
    115 
    116 struct hwcmap {
    117 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    118 	u_int8_t r[CMAP_SIZE];
    119 	u_int8_t g[CMAP_SIZE];
    120 	u_int8_t b[CMAP_SIZE];
    121 };
    122 
    123 struct hwcursor {
    124 	struct wsdisplay_curpos cc_pos;
    125 	struct wsdisplay_curpos cc_hot;
    126 	struct wsdisplay_curpos cc_size;
    127 #define	CURSOR_MAX_SIZE	64
    128 	u_int8_t cc_color[6];
    129 	u_int64_t cc_image[64 + 64];
    130 };
    131 
    132 struct cfb_softc {
    133 	struct device sc_dev;
    134 	struct fb_devconfig *sc_dc;	/* device configuration */
    135 	struct hwcmap sc_cmap;		/* software copy of colormap */
    136 	struct hwcursor sc_cursor;	/* software copy of cursor */
    137 	int sc_curenb;			/* cursor sprite enabled */
    138 	int sc_changed;			/* need update of colormap */
    139 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    140 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    141 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    142 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    143 #define	DATA_ALL_CHANGED	0x0f
    144 	int nscreens;
    145 	short magic_x, magic_y;		/* CX cursor location offset */
    146 #define	CX_MAGIC_X 220
    147 #define	CX_MAGIC_Y 35
    148 };
    149 
    150 #define	CX_FB_OFFSET	0x000000
    151 #define	CX_FB_SIZE	0x100000
    152 #define	CX_BT459_OFFSET	0x200000
    153 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
    154 
    155 int  cfbmatch __P((struct device *, struct cfdata *, void *));
    156 void cfbattach __P((struct device *, struct device *, void *));
    157 
    158 struct cfattach cfb_ca = {
    159 	sizeof(struct cfb_softc), cfbmatch, cfbattach,
    160 };
    161 
    162 void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    163 struct fb_devconfig cfb_console_dc;
    164 tc_addr_t cfb_consaddr;
    165 
    166 struct wsdisplay_emulops cfb_emulops = {
    167 	rcons_cursor,			/* could use hardware cursor; punt */
    168 	rcons_mapchar,
    169 	rcons_putchar,
    170 	rcons_copycols,
    171 	rcons_erasecols,
    172 	rcons_copyrows,
    173 	rcons_eraserows,
    174 	rcons_alloc_attr
    175 };
    176 
    177 struct wsscreen_descr cfb_stdscreen = {
    178 	"std", 0, 0,
    179 	&cfb_emulops,
    180 	0, 0,
    181 	0
    182 };
    183 
    184 const struct wsscreen_descr *_cfb_scrlist[] = {
    185 	&cfb_stdscreen,
    186 };
    187 
    188 struct wsscreen_list cfb_screenlist = {
    189 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
    190 };
    191 
    192 int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    193 int	cfbmmap __P((void *, off_t, int));
    194 
    195 int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    196 				      void **, int *, int *, long *));
    197 void	cfb_free_screen __P((void *, void *));
    198 void	cfb_show_screen __P((void *, void *));
    199 
    200 struct wsdisplay_accessops cfb_accessops = {
    201 	cfbioctl,
    202 	cfbmmap,
    203 	cfb_alloc_screen,
    204 	cfb_free_screen,
    205 	cfb_show_screen,
    206 	0 /* load_font */
    207 };
    208 
    209 int  cfb_cnattach __P((tc_addr_t));
    210 int  cfbintr __P((void *));
    211 void cfbinit __P((struct fb_devconfig *));
    212 
    213 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    214 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    215 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    216 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    217 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
    218 static void bt459_set_curpos __P((struct cfb_softc *));
    219 
    220 /* XXX XXX XXX */
    221 #define	BT459_SELECT(vdac, regno) do {		\
    222 	vdac->bt_lo = (regno) & 0x00ff;		\
    223 	vdac->bt_hi = ((regno)& 0x0f00) >> 8;	\
    224 	tc_wmb();				\
    225    } while (0)
    226 /* XXX XXX XXX */
    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 const static 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 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 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 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 hwcmap *cm;
    339 	int console, i;
    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 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    356 	for (i = 1; i < CMAP_SIZE; i++) {
    357 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    358 	}
    359 	sc->magic_x = CX_MAGIC_X;
    360 	sc->magic_y = CX_MAGIC_Y;
    361 
    362 	/* Establish an interrupt handler, and clear any pending interrupts */
    363         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc);
    364 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
    365 
    366 	waa.console = console;
    367 	waa.scrdata = &cfb_screenlist;
    368 	waa.accessops = &cfb_accessops;
    369 	waa.accesscookie = sc;
    370 
    371 	config_found(self, &waa, wsemuldisplaydevprint);
    372 }
    373 
    374 int
    375 cfbioctl(v, cmd, data, flag, p)
    376 	void *v;
    377 	u_long cmd;
    378 	caddr_t data;
    379 	int flag;
    380 	struct proc *p;
    381 {
    382 	struct cfb_softc *sc = v;
    383 	struct fb_devconfig *dc = sc->sc_dc;
    384 	int turnoff;
    385 
    386 	switch (cmd) {
    387 	case WSDISPLAYIO_GTYPE:
    388 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
    389 		return (0);
    390 
    391 	case WSDISPLAYIO_GINFO:
    392 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    393 		wsd_fbip->height = sc->sc_dc->dc_ht;
    394 		wsd_fbip->width = sc->sc_dc->dc_wid;
    395 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    396 		wsd_fbip->cmsize = CMAP_SIZE;
    397 #undef fbt
    398 		return (0);
    399 
    400 	case WSDISPLAYIO_GETCMAP:
    401 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    402 
    403 	case WSDISPLAYIO_PUTCMAP:
    404 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    405 
    406 	case WSDISPLAYIO_SVIDEO:
    407 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    408 		if ((dc->dc_blanked == 0) ^ turnoff) {
    409 			dc->dc_blanked = turnoff;
    410 			/* XXX later XXX */
    411 		}
    412 		return (0);
    413 
    414 	case WSDISPLAYIO_GVIDEO:
    415 		*(u_int *)data = dc->dc_blanked ?
    416 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    417 		return (0);
    418 
    419 	case WSDISPLAYIO_GCURPOS:
    420 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    421 		return (0);
    422 
    423 	case WSDISPLAYIO_SCURPOS:
    424 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    425 		bt459_set_curpos(sc);
    426 		return (0);
    427 
    428 	case WSDISPLAYIO_GCURMAX:
    429 		((struct wsdisplay_curpos *)data)->x =
    430 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    431 		return (0);
    432 
    433 	case WSDISPLAYIO_GCURSOR:
    434 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    435 
    436 	case WSDISPLAYIO_SCURSOR:
    437 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    438 	}
    439 	return ENOTTY;
    440 }
    441 
    442 int
    443 cfbmmap(v, offset, prot)
    444 	void *v;
    445 	off_t offset;
    446 	int prot;
    447 {
    448 	struct cfb_softc *sc = v;
    449 
    450 	if (offset >= CX_FB_SIZE || offset < 0)
    451 		return (-1);
    452 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    453 }
    454 
    455 int
    456 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    457 	void *v;
    458 	const struct wsscreen_descr *type;
    459 	void **cookiep;
    460 	int *curxp, *curyp;
    461 	long *attrp;
    462 {
    463 	struct cfb_softc *sc = v;
    464 	long defattr;
    465 
    466 	if (sc->nscreens > 0)
    467 		return (ENOMEM);
    468 
    469 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    470 	*curxp = 0;
    471 	*curyp = 0;
    472 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    473 	*attrp = defattr;
    474 	sc->nscreens++;
    475 	return (0);
    476 }
    477 
    478 void
    479 cfb_free_screen(v, cookie)
    480 	void *v;
    481 	void *cookie;
    482 {
    483 	struct cfb_softc *sc = v;
    484 
    485 	if (sc->sc_dc == &cfb_console_dc)
    486 		panic("cfb_free_screen: console");
    487 
    488 	sc->nscreens--;
    489 }
    490 
    491 void
    492 cfb_show_screen(v, cookie)
    493 	void *v;
    494 	void *cookie;
    495 {
    496 }
    497 
    498 int
    499 cfb_cnattach(addr)
    500         tc_addr_t addr;
    501 {
    502         struct fb_devconfig *dcp = &cfb_console_dc;
    503         long defattr;
    504 
    505         cfb_getdevconfig(addr, dcp);
    506 
    507         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    508 
    509         wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
    510                            0, 0, defattr);
    511         cfb_consaddr = addr;
    512         return(0);
    513 }
    514 
    515 
    516 int
    517 cfbintr(arg)
    518 	void *arg;
    519 {
    520 	struct cfb_softc *sc = arg;
    521 	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    522 	struct bt459reg *vdac;
    523 	int v;
    524 
    525 	*(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
    526 	if (sc->sc_changed == 0)
    527 		return (1);
    528 
    529 	vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    530 	v = sc->sc_changed;
    531 	sc->sc_changed = 0;
    532 	if (v & DATA_ENB_CHANGED) {
    533 		BT459_SELECT(vdac, BT459_REG_CCR);
    534 		vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
    535 	}
    536 	if (v & DATA_CURCMAP_CHANGED) {
    537 		u_int8_t *cp = sc->sc_cursor.cc_color;
    538 
    539 		BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
    540 		vdac->bt_reg = cp[1];	tc_wmb();
    541 		vdac->bt_reg = cp[3];	tc_wmb();
    542 		vdac->bt_reg = cp[5];	tc_wmb();
    543 
    544 		vdac->bt_reg = cp[0];	tc_wmb();
    545 		vdac->bt_reg = cp[2];	tc_wmb();
    546 		vdac->bt_reg = cp[4];	tc_wmb();
    547 	}
    548 	if (v & DATA_CURSHAPE_CHANGED) {
    549 		u_int8_t *ip, *mp, img, msk;
    550 		u_int8_t u;
    551 		int bcnt;
    552 
    553 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    554 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    555 
    556 		bcnt = 0;
    557 		BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
    558 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    559 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    560 			/* pad right half 32 pixel when smaller than 33 */
    561 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    562 				vdac->bt_reg = 0; tc_wmb();
    563 				vdac->bt_reg = 0; tc_wmb();
    564 			}
    565 			else {
    566 				img = *ip++;
    567 				msk = *mp++;
    568 				img &= msk;	/* cookie off image */
    569 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    570 				vdac->bt_reg = shuffle[u];	tc_wmb();
    571 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    572 				vdac->bt_reg = shuffle[u];	tc_wmb();
    573 			}
    574 			bcnt += 2;
    575 		}
    576 		/* pad unoccupied scan lines */
    577 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    578 			vdac->bt_reg = 0; tc_wmb();
    579 			vdac->bt_reg = 0; tc_wmb();
    580 			bcnt += 2;
    581 		}
    582 	}
    583 	if (v & DATA_CMAP_CHANGED) {
    584 		struct hwcmap *cm = &sc->sc_cmap;
    585 		int index;
    586 
    587 		BT459_SELECT(vdac, 0);
    588 		for (index = 0; index < CMAP_SIZE; index++) {
    589 			vdac->bt_cmap = cm->r[index];	tc_wmb();
    590 			vdac->bt_cmap = cm->g[index];	tc_wmb();
    591 			vdac->bt_cmap = cm->b[index];	tc_wmb();
    592 		}
    593 	}
    594 	return (1);
    595 }
    596 
    597 void
    598 cfbinit(dc)
    599 	struct fb_devconfig *dc;
    600 {
    601 	caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
    602 	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    603 	int i;
    604 
    605 	BT459_SELECT(vdac, BT459_REG_COMMAND_0);
    606 	vdac->bt_reg = 0x40; /* CMD0 */	tc_wmb();
    607 	vdac->bt_reg = 0x0;  /* CMD1 */	tc_wmb();
    608 	vdac->bt_reg = 0xc0; /* CMD2 */	tc_wmb();
    609 	vdac->bt_reg = 0xff; /* PRM */	tc_wmb();
    610 	vdac->bt_reg = 0;    /* 205 */	tc_wmb();
    611 	vdac->bt_reg = 0x0;  /* PBM */	tc_wmb();
    612 	vdac->bt_reg = 0;    /* 207 */	tc_wmb();
    613 	vdac->bt_reg = 0x0;  /* ORM */	tc_wmb();
    614 	vdac->bt_reg = 0x0;  /* OBM */	tc_wmb();
    615 	vdac->bt_reg = 0x0;  /* ILV */	tc_wmb();
    616 	vdac->bt_reg = 0x0;  /* TEST */	tc_wmb();
    617 
    618 	BT459_SELECT(vdac, BT459_REG_CCR);
    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 	vdac->bt_reg = 0x0;	tc_wmb();
    629 	vdac->bt_reg = 0x0;	tc_wmb();
    630 	vdac->bt_reg = 0x0;	tc_wmb();
    631 	vdac->bt_reg = 0x0;	tc_wmb();
    632 
    633 	/* build sane colormap */
    634 	BT459_SELECT(vdac, 0);
    635 	vdac->bt_cmap = 0;	tc_wmb();
    636 	vdac->bt_cmap = 0;	tc_wmb();
    637 	vdac->bt_cmap = 0;	tc_wmb();
    638 	for (i = 1; i < CMAP_SIZE; i++) {
    639 		vdac->bt_cmap = 0xff;	tc_wmb();
    640 		vdac->bt_cmap = 0xff;	tc_wmb();
    641 		vdac->bt_cmap = 0xff;	tc_wmb();
    642 	}
    643 
    644 	/* clear out cursor image */
    645 	BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
    646 	for (i = 0; i < 1024; i++)
    647 		vdac->bt_reg = 0xff;	tc_wmb();
    648 
    649 	/*
    650 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    651 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    652 	 * image color.  CCOLOR_1 will be never used.
    653 	 */
    654 	BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
    655 	vdac->bt_reg = 0xff;	tc_wmb();
    656 	vdac->bt_reg = 0xff;	tc_wmb();
    657 	vdac->bt_reg = 0xff;	tc_wmb();
    658 
    659 	vdac->bt_reg = 0;	tc_wmb();
    660 	vdac->bt_reg = 0;	tc_wmb();
    661 	vdac->bt_reg = 0;	tc_wmb();
    662 
    663 	vdac->bt_reg = 0xff;	tc_wmb();
    664 	vdac->bt_reg = 0xff;	tc_wmb();
    665 	vdac->bt_reg = 0xff;	tc_wmb();
    666 }
    667 
    668 static int
    669 get_cmap(sc, p)
    670 	struct cfb_softc *sc;
    671 	struct wsdisplay_cmap *p;
    672 {
    673 	u_int index = p->index, count = p->count;
    674 
    675 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    676 		return (EINVAL);
    677 
    678 	if (!useracc(p->red, count, B_WRITE) ||
    679 	    !useracc(p->green, count, B_WRITE) ||
    680 	    !useracc(p->blue, count, B_WRITE))
    681 		return (EFAULT);
    682 
    683 	copyout(&sc->sc_cmap.r[index], p->red, count);
    684 	copyout(&sc->sc_cmap.g[index], p->green, count);
    685 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    686 
    687 	return (0);
    688 }
    689 
    690 static int
    691 set_cmap(sc, p)
    692 	struct cfb_softc *sc;
    693 	struct wsdisplay_cmap *p;
    694 {
    695 	u_int index = p->index, count = p->count;
    696 
    697 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    698 		return (EINVAL);
    699 
    700 	if (!useracc(p->red, count, B_READ) ||
    701 	    !useracc(p->green, count, B_READ) ||
    702 	    !useracc(p->blue, count, B_READ))
    703 		return (EFAULT);
    704 
    705 	copyin(p->red, &sc->sc_cmap.r[index], count);
    706 	copyin(p->green, &sc->sc_cmap.g[index], count);
    707 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    708 
    709 	sc->sc_changed |= DATA_CMAP_CHANGED;
    710 
    711 	return (0);
    712 }
    713 
    714 static int
    715 set_cursor(sc, p)
    716 	struct cfb_softc *sc;
    717 	struct wsdisplay_cursor *p;
    718 {
    719 #define	cc (&sc->sc_cursor)
    720 	int v, index, count, icount;
    721 
    722 	v = p->which;
    723 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    724 		index = p->cmap.index;
    725 		count = p->cmap.count;
    726 		if (index >= 2 || (index + count) > 2)
    727 			return (EINVAL);
    728 		if (!useracc(p->cmap.red, count, B_READ) ||
    729 		    !useracc(p->cmap.green, count, B_READ) ||
    730 		    !useracc(p->cmap.blue, count, B_READ))
    731 			return (EFAULT);
    732 	}
    733 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    734 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    735 			return (EINVAL);
    736 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    737 		if (!useracc(p->image, count, B_READ) ||
    738 		    !useracc(p->mask, count, B_READ))
    739 			return (EFAULT);
    740 	}
    741 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    742 		if (v & WSDISPLAY_CURSOR_DOCUR)
    743 			cc->cc_hot = p->hot;
    744 		if (v & WSDISPLAY_CURSOR_DOPOS)
    745 			set_curpos(sc, &p->pos);
    746 		bt459_set_curpos(sc);
    747 	}
    748 
    749 	sc->sc_changed = 0;
    750 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    751 		sc->sc_curenb = p->enable;
    752 		sc->sc_changed |= DATA_ENB_CHANGED;
    753 	}
    754 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    755 		copyin(p->cmap.red, &cc->cc_color[index], count);
    756 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    757 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    758 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    759 	}
    760 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    761 		cc->cc_size = p->size;
    762 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    763 		copyin(p->image, cc->cc_image, icount);
    764 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    765 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    766 	}
    767 
    768 	return (0);
    769 #undef cc
    770 }
    771 
    772 static int
    773 get_cursor(sc, p)
    774 	struct cfb_softc *sc;
    775 	struct wsdisplay_cursor *p;
    776 {
    777 	return (ENOTTY); /* XXX */
    778 }
    779 
    780 static void
    781 set_curpos(sc, curpos)
    782 	struct cfb_softc *sc;
    783 	struct wsdisplay_curpos *curpos;
    784 {
    785 	struct fb_devconfig *dc = sc->sc_dc;
    786 	int x = curpos->x, y = curpos->y;
    787 
    788 	if (y < 0)
    789 		y = 0;
    790 	else if (y > dc->dc_ht)
    791 		y = dc->dc_ht;
    792 	if (x < 0)
    793 		x = 0;
    794 	else if (x > dc->dc_wid)
    795 		x = dc->dc_wid;
    796 	sc->sc_cursor.cc_pos.x = x;
    797 	sc->sc_cursor.cc_pos.y = y;
    798 }
    799 
    800 void
    801 bt459_set_curpos(sc)
    802 	struct cfb_softc *sc;
    803 {
    804 	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    805 	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
    806 	int x, y, s;
    807 
    808 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    809 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    810 	x += sc->magic_x; y += sc->magic_y; /* magic offset of CX coordinate */
    811 
    812 	s = spltty();
    813 
    814 	BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
    815 	vdac->bt_reg = x;	tc_wmb();
    816 	vdac->bt_reg = x >> 8;	tc_wmb();
    817 	vdac->bt_reg = y;	tc_wmb();
    818 	vdac->bt_reg = y >> 8;	tc_wmb();
    819 
    820 	splx(s);
    821 }
    822