Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.26
      1 /* $NetBSD: tfb.c,v 1.26 2000/06/28 17:05:24 mrg 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.26 2000/06/28 17:05:24 mrg 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 
     45 #include <machine/bus.h>
     46 #include <machine/intr.h>
     47 
     48 #include <dev/wscons/wsconsio.h>
     49 #include <dev/wscons/wsdisplayvar.h>
     50 
     51 #include <dev/rasops/rasops.h>
     52 #include <dev/wsfont/wsfont.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 mask
     79  *			u_int8_t u1;	for sprite image
     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 	int	    dc_blanked;		/* currently has video disabled */
    161 
    162 	struct rasops_info rinfo;
    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_8BPP_OFFSET	0x200000
    207 #define	TX_8BPP_SIZE	0x200000
    208 #define	TX_24BPP_OFFSET	0x400000
    209 #define	TX_24BPP_SIZE	0x600000
    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 static int  tfbmatch __P((struct device *, struct cfdata *, void *));
    219 static void tfbattach __P((struct device *, struct device *, void *));
    220 
    221 const struct cfattach tfb_ca = {
    222 	sizeof(struct tfb_softc), tfbmatch, tfbattach,
    223 };
    224 
    225 static void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    226 static struct fb_devconfig tfb_console_dc;
    227 static tc_addr_t tfb_consaddr;
    228 
    229 static struct wsscreen_descr tfb_stdscreen = {
    230 	"std", 0, 0,
    231 	0, /* textops */
    232 	0, 0,
    233 	WSSCREEN_REVERSE
    234 };
    235 
    236 static const struct wsscreen_descr *_tfb_scrlist[] = {
    237 	&tfb_stdscreen,
    238 };
    239 
    240 static const struct wsscreen_list tfb_screenlist = {
    241 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
    242 };
    243 
    244 static int	tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    245 static paddr_t	tfbmmap __P((void *, off_t, int));
    246 
    247 static int	tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    248 				      void **, int *, int *, long *));
    249 static void	tfb_free_screen __P((void *, void *));
    250 static int	tfb_show_screen __P((void *, void *, int,
    251 				     void (*) (void *, int, int), void *));
    252 
    253 static const struct wsdisplay_accessops tfb_accessops = {
    254 	tfbioctl,
    255 	tfbmmap,
    256 	tfb_alloc_screen,
    257 	tfb_free_screen,
    258 	tfb_show_screen,
    259 	0 /* load_font */
    260 };
    261 
    262 int  tfb_cnattach __P((tc_addr_t));
    263 static int  tfbintr __P((void *));
    264 static void tfbinit __P((struct fb_devconfig *));
    265 
    266 static int  get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    267 static int  set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    268 static int  set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    269 static int  get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    270 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
    271 static void bt431_set_curpos __P((struct tfb_softc *));
    272 
    273 /* bit order reverse */
    274 static const u_int8_t flip[256] = {
    275 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    276 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    277 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    278 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    279 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    280 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    281 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    282 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    283 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    284 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    285 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    286 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    287 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    288 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    289 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    290 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    291 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    292 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    293 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    294 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    295 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    296 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    297 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    298 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    299 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    300 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    301 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    302 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    303 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    304 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    305 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    306 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    307 };
    308 
    309 static int
    310 tfbmatch(parent, match, aux)
    311 	struct device *parent;
    312 	struct cfdata *match;
    313 	void *aux;
    314 {
    315 	struct tc_attach_args *ta = aux;
    316 
    317 	if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
    318 	    && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    319 		return (0);
    320 
    321 	return (1);
    322 }
    323 
    324 static void
    325 tfb_getdevconfig(dense_addr, dc)
    326 	tc_addr_t dense_addr;
    327 	struct fb_devconfig *dc;
    328 {
    329 	int i, cookie;
    330 
    331 	dc->dc_vaddr = dense_addr;
    332 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    333 
    334 	dc->dc_wid = 1280;
    335 	dc->dc_ht = 1024;
    336 	dc->dc_depth = 8;
    337 	dc->dc_rowbytes = 1280;
    338 	dc->dc_videobase = dc->dc_vaddr + TX_8BPP_OFFSET;
    339 	dc->dc_blanked = 0;
    340 
    341 	/* initialize colormap and cursor resource */
    342 	tfbinit(dc);
    343 
    344 	/* clear the screen */
    345 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    346 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    347 
    348 	dc->rinfo.ri_flg = RI_CENTER;
    349 	dc->rinfo.ri_depth = dc->dc_depth;
    350 	dc->rinfo.ri_bits = (void *)dc->dc_videobase;
    351 	dc->rinfo.ri_width = dc->dc_wid;
    352 	dc->rinfo.ri_height = dc->dc_ht;
    353 	dc->rinfo.ri_stride = dc->dc_rowbytes;
    354 
    355 	wsfont_init();
    356 	/* prefer 8 pixel wide font */
    357 	if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
    358 		cookie = wsfont_find(NULL, 0, 0, 0);
    359 	if (cookie <= 0) {
    360 		printf("tfb: font table is empty\n");
    361 		return;
    362 	}
    363 
    364 	if (wsfont_lock(cookie, &dc->rinfo.ri_font,
    365 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
    366 		printf("tfb: couldn't lock font\n");
    367 		return;
    368 	}
    369 	dc->rinfo.ri_wsfcookie = cookie;
    370 
    371 	rasops_init(&dc->rinfo, 34, 80);
    372 
    373 	/* XXX shouldn't be global */
    374 	tfb_stdscreen.nrows = dc->rinfo.ri_rows;
    375 	tfb_stdscreen.ncols = dc->rinfo.ri_cols;
    376 	tfb_stdscreen.textops = &dc->rinfo.ri_ops;
    377 	tfb_stdscreen.capabilities = dc->rinfo.ri_caps;
    378 }
    379 
    380 static 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 	int console;
    389 
    390 	console = (ta->ta_addr == tfb_consaddr);
    391 	if (console) {
    392 		sc->sc_dc = &tfb_console_dc;
    393 		sc->nscreens = 1;
    394 	}
    395 	else {
    396 		sc->sc_dc = (struct fb_devconfig *)
    397 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    398 		tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    399 	}
    400 	printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
    401 
    402 	memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256));
    403 
    404 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
    405 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
    406 
    407 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
    408 
    409 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
    410 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
    411 
    412 	waa.console = console;
    413 	waa.scrdata = &tfb_screenlist;
    414 	waa.accessops = &tfb_accessops;
    415 	waa.accesscookie = sc;
    416 
    417 	config_found(self, &waa, wsemuldisplaydevprint);
    418 }
    419 
    420 static int
    421 tfbioctl(v, cmd, data, flag, p)
    422 	void *v;
    423 	u_long cmd;
    424 	caddr_t data;
    425 	int flag;
    426 	struct proc *p;
    427 {
    428 	struct tfb_softc *sc = v;
    429 	struct fb_devconfig *dc = sc->sc_dc;
    430 	int turnoff;
    431 
    432 	switch (cmd) {
    433 	case WSDISPLAYIO_GTYPE:
    434 		*(u_int *)data = WSDISPLAY_TYPE_TX;
    435 		return (0);
    436 
    437 	case WSDISPLAYIO_GINFO:
    438 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    439 		wsd_fbip->height = sc->sc_dc->dc_ht;
    440 		wsd_fbip->width = sc->sc_dc->dc_wid;
    441 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    442 		wsd_fbip->cmsize = CMAP_SIZE;
    443 #undef fbt
    444 		return (0);
    445 
    446 	case WSDISPLAYIO_GETCMAP:
    447 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    448 
    449 	case WSDISPLAYIO_PUTCMAP:
    450 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    451 
    452 	case WSDISPLAYIO_SVIDEO:
    453 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    454 		if ((dc->dc_blanked == 0) ^ turnoff) {
    455 			dc->dc_blanked = turnoff;
    456 #if 0	/* XXX later XXX */
    457 	To turn off;
    458 	- clear the MSB of TX control register; &= ~0x80,
    459 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
    460 #endif	/* XXX XXX XXX */
    461 		}
    462 		return (0);
    463 
    464 	case WSDISPLAYIO_GVIDEO:
    465 		*(u_int *)data = dc->dc_blanked ?
    466 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    467 		return (0);
    468 
    469 	case WSDISPLAYIO_GCURPOS:
    470 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    471 		return (0);
    472 
    473 	case WSDISPLAYIO_SCURPOS:
    474 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    475 		bt431_set_curpos(sc);
    476 		return (0);
    477 
    478 	case WSDISPLAYIO_GCURMAX:
    479 		((struct wsdisplay_curpos *)data)->x =
    480 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    481 		return (0);
    482 
    483 	case WSDISPLAYIO_GCURSOR:
    484 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    485 
    486 	case WSDISPLAYIO_SCURSOR:
    487 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    488 	}
    489 	return (ENOTTY);
    490 }
    491 
    492 static paddr_t
    493 tfbmmap(v, offset, prot)
    494 	void *v;
    495 	off_t offset;
    496 	int prot;
    497 {
    498 	struct tfb_softc *sc = v;
    499 
    500 	if (offset >= TX_8BPP_SIZE || offset < 0)
    501 		return (-1);
    502 	return machine_btop(sc->sc_dc->dc_paddr + TX_8BPP_OFFSET + offset);
    503 }
    504 
    505 static int
    506 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    507 	void *v;
    508 	const struct wsscreen_descr *type;
    509 	void **cookiep;
    510 	int *curxp, *curyp;
    511 	long *attrp;
    512 {
    513 	struct tfb_softc *sc = v;
    514 	long defattr;
    515 
    516 	if (sc->nscreens > 0)
    517 		return (ENOMEM);
    518 
    519 	*cookiep = &sc->sc_dc->rinfo; /* one and only for now */
    520 	*curxp = 0;
    521 	*curyp = 0;
    522 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
    523 	*attrp = defattr;
    524 	sc->nscreens++;
    525 	return (0);
    526 }
    527 
    528 static void
    529 tfb_free_screen(v, cookie)
    530 	void *v;
    531 	void *cookie;
    532 {
    533 	struct tfb_softc *sc = v;
    534 
    535 	if (sc->sc_dc == &tfb_console_dc)
    536 		panic("tfb_free_screen: console");
    537 
    538 	sc->nscreens--;
    539 }
    540 
    541 static int
    542 tfb_show_screen(v, cookie, waitok, cb, cbarg)
    543 	void *v;
    544 	void *cookie;
    545 	int waitok;
    546 	void (*cb) __P((void *, int, int));
    547 	void *cbarg;
    548 {
    549 
    550 	return (0);
    551 }
    552 
    553 /* EXPORT */ int
    554 tfb_cnattach(addr)
    555 	tc_addr_t addr;
    556 {
    557 	struct fb_devconfig *dcp = &tfb_console_dc;
    558 	long defattr;
    559 
    560 	tfb_getdevconfig(addr, dcp);
    561 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
    562 	wsdisplay_cnattach(&tfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
    563 	tfb_consaddr = addr;
    564 	return (0);
    565 }
    566 
    567 static int
    568 tfbintr(arg)
    569 	void *arg;
    570 {
    571 	struct tfb_softc *sc = arg;
    572 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    573 	void *vdac, *curs;
    574 	int v;
    575 
    576 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
    577 	if (sc->sc_changed == 0)
    578 		goto done;
    579 
    580 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    581 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
    582 	v = sc->sc_changed;
    583 	sc->sc_changed = 0;
    584 	if (v & DATA_ENB_CHANGED) {
    585 		SELECT431(curs, BT431_REG_COMMAND);
    586 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
    587 	}
    588 	if (v & DATA_CURCMAP_CHANGED) {
    589 		u_int8_t *cp = sc->sc_cursor.cc_color;
    590 
    591 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
    592 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    593 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    594 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    595 
    596 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    597 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    598 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    599 
    600 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    601 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    602 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    603 
    604 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    605 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    606 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    607 	}
    608 	if (v & DATA_CURSHAPE_CHANGED) {
    609 		u_int8_t *ip, *mp, img, msk;
    610 		int bcnt;
    611 
    612 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    613 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    614 		bcnt = 0;
    615 		SELECT431(curs, BT431_REG_CRAM_BASE);
    616 
    617 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    618 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    619 			/* pad right half 32 pixel when smaller than 33 */
    620 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    621 				HALF(curs, bt_ram) = 0;
    622 				tc_wmb();
    623 			}
    624 			else {
    625 				img = *ip++;
    626 				msk = *mp++;
    627 				img &= msk;	/* cookie off image */
    628 				HALF(curs, bt_ram)
    629 				    = (flip[img] << 8) | flip[msk];
    630 				tc_wmb();
    631 			}
    632 			bcnt += 2;
    633 		}
    634 		/* pad unoccupied scan lines */
    635 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    636 			HALF(curs, bt_ram) = 0;
    637 			tc_wmb();
    638 			bcnt += 2;
    639 		}
    640 	}
    641 	if (v & DATA_CMAP_CHANGED) {
    642 		struct hwcmap256 *cm = &sc->sc_cmap;
    643 		int index;
    644 
    645 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    646 		for (index = 0; index < CMAP_SIZE; index++) {
    647 			BYTE(vdac, bt_cmap) = cm->r[index];
    648 			BYTE(vdac, bt_cmap) = cm->g[index];
    649 			BYTE(vdac, bt_cmap) = cm->b[index];
    650 		}
    651 	}
    652 done:
    653 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
    654 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
    655 	return (1);
    656 }
    657 
    658 static void
    659 tfbinit(dc)
    660 	struct fb_devconfig *dc;
    661 {
    662 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
    663 	void *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    664 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    665 	int i;
    666 
    667 	SELECT463(vdac, BT463_IREG_COMMAND_0);
    668 	BYTE(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
    669 	BYTE(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
    670 	BYTE(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
    671 	BYTE(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
    672 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
    673 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
    674 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
    675 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
    676 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
    677 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
    678 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
    679 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
    680 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();
    681 
    682 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
    683   {
    684 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
    685 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    686 	};
    687 
    688 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    689 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    690 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
    691 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
    692 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
    693 	}
    694   }
    695 #endif
    696 
    697 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    698 	for (i = 0; i < 256; i++) {
    699 		BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 0];
    700 		tc_wmb();
    701 		BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 1];
    702 		tc_wmb();
    703 		BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 2];
    704 		tc_wmb();
    705 	}
    706 
    707 	/* !? Eeeh !? */
    708 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
    709 	for (i = 0; i < 256; i++) {
    710 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    711 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    712 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    713 	}
    714 
    715 	SELECT431(curs, BT431_REG_COMMAND);
    716 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
    717 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
    718 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
    719 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
    720 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
    721 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
    722 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
    723 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    724 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    725 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
    726 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
    727 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
    728 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
    729 
    730 	SELECT431(curs, BT431_REG_CRAM_BASE);
    731 	for (i = 0; i < 512; i++) {
    732 		HALF(curs, bt_ram) = 0;	tc_wmb();
    733 	}
    734 }
    735 
    736 static int
    737 get_cmap(sc, p)
    738 	struct tfb_softc *sc;
    739 	struct wsdisplay_cmap *p;
    740 {
    741 	u_int index = p->index, count = p->count;
    742 
    743 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    744 		return (EINVAL);
    745 
    746 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    747 	    !uvm_useracc(p->green, count, B_WRITE) ||
    748 	    !uvm_useracc(p->blue, count, B_WRITE))
    749 		return (EFAULT);
    750 
    751 	copyout(&sc->sc_cmap.r[index], p->red, count);
    752 	copyout(&sc->sc_cmap.g[index], p->green, count);
    753 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    754 
    755 	return (0);
    756 }
    757 
    758 static int
    759 set_cmap(sc, p)
    760 	struct tfb_softc *sc;
    761 	struct wsdisplay_cmap *p;
    762 {
    763 	u_int index = p->index, count = p->count;
    764 
    765 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    766 		return (EINVAL);
    767 
    768 	if (!uvm_useracc(p->red, count, B_READ) ||
    769 	    !uvm_useracc(p->green, count, B_READ) ||
    770 	    !uvm_useracc(p->blue, count, B_READ))
    771 		return (EFAULT);
    772 
    773 	copyin(p->red, &sc->sc_cmap.r[index], count);
    774 	copyin(p->green, &sc->sc_cmap.g[index], count);
    775 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    776 
    777 	sc->sc_changed |= DATA_CMAP_CHANGED;
    778 
    779 	return (0);
    780 }
    781 
    782 static int
    783 set_cursor(sc, p)
    784 	struct tfb_softc *sc;
    785 	struct wsdisplay_cursor *p;
    786 {
    787 #define	cc (&sc->sc_cursor)
    788 	int v, index, count, icount;
    789 
    790 	v = p->which;
    791 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    792 		index = p->cmap.index;
    793 		count = p->cmap.count;
    794 		if (index >= 2 || (index + count) > 2)
    795 			return (EINVAL);
    796 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    797 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    798 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    799 			return (EFAULT);
    800 	}
    801 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    802 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    803 			return (EINVAL);
    804 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    805 		if (!uvm_useracc(p->image, icount, B_READ) ||
    806 		    !uvm_useracc(p->mask, icount, B_READ))
    807 			return (EFAULT);
    808 	}
    809 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    810 		if (v & WSDISPLAY_CURSOR_DOCUR)
    811 			cc->cc_hot = p->hot;
    812 		if (v & WSDISPLAY_CURSOR_DOPOS)
    813 			set_curpos(sc, &p->pos);
    814 		bt431_set_curpos(sc);
    815 	}
    816 
    817 	sc->sc_changed = 0;
    818 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    819 		sc->sc_curenb = p->enable;
    820 		sc->sc_changed |= DATA_ENB_CHANGED;
    821 	}
    822 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    823 		copyin(p->cmap.red, &cc->cc_color[index], count);
    824 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    825 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    826 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    827 	}
    828 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    829 		cc->cc_size = p->size;
    830 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    831 		copyin(p->image, cc->cc_image, icount);
    832 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    833 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    834 	}
    835 
    836 	return (0);
    837 #undef cc
    838 }
    839 
    840 static int
    841 get_cursor(sc, p)
    842 	struct tfb_softc *sc;
    843 	struct wsdisplay_cursor *p;
    844 {
    845 	return (ENOTTY); /* XXX */
    846 }
    847 
    848 static void
    849 set_curpos(sc, curpos)
    850 	struct tfb_softc *sc;
    851 	struct wsdisplay_curpos *curpos;
    852 {
    853 	struct fb_devconfig *dc = sc->sc_dc;
    854 	int x = curpos->x, y = curpos->y;
    855 
    856 	if (y < 0)
    857 		y = 0;
    858 	else if (y > dc->dc_ht)
    859 		y = dc->dc_ht;
    860 	if (x < 0)
    861 		x = 0;
    862 	else if (x > dc->dc_wid)
    863 		x = dc->dc_wid;
    864 	sc->sc_cursor.cc_pos.x = x;
    865 	sc->sc_cursor.cc_pos.y = y;
    866 }
    867 
    868 static void
    869 bt431_set_curpos(sc)
    870 	struct tfb_softc *sc;
    871 {
    872 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    873 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    874 	u_int16_t twin;
    875 	int x, y, s;
    876 
    877 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    878 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    879 
    880 	x += sc->sc_cursor.cc_magic.x;
    881 	y += sc->sc_cursor.cc_magic.y;
    882 
    883 	s = spltty();
    884 
    885 	SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    886 	HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
    887 	HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
    888 	HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
    889 	HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
    890 
    891 	splx(s);
    892 }
    893