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