Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.51
      1 /* $NetBSD: sfb.c,v 1.51 2002/03/17 19:41:02 atatat 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.51 2002/03/17 19:41:02 atatat 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[64 + 64];
    116 };
    117 
    118 struct sfb_softc {
    119 	struct device sc_dev;
    120 	vaddr_t sc_vaddr;
    121 	size_t sc_size;
    122 	struct rasops_info *sc_ri;
    123 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    124 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    125 	int sc_blanked;			/* video visibility disabled */
    126 	int sc_curenb;			/* cursor sprite enabled */
    127 	int sc_changed;			/* need update of hardware */
    128 #define	WSDISPLAY_CMAP_DOLUT	0x20
    129 	int nscreens;
    130 };
    131 
    132 #define	HX_MAGIC_X	368
    133 #define	HX_MAGIC_Y	38
    134 
    135 static int  sfbmatch __P((struct device *, struct cfdata *, void *));
    136 static void sfbattach __P((struct device *, struct device *, void *));
    137 
    138 const struct cfattach sfb_ca = {
    139 	sizeof(struct sfb_softc), sfbmatch, sfbattach,
    140 };
    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.alloc_attr)(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.alloc_attr)(&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_image + CURSOR_MAX_SIZE);
    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 
    705 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    706 		return (EINVAL);
    707 
    708 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    709 	    !uvm_useracc(p->green, count, B_WRITE) ||
    710 	    !uvm_useracc(p->blue, count, B_WRITE))
    711 		return (EFAULT);
    712 
    713 	copyout(&sc->sc_cmap.r[index], p->red, count);
    714 	copyout(&sc->sc_cmap.g[index], p->green, count);
    715 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    716 
    717 	return (0);
    718 }
    719 
    720 static int
    721 set_cmap(sc, p)
    722 	struct sfb_softc *sc;
    723 	struct wsdisplay_cmap *p;
    724 {
    725 	u_int index = p->index, count = p->count;
    726 
    727 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    728 		return (EINVAL);
    729 
    730 	if (!uvm_useracc(p->red, count, B_READ) ||
    731 	    !uvm_useracc(p->green, count, B_READ) ||
    732 	    !uvm_useracc(p->blue, count, B_READ))
    733 		return (EFAULT);
    734 
    735 	copyin(p->red, &sc->sc_cmap.r[index], count);
    736 	copyin(p->green, &sc->sc_cmap.g[index], count);
    737 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    738 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    739 	return (0);
    740 }
    741 
    742 static int
    743 set_cursor(sc, p)
    744 	struct sfb_softc *sc;
    745 	struct wsdisplay_cursor *p;
    746 {
    747 #define	cc (&sc->sc_cursor)
    748 	u_int v, index, count, icount;
    749 
    750 	v = p->which;
    751 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    752 		index = p->cmap.index;
    753 		count = p->cmap.count;
    754 		if (index >= 2 || (index + count) > 2)
    755 			return (EINVAL);
    756 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    757 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    758 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    759 			return (EFAULT);
    760 	}
    761 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    762 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    763 			return (EINVAL);
    764 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    765 		if (!uvm_useracc(p->image, icount, B_READ) ||
    766 		    !uvm_useracc(p->mask, icount, B_READ))
    767 			return (EFAULT);
    768 	}
    769 
    770 	if (v & WSDISPLAY_CURSOR_DOCUR)
    771 		sc->sc_curenb = p->enable;
    772 	if (v & WSDISPLAY_CURSOR_DOPOS)
    773 		set_curpos(sc, &p->pos);
    774 	if (v & WSDISPLAY_CURSOR_DOHOT)
    775 		cc->cc_hot = p->hot;
    776 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    777 		copyin(p->cmap.red, &cc->cc_color[index], count);
    778 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    779 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    780 	}
    781 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    782 		cc->cc_size = p->size;
    783 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    784 		copyin(p->image, cc->cc_image, icount);
    785 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    786 	}
    787 	sc->sc_changed |= v;
    788 
    789 	return (0);
    790 #undef cc
    791 }
    792 
    793 static int
    794 get_cursor(sc, p)
    795 	struct sfb_softc *sc;
    796 	struct wsdisplay_cursor *p;
    797 {
    798 
    799 	return (EPASSTHROUGH); /* XXX */
    800 }
    801 
    802 static void
    803 set_curpos(sc, curpos)
    804 	struct sfb_softc *sc;
    805 	struct wsdisplay_curpos *curpos;
    806 {
    807 	struct rasops_info *ri = sc->sc_ri;
    808 	int x = curpos->x, y = curpos->y;
    809 
    810 	if (y < 0)
    811 		y = 0;
    812 	else if (y > ri->ri_height);
    813 		y = ri->ri_height;
    814 	if (x < 0)
    815 		x = 0;
    816 	else if (x > ri->ri_width);
    817 		x = ri->ri_width;
    818 	sc->sc_cursor.cc_pos.x = x;
    819 	sc->sc_cursor.cc_pos.y = y;
    820 }
    821 
    822 #define	MODE_SIMPLE		0
    823 #define	MODE_OPAQUESTIPPLE	1
    824 #define	MODE_OPAQUELINE		2
    825 #define	MODE_TRANSPARENTSTIPPLE	5
    826 #define	MODE_TRANSPARENTLINE	6
    827 #define	MODE_COPY		7
    828 
    829 /* parameters for 8bpp configuration */
    830 #define	SFBALIGNMASK		0x7
    831 #define	SFBSTIPPLEALL1		0xffffffff
    832 #define	SFBSTIPPLEBITS		32
    833 #define	SFBSTIPPLEBITMASK	0x1f
    834 #define	SFBSTIPPLEBYTESDONE	32
    835 #define	SFBCOPYALL1		0xffffffff
    836 #define	SFBCOPYBITS		32
    837 #define	SFBCOPYBITMASK		0x1f
    838 #define	SFBCOPYBYTESDONE	32
    839 
    840 #if defined(pmax)
    841 #define	WRITE_MB()
    842 #define	BUMP(p) (p)
    843 #endif
    844 
    845 #if defined(alpha)
    846 #define	WRITE_MB() tc_wmb()
    847 /* SFB registers replicated in 128B stride; cycle after eight iterations */
    848 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x80) & ~0x400))
    849 #endif
    850 
    851 #define	SFBMODE(p, v) \
    852 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
    853 #define	SFBROP(p, v) \
    854 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
    855 #define	SFBPLANEMASK(p, v) \
    856 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
    857 #define	SFBPIXELMASK(p, v) \
    858 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
    859 #define	SFBADDRESS(p, v) \
    860 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
    861 #define	SFBSTART(p, v) \
    862 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
    863 #define	SFBPIXELSHIFT(p, v) \
    864 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
    865 #define	SFBFG(p, v) \
    866 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
    867 #define	SFBBG(p, v) \
    868 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
    869 
    870 /*
    871  * Paint the cursor.
    872  */
    873 static void
    874 sfb_do_cursor(ri)
    875 	struct rasops_info *ri;
    876 {
    877 	caddr_t sfb, p;
    878 	int scanspan, height, width, align, x, y;
    879 	u_int32_t lmask, rmask;
    880 
    881 	x = ri->ri_ccol * ri->ri_font->fontwidth;
    882 	y = ri->ri_crow * ri->ri_font->fontheight;
    883 	scanspan = ri->ri_stride;
    884 	height = ri->ri_font->fontheight;
    885 
    886 	p = ri->ri_bits + y * scanspan + x;
    887 	align = (long)p & SFBALIGNMASK;
    888 	p -= align;
    889 	width = ri->ri_font->fontwidth + align;
    890 	lmask = SFBSTIPPLEALL1 << align;
    891 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    892 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    893 
    894 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    895 	SFBPLANEMASK(sfb, ~0);
    896 	SFBROP(sfb, 6);  /* ROP_XOR */
    897 	SFBFG(sfb, ~0);
    898 
    899 	lmask = lmask & rmask;
    900 	while (height > 0) {
    901 		SFBADDRESS(sfb, (long)p);
    902 		SFBSTART(sfb, lmask);
    903 		p += scanspan;
    904 		height--;
    905 	}
    906 	SFBMODE(sfb, MODE_SIMPLE);
    907 	SFBROP(sfb, 3); /* ROP_COPY */
    908 }
    909 
    910 /*
    911  * Paint a character.
    912  */
    913 static void
    914 sfb_putchar(id, row, col, uc, attr)
    915 	void *id;
    916 	int row, col;
    917 	u_int uc;
    918 	long attr;
    919 {
    920 	struct rasops_info *ri = id;
    921 	caddr_t sfb, p;
    922 	int scanspan, height, width, align, x, y;
    923 	u_int32_t lmask, rmask, glyph;
    924 	u_int8_t *g;
    925 
    926 	x = col * ri->ri_font->fontwidth;
    927 	y = row * ri->ri_font->fontheight;
    928 	scanspan = ri->ri_stride;
    929 	height = ri->ri_font->fontheight;
    930 	uc -= ri->ri_font->firstchar;
    931 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
    932 
    933 	p = ri->ri_bits + y * scanspan + x;
    934 	align = (long)p & SFBALIGNMASK;
    935 	p -= align;
    936 	width = ri->ri_font->fontwidth + align;
    937 	lmask = SFBSTIPPLEALL1 << align;
    938 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    939 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    940 
    941 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
    942 	SFBPLANEMASK(sfb, ~0);
    943 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
    944 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
    945 
    946 	/* XXX 2B stride fonts only XXX */
    947 	lmask = lmask & rmask;
    948 	while (height > 0) {
    949 		glyph = *(u_int16_t *)g;		/* XXX */
    950 		SFBPIXELMASK(sfb, lmask);
    951 		SFBADDRESS(sfb, (long)p);
    952 		SFBSTART(sfb, glyph << align);
    953 		p += scanspan;
    954 		g += 2;					/* XXX */
    955 		height--;
    956 	}
    957 	if (attr & 1 /* UNDERLINE */) {
    958 		p -= scanspan * 2;
    959 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    960 		SFBADDRESS(sfb, (long)p);
    961 		SFBSTART(sfb, lmask);
    962 	}
    963 
    964 	SFBMODE(sfb, MODE_SIMPLE);
    965 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
    966 }
    967 
    968 #if 0
    969 /*
    970  * Copy characters in a line.
    971  */
    972 static void
    973 sfb_copycols(id, row, srccol, dstcol, ncols)
    974 	void *id;
    975 	int row, srccol, dstcol, ncols;
    976 {
    977 	struct rasops_info *ri = id;
    978 	caddr_t sp, dp, basex, sfb;
    979 	int scanspan, height, width, aligns, alignd, shift, w, y;
    980 	u_int32_t lmaskd, rmaskd;
    981 
    982 	scanspan = ri->ri_stride;
    983 	y = row * ri->ri_font->fontheight;
    984 	basex = ri->ri_bits + y * scanspan;
    985 	height = ri->ri_font->fontheight;
    986 	w = ri->ri_font->fontwidth * ncols;
    987 
    988 	sp = basex + ri->ri_font->fontwidth * srccol;
    989 	aligns = (long)sp & SFBALIGNMASK;
    990 	dp = basex + ri->ri_font->fontwidth * dstcol;
    991 	alignd = (long)dp & SFBALIGNMASK;
    992 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    993 
    994 	SFBMODE(sfb, MODE_COPY);
    995 	SFBPLANEMASK(sfb, ~0);
    996 	/* small enough to fit in a single 32bit */
    997 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
    998 		SFBPIXELSHIFT(sfb, alignd - aligns);
    999 		lmaskd = SFBCOPYALL1 << alignd;
   1000 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
   1001 		lmaskd = lmaskd & rmaskd;
   1002 		sp -= aligns;
   1003 		dp -= alignd;
   1004 		while (height > 0) {
   1005 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1006 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1007 			sp += scanspan;
   1008 			dp += scanspan;
   1009 			height--;
   1010 		}
   1011 	}
   1012 	/* copy forward (left-to-right) */
   1013 	else if (dstcol < srccol || srccol + ncols < dstcol) {
   1014 		caddr_t sq, dq;
   1015 
   1016 		shift = alignd - aligns;
   1017 		if (shift < 0) {
   1018 			shift = 8 + shift;	/* enforce right rotate */
   1019 			alignd += 8;		/* bearing on left edge */
   1020 		}
   1021 		width = alignd + w;
   1022 		lmaskd = SFBCOPYALL1 << alignd;
   1023 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1024 		sp -= aligns;
   1025 		dp -= alignd;
   1026 
   1027 		SFBPIXELSHIFT(sfb, shift);
   1028 		w = width;
   1029 		sq = sp;
   1030 		dq = dp;
   1031 		while (height > 0) {
   1032 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1033 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1034 			width -= 2 * SFBCOPYBITS;
   1035 			while (width > 0) {
   1036 				sp += SFBCOPYBYTESDONE;
   1037 				dp += SFBCOPYBYTESDONE;
   1038 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1039 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1040 				width -= SFBCOPYBITS;
   1041 			}
   1042 			sp += SFBCOPYBYTESDONE;
   1043 			dp += SFBCOPYBYTESDONE;
   1044 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1045 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1046 			sp = (sq += scanspan);
   1047 			dp = (dq += scanspan);
   1048 			width = w;
   1049 			height--;
   1050 		}
   1051 	}
   1052 	/* copy backward (right-to-left) */
   1053 	else {
   1054 		caddr_t sq, dq;
   1055 
   1056 		shift = alignd - aligns;
   1057 		if (shift > 0) {
   1058 			shift = shift - 8;	/* force left rotate */
   1059 			alignd += 24;
   1060 		}
   1061 		width = alignd + w;
   1062 		lmaskd = SFBCOPYALL1 << alignd;
   1063 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1064 		sp -= aligns;
   1065 		dp -= alignd;
   1066 
   1067 		SFBPIXELSHIFT(sfb, shift);
   1068 		w = width;
   1069 		sq = sp += (((aligns + w) - 1) & ~31);
   1070 		dq = dp += (((alignd + w) - 1) & ~31);
   1071 		while (height > 0) {
   1072 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1073 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1074 			width -= 2 * SFBCOPYBITS;
   1075 			while (width > 0) {
   1076 				sp -= SFBCOPYBYTESDONE;
   1077 				dp -= SFBCOPYBYTESDONE;
   1078 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1079 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1080 				width -= SFBCOPYBITS;
   1081 			}
   1082 			sp -= SFBCOPYBYTESDONE;
   1083 			dp -= SFBCOPYBYTESDONE;
   1084 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1085 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1086 
   1087 			sp = (sq += scanspan);
   1088 			dp = (dq += scanspan);
   1089 			width = w;
   1090 			height--;
   1091 		}
   1092 	}
   1093 	SFBMODE(sfb, MODE_SIMPLE);
   1094 	SFBPIXELSHIFT(sfb, 0);
   1095 }
   1096 #endif
   1097 
   1098 /*
   1099  * Clear characters in a line.
   1100  */
   1101 static void
   1102 sfb_erasecols(id, row, startcol, ncols, attr)
   1103 	void *id;
   1104 	int row, startcol, ncols;
   1105 	long attr;
   1106 {
   1107 	struct rasops_info *ri = id;
   1108 	caddr_t sfb, p;
   1109 	int scanspan, startx, height, width, align, w, y;
   1110 	u_int32_t lmask, rmask;
   1111 
   1112 	scanspan = ri->ri_stride;
   1113 	y = row * ri->ri_font->fontheight;
   1114 	startx = startcol * ri->ri_font->fontwidth;
   1115 	height = ri->ri_font->fontheight;
   1116 	w = ri->ri_font->fontwidth * ncols;
   1117 
   1118 	p = ri->ri_bits + y * scanspan + startx;
   1119 	align = (long)p & SFBALIGNMASK;
   1120 	p -= align;
   1121 	width = w + align;
   1122 	lmask = SFBSTIPPLEALL1 << align;
   1123 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1124 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1125 
   1126 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1127 	SFBPLANEMASK(sfb, ~0);
   1128 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1129 	if (width <= SFBSTIPPLEBITS) {
   1130 		lmask = lmask & rmask;
   1131 		while (height > 0) {
   1132 			SFBADDRESS(sfb, (long)p);
   1133 			SFBSTART(sfb, lmask);
   1134 			p += scanspan;
   1135 			height--;
   1136 		}
   1137 	}
   1138 	else {
   1139 		caddr_t q = p;
   1140 		while (height > 0) {
   1141 			*(u_int32_t *)p = lmask;
   1142 			WRITE_MB();
   1143 			width -= 2 * SFBSTIPPLEBITS;
   1144 			while (width > 0) {
   1145 				p += SFBSTIPPLEBYTESDONE;
   1146 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1147 				WRITE_MB();
   1148 				width -= SFBSTIPPLEBITS;
   1149 			}
   1150 			p += SFBSTIPPLEBYTESDONE;
   1151 			*(u_int32_t *)p = rmask;
   1152 			WRITE_MB();
   1153 
   1154 			p = (q += scanspan);
   1155 			width = w + align;
   1156 			height--;
   1157 		}
   1158 	}
   1159 	SFBMODE(sfb, MODE_SIMPLE);
   1160 }
   1161 
   1162 /*
   1163  * Copy lines.
   1164  */
   1165 static void
   1166 sfb_copyrows(id, srcrow, dstrow, nrows)
   1167 	void *id;
   1168 	int srcrow, dstrow, nrows;
   1169 {
   1170 	struct rasops_info *ri = id;
   1171 	caddr_t sfb, p;
   1172 	int scanspan, offset, srcy, height, width, align, w;
   1173 	u_int32_t lmask, rmask;
   1174 
   1175 	scanspan = ri->ri_stride;
   1176 	height = ri->ri_font->fontheight * nrows;
   1177 	offset = (dstrow - srcrow) * ri->ri_yscale;
   1178 	srcy = ri->ri_font->fontheight * srcrow;
   1179 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
   1180 		scanspan = -scanspan;
   1181 		srcy += height;
   1182 	}
   1183 
   1184 	p = ri->ri_bits + srcy * ri->ri_stride;
   1185 	align = (long)p & SFBALIGNMASK;
   1186 	p -= align;
   1187 	w = ri->ri_emuwidth;
   1188 	width = w + align;
   1189 	lmask = SFBCOPYALL1 << align;
   1190 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1191 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1192 
   1193 	SFBMODE(sfb, MODE_COPY);
   1194 	SFBPLANEMASK(sfb, ~0);
   1195 	SFBPIXELSHIFT(sfb, 0);
   1196 	if (width <= SFBCOPYBITS) {
   1197 		/* never happens */;
   1198 	}
   1199 	else {
   1200 		caddr_t q = p;
   1201 		while (height > 0) {
   1202 			*(u_int32_t *)p = lmask;
   1203 			*(u_int32_t *)(p + offset) = lmask;
   1204 			width -= 2 * SFBCOPYBITS;
   1205 			while (width > 0) {
   1206 				p += SFBCOPYBYTESDONE;
   1207 				*(u_int32_t *)p = SFBCOPYALL1;
   1208 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
   1209 				width -= SFBCOPYBITS;
   1210 			}
   1211 			p += SFBCOPYBYTESDONE;
   1212 			*(u_int32_t *)p = rmask;
   1213 			*(u_int32_t *)(p + offset) = rmask;
   1214 
   1215 			p = (q += scanspan);
   1216 			width = w + align;
   1217 			height--;
   1218 		}
   1219 	}
   1220 	SFBMODE(sfb, MODE_SIMPLE);
   1221 }
   1222 
   1223 /*
   1224  * Erase lines.
   1225  */
   1226 void
   1227 sfb_eraserows(id, startrow, nrows, attr)
   1228 	void *id;
   1229 	int startrow, nrows;
   1230 	long attr;
   1231 {
   1232 	struct rasops_info *ri = id;
   1233 	caddr_t sfb, p;
   1234 	int scanspan, starty, height, width, align, w;
   1235 	u_int32_t lmask, rmask;
   1236 
   1237 	scanspan = ri->ri_stride;
   1238 	starty = ri->ri_font->fontheight * startrow;
   1239 	height = ri->ri_font->fontheight * nrows;
   1240 
   1241 	p = ri->ri_bits + starty * scanspan;
   1242 	align = (long)p & SFBALIGNMASK;
   1243 	p -= align;
   1244 	w = ri->ri_emuwidth;
   1245 	width = w + align;
   1246 	lmask = SFBSTIPPLEALL1 << align;
   1247 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1248 	sfb = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
   1249 
   1250 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1251 	SFBPLANEMASK(sfb, ~0);
   1252 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1253 	if (width <= SFBSTIPPLEBITS) {
   1254 		/* never happens */;
   1255 	}
   1256 	else {
   1257 		caddr_t q = p;
   1258 		while (height > 0) {
   1259 			*(u_int32_t *)p = lmask;
   1260 			WRITE_MB();
   1261 			width -= 2 * SFBSTIPPLEBITS;
   1262 			while (width > 0) {
   1263 				p += SFBSTIPPLEBYTESDONE;
   1264 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1265 				WRITE_MB();
   1266 				width -= SFBSTIPPLEBITS;
   1267 			}
   1268 			p += SFBSTIPPLEBYTESDONE;
   1269 			*(u_int32_t *)p = rmask;
   1270 			WRITE_MB();
   1271 
   1272 			p = (q += scanspan);
   1273 			width = w + align;
   1274 			height--;
   1275 		}
   1276 	}
   1277 	SFBMODE(sfb, MODE_SIMPLE);
   1278 }
   1279