Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.15
      1 /* $NetBSD: tfb.c,v 1.15 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: tfb.c,v 1.15 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/bt463reg.h>
     56 #include <dev/ic/bt431reg.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_KSEG0_TO_PHYS(x)
     63 
     64 /*
     65  * struct bt463reg {
     66  * 	u_int8_t	bt_lo;
     67  * 	unsigned : 24;
     68  * 	u_int8_t	bt_hi;
     69  * 	unsigned : 24;
     70  * 	u_int8_t	bt_reg;
     71  * 	unsigned : 24;
     72  * 	u_int8_t	bt_cmap;
     73  * };
     74  *
     75  * N.B. a pair of Bt431s are located adjascently.
     76  * 	struct bt431twin {
     77  *		struct {
     78  *			u_int8_t u0;	for sprite image
     79  *			u_int8_t u1;	for sprite mask
     80  *			unsigned :16;
     81  *		} bt_lo;
     82  *		...
     83  *
     84  * struct bt431reg {
     85  * 	u_int16_t	bt_lo;
     86  * 	unsigned : 16;
     87  * 	u_int16_t	bt_hi;
     88  * 	unsigned : 16;
     89  * 	u_int16_t	bt_ram;
     90  * 	unsigned : 16;
     91  * 	u_int16_t	bt_ctl;
     92  * };
     93  */
     94 
     95 #define	BYTE(base, index)	*((u_int8_t *)(base) + ((index)<<2))
     96 #define	HALF(base, index)	*((u_int16_t *)(base) + ((index)<<1))
     97 
     98 #endif
     99 
    100 #if defined(__alpha__) || defined(alpha)
    101 #define machine_btop(x) alpha_btop(x)
    102 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
    103 
    104 /*
    105  * struct bt463reg {
    106  * 	u_int32_t	bt_lo;
    107  * 	u_int32_t	bt_hi;
    108  * 	u_int32_t	bt_reg;
    109  * 	u_int32_t	bt_cmap;
    110  * };
    111  *
    112  * struct bt431reg {
    113  * 	u_int32_t	bt_lo;
    114  * 	u_int32_t	bt_hi;
    115  * 	u_int32_t	bt_ram;
    116  * 	u_int32_t	bt_ctl;
    117  * };
    118  */
    119 
    120 #define	BYTE(base, index)	*((u_int32_t *)(base) + (index))
    121 #define	HALF(base, index)	*((u_int32_t *)(base) + (index))
    122 
    123 #endif
    124 
    125 /* Bt463 hardware registers */
    126 #define	bt_lo	0
    127 #define	bt_hi	1
    128 #define	bt_reg	2
    129 #define	bt_cmap	3
    130 
    131 /* Bt431 hardware registers */
    132 #define	bt_ram	2
    133 #define	bt_ctl	3
    134 
    135 #define	SELECT463(vdac, regno) do {			\
    136 	BYTE(vdac, bt_lo) = (regno) & 0x00ff;		\
    137 	BYTE(vdac, bt_hi) = ((regno)& 0xff00) >> 8;	\
    138 	tc_wmb();					\
    139    } while (0)
    140 
    141 #define	TWIN(x)	   ((x) | ((x) << 8))
    142 #define	TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin)
    143 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8))
    144 
    145 #define	SELECT431(curs, regno) do {	\
    146 	HALF(curs, bt_lo) = TWIN(regno);\
    147 	HALF(curs, bt_hi) = 0;		\
    148 	tc_wmb();			\
    149    } while (0)
    150 
    151 struct fb_devconfig {
    152 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    153 	paddr_t dc_paddr;		/* memory space physical base address */
    154 	vsize_t dc_size;		/* size of slot memory */
    155 	int	dc_wid;			/* width of frame buffer */
    156 	int	dc_ht;			/* height of frame buffer */
    157 	int	dc_depth;		/* depth, bits per pixel */
    158 	int	dc_rowbytes;		/* bytes in a FB scan line */
    159 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    160 	struct raster	dc_raster;	/* raster description */
    161 	struct rcons	dc_rcons;	/* raster blitter control info */
    162 	int	    dc_blanked;		/* currently has video disabled */
    163 };
    164 
    165 struct hwcmap256 {
    166 #define	CMAP_SIZE	256	/* R/G/B entries */
    167 	u_int8_t r[CMAP_SIZE];
    168 	u_int8_t g[CMAP_SIZE];
    169 	u_int8_t b[CMAP_SIZE];
    170 };
    171 
    172 struct hwcursor64 {
    173 	struct wsdisplay_curpos cc_pos;
    174 	struct wsdisplay_curpos cc_hot;
    175 	struct wsdisplay_curpos cc_size;
    176 	struct wsdisplay_curpos cc_magic;
    177 #define	CURSOR_MAX_SIZE	64
    178 	u_int8_t cc_color[6];
    179 	u_int64_t cc_image[64 + 64];
    180 };
    181 
    182 struct tfb_softc {
    183 	struct device sc_dev;
    184 	struct fb_devconfig *sc_dc;	/* device configuration */
    185 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    186 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    187 	int sc_curenb;			/* cursor sprite enabled */
    188 	int sc_changed;			/* need update of colormap */
    189 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    190 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    191 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    192 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    193 #define	DATA_ALL_CHANGED	0x0f
    194 	int nscreens;
    195 };
    196 
    197 #define	TX_MAGIC_X	360
    198 #define	TX_MAGIC_Y	36
    199 
    200 #define	TX_BT463_OFFSET	0x040000
    201 #define	TX_BT431_OFFSET	0x040010
    202 #define	TX_CONTROL	0x040030
    203 #define	TX_MAP_REGISTER	0x040030
    204 #define	TX_PIP_OFFSET	0x0800c0
    205 #define	TX_SELECTION	0x100000
    206 #define	TX_8FB_OFFSET	0x200000
    207 #define	TX_8FB_SIZE	0x200000
    208 #define	TX_24FB_OFFSET	0x400000
    209 #define	TX_24FB_SIZE	0x400000
    210 #define	TX_VIDEO_ENABLE	0xa00000
    211 
    212 #define	TX_CTL_VIDEO_ON	0x80
    213 #define	TX_CTL_INT_ENA	0x40
    214 #define	TX_CTL_INT_PEND	0x20
    215 #define	TX_CTL_SEG_ENA	0x10
    216 #define	TX_CTL_SEG	0x0f
    217 
    218 int  tfbmatch __P((struct device *, struct cfdata *, void *));
    219 void tfbattach __P((struct device *, struct device *, void *));
    220 
    221 struct cfattach tfb_ca = {
    222 	sizeof(struct tfb_softc), tfbmatch, tfbattach,
    223 };
    224 
    225 void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    226 struct fb_devconfig tfb_console_dc;
    227 tc_addr_t tfb_consaddr;
    228 
    229 struct wsdisplay_emulops tfb_emulops = {
    230 	rcons_cursor,			/* could use hardware cursor; punt */
    231 	rcons_mapchar,
    232 	rcons_putchar,
    233 	rcons_copycols,
    234 	rcons_erasecols,
    235 	rcons_copyrows,
    236 	rcons_eraserows,
    237 	rcons_alloc_attr
    238 };
    239 
    240 struct wsscreen_descr tfb_stdscreen = {
    241 	"std", 0, 0,
    242 	&tfb_emulops,
    243 	0, 0,
    244 	0
    245 };
    246 
    247 const struct wsscreen_descr *_tfb_scrlist[] = {
    248 	&tfb_stdscreen,
    249 };
    250 
    251 struct wsscreen_list tfb_screenlist = {
    252 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
    253 };
    254 
    255 int	tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    256 int	tfbmmap __P((void *, off_t, int));
    257 
    258 int	tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    259 				      void **, int *, int *, long *));
    260 void	tfb_free_screen __P((void *, void *));
    261 void	tfb_show_screen __P((void *, void *));
    262 
    263 struct wsdisplay_accessops tfb_accessops = {
    264 	tfbioctl,
    265 	tfbmmap,
    266 	tfb_alloc_screen,
    267 	tfb_free_screen,
    268 	tfb_show_screen,
    269 	0 /* load_font */
    270 };
    271 
    272 int  tfb_cnattach __P((tc_addr_t));
    273 int  tfbintr __P((void *));
    274 void tfbinit __P((struct fb_devconfig *));
    275 
    276 static int  get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    277 static int  set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    278 static int  set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    279 static int  get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    280 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
    281 static void bt431_set_curpos __P((struct tfb_softc *));
    282 
    283 /* bit order reverse */
    284 const static u_int8_t flip[256] = {
    285 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    286 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    287 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    288 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    289 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    290 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    291 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    292 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    293 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    294 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    295 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    296 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    297 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    298 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    299 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    300 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    301 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    302 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    303 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    304 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    305 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    306 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    307 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    308 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    309 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    310 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    311 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    312 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    313 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    314 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    315 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    316 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    317 };
    318 
    319 int
    320 tfbmatch(parent, match, aux)
    321 	struct device *parent;
    322 	struct cfdata *match;
    323 	void *aux;
    324 {
    325 	struct tc_attach_args *ta = aux;
    326 
    327 	if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
    328 	    && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    329 		return (0);
    330 
    331 	return (1);
    332 }
    333 
    334 void
    335 tfb_getdevconfig(dense_addr, dc)
    336 	tc_addr_t dense_addr;
    337 	struct fb_devconfig *dc;
    338 {
    339 	struct raster *rap;
    340 	struct rcons *rcp;
    341 	int i;
    342 
    343 	dc->dc_vaddr = dense_addr;
    344 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    345 
    346 	dc->dc_wid = 1280;
    347 	dc->dc_ht = 1024;
    348 	dc->dc_depth = 8;
    349 	dc->dc_rowbytes = 1280;
    350 	dc->dc_videobase = dc->dc_vaddr + TX_8FB_OFFSET;
    351 	dc->dc_blanked = 0;
    352 
    353 	/* initialize colormap and cursor resource */
    354 	tfbinit(dc);
    355 
    356 	/* clear the screen */
    357 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    358 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    359 
    360 	/* initialize the raster */
    361 	rap = &dc->dc_raster;
    362 	rap->width = dc->dc_wid;
    363 	rap->height = dc->dc_ht;
    364 	rap->depth = dc->dc_depth;
    365 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    366 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    367 
    368 	/* initialize the raster console blitter */
    369 	rcp = &dc->dc_rcons;
    370 	rcp->rc_sp = rap;
    371 	rcp->rc_crow = rcp->rc_ccol = -1;
    372 	rcp->rc_crowp = &rcp->rc_crow;
    373 	rcp->rc_ccolp = &rcp->rc_ccol;
    374 	rcons_init(rcp, 34, 80);
    375 
    376 	tfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    377 	tfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    378 }
    379 
    380 void
    381 tfbattach(parent, self, aux)
    382 	struct device *parent, *self;
    383 	void *aux;
    384 {
    385 	struct tfb_softc *sc = (struct tfb_softc *)self;
    386 	struct tc_attach_args *ta = aux;
    387 	struct wsemuldisplaydev_attach_args waa;
    388 	struct hwcmap256 *cm;
    389 	int console;
    390 
    391 	console = (ta->ta_addr == tfb_consaddr);
    392 	if (console) {
    393 		sc->sc_dc = &tfb_console_dc;
    394 		sc->nscreens = 1;
    395 	}
    396 	else {
    397 		sc->sc_dc = (struct fb_devconfig *)
    398 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    399 		tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    400 	}
    401 	printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
    402 
    403 	cm = &sc->sc_cmap;
    404 	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
    405 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
    406 
    407 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
    408 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
    409 
    410 	tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, tfbintr, sc);
    411 
    412 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
    413 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
    414 
    415 	waa.console = console;
    416 	waa.scrdata = &tfb_screenlist;
    417 	waa.accessops = &tfb_accessops;
    418 	waa.accesscookie = sc;
    419 
    420 	config_found(self, &waa, wsemuldisplaydevprint);
    421 }
    422 
    423 int
    424 tfbioctl(v, cmd, data, flag, p)
    425 	void *v;
    426 	u_long cmd;
    427 	caddr_t data;
    428 	int flag;
    429 	struct proc *p;
    430 {
    431 	struct tfb_softc *sc = v;
    432 	struct fb_devconfig *dc = sc->sc_dc;
    433 	int turnoff;
    434 
    435 	switch (cmd) {
    436 	case WSDISPLAYIO_GTYPE:
    437 		*(u_int *)data = /* WSDISPLAY_TYPE_TX */ 0x19980910;
    438 		return (0);
    439 
    440 	case WSDISPLAYIO_GINFO:
    441 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    442 		wsd_fbip->height = sc->sc_dc->dc_ht;
    443 		wsd_fbip->width = sc->sc_dc->dc_wid;
    444 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    445 		wsd_fbip->cmsize = CMAP_SIZE;
    446 #undef fbt
    447 		return (0);
    448 
    449 	case WSDISPLAYIO_GETCMAP:
    450 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    451 
    452 	case WSDISPLAYIO_PUTCMAP:
    453 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    454 
    455 	case WSDISPLAYIO_SVIDEO:
    456 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    457 		if ((dc->dc_blanked == 0) ^ turnoff) {
    458 			dc->dc_blanked = turnoff;
    459 #if 0	/* XXX later XXX */
    460 	To turn off;
    461 	- clear the MSB of TX control register; &= ~0x80,
    462 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
    463 #endif	/* XXX XXX XXX */
    464 		}
    465 		return (0);
    466 
    467 	case WSDISPLAYIO_GVIDEO:
    468 		*(u_int *)data = dc->dc_blanked ?
    469 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    470 		return (0);
    471 
    472 	case WSDISPLAYIO_GCURPOS:
    473 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    474 		return (0);
    475 
    476 	case WSDISPLAYIO_SCURPOS:
    477 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    478 		bt431_set_curpos(sc);
    479 		return (0);
    480 
    481 	case WSDISPLAYIO_GCURMAX:
    482 		((struct wsdisplay_curpos *)data)->x =
    483 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    484 		return (0);
    485 
    486 	case WSDISPLAYIO_GCURSOR:
    487 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    488 
    489 	case WSDISPLAYIO_SCURSOR:
    490 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    491 	}
    492 	return (ENOTTY);
    493 }
    494 
    495 int
    496 tfbmmap(v, offset, prot)
    497 	void *v;
    498 	off_t offset;
    499 	int prot;
    500 {
    501 	struct tfb_softc *sc = v;
    502 
    503 	if (offset >= TX_8FB_SIZE || offset < 0)
    504 		return (-1);
    505 	return machine_btop(sc->sc_dc->dc_paddr + TX_8FB_OFFSET + offset);
    506 }
    507 
    508 int
    509 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    510 	void *v;
    511 	const struct wsscreen_descr *type;
    512 	void **cookiep;
    513 	int *curxp, *curyp;
    514 	long *attrp;
    515 {
    516 	struct tfb_softc *sc = v;
    517 	long defattr;
    518 
    519 	if (sc->nscreens > 0)
    520 		return (ENOMEM);
    521 
    522 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    523 	*curxp = 0;
    524 	*curyp = 0;
    525 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    526 	*attrp = defattr;
    527 	sc->nscreens++;
    528 	return (0);
    529 }
    530 
    531 void
    532 tfb_free_screen(v, cookie)
    533 	void *v;
    534 	void *cookie;
    535 {
    536 	struct tfb_softc *sc = v;
    537 
    538 	if (sc->sc_dc == &tfb_console_dc)
    539 		panic("tfb_free_screen: console");
    540 
    541 	sc->nscreens--;
    542 }
    543 
    544 void
    545 tfb_show_screen(v, cookie)
    546 	void *v;
    547 	void *cookie;
    548 {
    549 }
    550 
    551 int
    552 tfb_cnattach(addr)
    553         tc_addr_t addr;
    554 {
    555         struct fb_devconfig *dcp = &tfb_console_dc;
    556         long defattr;
    557 
    558         tfb_getdevconfig(addr, dcp);
    559 
    560         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    561 
    562         wsdisplay_cnattach(&tfb_stdscreen, &dcp->dc_rcons,
    563                            0, 0, defattr);
    564         tfb_consaddr = addr;
    565         return(0);
    566 }
    567 
    568 int
    569 tfbintr(arg)
    570 	void *arg;
    571 {
    572 	struct tfb_softc *sc = arg;
    573 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    574 	void *vdac, *curs;
    575 	int v;
    576 
    577 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
    578 	if (sc->sc_changed == 0)
    579 		goto done;
    580 
    581 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    582 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
    583 	v = sc->sc_changed;
    584 	sc->sc_changed = 0;
    585 	if (v & DATA_ENB_CHANGED) {
    586 		SELECT431(curs, BT431_REG_COMMAND);
    587 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
    588 	}
    589 	if (v & DATA_CURCMAP_CHANGED) {
    590 		u_int8_t *cp = sc->sc_cursor.cc_color;
    591 
    592 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
    593 #if 0
    594 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    595 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    596 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    597 
    598 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    599 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    600 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    601 
    602 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    603 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    604 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    605 
    606 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    607 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    608 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    609 #else
    610 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    611 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    612 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    613 
    614 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    615 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    616 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    617 
    618 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    619 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    620 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    621 
    622 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    623 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    624 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    625 #endif
    626 	}
    627 	if (v & DATA_CURSHAPE_CHANGED) {
    628 		u_int8_t *ip, *mp, img, msk;
    629 		int bcnt;
    630 
    631 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    632 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    633 		bcnt = 0;
    634 		SELECT431(curs, BT431_REG_CRAM_BASE);
    635 
    636 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    637 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    638 			/* pad right half 32 pixel when smaller than 33 */
    639 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    640 				HALF(curs, bt_ram) = 0;
    641 				tc_wmb();
    642 			}
    643 			else {
    644 				img = *ip++;
    645 				msk = *mp++;
    646 				img &= msk;	/* cookie off image */
    647 				HALF(curs, bt_ram)
    648 				    = (flip[msk] << 8) | flip[img];
    649 				tc_wmb();
    650 			}
    651 			bcnt += 2;
    652 		}
    653 		/* pad unoccupied scan lines */
    654 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    655 			HALF(curs, bt_ram) = 0;
    656 			tc_wmb();
    657 			bcnt += 2;
    658 		}
    659 	}
    660 	if (v & DATA_CMAP_CHANGED) {
    661 		struct hwcmap256 *cm = &sc->sc_cmap;
    662 		int index;
    663 
    664 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    665 		for (index = 0; index < CMAP_SIZE; index++) {
    666 			BYTE(vdac, bt_cmap) = cm->r[index];
    667 			BYTE(vdac, bt_cmap) = cm->g[index];
    668 			BYTE(vdac, bt_cmap) = cm->b[index];
    669 		}
    670 	}
    671 done:
    672 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
    673 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
    674 	return (1);
    675 }
    676 
    677 void
    678 tfbinit(dc)
    679 	struct fb_devconfig *dc;
    680 {
    681 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
    682 	void *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    683 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    684 	int i;
    685 
    686 	SELECT463(vdac, BT463_IREG_COMMAND_0);
    687 	BYTE(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
    688 	BYTE(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
    689 	BYTE(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
    690 	BYTE(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
    691 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
    692 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
    693 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
    694 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
    695 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
    696 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
    697 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
    698 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
    699 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();
    700 
    701 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
    702   {
    703 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
    704 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    705 	};
    706 
    707 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    708 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    709 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
    710 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
    711 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
    712 	}
    713   }
    714 #endif
    715 
    716 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    717 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    718 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    719 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    720 	for (i = 1; i < 256; i++) {
    721 		BYTE(vdac, bt_cmap) = 0xff;	tc_wmb();
    722 		BYTE(vdac, bt_cmap) = 0xff;	tc_wmb();
    723 		BYTE(vdac, bt_cmap) = 0xff;	tc_wmb();
    724 	}
    725 
    726 	/* !? Eeeh !? */
    727 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
    728 	for (i = 0; i < 256; i++) {
    729 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    730 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    731 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    732 	}
    733 
    734 	SELECT431(curs, BT431_REG_COMMAND);
    735 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
    736 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
    737 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
    738 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
    739 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
    740 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
    741 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
    742 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    743 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    744 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
    745 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
    746 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
    747 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
    748 
    749 	SELECT431(curs, BT431_REG_CRAM_BASE);
    750 	for (i = 0; i < 512; i++) {
    751 		HALF(curs, bt_ram) = 0;	tc_wmb();
    752 	}
    753 }
    754 
    755 static int
    756 get_cmap(sc, p)
    757 	struct tfb_softc *sc;
    758 	struct wsdisplay_cmap *p;
    759 {
    760 	u_int index = p->index, count = p->count;
    761 
    762 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    763 		return (EINVAL);
    764 
    765 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    766 	    !uvm_useracc(p->green, count, B_WRITE) ||
    767 	    !uvm_useracc(p->blue, count, B_WRITE))
    768 		return (EFAULT);
    769 
    770 	copyout(&sc->sc_cmap.r[index], p->red, count);
    771 	copyout(&sc->sc_cmap.g[index], p->green, count);
    772 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    773 
    774 	return (0);
    775 }
    776 
    777 static int
    778 set_cmap(sc, p)
    779 	struct tfb_softc *sc;
    780 	struct wsdisplay_cmap *p;
    781 {
    782 	u_int index = p->index, count = p->count;
    783 
    784 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    785 		return (EINVAL);
    786 
    787 	if (!uvm_useracc(p->red, count, B_READ) ||
    788 	    !uvm_useracc(p->green, count, B_READ) ||
    789 	    !uvm_useracc(p->blue, count, B_READ))
    790 		return (EFAULT);
    791 
    792 	copyin(p->red, &sc->sc_cmap.r[index], count);
    793 	copyin(p->green, &sc->sc_cmap.g[index], count);
    794 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    795 
    796 	sc->sc_changed |= DATA_CMAP_CHANGED;
    797 
    798 	return (0);
    799 }
    800 
    801 static int
    802 set_cursor(sc, p)
    803 	struct tfb_softc *sc;
    804 	struct wsdisplay_cursor *p;
    805 {
    806 #define	cc (&sc->sc_cursor)
    807 	int v, index, count, icount;
    808 
    809 	v = p->which;
    810 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    811 		index = p->cmap.index;
    812 		count = p->cmap.count;
    813 		if (index >= 2 || (index + count) > 2)
    814 			return (EINVAL);
    815 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    816 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    817 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    818 			return (EFAULT);
    819 	}
    820 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    821 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    822 			return (EINVAL);
    823 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    824 		if (!uvm_useracc(p->image, icount, B_READ) ||
    825 		    !uvm_useracc(p->mask, icount, B_READ))
    826 			return (EFAULT);
    827 	}
    828 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    829 		if (v & WSDISPLAY_CURSOR_DOCUR)
    830 			cc->cc_hot = p->hot;
    831 		if (v & WSDISPLAY_CURSOR_DOPOS)
    832 			set_curpos(sc, &p->pos);
    833 		bt431_set_curpos(sc);
    834 	}
    835 
    836 	sc->sc_changed = 0;
    837 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    838 		sc->sc_curenb = p->enable;
    839 		sc->sc_changed |= DATA_ENB_CHANGED;
    840 	}
    841 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    842 		copyin(p->cmap.red, &cc->cc_color[index], count);
    843 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    844 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    845 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    846 	}
    847 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    848 		cc->cc_size = p->size;
    849 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    850 		copyin(p->image, cc->cc_image, icount);
    851 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    852 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    853 	}
    854 
    855 	return (0);
    856 #undef cc
    857 }
    858 
    859 static int
    860 get_cursor(sc, p)
    861 	struct tfb_softc *sc;
    862 	struct wsdisplay_cursor *p;
    863 {
    864 	return (ENOTTY); /* XXX */
    865 }
    866 
    867 static void
    868 set_curpos(sc, curpos)
    869 	struct tfb_softc *sc;
    870 	struct wsdisplay_curpos *curpos;
    871 {
    872 	struct fb_devconfig *dc = sc->sc_dc;
    873 	int x = curpos->x, y = curpos->y;
    874 
    875 	if (y < 0)
    876 		y = 0;
    877 	else if (y > dc->dc_ht)
    878 		y = dc->dc_ht;
    879 	if (x < 0)
    880 		x = 0;
    881 	else if (x > dc->dc_wid)
    882 		x = dc->dc_wid;
    883 	sc->sc_cursor.cc_pos.x = x;
    884 	sc->sc_cursor.cc_pos.y = y;
    885 }
    886 
    887 void
    888 bt431_set_curpos(sc)
    889 	struct tfb_softc *sc;
    890 {
    891 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    892 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    893 	u_int16_t twin;
    894 	int x, y, s;
    895 
    896 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    897 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    898 
    899 	x += sc->sc_cursor.cc_magic.x;
    900 	y += sc->sc_cursor.cc_magic.y;
    901 
    902 	s = spltty();
    903 
    904 	SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    905 	HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
    906 	HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
    907 	HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
    908 	HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
    909 
    910 	splx(s);
    911 }
    912