Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.62
      1 /* $NetBSD: sfb.c,v 1.62 2003/12/17 03:59:33 ad 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>
     34 __KERNEL_RCSID(0, "$NetBSD: sfb.c,v 1.62 2003/12/17 03:59:33 ad Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/kernel.h>
     39 #include <sys/device.h>
     40 #include <sys/malloc.h>
     41 #include <sys/buf.h>
     42 #include <sys/ioctl.h>
     43 
     44 #include <machine/bus.h>
     45 #include <machine/intr.h>
     46 
     47 #include <dev/wscons/wsconsio.h>
     48 #include <dev/wscons/wsdisplayvar.h>
     49 
     50 #include <dev/rasops/rasops.h>
     51 #include <dev/wsfont/wsfont.h>
     52 
     53 #include <dev/tc/tcvar.h>
     54 #include <dev/ic/bt459reg.h>
     55 #include <dev/tc/sfbreg.h>
     56 
     57 #include <uvm/uvm_extern.h>
     58 
     59 #if defined(pmax)
     60 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
     61 #endif
     62 
     63 #if defined(alpha)
     64 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
     65 #endif
     66 
     67 /*
     68  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     69  * obscure register layout such as 2nd and 3rd Bt459 registers are
     70  * adjacent each other in a word, i.e.,
     71  *	struct bt459triplet {
     72  * 		struct {
     73  *			u_int8_t u0;
     74  *			u_int8_t u1;
     75  *			u_int8_t u2;
     76  *			unsigned :8;
     77  *		} bt_lo;
     78  *
     79  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
     80  *	struct bt459reg {
     81  *		   u_int32_t	   bt_lo;
     82  *		   u_int32_t	   bt_hi;
     83  *		   u_int32_t	   bt_reg;
     84  *		   u_int32_t	   bt_cmap;
     85  *	};
     86  */
     87 
     88 /* Bt459 hardware registers */
     89 #define	bt_lo	0
     90 #define	bt_hi	1
     91 #define	bt_reg	2
     92 #define	bt_cmap 3
     93 
     94 #define	REG(base, index)	*((u_int32_t *)(base) + (index))
     95 #define	SELECT(vdac, regno) do {			\
     96 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
     97 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
     98 	tc_wmb();					\
     99    } while (0)
    100 
    101 struct hwcmap256 {
    102 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    103 	u_int8_t r[CMAP_SIZE];
    104 	u_int8_t g[CMAP_SIZE];
    105 	u_int8_t b[CMAP_SIZE];
    106 };
    107 
    108 struct hwcursor64 {
    109 	struct wsdisplay_curpos cc_pos;
    110 	struct wsdisplay_curpos cc_hot;
    111 	struct wsdisplay_curpos cc_size;
    112 	struct wsdisplay_curpos cc_magic;
    113 #define	CURSOR_MAX_SIZE	64
    114 	u_int8_t cc_color[6];
    115 	u_int64_t cc_image[CURSOR_MAX_SIZE];
    116 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
    117 };
    118 
    119 struct sfb_softc {
    120 	struct device sc_dev;
    121 	vaddr_t sc_vaddr;
    122 	size_t sc_size;
    123 	struct rasops_info *sc_ri;
    124 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    125 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    126 	int sc_blanked;			/* video visibility disabled */
    127 	int sc_curenb;			/* cursor sprite enabled */
    128 	int sc_changed;			/* need update of hardware */
    129 #define	WSDISPLAY_CMAP_DOLUT	0x20
    130 	int nscreens;
    131 };
    132 
    133 #define	HX_MAGIC_X	368
    134 #define	HX_MAGIC_Y	38
    135 
    136 static int  sfbmatch __P((struct device *, struct cfdata *, void *));
    137 static void sfbattach __P((struct device *, struct device *, void *));
    138 
    139 CFATTACH_DECL(sfb, sizeof(struct sfb_softc),
    140     sfbmatch, sfbattach, NULL, NULL);
    141 
    142 static void sfb_common_init __P((struct rasops_info *));
    143 static struct rasops_info sfb_console_ri;
    144 static tc_addr_t sfb_consaddr;
    145 
    146 static void sfb_putchar __P((void *, int, int, u_int, long));
    147 static void sfb_erasecols __P((void *, int, int, int, long));
    148 static void sfb_eraserows __P((void *, int, int, long));
    149 static void sfb_copyrows __P((void *, int, int, int));
    150 static void sfb_do_cursor __P((struct rasops_info *));
    151 #if 0
    152 static void sfb_copycols __P((void *, int, int, int, int));
    153 #endif
    154 
    155 static struct wsscreen_descr sfb_stdscreen = {
    156 	"std", 0, 0,
    157 	0, /* textops */
    158 	0, 0,
    159 	WSSCREEN_REVERSE
    160 };
    161 
    162 static const struct wsscreen_descr *_sfb_scrlist[] = {
    163 	&sfb_stdscreen,
    164 };
    165 
    166 static const struct wsscreen_list sfb_screenlist = {
    167 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
    168 };
    169 
    170 static int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    171 static paddr_t	sfbmmap __P((void *, off_t, int));
    172 
    173 static int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    174 				      void **, int *, int *, long *));
    175 static void	sfb_free_screen __P((void *, void *));
    176 static int	sfb_show_screen __P((void *, void *, int,
    177 				     void (*) (void *, int, int), void *));
    178 
    179 static const struct wsdisplay_accessops sfb_accessops = {
    180 	sfbioctl,
    181 	sfbmmap,
    182 	sfb_alloc_screen,
    183 	sfb_free_screen,
    184 	sfb_show_screen,
    185 	0 /* load_font */
    186 };
    187 
    188 int  sfb_cnattach __P((tc_addr_t));
    189 static int  sfbintr __P((void *));
    190 static void sfbhwinit __P((caddr_t));
    191 static void sfb_cmap_init __P((struct sfb_softc *));
    192 static void sfb_screenblank __P((struct sfb_softc *, int));
    193 
    194 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    195 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
    196 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    197 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
    198 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
    199 
    200 /*
    201  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    202  *   M M M M I I I I		M I M I M I M I
    203  *	[ before ]		   [ after ]
    204  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    205  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    206  */
    207 static const u_int8_t shuffle[256] = {
    208 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    209 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    210 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    211 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    212 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    213 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    214 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    215 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    216 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    217 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    218 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    219 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    220 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    221 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    222 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    223 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    224 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    225 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    226 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    227 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    228 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    229 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    230 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    231 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    232 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    233 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    234 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    235 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    236 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    237 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    238 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    239 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    240 };
    241 
    242 static int
    243 sfbmatch(parent, match, aux)
    244 	struct device *parent;
    245 	struct cfdata *match;
    246 	void *aux;
    247 {
    248 	struct tc_attach_args *ta = aux;
    249 
    250 	if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
    251 		return (0);
    252 	return (1);
    253 }
    254 
    255 static void
    256 sfbattach(parent, self, aux)
    257 	struct device *parent, *self;
    258 	void *aux;
    259 {
    260 	struct sfb_softc *sc = (struct sfb_softc *)self;
    261 	struct tc_attach_args *ta = aux;
    262 	struct rasops_info *ri;
    263 	struct wsemuldisplaydev_attach_args waa;
    264 	caddr_t asic;
    265 	int console;
    266 
    267 	console = (ta->ta_addr == sfb_consaddr);
    268 	if (console) {
    269 		sc->sc_ri = ri = &sfb_console_ri;
    270 		sc->nscreens = 1;
    271 	}
    272 	else {
    273 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    274 			M_DEVBUF, M_NOWAIT);
    275 		if (ri == NULL) {
    276 			printf(": can't alloc memory\n");
    277 			return;
    278 		}
    279 		memset(ri, 0, sizeof(struct rasops_info));
    280 
    281 		ri->ri_hw = (void *)ta->ta_addr;
    282 		sfb_common_init(ri);
    283 		sc->sc_ri = ri;
    284 	}
    285 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    286 
    287 	sfb_cmap_init(sc);
    288 
    289 	sc->sc_vaddr = ta->ta_addr;
    290 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
    291 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
    292 	sc->sc_blanked = sc->sc_curenb = 0;
    293 
    294 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
    295 
    296 	asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    297 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
    298 	*(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
    299 
    300 	waa.console = console;
    301 	waa.scrdata = &sfb_screenlist;
    302 	waa.accessops = &sfb_accessops;
    303 	waa.accesscookie = sc;
    304 
    305 	config_found(self, &waa, wsemuldisplaydevprint);
    306 }
    307 
    308 static void
    309 sfb_cmap_init(sc)
    310 	struct sfb_softc *sc;
    311 {
    312 	struct hwcmap256 *cm;
    313 	const u_int8_t *p;
    314 	int index;
    315 
    316 	cm = &sc->sc_cmap;
    317 	p = rasops_cmap;
    318 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    319 		cm->r[index] = p[0];
    320 		cm->g[index] = p[1];
    321 		cm->b[index] = p[2];
    322 	}
    323 }
    324 
    325 static void
    326 sfb_common_init(ri)
    327 	struct rasops_info *ri;
    328 {
    329 	caddr_t base, asic;
    330 	int hsetup, vsetup, vbase, cookie;
    331 
    332 	base = (caddr_t)ri->ri_hw;
    333 	asic = base + SFB_ASIC_OFFSET;
    334 	hsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
    335 	vsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
    336 
    337 	*(u_int32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
    338 	*(u_int32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
    339 	*(u_int32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
    340 	*(u_int32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
    341 	*(u_int32_t *)(asic + SFB_ASIC_ROP) = 3; 	/* ROP_COPY */
    342 	*(u_int32_t *)(asic + 0x180000) = 0; 		/* Bt459 reset */
    343 
    344 	/* initialize colormap and cursor hardware */
    345 	sfbhwinit(base);
    346 
    347 	ri->ri_flg = RI_CENTER;
    348 	ri->ri_depth = 8;
    349 	ri->ri_width = (hsetup & 0x1ff) << 2;
    350 	ri->ri_height = (vsetup & 0x7ff);
    351 	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
    352 	ri->ri_bits = base + SFB_FB_OFFSET + vbase * 4096;
    353 
    354 	/* clear the screen */
    355 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    356 
    357 	wsfont_init();
    358 	/* prefer 12 pixel wide font */
    359 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
    360 	    WSDISPLAY_FONTORDER_L2R);
    361 	if (cookie <= 0)
    362 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
    363 		    WSDISPLAY_FONTORDER_L2R);
    364 	if (cookie <= 0) {
    365 		printf("sfb: font table is empty\n");
    366 		return;
    367 	}
    368 
    369 	/* the accelerated sfb_putchar() needs LSbit left */
    370 	if (wsfont_lock(cookie, &ri->ri_font)) {
    371 		printf("sfb: couldn't lock font\n");
    372 		return;
    373 	}
    374 	ri->ri_wsfcookie = cookie;
    375 
    376 	rasops_init(ri, 34, 80);
    377 
    378 	/* add our accelerated functions */
    379 	ri->ri_ops.putchar = sfb_putchar;
    380 	ri->ri_ops.erasecols = sfb_erasecols;
    381 	ri->ri_ops.copyrows = sfb_copyrows;
    382 	ri->ri_ops.eraserows = sfb_eraserows;
    383 	ri->ri_do_cursor = sfb_do_cursor;
    384 
    385 	/* XXX shouldn't be global */
    386 	sfb_stdscreen.nrows = ri->ri_rows;
    387 	sfb_stdscreen.ncols = ri->ri_cols;
    388 	sfb_stdscreen.textops = &ri->ri_ops;
    389 	sfb_stdscreen.capabilities = ri->ri_caps;
    390 }
    391 
    392 static int
    393 sfbioctl(v, cmd, data, flag, p)
    394 	void *v;
    395 	u_long cmd;
    396 	caddr_t data;
    397 	int flag;
    398 	struct proc *p;
    399 {
    400 	struct sfb_softc *sc = v;
    401 	struct rasops_info *ri = sc->sc_ri;
    402 	int turnoff, s;
    403 
    404 	switch (cmd) {
    405 	case WSDISPLAYIO_GTYPE:
    406 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
    407 		return (0);
    408 
    409 	case WSDISPLAYIO_GINFO:
    410 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    411 		wsd_fbip->height = ri->ri_height;
    412 		wsd_fbip->width = ri->ri_width;
    413 		wsd_fbip->depth = ri->ri_depth;
    414 		wsd_fbip->cmsize = CMAP_SIZE;
    415 #undef fbt
    416 		return (0);
    417 
    418 	case WSDISPLAYIO_GETCMAP:
    419 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    420 
    421 	case WSDISPLAYIO_PUTCMAP:
    422 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    423 
    424 	case WSDISPLAYIO_SVIDEO:
    425 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    426 		sfb_screenblank(sc, turnoff);
    427 		return (0);
    428 
    429 	case WSDISPLAYIO_GVIDEO:
    430 		*(u_int *)data = sc->sc_blanked ?
    431 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    432 		return (0);
    433 
    434 	case WSDISPLAYIO_GCURPOS:
    435 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    436 		return (0);
    437 
    438 	case WSDISPLAYIO_SCURPOS:
    439 		s = spltty();
    440 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    441 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    442 		splx(s);
    443 		return (0);
    444 
    445 	case WSDISPLAYIO_GCURMAX:
    446 		((struct wsdisplay_curpos *)data)->x =
    447 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    448 		return (0);
    449 
    450 	case WSDISPLAYIO_GCURSOR:
    451 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    452 
    453 	case WSDISPLAYIO_SCURSOR:
    454 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    455 
    456 	case WSDISPLAYIO_SMODE:
    457 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    458 			s = spltty();
    459 			sfb_cmap_init(sc);
    460 			sc->sc_curenb = 0;
    461 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
    462 			    WSDISPLAY_CMAP_DOLUT);
    463 			splx(s);
    464 			sfb_screenblank(sc, 0);
    465 		}
    466 		return (0);
    467 	}
    468 	return (EPASSTHROUGH);
    469 }
    470 
    471 static void
    472 sfb_screenblank(sc, turnoff)
    473 	struct sfb_softc *sc;
    474 	int turnoff;
    475 {
    476 	struct rasops_info *ri;
    477 	caddr_t asic;
    478 
    479 	ri = sc->sc_ri;
    480 	asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    481 	*(u_int32_t *)(asic + SFB_ASIC_VIDEO_VALID) = !turnoff;
    482 	tc_wmb();
    483 	sc->sc_blanked = turnoff;
    484 }
    485 
    486 static paddr_t
    487 sfbmmap(v, offset, prot)
    488 	void *v;
    489 	off_t offset;
    490 	int prot;
    491 {
    492 	struct sfb_softc *sc = v;
    493 
    494 	if (offset >= SFB_SIZE || offset < 0)
    495 		return (-1);
    496 	return machine_btop(sc->sc_vaddr + offset);
    497 }
    498 
    499 static int
    500 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    501 	void *v;
    502 	const struct wsscreen_descr *type;
    503 	void **cookiep;
    504 	int *curxp, *curyp;
    505 	long *attrp;
    506 {
    507 	struct sfb_softc *sc = v;
    508 	struct rasops_info *ri = sc->sc_ri;
    509 	long defattr;
    510 
    511 	if (sc->nscreens > 0)
    512 		return (ENOMEM);
    513 
    514 	*cookiep = ri;	 /* one and only for now */
    515 	*curxp = 0;
    516 	*curyp = 0;
    517 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    518 	*attrp = defattr;
    519 	sc->nscreens++;
    520 	return (0);
    521 }
    522 
    523 static void
    524 sfb_free_screen(v, cookie)
    525 	void *v;
    526 	void *cookie;
    527 {
    528 	struct sfb_softc *sc = v;
    529 
    530 	if (sc->sc_ri == &sfb_console_ri)
    531 		panic("sfb_free_screen: console");
    532 
    533 	sc->nscreens--;
    534 }
    535 
    536 static int
    537 sfb_show_screen(v, cookie, waitok, cb, cbarg)
    538 	void *v;
    539 	void *cookie;
    540 	int waitok;
    541 	void (*cb) __P((void *, int, int));
    542 	void *cbarg;
    543 {
    544 
    545 	return (0);
    546 }
    547 
    548 /* EXPORT */ int
    549 sfb_cnattach(addr)
    550 	tc_addr_t addr;
    551 {
    552 	struct rasops_info *ri;
    553 	long defattr;
    554 
    555 	ri = &sfb_console_ri;
    556 	ri->ri_hw = (void *)addr;
    557 	sfb_common_init(ri);
    558 	(*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
    559 	wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
    560 	sfb_consaddr = addr;
    561 	return (0);
    562 }
    563 
    564 static int
    565 sfbintr(arg)
    566 	void *arg;
    567 {
    568 	struct sfb_softc *sc = arg;
    569 	caddr_t base, asic, vdac;
    570 	int v;
    571 
    572 	base = (caddr_t)sc->sc_ri->ri_hw;
    573 	asic = base + SFB_ASIC_OFFSET;
    574 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
    575 	/* *(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1; */
    576 
    577 	if (sc->sc_changed == 0)
    578 		goto done;
    579 
    580 	vdac = base + SFB_RAMDAC_OFFSET;
    581 	v = sc->sc_changed;
    582 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    583 		SELECT(vdac, BT459_IREG_CCR);
    584 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
    585 	}
    586 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    587 		int x, y;
    588 
    589 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    590 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    591 		x += sc->sc_cursor.cc_magic.x;
    592 		y += sc->sc_cursor.cc_magic.y;
    593 
    594 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
    595 		REG(vdac, bt_reg) = x;		tc_wmb();
    596 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
    597 		REG(vdac, bt_reg) = y;		tc_wmb();
    598 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
    599 	}
    600 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    601 		u_int8_t *cp = sc->sc_cursor.cc_color;
    602 
    603 		SELECT(vdac, BT459_IREG_CCOLOR_2);
    604 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
    605 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
    606 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
    607 
    608 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
    609 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
    610 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
    611 	}
    612 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    613 		u_int8_t *ip, *mp, img, msk;
    614 		u_int8_t u;
    615 		int bcnt;
    616 
    617 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    618 		mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    619 
    620 		bcnt = 0;
    621 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
    622 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    623 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    624 			/* pad right half 32 pixel when smaller than 33 */
    625 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    626 				REG(vdac, bt_reg) = 0; tc_wmb();
    627 				REG(vdac, bt_reg) = 0; tc_wmb();
    628 			}
    629 			else {
    630 				img = *ip++;
    631 				msk = *mp++;
    632 				img &= msk;	/* cookie off image */
    633 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    634 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    635 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    636 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    637 			}
    638 			bcnt += 2;
    639 		}
    640 		/* pad unoccupied scan lines */
    641 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    642 			REG(vdac, bt_reg) = 0; tc_wmb();
    643 			REG(vdac, bt_reg) = 0; tc_wmb();
    644 			bcnt += 2;
    645 		}
    646 	}
    647 	if (v & WSDISPLAY_CMAP_DOLUT) {
    648 		struct hwcmap256 *cm = &sc->sc_cmap;
    649 		int index;
    650 
    651 		SELECT(vdac, 0);
    652 		for (index = 0; index < CMAP_SIZE; index++) {
    653 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
    654 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
    655 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
    656 		}
    657 	}
    658 	sc->sc_changed = 0;
    659 done:
    660 	return (1);
    661 }
    662 
    663 static void
    664 sfbhwinit(base)
    665 	caddr_t base;
    666 {
    667 	caddr_t vdac = base + SFB_RAMDAC_OFFSET;
    668 	const u_int8_t *p;
    669 	int i;
    670 
    671 	SELECT(vdac, BT459_IREG_COMMAND_0);
    672 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
    673 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
    674 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
    675 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
    676 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
    677 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
    678 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
    679 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
    680 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
    681 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
    682 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
    683 
    684 	SELECT(vdac, BT459_IREG_CCR);
    685 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    686 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    687 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    688 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    689 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    690 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    691 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    692 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    693 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    694 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    695 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    696 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    697 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    698 
    699 	/* build sane colormap */
    700 	SELECT(vdac, 0);
    701 	p = rasops_cmap;
    702 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    703 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
    704 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
    705 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
    706 	}
    707 
    708 	/* clear out cursor image */
    709 	SELECT(vdac, BT459_IREG_CRAM_BASE);
    710 	for (i = 0; i < 1024; i++)
    711 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
    712 
    713 	/*
    714 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    715 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    716 	 * image color.  CCOLOR_1 will be never used.
    717 	 */
    718 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    719 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    720 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    721 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    722 
    723 	REG(vdac, bt_reg) = 0;		tc_wmb();
    724 	REG(vdac, bt_reg) = 0;		tc_wmb();
    725 	REG(vdac, bt_reg) = 0;		tc_wmb();
    726 
    727 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    728 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    729 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    730 }
    731 
    732 static int
    733 get_cmap(sc, p)
    734 	struct sfb_softc *sc;
    735 	struct wsdisplay_cmap *p;
    736 {
    737 	u_int index = p->index, count = p->count;
    738 	int error;
    739 
    740 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    741 		return (EINVAL);
    742 
    743 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
    744 	if (error)
    745 		return error;
    746 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
    747 	if (error)
    748 		return error;
    749 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
    750 	return error;
    751 }
    752 
    753 static int
    754 set_cmap(sc, p)
    755 	struct sfb_softc *sc;
    756 	struct wsdisplay_cmap *p;
    757 {
    758 	struct hwcmap256 cmap;
    759 	u_int index = p->index, count = p->count;
    760 	int error, s;
    761 
    762 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    763 		return (EINVAL);
    764 
    765 	error = copyin(p->red, &cmap.r[index], count);
    766 	if (error)
    767 		return error;
    768 	error = copyin(p->green, &cmap.g[index], count);
    769 	if (error)
    770 		return error;
    771 	error = copyin(p->blue, &cmap.b[index], count);
    772 	if (error)
    773 		return error;
    774 
    775 	s = spltty();
    776 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
    777 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
    778 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
    779 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    780 	splx(s);
    781 	return (0);
    782 }
    783 
    784 static int
    785 set_cursor(sc, p)
    786 	struct sfb_softc *sc;
    787 	struct wsdisplay_cursor *p;
    788 {
    789 #define	cc (&sc->sc_cursor)
    790 	u_int v, index = 0, count = 0, icount = 0;
    791 	uint8_t r[2], g[2], b[2], image[512], mask[512];
    792 	int error, s;
    793 
    794 	v = p->which;
    795 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    796 		index = p->cmap.index;
    797 		count = p->cmap.count;
    798 		if (index >= 2 || (index + count) > 2)
    799 			return (EINVAL);
    800 		error = copyin(p->cmap.red, &r[index], count);
    801 		if (error)
    802 			return error;
    803 		error = copyin(p->cmap.green, &g[index], count);
    804 		if (error)
    805 			return error;
    806 		error = copyin(p->cmap.blue, &b[index], count);
    807 		if (error)
    808 			return error;
    809 	}
    810 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    811 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    812 			return (EINVAL);
    813 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    814 		error = copyin(p->image, image, icount);
    815 		if (error)
    816 			return error;
    817 		error = copyin(p->mask, mask, icount);
    818 		if (error)
    819 			return error;
    820 	}
    821 
    822 	s = spltty();
    823 	if (v & WSDISPLAY_CURSOR_DOCUR)
    824 		sc->sc_curenb = p->enable;
    825 	if (v & WSDISPLAY_CURSOR_DOPOS)
    826 		set_curpos(sc, &p->pos);
    827 	if (v & WSDISPLAY_CURSOR_DOHOT)
    828 		cc->cc_hot = p->hot;
    829 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    830 		memcpy(&cc->cc_color[index], &r[index], count);
    831 		memcpy(&cc->cc_color[index + 2], &g[index], count);
    832 		memcpy(&cc->cc_color[index + 4], &b[index], count);
    833 	}
    834 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    835 		cc->cc_size = p->size;
    836 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    837 		memcpy(cc->cc_image, image, icount);
    838 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    839 		memcpy(cc->cc_mask, mask, icount);
    840 	}
    841 	sc->sc_changed |= v;
    842 	splx(s);
    843 
    844 	return (0);
    845 #undef cc
    846 }
    847 
    848 static int
    849 get_cursor(sc, p)
    850 	struct sfb_softc *sc;
    851 	struct wsdisplay_cursor *p;
    852 {
    853 
    854 	return (EPASSTHROUGH); /* XXX */
    855 }
    856 
    857 static void
    858 set_curpos(sc, curpos)
    859 	struct sfb_softc *sc;
    860 	struct wsdisplay_curpos *curpos;
    861 {
    862 	struct rasops_info *ri = sc->sc_ri;
    863 	int x = curpos->x, y = curpos->y;
    864 
    865 	if (y < 0)
    866 		y = 0;
    867 	else if (y > ri->ri_height);
    868 		y = ri->ri_height;
    869 	if (x < 0)
    870 		x = 0;
    871 	else if (x > ri->ri_width);
    872 		x = ri->ri_width;
    873 	sc->sc_cursor.cc_pos.x = x;
    874 	sc->sc_cursor.cc_pos.y = y;
    875 }
    876 
    877 #define	MODE_SIMPLE		0
    878 #define	MODE_OPAQUESTIPPLE	1
    879 #define	MODE_OPAQUELINE		2
    880 #define	MODE_TRANSPARENTSTIPPLE	5
    881 #define	MODE_TRANSPARENTLINE	6
    882 #define	MODE_COPY		7
    883 
    884 /* parameters for 8bpp configuration */
    885 #define	SFBALIGNMASK		0x7
    886 #define	SFBSTIPPLEALL1		0xffffffff
    887 #define	SFBSTIPPLEBITS		32
    888 #define	SFBSTIPPLEBITMASK	0x1f
    889 #define	SFBSTIPPLEBYTESDONE	32
    890 #define	SFBCOPYALL1		0xffffffff
    891 #define	SFBCOPYBITS		32
    892 #define	SFBCOPYBITMASK		0x1f
    893 #define	SFBCOPYBYTESDONE	32
    894 
    895 #if defined(pmax)
    896 #define	WRITE_MB()
    897 #define	BUMP(p) (p)
    898 #endif
    899 
    900 #if defined(alpha)
    901 #define	WRITE_MB() tc_wmb()
    902 /* SFB registers replicated in 128B stride; cycle after eight iterations */
    903 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x80) & ~0x400))
    904 #endif
    905 
    906 #define	SFBMODE(p, v) \
    907 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
    908 #define	SFBROP(p, v) \
    909 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
    910 #define	SFBPLANEMASK(p, v) \
    911 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
    912 #define	SFBPIXELMASK(p, v) \
    913 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
    914 #define	SFBADDRESS(p, v) \
    915 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
    916 #define	SFBSTART(p, v) \
    917 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
    918 #define	SFBPIXELSHIFT(p, v) \
    919 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
    920 #define	SFBFG(p, v) \
    921 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
    922 #define	SFBBG(p, v) \
    923 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
    924 
    925 /*
    926  * Paint the cursor.
    927  */
    928 static void
    929 sfb_do_cursor(ri)
    930 	struct rasops_info *ri;
    931 {
    932 	caddr_t sfb, p;
    933 	int scanspan, height, width, align, x, y;
    934 	u_int32_t lmask, rmask;
    935 
    936 	x = ri->ri_ccol * ri->ri_font->fontwidth;
    937 	y = ri->ri_crow * ri->ri_font->fontheight;
    938 	scanspan = ri->ri_stride;
    939 	height = ri->ri_font->fontheight;
    940 
    941 	p = ri->ri_bits + y * scanspan + x;
    942 	align = (long)p & SFBALIGNMASK;
    943 	p -= align;
    944 	width = ri->ri_font->fontwidth + align;
    945 	lmask = SFBSTIPPLEALL1 << align;
    946 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    947 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    948 
    949 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    950 	SFBPLANEMASK(sfb, ~0);
    951 	SFBROP(sfb, 6);  /* ROP_XOR */
    952 	SFBFG(sfb, ~0);
    953 
    954 	lmask = lmask & rmask;
    955 	while (height > 0) {
    956 		SFBADDRESS(sfb, (long)p);
    957 		SFBSTART(sfb, lmask);
    958 		p += scanspan;
    959 		height--;
    960 	}
    961 	SFBMODE(sfb, MODE_SIMPLE);
    962 	SFBROP(sfb, 3); /* ROP_COPY */
    963 }
    964 
    965 /*
    966  * Paint a character.
    967  */
    968 static void
    969 sfb_putchar(id, row, col, uc, attr)
    970 	void *id;
    971 	int row, col;
    972 	u_int uc;
    973 	long attr;
    974 {
    975 	struct rasops_info *ri = id;
    976 	caddr_t sfb, p;
    977 	int scanspan, height, width, align, x, y;
    978 	u_int32_t lmask, rmask, glyph;
    979 	u_int8_t *g;
    980 
    981 	x = col * ri->ri_font->fontwidth;
    982 	y = row * ri->ri_font->fontheight;
    983 	scanspan = ri->ri_stride;
    984 	height = ri->ri_font->fontheight;
    985 	uc -= ri->ri_font->firstchar;
    986 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
    987 
    988 	p = ri->ri_bits + y * scanspan + x;
    989 	align = (long)p & SFBALIGNMASK;
    990 	p -= align;
    991 	width = ri->ri_font->fontwidth + align;
    992 	lmask = SFBSTIPPLEALL1 << align;
    993 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    994 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    995 
    996 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
    997 	SFBPLANEMASK(sfb, ~0);
    998 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
    999 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
   1000 
   1001 	/* XXX 2B stride fonts only XXX */
   1002 	lmask = lmask & rmask;
   1003 	while (height > 0) {
   1004 		glyph = *(u_int16_t *)g;		/* XXX */
   1005 		SFBPIXELMASK(sfb, lmask);
   1006 		SFBADDRESS(sfb, (long)p);
   1007 		SFBSTART(sfb, glyph << align);
   1008 		p += scanspan;
   1009 		g += 2;					/* XXX */
   1010 		height--;
   1011 	}
   1012 	if (attr & 1 /* UNDERLINE */) {
   1013 		p -= scanspan * 2;
   1014 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1015 		SFBADDRESS(sfb, (long)p);
   1016 		SFBSTART(sfb, lmask);
   1017 	}
   1018 
   1019 	SFBMODE(sfb, MODE_SIMPLE);
   1020 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
   1021 }
   1022 
   1023 #if 0
   1024 /*
   1025  * Copy characters in a line.
   1026  */
   1027 static void
   1028 sfb_copycols(id, row, srccol, dstcol, ncols)
   1029 	void *id;
   1030 	int row, srccol, dstcol, ncols;
   1031 {
   1032 	struct rasops_info *ri = id;
   1033 	caddr_t sp, dp, basex, sfb;
   1034 	int scanspan, height, width, aligns, alignd, shift, w, y;
   1035 	u_int32_t lmaskd, rmaskd;
   1036 
   1037 	scanspan = ri->ri_stride;
   1038 	y = row * ri->ri_font->fontheight;
   1039 	basex = ri->ri_bits + y * scanspan;
   1040 	height = ri->ri_font->fontheight;
   1041 	w = ri->ri_font->fontwidth * ncols;
   1042 
   1043 	sp = basex + ri->ri_font->fontwidth * srccol;
   1044 	aligns = (long)sp & SFBALIGNMASK;
   1045 	dp = basex + ri->ri_font->fontwidth * dstcol;
   1046 	alignd = (long)dp & SFBALIGNMASK;
   1047 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1048 
   1049 	SFBMODE(sfb, MODE_COPY);
   1050 	SFBPLANEMASK(sfb, ~0);
   1051 	/* small enough to fit in a single 32bit */
   1052 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
   1053 		SFBPIXELSHIFT(sfb, alignd - aligns);
   1054 		lmaskd = SFBCOPYALL1 << alignd;
   1055 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
   1056 		lmaskd = lmaskd & rmaskd;
   1057 		sp -= aligns;
   1058 		dp -= alignd;
   1059 		while (height > 0) {
   1060 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1061 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1062 			sp += scanspan;
   1063 			dp += scanspan;
   1064 			height--;
   1065 		}
   1066 	}
   1067 	/* copy forward (left-to-right) */
   1068 	else if (dstcol < srccol || srccol + ncols < dstcol) {
   1069 		caddr_t sq, dq;
   1070 
   1071 		shift = alignd - aligns;
   1072 		if (shift < 0) {
   1073 			shift = 8 + shift;	/* enforce right rotate */
   1074 			alignd += 8;		/* bearing on left edge */
   1075 		}
   1076 		width = alignd + w;
   1077 		lmaskd = SFBCOPYALL1 << alignd;
   1078 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1079 		sp -= aligns;
   1080 		dp -= alignd;
   1081 
   1082 		SFBPIXELSHIFT(sfb, shift);
   1083 		w = width;
   1084 		sq = sp;
   1085 		dq = dp;
   1086 		while (height > 0) {
   1087 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1088 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1089 			width -= 2 * SFBCOPYBITS;
   1090 			while (width > 0) {
   1091 				sp += SFBCOPYBYTESDONE;
   1092 				dp += SFBCOPYBYTESDONE;
   1093 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1094 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1095 				width -= SFBCOPYBITS;
   1096 			}
   1097 			sp += SFBCOPYBYTESDONE;
   1098 			dp += SFBCOPYBYTESDONE;
   1099 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1100 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1101 			sp = (sq += scanspan);
   1102 			dp = (dq += scanspan);
   1103 			width = w;
   1104 			height--;
   1105 		}
   1106 	}
   1107 	/* copy backward (right-to-left) */
   1108 	else {
   1109 		caddr_t sq, dq;
   1110 
   1111 		shift = alignd - aligns;
   1112 		if (shift > 0) {
   1113 			shift = shift - 8;	/* force left rotate */
   1114 			alignd += 24;
   1115 		}
   1116 		width = alignd + w;
   1117 		lmaskd = SFBCOPYALL1 << alignd;
   1118 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1119 		sp -= aligns;
   1120 		dp -= alignd;
   1121 
   1122 		SFBPIXELSHIFT(sfb, shift);
   1123 		w = width;
   1124 		sq = sp += (((aligns + w) - 1) & ~31);
   1125 		dq = dp += (((alignd + w) - 1) & ~31);
   1126 		while (height > 0) {
   1127 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1128 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1129 			width -= 2 * SFBCOPYBITS;
   1130 			while (width > 0) {
   1131 				sp -= SFBCOPYBYTESDONE;
   1132 				dp -= SFBCOPYBYTESDONE;
   1133 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1134 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1135 				width -= SFBCOPYBITS;
   1136 			}
   1137 			sp -= SFBCOPYBYTESDONE;
   1138 			dp -= SFBCOPYBYTESDONE;
   1139 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1140 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1141 
   1142 			sp = (sq += scanspan);
   1143 			dp = (dq += scanspan);
   1144 			width = w;
   1145 			height--;
   1146 		}
   1147 	}
   1148 	SFBMODE(sfb, MODE_SIMPLE);
   1149 	SFBPIXELSHIFT(sfb, 0);
   1150 }
   1151 #endif
   1152 
   1153 /*
   1154  * Clear characters in a line.
   1155  */
   1156 static void
   1157 sfb_erasecols(id, row, startcol, ncols, attr)
   1158 	void *id;
   1159 	int row, startcol, ncols;
   1160 	long attr;
   1161 {
   1162 	struct rasops_info *ri = id;
   1163 	caddr_t sfb, p;
   1164 	int scanspan, startx, height, width, align, w, y;
   1165 	u_int32_t lmask, rmask;
   1166 
   1167 	scanspan = ri->ri_stride;
   1168 	y = row * ri->ri_font->fontheight;
   1169 	startx = startcol * ri->ri_font->fontwidth;
   1170 	height = ri->ri_font->fontheight;
   1171 	w = ri->ri_font->fontwidth * ncols;
   1172 
   1173 	p = ri->ri_bits + y * scanspan + startx;
   1174 	align = (long)p & SFBALIGNMASK;
   1175 	p -= align;
   1176 	width = w + align;
   1177 	lmask = SFBSTIPPLEALL1 << align;
   1178 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1179 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1180 
   1181 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1182 	SFBPLANEMASK(sfb, ~0);
   1183 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1184 	if (width <= SFBSTIPPLEBITS) {
   1185 		lmask = lmask & rmask;
   1186 		while (height > 0) {
   1187 			SFBADDRESS(sfb, (long)p);
   1188 			SFBSTART(sfb, lmask);
   1189 			p += scanspan;
   1190 			height--;
   1191 		}
   1192 	}
   1193 	else {
   1194 		caddr_t q = p;
   1195 		while (height > 0) {
   1196 			*(u_int32_t *)p = lmask;
   1197 			WRITE_MB();
   1198 			width -= 2 * SFBSTIPPLEBITS;
   1199 			while (width > 0) {
   1200 				p += SFBSTIPPLEBYTESDONE;
   1201 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1202 				WRITE_MB();
   1203 				width -= SFBSTIPPLEBITS;
   1204 			}
   1205 			p += SFBSTIPPLEBYTESDONE;
   1206 			*(u_int32_t *)p = rmask;
   1207 			WRITE_MB();
   1208 
   1209 			p = (q += scanspan);
   1210 			width = w + align;
   1211 			height--;
   1212 		}
   1213 	}
   1214 	SFBMODE(sfb, MODE_SIMPLE);
   1215 }
   1216 
   1217 /*
   1218  * Copy lines.
   1219  */
   1220 static void
   1221 sfb_copyrows(id, srcrow, dstrow, nrows)
   1222 	void *id;
   1223 	int srcrow, dstrow, nrows;
   1224 {
   1225 	struct rasops_info *ri = id;
   1226 	caddr_t sfb, p;
   1227 	int scanspan, offset, srcy, height, width, align, w;
   1228 	u_int32_t lmask, rmask;
   1229 
   1230 	scanspan = ri->ri_stride;
   1231 	height = ri->ri_font->fontheight * nrows;
   1232 	offset = (dstrow - srcrow) * ri->ri_yscale;
   1233 	srcy = ri->ri_font->fontheight * srcrow;
   1234 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
   1235 		scanspan = -scanspan;
   1236 		srcy += height;
   1237 	}
   1238 
   1239 	p = ri->ri_bits + srcy * ri->ri_stride;
   1240 	align = (long)p & SFBALIGNMASK;
   1241 	p -= align;
   1242 	w = ri->ri_emuwidth;
   1243 	width = w + align;
   1244 	lmask = SFBCOPYALL1 << align;
   1245 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1246 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1247 
   1248 	SFBMODE(sfb, MODE_COPY);
   1249 	SFBPLANEMASK(sfb, ~0);
   1250 	SFBPIXELSHIFT(sfb, 0);
   1251 	if (width <= SFBCOPYBITS) {
   1252 		/* never happens */;
   1253 	}
   1254 	else {
   1255 		caddr_t q = p;
   1256 		while (height > 0) {
   1257 			*(u_int32_t *)p = lmask;
   1258 			*(u_int32_t *)(p + offset) = lmask;
   1259 			width -= 2 * SFBCOPYBITS;
   1260 			while (width > 0) {
   1261 				p += SFBCOPYBYTESDONE;
   1262 				*(u_int32_t *)p = SFBCOPYALL1;
   1263 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
   1264 				width -= SFBCOPYBITS;
   1265 			}
   1266 			p += SFBCOPYBYTESDONE;
   1267 			*(u_int32_t *)p = rmask;
   1268 			*(u_int32_t *)(p + offset) = rmask;
   1269 
   1270 			p = (q += scanspan);
   1271 			width = w + align;
   1272 			height--;
   1273 		}
   1274 	}
   1275 	SFBMODE(sfb, MODE_SIMPLE);
   1276 }
   1277 
   1278 /*
   1279  * Erase lines.
   1280  */
   1281 void
   1282 sfb_eraserows(id, startrow, nrows, attr)
   1283 	void *id;
   1284 	int startrow, nrows;
   1285 	long attr;
   1286 {
   1287 	struct rasops_info *ri = id;
   1288 	caddr_t sfb, p;
   1289 	int scanspan, starty, height, width, align, w;
   1290 	u_int32_t lmask, rmask;
   1291 
   1292 	scanspan = ri->ri_stride;
   1293 	starty = ri->ri_font->fontheight * startrow;
   1294 	height = ri->ri_font->fontheight * nrows;
   1295 
   1296 	p = ri->ri_bits + starty * scanspan;
   1297 	align = (long)p & SFBALIGNMASK;
   1298 	p -= align;
   1299 	w = ri->ri_emuwidth;
   1300 	width = w + align;
   1301 	lmask = SFBSTIPPLEALL1 << align;
   1302 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1303 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1304 
   1305 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1306 	SFBPLANEMASK(sfb, ~0);
   1307 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1308 	if (width <= SFBSTIPPLEBITS) {
   1309 		/* never happens */;
   1310 	}
   1311 	else {
   1312 		caddr_t q = p;
   1313 		while (height > 0) {
   1314 			*(u_int32_t *)p = lmask;
   1315 			WRITE_MB();
   1316 			width -= 2 * SFBSTIPPLEBITS;
   1317 			while (width > 0) {
   1318 				p += SFBSTIPPLEBYTESDONE;
   1319 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1320 				WRITE_MB();
   1321 				width -= SFBSTIPPLEBITS;
   1322 			}
   1323 			p += SFBSTIPPLEBYTESDONE;
   1324 			*(u_int32_t *)p = rmask;
   1325 			WRITE_MB();
   1326 
   1327 			p = (q += scanspan);
   1328 			width = w + align;
   1329 			height--;
   1330 		}
   1331 	}
   1332 	SFBMODE(sfb, MODE_SIMPLE);
   1333 }
   1334