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