Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.46
      1 /* $NetBSD: sfb.c,v 1.46 2001/08/05 18:07:54 jdolecek 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.46 2001/08/05 18:07:54 jdolecek 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 static void sfb_do_cursor __P((struct rasops_info *));
    165 #if 0
    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 	dc->rinfo.ri_do_cursor = sfb_do_cursor;
    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 }
    343 
    344 static void
    345 sfbattach(parent, self, aux)
    346 	struct device *parent, *self;
    347 	void *aux;
    348 {
    349 	struct sfb_softc *sc = (struct sfb_softc *)self;
    350 	struct tc_attach_args *ta = aux;
    351 	struct wsemuldisplaydev_attach_args waa;
    352 	struct hwcmap256 *cm;
    353 	const u_int8_t *p;
    354 	caddr_t sfbasic;
    355 	int console, index;
    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 	cm = &sc->sc_cmap;
    372 	p = rasops_cmap;
    373 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    374 		cm->r[index] = p[0];
    375 		cm->g[index] = p[1];
    376 		cm->b[index] = p[2];
    377 	}
    378 
    379 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
    380 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
    381 
    382         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbintr, sc);
    383 
    384 	sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
    385 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    386 	*(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
    387 
    388 	waa.console = console;
    389 	waa.scrdata = &sfb_screenlist;
    390 	waa.accessops = &sfb_accessops;
    391 	waa.accesscookie = sc;
    392 
    393 	config_found(self, &waa, wsemuldisplaydevprint);
    394 }
    395 
    396 static int
    397 sfbioctl(v, cmd, data, flag, p)
    398 	void *v;
    399 	u_long cmd;
    400 	caddr_t data;
    401 	int flag;
    402 	struct proc *p;
    403 {
    404 	struct sfb_softc *sc = v;
    405 	struct fb_devconfig *dc = sc->sc_dc;
    406 	int turnoff;
    407 
    408 	switch (cmd) {
    409 	case WSDISPLAYIO_GTYPE:
    410 		*(u_int *)data = WSDISPLAY_TYPE_SFB;
    411 		return (0);
    412 
    413 	case WSDISPLAYIO_GINFO:
    414 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    415 		wsd_fbip->height = sc->sc_dc->dc_ht;
    416 		wsd_fbip->width = sc->sc_dc->dc_wid;
    417 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    418 		wsd_fbip->cmsize = CMAP_SIZE;
    419 #undef fbt
    420 		return (0);
    421 
    422 	case WSDISPLAYIO_GETCMAP:
    423 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    424 
    425 	case WSDISPLAYIO_PUTCMAP:
    426 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    427 
    428 	case WSDISPLAYIO_SVIDEO:
    429 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    430 		if (dc->dc_blanked ^ turnoff) {
    431 			vaddr_t sfbasic = dc->dc_vaddr + SFB_ASIC_OFFSET;
    432 			*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID)
    433 				= !turnoff;
    434 			tc_wmb();
    435 			dc->dc_blanked = turnoff;
    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 	u_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 /*
    884  * Paint the cursor.
    885  */
    886 static void
    887 sfb_do_cursor(ri)
    888 	struct rasops_info *ri;
    889 {
    890 	caddr_t sfb, p;
    891 	int scanspan, height, width, align, x, y;
    892 	u_int32_t lmask, rmask;
    893 
    894 	x = ri->ri_ccol * ri->ri_font->fontwidth;
    895 	y = ri->ri_crow * ri->ri_font->fontheight;
    896 	scanspan = ri->ri_stride;
    897 	height = ri->ri_font->fontheight;
    898 
    899 	p = ri->ri_bits + y * scanspan + x;
    900 	align = (long)p & SFBALIGNMASK;
    901 	p -= align;
    902 	width = ri->ri_font->fontwidth + align;
    903 	lmask = SFBSTIPPLEALL1 << align;
    904 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    905 	sfb = ri->ri_hw;
    906 
    907 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    908 	SFBPLANEMASK(sfb, ~0);
    909 	SFBROP(sfb, 6);  /* ROP_XOR */
    910 	SFBFG(sfb, ~0);
    911 
    912 	lmask = lmask & rmask;
    913 	while (height > 0) {
    914 		SFBADDRESS(sfb, (long)p);
    915 		SFBSTART(sfb, lmask);
    916 		p += scanspan;
    917 		height--;
    918 	}
    919 	SFBMODE(sfb, MODE_SIMPLE);
    920 	SFBROP(sfb, 3); /* ROP_COPY */
    921 }
    922 
    923 /*
    924  * Paint a character.
    925  */
    926 static void
    927 sfb_putchar(id, row, col, uc, attr)
    928 	void *id;
    929 	int row, col;
    930 	u_int uc;
    931 	long attr;
    932 {
    933 	struct rasops_info *ri = id;
    934 	caddr_t sfb, p;
    935 	int scanspan, height, width, align, x, y;
    936 	u_int32_t lmask, rmask, glyph;
    937 	u_int8_t *g;
    938 
    939 	x = col * ri->ri_font->fontwidth;
    940 	y = row * ri->ri_font->fontheight;
    941 	scanspan = ri->ri_stride;
    942 	height = ri->ri_font->fontheight;
    943 	uc -= ri->ri_font->firstchar;
    944 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
    945 
    946 	p = ri->ri_bits + y * scanspan + x;
    947 	align = (long)p & SFBALIGNMASK;
    948 	p -= align;
    949 	width = ri->ri_font->fontwidth + align;
    950 	lmask = SFBSTIPPLEALL1 << align;
    951 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    952 	sfb = ri->ri_hw;
    953 
    954 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
    955 	SFBPLANEMASK(sfb, ~0);
    956 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
    957 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
    958 
    959 	/* XXX 2B stride fonts only XXX */
    960 	lmask = lmask & rmask;
    961 	while (height > 0) {
    962 		glyph = *(u_int16_t *)g;		/* XXX */
    963 		SFBPIXELMASK(sfb, lmask);
    964 		SFBADDRESS(sfb, (long)p);
    965 		SFBSTART(sfb, glyph << align);
    966 		p += scanspan;
    967 		g += 2;					/* XXX */
    968 		height--;
    969 	}
    970 	if (attr & 1 /* UNDERLINE */) {
    971 		p -= scanspan * 2;
    972 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    973 		SFBADDRESS(sfb, (long)p);
    974 		SFBSTART(sfb, lmask);
    975 	}
    976 
    977 	SFBMODE(sfb, MODE_SIMPLE);
    978 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
    979 }
    980 
    981 #if 0
    982 /*
    983  * Copy characters in a line.
    984  */
    985 static void
    986 sfb_copycols(id, row, srccol, dstcol, ncols)
    987 	void *id;
    988 	int row, srccol, dstcol, ncols;
    989 {
    990 	struct rasops_info *ri = id;
    991 	caddr_t sp, dp, basex, sfb;
    992 	int scanspan, height, width, aligns, alignd, shift, w, y;
    993 	u_int32_t lmaskd, rmaskd;
    994 
    995 	scanspan = ri->ri_stride;
    996 	y = row * ri->ri_font->fontheight;
    997 	basex = ri->ri_bits + y * scanspan;
    998 	height = ri->ri_font->fontheight;
    999 	w = ri->ri_font->fontwidth * ncols;
   1000 
   1001 	sp = basex + ri->ri_font->fontwidth * srccol;
   1002 	aligns = (long)sp & SFBALIGNMASK;
   1003 	dp = basex + ri->ri_font->fontwidth * dstcol;
   1004 	alignd = (long)dp & SFBALIGNMASK;
   1005 	sfb = ri->ri_hw;
   1006 
   1007 	SFBMODE(sfb, MODE_COPY);
   1008 	SFBPLANEMASK(sfb, ~0);
   1009 	/* small enough to fit in a single 32bit */
   1010 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
   1011 		SFBPIXELSHIFT(sfb, alignd - aligns);
   1012 		lmaskd = SFBCOPYALL1 << alignd;
   1013 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
   1014 		lmaskd = lmaskd & rmaskd;
   1015 		sp -= aligns;
   1016 		dp -= alignd;
   1017 		while (height > 0) {
   1018 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1019 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1020 			sp += scanspan;
   1021 			dp += scanspan;
   1022 			height--;
   1023 		}
   1024 	}
   1025 	/* copy forward (left-to-right) */
   1026 	else if (dstcol < srccol || srccol + ncols < dstcol) {
   1027 		caddr_t sq, dq;
   1028 
   1029 		shift = alignd - aligns;
   1030 		if (shift < 0) {
   1031 			shift = 8 + shift;	/* enforce right rotate */
   1032 			alignd += 8;		/* bearing on left edge */
   1033 		}
   1034 		width = alignd + w;
   1035 		lmaskd = SFBCOPYALL1 << alignd;
   1036 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1037 		sp -= aligns;
   1038 		dp -= alignd;
   1039 
   1040 		SFBPIXELSHIFT(sfb, shift);
   1041 		w = width;
   1042 		sq = sp;
   1043 		dq = dp;
   1044 		while (height > 0) {
   1045 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1046 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1047 			width -= 2 * SFBCOPYBITS;
   1048 			while (width > 0) {
   1049 				sp += SFBCOPYBYTESDONE;
   1050 				dp += SFBCOPYBYTESDONE;
   1051 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1052 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1053 				width -= SFBCOPYBITS;
   1054 			}
   1055 			sp += SFBCOPYBYTESDONE;
   1056 			dp += SFBCOPYBYTESDONE;
   1057 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1058 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1059 			sp = (sq += scanspan);
   1060 			dp = (dq += scanspan);
   1061 			width = w;
   1062 			height--;
   1063 		}
   1064 	}
   1065 	/* copy backward (right-to-left) */
   1066 	else {
   1067 		caddr_t sq, dq;
   1068 
   1069 		shift = alignd - aligns;
   1070 		if (shift > 0) {
   1071 			shift = shift - 8;	/* force left rotate */
   1072 			alignd += 24;
   1073 		}
   1074 		width = alignd + w;
   1075 		lmaskd = SFBCOPYALL1 << alignd;
   1076 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1077 		sp -= aligns;
   1078 		dp -= alignd;
   1079 
   1080 		SFBPIXELSHIFT(sfb, shift);
   1081 		w = width;
   1082 		sq = sp += (((aligns + w) - 1) & ~31);
   1083 		dq = dp += (((alignd + w) - 1) & ~31);
   1084 		while (height > 0) {
   1085 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1086 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1087 			width -= 2 * SFBCOPYBITS;
   1088 			while (width > 0) {
   1089 				sp -= SFBCOPYBYTESDONE;
   1090 				dp -= SFBCOPYBYTESDONE;
   1091 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1092 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1093 				width -= SFBCOPYBITS;
   1094 			}
   1095 			sp -= SFBCOPYBYTESDONE;
   1096 			dp -= SFBCOPYBYTESDONE;
   1097 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1098 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1099 
   1100 			sp = (sq += scanspan);
   1101 			dp = (dq += scanspan);
   1102 			width = w;
   1103 			height--;
   1104 		}
   1105 	}
   1106 	SFBMODE(sfb, MODE_SIMPLE);
   1107 	SFBPIXELSHIFT(sfb, 0);
   1108 }
   1109 #endif
   1110 
   1111 /*
   1112  * Clear characters in a line.
   1113  */
   1114 static void
   1115 sfb_erasecols(id, row, startcol, ncols, attr)
   1116 	void *id;
   1117 	int row, startcol, ncols;
   1118 	long attr;
   1119 {
   1120 	struct rasops_info *ri = id;
   1121 	caddr_t sfb, p;
   1122 	int scanspan, startx, height, width, align, w, y;
   1123 	u_int32_t lmask, rmask;
   1124 
   1125 	scanspan = ri->ri_stride;
   1126 	y = row * ri->ri_font->fontheight;
   1127 	startx = startcol * ri->ri_font->fontwidth;
   1128 	height = ri->ri_font->fontheight;
   1129 	w = ri->ri_font->fontwidth * ncols;
   1130 
   1131 	p = ri->ri_bits + y * scanspan + startx;
   1132 	align = (long)p & SFBALIGNMASK;
   1133 	p -= align;
   1134 	width = w + align;
   1135 	lmask = SFBSTIPPLEALL1 << align;
   1136 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1137 	sfb = ri->ri_hw;
   1138 
   1139 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1140 	SFBPLANEMASK(sfb, ~0);
   1141 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1142 	if (width <= SFBSTIPPLEBITS) {
   1143 		lmask = lmask & rmask;
   1144 		while (height > 0) {
   1145 			SFBADDRESS(sfb, (long)p);
   1146 			SFBSTART(sfb, lmask);
   1147 			p += scanspan;
   1148 			height--;
   1149 		}
   1150 	}
   1151 	else {
   1152 		caddr_t q = p;
   1153 		while (height > 0) {
   1154 			*(u_int32_t *)p = lmask;
   1155 			WRITE_MB();
   1156 			width -= 2 * SFBSTIPPLEBITS;
   1157 			while (width > 0) {
   1158 				p += SFBSTIPPLEBYTESDONE;
   1159 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1160 				WRITE_MB();
   1161 				width -= SFBSTIPPLEBITS;
   1162 			}
   1163 			p += SFBSTIPPLEBYTESDONE;
   1164 			*(u_int32_t *)p = rmask;
   1165 			WRITE_MB();
   1166 
   1167 			p = (q += scanspan);
   1168 			width = w + align;
   1169 			height--;
   1170 		}
   1171 	}
   1172 	SFBMODE(sfb, MODE_SIMPLE);
   1173 }
   1174 
   1175 /*
   1176  * Copy lines.
   1177  */
   1178 static void
   1179 sfb_copyrows(id, srcrow, dstrow, nrows)
   1180 	void *id;
   1181 	int srcrow, dstrow, nrows;
   1182 {
   1183 	struct rasops_info *ri = id;
   1184 	caddr_t sfb, p;
   1185 	int scanspan, offset, srcy, height, width, align, w;
   1186 	u_int32_t lmask, rmask;
   1187 
   1188 	scanspan = ri->ri_stride;
   1189 	height = ri->ri_font->fontheight * nrows;
   1190 	offset = (dstrow - srcrow) * ri->ri_yscale;
   1191 	srcy = ri->ri_font->fontheight * srcrow;
   1192 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
   1193 		scanspan = -scanspan;
   1194 		srcy += height;
   1195 	}
   1196 
   1197 	p = ri->ri_bits + srcy * ri->ri_stride;
   1198 	align = (long)p & SFBALIGNMASK;
   1199 	p -= align;
   1200 	w = ri->ri_emuwidth;
   1201 	width = w + align;
   1202 	lmask = SFBCOPYALL1 << align;
   1203 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1204 	sfb = ri->ri_hw;
   1205 
   1206 	SFBMODE(sfb, MODE_COPY);
   1207 	SFBPLANEMASK(sfb, ~0);
   1208 	SFBPIXELSHIFT(sfb, 0);
   1209 	if (width <= SFBCOPYBITS) {
   1210 		/* never happens */;
   1211 	}
   1212 	else {
   1213 		caddr_t q = p;
   1214 		while (height > 0) {
   1215 			*(u_int32_t *)p = lmask;
   1216 			*(u_int32_t *)(p + offset) = lmask;
   1217 			width -= 2 * SFBCOPYBITS;
   1218 			while (width > 0) {
   1219 				p += SFBCOPYBYTESDONE;
   1220 				*(u_int32_t *)p = SFBCOPYALL1;
   1221 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
   1222 				width -= SFBCOPYBITS;
   1223 			}
   1224 			p += SFBCOPYBYTESDONE;
   1225 			*(u_int32_t *)p = rmask;
   1226 			*(u_int32_t *)(p + offset) = rmask;
   1227 
   1228 			p = (q += scanspan);
   1229 			width = w + align;
   1230 			height--;
   1231 		}
   1232 	}
   1233 	SFBMODE(sfb, MODE_SIMPLE);
   1234 }
   1235 
   1236 /*
   1237  * Erase lines.
   1238  */
   1239 void
   1240 sfb_eraserows(id, startrow, nrows, attr)
   1241 	void *id;
   1242 	int startrow, nrows;
   1243 	long attr;
   1244 {
   1245 	struct rasops_info *ri = id;
   1246 	caddr_t sfb, p;
   1247 	int scanspan, starty, height, width, align, w;
   1248 	u_int32_t lmask, rmask;
   1249 
   1250 	scanspan = ri->ri_stride;
   1251 	starty = ri->ri_font->fontheight * startrow;
   1252 	height = ri->ri_font->fontheight * nrows;
   1253 
   1254 	p = ri->ri_bits + starty * scanspan;
   1255 	align = (long)p & SFBALIGNMASK;
   1256 	p -= align;
   1257 	w = ri->ri_emuwidth;
   1258 	width = w + align;
   1259 	lmask = SFBSTIPPLEALL1 << align;
   1260 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1261 	sfb = ri->ri_hw;
   1262 
   1263 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1264 	SFBPLANEMASK(sfb, ~0);
   1265 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1266 	if (width <= SFBSTIPPLEBITS) {
   1267 		/* never happens */;
   1268 	}
   1269 	else {
   1270 		caddr_t q = p;
   1271 		while (height > 0) {
   1272 			*(u_int32_t *)p = lmask;
   1273 			WRITE_MB();
   1274 			width -= 2 * SFBSTIPPLEBITS;
   1275 			while (width > 0) {
   1276 				p += SFBSTIPPLEBYTESDONE;
   1277 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1278 				WRITE_MB();
   1279 				width -= SFBSTIPPLEBITS;
   1280 			}
   1281 			p += SFBSTIPPLEBYTESDONE;
   1282 			*(u_int32_t *)p = rmask;
   1283 			WRITE_MB();
   1284 
   1285 			p = (q += scanspan);
   1286 			width = w + align;
   1287 			height--;
   1288 		}
   1289 	}
   1290 	SFBMODE(sfb, MODE_SIMPLE);
   1291 }
   1292