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