Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.49
      1 /* $NetBSD: sfb.c,v 1.49 2001/11/13 06:26:10 lukem 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.49 2001/11/13 06:26:10 lukem 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 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
    349 		cookie = wsfont_find(NULL, 0, 0, 0);
    350 	if (cookie <= 0) {
    351 		printf("sfb: font table is empty\n");
    352 		return;
    353 	}
    354 
    355 	/* the accelerated sfb_putchar() needs LSbit left */
    356 	if (wsfont_lock(cookie, &ri->ri_font,
    357 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
    358 		printf("sfb: couldn't lock font\n");
    359 		return;
    360 	}
    361 	ri->ri_wsfcookie = cookie;
    362 
    363 	rasops_init(ri, 34, 80);
    364 
    365 	/* add our accelerated functions */
    366 	ri->ri_ops.putchar = sfb_putchar;
    367 	ri->ri_ops.erasecols = sfb_erasecols;
    368 	ri->ri_ops.copyrows = sfb_copyrows;
    369 	ri->ri_ops.eraserows = sfb_eraserows;
    370 	ri->ri_do_cursor = sfb_do_cursor;
    371 
    372 	/* XXX shouldn't be global */
    373 	sfb_stdscreen.nrows = ri->ri_rows;
    374 	sfb_stdscreen.ncols = ri->ri_cols;
    375 	sfb_stdscreen.textops = &ri->ri_ops;
    376 	sfb_stdscreen.capabilities = ri->ri_caps;
    377 }
    378 
    379 static int
    380 sfbioctl(v, cmd, data, flag, p)
    381 	void *v;
    382 	u_long cmd;
    383 	caddr_t data;
    384 	int flag;
    385 	struct proc *p;
    386 {
    387 	struct sfb_softc *sc = v;
    388 	struct rasops_info *ri = sc->sc_ri;
    389 	int turnoff;
    390 
    391 	switch (cmd) {
    392 	case WSDISPLAYIO_GTYPE:
    393 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
    394 		return (0);
    395 
    396 	case WSDISPLAYIO_GINFO:
    397 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    398 		wsd_fbip->height = ri->ri_height;
    399 		wsd_fbip->width = ri->ri_width;
    400 		wsd_fbip->depth = ri->ri_depth;
    401 		wsd_fbip->cmsize = CMAP_SIZE;
    402 #undef fbt
    403 		return (0);
    404 
    405 	case WSDISPLAYIO_GETCMAP:
    406 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    407 
    408 	case WSDISPLAYIO_PUTCMAP:
    409 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    410 
    411 	case WSDISPLAYIO_SVIDEO:
    412 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    413 		if (sc->sc_blanked ^ turnoff) {
    414 			caddr_t asic = (caddr_t)ri->ri_hw + SFB_ASIC_OFFSET;
    415 			*(u_int32_t *)(asic + SFB_ASIC_VIDEO_VALID)
    416 				= !turnoff;
    417 			tc_wmb();
    418 			sc->sc_blanked = turnoff;
    419 		}
    420 		return (0);
    421 
    422 	case WSDISPLAYIO_GVIDEO:
    423 		*(u_int *)data = sc->sc_blanked ?
    424 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    425 		return (0);
    426 
    427 	case WSDISPLAYIO_GCURPOS:
    428 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    429 		return (0);
    430 
    431 	case WSDISPLAYIO_SCURPOS:
    432 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    433 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    434 		return (0);
    435 
    436 	case WSDISPLAYIO_GCURMAX:
    437 		((struct wsdisplay_curpos *)data)->x =
    438 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    439 		return (0);
    440 
    441 	case WSDISPLAYIO_GCURSOR:
    442 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    443 
    444 	case WSDISPLAYIO_SCURSOR:
    445 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    446 	}
    447 	return (ENOTTY);
    448 }
    449 
    450 static paddr_t
    451 sfbmmap(v, offset, prot)
    452 	void *v;
    453 	off_t offset;
    454 	int prot;
    455 {
    456 	struct sfb_softc *sc = v;
    457 
    458 	if (offset >= SFB_SIZE || offset < 0)
    459 		return (-1);
    460 	return machine_btop(sc->sc_vaddr + offset);
    461 }
    462 
    463 static int
    464 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    465 	void *v;
    466 	const struct wsscreen_descr *type;
    467 	void **cookiep;
    468 	int *curxp, *curyp;
    469 	long *attrp;
    470 {
    471 	struct sfb_softc *sc = v;
    472 	struct rasops_info *ri = sc->sc_ri;
    473 	long defattr;
    474 
    475 	if (sc->nscreens > 0)
    476 		return (ENOMEM);
    477 
    478 	*cookiep = ri;	 /* one and only for now */
    479 	*curxp = 0;
    480 	*curyp = 0;
    481 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
    482 	*attrp = defattr;
    483 	sc->nscreens++;
    484 	return (0);
    485 }
    486 
    487 static void
    488 sfb_free_screen(v, cookie)
    489 	void *v;
    490 	void *cookie;
    491 {
    492 	struct sfb_softc *sc = v;
    493 
    494 	if (sc->sc_ri == &sfb_console_ri)
    495 		panic("sfb_free_screen: console");
    496 
    497 	sc->nscreens--;
    498 }
    499 
    500 static int
    501 sfb_show_screen(v, cookie, waitok, cb, cbarg)
    502 	void *v;
    503 	void *cookie;
    504 	int waitok;
    505 	void (*cb) __P((void *, int, int));
    506 	void *cbarg;
    507 {
    508 
    509 	return (0);
    510 }
    511 
    512 /* EXPORT */ int
    513 sfb_cnattach(addr)
    514 	tc_addr_t addr;
    515 {
    516 	struct rasops_info *ri;
    517 	long defattr;
    518 
    519 	ri = &sfb_console_ri;
    520 	ri->ri_hw = (void *)addr;
    521 	sfb_common_init(ri);
    522 	(*ri->ri_ops.alloc_attr)(&ri, 0, 0, 0, &defattr);
    523 	wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
    524 	sfb_consaddr = addr;
    525 	return (0);
    526 }
    527 
    528 static int
    529 sfbintr(arg)
    530 	void *arg;
    531 {
    532 	struct sfb_softc *sc = arg;
    533 	caddr_t base, asic, vdac;
    534 	int v;
    535 
    536 	base = (caddr_t)sc->sc_ri->ri_hw;
    537 	asic = base + 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 done;
    543 
    544 	vdac = base + 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 done:
    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