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