Home | History | Annotate | Line # | Download | only in tc
sfb.c revision 1.43
      1 /* $NetBSD: sfb.c,v 1.43 2001/01/19 05:43:43 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.43 2001/01/19 05:43:43 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 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 == 0) ^ turnoff) {
    431 			dc->dc_blanked = turnoff;
    432 #if 0 /* XXX later XXX */
    433 		To turn off, assign value 0 in ASIC_VIDEO_VALID register.
    434 #endif	/* XXX XXX XXX */
    435 		}
    436 		return (0);
    437 
    438 	case WSDISPLAYIO_GVIDEO:
    439 		*(u_int *)data = dc->dc_blanked ?
    440 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    441 		return (0);
    442 
    443 	case WSDISPLAYIO_GCURPOS:
    444 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    445 		return (0);
    446 
    447 	case WSDISPLAYIO_SCURPOS:
    448 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    449 		sc->sc_changed = WSDISPLAY_CURSOR_DOPOS;
    450 		return (0);
    451 
    452 	case WSDISPLAYIO_GCURMAX:
    453 		((struct wsdisplay_curpos *)data)->x =
    454 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    455 		return (0);
    456 
    457 	case WSDISPLAYIO_GCURSOR:
    458 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    459 
    460 	case WSDISPLAYIO_SCURSOR:
    461 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    462 	}
    463 	return (ENOTTY);
    464 }
    465 
    466 static paddr_t
    467 sfbmmap(v, offset, prot)
    468 	void *v;
    469 	off_t offset;
    470 	int prot;
    471 {
    472 	struct sfb_softc *sc = v;
    473 
    474 	if (offset >= SFB_SIZE || offset < 0)
    475 		return (-1);
    476 	return machine_btop(sc->sc_dc->dc_paddr + offset);
    477 }
    478 
    479 static int
    480 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    481 	void *v;
    482 	const struct wsscreen_descr *type;
    483 	void **cookiep;
    484 	int *curxp, *curyp;
    485 	long *attrp;
    486 {
    487 	struct sfb_softc *sc = v;
    488 	long defattr;
    489 
    490 	if (sc->nscreens > 0)
    491 		return (ENOMEM);
    492 
    493 	*cookiep = &sc->sc_dc->rinfo; /* one and only for now */
    494 	*curxp = 0;
    495 	*curyp = 0;
    496 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
    497 	*attrp = defattr;
    498 	sc->nscreens++;
    499 	return (0);
    500 }
    501 
    502 static void
    503 sfb_free_screen(v, cookie)
    504 	void *v;
    505 	void *cookie;
    506 {
    507 	struct sfb_softc *sc = v;
    508 
    509 	if (sc->sc_dc == &sfb_console_dc)
    510 		panic("sfb_free_screen: console");
    511 
    512 	sc->nscreens--;
    513 }
    514 
    515 static int
    516 sfb_show_screen(v, cookie, waitok, cb, cbarg)
    517 	void *v;
    518 	void *cookie;
    519 	int waitok;
    520 	void (*cb) __P((void *, int, int));
    521 	void *cbarg;
    522 {
    523 
    524 	return (0);
    525 }
    526 
    527 /* EXPORT */ int
    528 sfb_cnattach(addr)
    529 	tc_addr_t addr;
    530 {
    531 	struct fb_devconfig *dcp = &sfb_console_dc;
    532 	long defattr;
    533 
    534 	sfb_getdevconfig(addr, dcp);
    535 
    536 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
    537 
    538 	wsdisplay_cnattach(&sfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
    539 	sfb_consaddr = addr;
    540 	return(0);
    541 }
    542 
    543 static int
    544 sfbintr(arg)
    545 	void *arg;
    546 {
    547 	struct sfb_softc *sc = arg;
    548 	caddr_t sfbasic = (caddr_t)sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET;
    549 	caddr_t vdac;
    550 	int v;
    551 
    552 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
    553 	/* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
    554 
    555 	if (sc->sc_changed == 0)
    556 		goto finish;
    557 
    558 	vdac = (caddr_t)sc->sc_dc->dc_vaddr + SFB_RAMDAC_OFFSET;
    559 	v = sc->sc_changed;
    560 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    561 		SELECT(vdac, BT459_IREG_CCR);
    562 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
    563 	}
    564 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    565 		int x, y;
    566 
    567 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    568 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    569 		x += sc->sc_cursor.cc_magic.x;
    570 		y += sc->sc_cursor.cc_magic.y;
    571 
    572 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
    573 		REG(vdac, bt_reg) = x;		tc_wmb();
    574 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
    575 		REG(vdac, bt_reg) = y;		tc_wmb();
    576 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
    577 	}
    578 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    579 		u_int8_t *cp = sc->sc_cursor.cc_color;
    580 
    581 		SELECT(vdac, BT459_IREG_CCOLOR_2);
    582 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
    583 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
    584 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
    585 
    586 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
    587 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
    588 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
    589 	}
    590 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    591 		u_int8_t *ip, *mp, img, msk;
    592 		u_int8_t u;
    593 		int bcnt;
    594 
    595 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    596 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    597 
    598 		bcnt = 0;
    599 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
    600 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    601 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    602 			/* pad right half 32 pixel when smaller than 33 */
    603 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    604 				REG(vdac, bt_reg) = 0; tc_wmb();
    605 				REG(vdac, bt_reg) = 0; tc_wmb();
    606 			}
    607 			else {
    608 				img = *ip++;
    609 				msk = *mp++;
    610 				img &= msk;	/* cookie off image */
    611 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    612 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    613 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    614 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    615 			}
    616 			bcnt += 2;
    617 		}
    618 		/* pad unoccupied scan lines */
    619 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    620 			REG(vdac, bt_reg) = 0; tc_wmb();
    621 			REG(vdac, bt_reg) = 0; tc_wmb();
    622 			bcnt += 2;
    623 		}
    624 	}
    625 	if (v & WSDISPLAY_CMAP_DOLUT) {
    626 		struct hwcmap256 *cm = &sc->sc_cmap;
    627 		int index;
    628 
    629 		SELECT(vdac, 0);
    630 		for (index = 0; index < CMAP_SIZE; index++) {
    631 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
    632 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
    633 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
    634 		}
    635 	}
    636 	sc->sc_changed = 0;
    637 finish:
    638 	return (1);
    639 }
    640 
    641 static void
    642 sfbinit(dc)
    643 	struct fb_devconfig *dc;
    644 {
    645 	caddr_t vdac = (caddr_t)dc->dc_vaddr + SFB_RAMDAC_OFFSET;
    646 	const u_int8_t *p;
    647 	int i;
    648 
    649 	SELECT(vdac, BT459_IREG_COMMAND_0);
    650 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
    651 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
    652 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
    653 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
    654 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
    655 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
    656 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
    657 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
    658 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
    659 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
    660 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
    661 
    662 	SELECT(vdac, BT459_IREG_CCR);
    663 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    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 
    677 	/* build sane colormap */
    678 	SELECT(vdac, 0);
    679 	p = rasops_cmap;
    680 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    681 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
    682 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
    683 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
    684 	}
    685 
    686 	/* clear out cursor image */
    687 	SELECT(vdac, BT459_IREG_CRAM_BASE);
    688 	for (i = 0; i < 1024; i++)
    689 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
    690 
    691 	/*
    692 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    693 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    694 	 * image color.  CCOLOR_1 will be never used.
    695 	 */
    696 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    697 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    698 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    699 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    700 
    701 	REG(vdac, bt_reg) = 0;		tc_wmb();
    702 	REG(vdac, bt_reg) = 0;		tc_wmb();
    703 	REG(vdac, bt_reg) = 0;		tc_wmb();
    704 
    705 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    706 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    707 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    708 }
    709 
    710 static int
    711 get_cmap(sc, p)
    712 	struct sfb_softc *sc;
    713 	struct wsdisplay_cmap *p;
    714 {
    715 	u_int index = p->index, count = p->count;
    716 
    717 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    718 		return (EINVAL);
    719 
    720 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    721 	    !uvm_useracc(p->green, count, B_WRITE) ||
    722 	    !uvm_useracc(p->blue, count, B_WRITE))
    723 		return (EFAULT);
    724 
    725 	copyout(&sc->sc_cmap.r[index], p->red, count);
    726 	copyout(&sc->sc_cmap.g[index], p->green, count);
    727 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    728 
    729 	return (0);
    730 }
    731 
    732 static int
    733 set_cmap(sc, p)
    734 	struct sfb_softc *sc;
    735 	struct wsdisplay_cmap *p;
    736 {
    737 	u_int index = p->index, count = p->count;
    738 
    739 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    740 		return (EINVAL);
    741 
    742 	if (!uvm_useracc(p->red, count, B_READ) ||
    743 	    !uvm_useracc(p->green, count, B_READ) ||
    744 	    !uvm_useracc(p->blue, count, B_READ))
    745 		return (EFAULT);
    746 
    747 	copyin(p->red, &sc->sc_cmap.r[index], count);
    748 	copyin(p->green, &sc->sc_cmap.g[index], count);
    749 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    750 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    751 	return (0);
    752 }
    753 
    754 static int
    755 set_cursor(sc, p)
    756 	struct sfb_softc *sc;
    757 	struct wsdisplay_cursor *p;
    758 {
    759 #define	cc (&sc->sc_cursor)
    760 	int v, index, count, icount;
    761 
    762 	v = p->which;
    763 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    764 		index = p->cmap.index;
    765 		count = p->cmap.count;
    766 		if (index >= 2 || (index + count) > 2)
    767 			return (EINVAL);
    768 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    769 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    770 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    771 			return (EFAULT);
    772 	}
    773 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    774 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    775 			return (EINVAL);
    776 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    777 		if (!uvm_useracc(p->image, icount, B_READ) ||
    778 		    !uvm_useracc(p->mask, icount, B_READ))
    779 			return (EFAULT);
    780 	}
    781 
    782 	if (v & WSDISPLAY_CURSOR_DOCUR)
    783 		sc->sc_curenb = p->enable;
    784 	if (v & WSDISPLAY_CURSOR_DOPOS)
    785 		set_curpos(sc, &p->pos);
    786 	if (v & WSDISPLAY_CURSOR_DOHOT)
    787 		cc->cc_hot = p->hot;
    788 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    789 		copyin(p->cmap.red, &cc->cc_color[index], count);
    790 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    791 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    792 	}
    793 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    794 		cc->cc_size = p->size;
    795 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    796 		copyin(p->image, cc->cc_image, icount);
    797 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    798 	}
    799 	sc->sc_changed = v;
    800 
    801 	return (0);
    802 #undef cc
    803 }
    804 
    805 static int
    806 get_cursor(sc, p)
    807 	struct sfb_softc *sc;
    808 	struct wsdisplay_cursor *p;
    809 {
    810 
    811 	return (ENOTTY); /* XXX */
    812 }
    813 
    814 static void
    815 set_curpos(sc, curpos)
    816 	struct sfb_softc *sc;
    817 	struct wsdisplay_curpos *curpos;
    818 {
    819 	struct fb_devconfig *dc = sc->sc_dc;
    820 	int x = curpos->x, y = curpos->y;
    821 
    822 	if (y < 0)
    823 		y = 0;
    824 	else if (y > dc->dc_ht)
    825 		y = dc->dc_ht;
    826 	if (x < 0)
    827 		x = 0;
    828 	else if (x > dc->dc_wid)
    829 		x = dc->dc_wid;
    830 	sc->sc_cursor.cc_pos.x = x;
    831 	sc->sc_cursor.cc_pos.y = y;
    832 }
    833 
    834 #define	MODE_SIMPLE		0
    835 #define	MODE_OPAQUESTIPPLE	1
    836 #define	MODE_OPAQUELINE		2
    837 #define	MODE_TRANSPARENTSTIPPLE	5
    838 #define	MODE_TRANSPARENTLINE	6
    839 #define	MODE_COPY		7
    840 
    841 /* parameters for 8bpp configuration */
    842 #define	SFBALIGNMASK		0x7
    843 #define	SFBSTIPPLEALL1		0xffffffff
    844 #define	SFBSTIPPLEBITS		32
    845 #define	SFBSTIPPLEBITMASK	0x1f
    846 #define	SFBSTIPPLEBYTESDONE	32
    847 #define	SFBCOPYALL1		0xffffffff
    848 #define	SFBCOPYBITS		32
    849 #define	SFBCOPYBITMASK		0x1f
    850 #define	SFBCOPYBYTESDONE	32
    851 
    852 #if defined(pmax)
    853 #define	WRITE_MB()
    854 #define	BUMP(p) (p)
    855 #endif
    856 
    857 #if defined(alpha)
    858 #define	WRITE_MB() tc_wmb()
    859 /* SFB registers replicated in 128B stride; cycle after eight iterations */
    860 #define	BUMP(p) ((p) = (caddr_t)(((long)(p) + 0x80) & ~0x400))
    861 #endif
    862 
    863 #define	SFBMODE(p, v) \
    864 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
    865 #define	SFBROP(p, v) \
    866 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
    867 #define	SFBPLANEMASK(p, v) \
    868 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
    869 #define	SFBPIXELMASK(p, v) \
    870 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
    871 #define	SFBADDRESS(p, v) \
    872 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
    873 #define	SFBSTART(p, v) \
    874 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
    875 #define	SFBPIXELSHIFT(p, v) \
    876 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
    877 #define	SFBFG(p, v) \
    878 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
    879 #define	SFBBG(p, v) \
    880 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
    881 
    882 /*
    883  * Paint the cursor.
    884  */
    885 static void
    886 sfb_do_cursor(ri)
    887 	struct rasops_info *ri;
    888 {
    889 	caddr_t sfb, p;
    890 	int scanspan, height, width, align, x, y;
    891 	u_int32_t lmask, rmask;
    892 
    893 	x = ri->ri_ccol * ri->ri_font->fontwidth;
    894 	y = ri->ri_crow * ri->ri_font->fontheight;
    895 	scanspan = ri->ri_stride;
    896 	height = ri->ri_font->fontheight;
    897 
    898 	p = ri->ri_bits + y * scanspan + x;
    899 	align = (long)p & SFBALIGNMASK;
    900 	p -= align;
    901 	width = ri->ri_font->fontwidth + align;
    902 	lmask = SFBSTIPPLEALL1 << align;
    903 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    904 	sfb = ri->ri_hw;
    905 
    906 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    907 	SFBPLANEMASK(sfb, ~0);
    908 	SFBROP(sfb, 6);  /* ROP_XOR */
    909 	SFBFG(sfb, ~0);
    910 
    911 	lmask = lmask & rmask;
    912 	while (height > 0) {
    913 		SFBADDRESS(sfb, (long)p);
    914 		SFBSTART(sfb, lmask);
    915 		p += scanspan;
    916 		height--;
    917 	}
    918 	SFBMODE(sfb, MODE_SIMPLE);
    919 	SFBROP(sfb, 3); /* ROP_COPY */
    920 }
    921 
    922 /*
    923  * Paint a character.
    924  */
    925 static void
    926 sfb_putchar(id, row, col, uc, attr)
    927 	void *id;
    928 	int row, col;
    929 	u_int uc;
    930 	long attr;
    931 {
    932 	struct rasops_info *ri = id;
    933 	caddr_t sfb, p;
    934 	int scanspan, height, width, align, x, y;
    935 	u_int32_t lmask, rmask, glyph;
    936 	u_int8_t *g;
    937 
    938 	x = col * ri->ri_font->fontwidth;
    939 	y = row * ri->ri_font->fontheight;
    940 	scanspan = ri->ri_stride;
    941 	height = ri->ri_font->fontheight;
    942 	uc -= ri->ri_font->firstchar;
    943 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
    944 
    945 	p = ri->ri_bits + y * scanspan + x;
    946 	align = (long)p & SFBALIGNMASK;
    947 	p -= align;
    948 	width = ri->ri_font->fontwidth + align;
    949 	lmask = SFBSTIPPLEALL1 << align;
    950 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
    951 	sfb = ri->ri_hw;
    952 
    953 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
    954 	SFBPLANEMASK(sfb, ~0);
    955 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
    956 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
    957 
    958 	/* XXX 2B stride fonts only XXX */
    959 	lmask = lmask & rmask;
    960 	while (height > 0) {
    961 		glyph = *(u_int16_t *)g;		/* XXX */
    962 		SFBPIXELMASK(sfb, lmask);
    963 		SFBADDRESS(sfb, (long)p);
    964 		SFBSTART(sfb, glyph << align);
    965 		p += scanspan;
    966 		g += 2;					/* XXX */
    967 		height--;
    968 	}
    969 	if (attr & 1 /* UNDERLINE */) {
    970 		p -= scanspan * 2;
    971 		SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
    972 		SFBADDRESS(sfb, (long)p);
    973 		SFBSTART(sfb, lmask);
    974 	}
    975 
    976 	SFBMODE(sfb, MODE_SIMPLE);
    977 	SFBPIXELMASK(sfb, ~0);		/* entire pixel */
    978 }
    979 
    980 #if 0
    981 /*
    982  * Copy characters in a line.
    983  */
    984 static void
    985 sfb_copycols(id, row, srccol, dstcol, ncols)
    986 	void *id;
    987 	int row, srccol, dstcol, ncols;
    988 {
    989 	struct rasops_info *ri = id;
    990 	caddr_t sp, dp, basex, sfb;
    991 	int scanspan, height, width, aligns, alignd, shift, w, y;
    992 	u_int32_t lmaskd, rmaskd;
    993 
    994 	scanspan = ri->ri_stride;
    995 	y = row * ri->ri_font->fontheight;
    996 	basex = ri->ri_bits + y * scanspan;
    997 	height = ri->ri_font->fontheight;
    998 	w = ri->ri_font->fontwidth * ncols;
    999 
   1000 	sp = basex + ri->ri_font->fontwidth * srccol;
   1001 	aligns = (long)sp & SFBALIGNMASK;
   1002 	dp = basex + ri->ri_font->fontwidth * dstcol;
   1003 	alignd = (long)dp & SFBALIGNMASK;
   1004 	sfb = ri->ri_hw;
   1005 
   1006 	SFBMODE(sfb, MODE_COPY);
   1007 	SFBPLANEMASK(sfb, ~0);
   1008 	/* small enough to fit in a single 32bit */
   1009 	if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
   1010 		SFBPIXELSHIFT(sfb, alignd - aligns);
   1011 		lmaskd = SFBCOPYALL1 << alignd;
   1012 		rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
   1013 		lmaskd = lmaskd & rmaskd;
   1014 		sp -= aligns;
   1015 		dp -= alignd;
   1016 		while (height > 0) {
   1017 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1018 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1019 			sp += scanspan;
   1020 			dp += scanspan;
   1021 			height--;
   1022 		}
   1023 	}
   1024 	/* copy forward (left-to-right) */
   1025 	else if (dstcol < srccol || srccol + ncols < dstcol) {
   1026 		caddr_t sq, dq;
   1027 
   1028 		shift = alignd - aligns;
   1029 		if (shift < 0) {
   1030 			shift = 8 + shift;	/* enforce right rotate */
   1031 			alignd += 8;		/* bearing on left edge */
   1032 		}
   1033 		width = alignd + w;
   1034 		lmaskd = SFBCOPYALL1 << alignd;
   1035 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1036 		sp -= aligns;
   1037 		dp -= alignd;
   1038 
   1039 		SFBPIXELSHIFT(sfb, shift);
   1040 		w = width;
   1041 		sq = sp;
   1042 		dq = dp;
   1043 		while (height > 0) {
   1044 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1045 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1046 			width -= 2 * SFBCOPYBITS;
   1047 			while (width > 0) {
   1048 				sp += SFBCOPYBYTESDONE;
   1049 				dp += SFBCOPYBYTESDONE;
   1050 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1051 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1052 				width -= SFBCOPYBITS;
   1053 			}
   1054 			sp += SFBCOPYBYTESDONE;
   1055 			dp += SFBCOPYBYTESDONE;
   1056 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1057 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1058 			sp = (sq += scanspan);
   1059 			dp = (dq += scanspan);
   1060 			width = w;
   1061 			height--;
   1062 		}
   1063 	}
   1064 	/* copy backward (right-to-left) */
   1065 	else {
   1066 		caddr_t sq, dq;
   1067 
   1068 		shift = alignd - aligns;
   1069 		if (shift > 0) {
   1070 			shift = shift - 8;	/* force left rotate */
   1071 			alignd += 24;
   1072 		}
   1073 		width = alignd + w;
   1074 		lmaskd = SFBCOPYALL1 << alignd;
   1075 		rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1076 		sp -= aligns;
   1077 		dp -= alignd;
   1078 
   1079 		SFBPIXELSHIFT(sfb, shift);
   1080 		w = width;
   1081 		sq = sp += (((aligns + w) - 1) & ~31);
   1082 		dq = dp += (((alignd + w) - 1) & ~31);
   1083 		while (height > 0) {
   1084 			*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1085 			*(u_int32_t *)dp = rmaskd;	WRITE_MB();
   1086 			width -= 2 * SFBCOPYBITS;
   1087 			while (width > 0) {
   1088 				sp -= SFBCOPYBYTESDONE;
   1089 				dp -= SFBCOPYBYTESDONE;
   1090 				*(u_int32_t *)sp = SFBCOPYALL1; WRITE_MB();
   1091 				*(u_int32_t *)dp = SFBCOPYALL1; WRITE_MB();
   1092 				width -= SFBCOPYBITS;
   1093 			}
   1094 			sp -= SFBCOPYBYTESDONE;
   1095 			dp -= SFBCOPYBYTESDONE;
   1096 			*(u_int32_t *)sp = SFBCOPYALL1;	WRITE_MB();
   1097 			*(u_int32_t *)dp = lmaskd;	WRITE_MB();
   1098 
   1099 			sp = (sq += scanspan);
   1100 			dp = (dq += scanspan);
   1101 			width = w;
   1102 			height--;
   1103 		}
   1104 	}
   1105 	SFBMODE(sfb, MODE_SIMPLE);
   1106 	SFBPIXELSHIFT(sfb, 0);
   1107 }
   1108 #endif
   1109 
   1110 /*
   1111  * Clear characters in a line.
   1112  */
   1113 static void
   1114 sfb_erasecols(id, row, startcol, ncols, attr)
   1115 	void *id;
   1116 	int row, startcol, ncols;
   1117 	long attr;
   1118 {
   1119 	struct rasops_info *ri = id;
   1120 	caddr_t sfb, p;
   1121 	int scanspan, startx, height, width, align, w, y;
   1122 	u_int32_t lmask, rmask;
   1123 
   1124 	scanspan = ri->ri_stride;
   1125 	y = row * ri->ri_font->fontheight;
   1126 	startx = startcol * ri->ri_font->fontwidth;
   1127 	height = ri->ri_font->fontheight;
   1128 	w = ri->ri_font->fontwidth * ncols;
   1129 
   1130 	p = ri->ri_bits + y * scanspan + startx;
   1131 	align = (long)p & SFBALIGNMASK;
   1132 	p -= align;
   1133 	width = w + align;
   1134 	lmask = SFBSTIPPLEALL1 << align;
   1135 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1136 	sfb = ri->ri_hw;
   1137 
   1138 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1139 	SFBPLANEMASK(sfb, ~0);
   1140 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1141 	if (width <= SFBSTIPPLEBITS) {
   1142 		lmask = lmask & rmask;
   1143 		while (height > 0) {
   1144 			SFBADDRESS(sfb, (long)p);
   1145 			SFBSTART(sfb, lmask);
   1146 			p += scanspan;
   1147 			height--;
   1148 		}
   1149 	}
   1150 	else {
   1151 		caddr_t q = p;
   1152 		while (height > 0) {
   1153 			*(u_int32_t *)p = lmask;
   1154 			WRITE_MB();
   1155 			width -= 2 * SFBSTIPPLEBITS;
   1156 			while (width > 0) {
   1157 				p += SFBSTIPPLEBYTESDONE;
   1158 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1159 				WRITE_MB();
   1160 				width -= SFBSTIPPLEBITS;
   1161 			}
   1162 			p += SFBSTIPPLEBYTESDONE;
   1163 			*(u_int32_t *)p = rmask;
   1164 			WRITE_MB();
   1165 
   1166 			p = (q += scanspan);
   1167 			width = w + align;
   1168 			height--;
   1169 		}
   1170 	}
   1171 	SFBMODE(sfb, MODE_SIMPLE);
   1172 }
   1173 
   1174 /*
   1175  * Copy lines.
   1176  */
   1177 static void
   1178 sfb_copyrows(id, srcrow, dstrow, nrows)
   1179 	void *id;
   1180 	int srcrow, dstrow, nrows;
   1181 {
   1182 	struct rasops_info *ri = id;
   1183 	caddr_t sfb, p;
   1184 	int scanspan, offset, srcy, height, width, align, w;
   1185 	u_int32_t lmask, rmask;
   1186 
   1187 	scanspan = ri->ri_stride;
   1188 	height = ri->ri_font->fontheight * nrows;
   1189 	offset = (dstrow - srcrow) * ri->ri_yscale;
   1190 	srcy = ri->ri_font->fontheight * srcrow;
   1191 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
   1192 		scanspan = -scanspan;
   1193 		srcy += height;
   1194 	}
   1195 
   1196 	p = ri->ri_bits + srcy * ri->ri_stride;
   1197 	align = (long)p & SFBALIGNMASK;
   1198 	p -= align;
   1199 	w = ri->ri_emuwidth;
   1200 	width = w + align;
   1201 	lmask = SFBCOPYALL1 << align;
   1202 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
   1203 	sfb = ri->ri_hw;
   1204 
   1205 	SFBMODE(sfb, MODE_COPY);
   1206 	SFBPLANEMASK(sfb, ~0);
   1207 	SFBPIXELSHIFT(sfb, 0);
   1208 	if (width <= SFBCOPYBITS) {
   1209 		/* never happens */;
   1210 	}
   1211 	else {
   1212 		caddr_t q = p;
   1213 		while (height > 0) {
   1214 			*(u_int32_t *)p = lmask;
   1215 			*(u_int32_t *)(p + offset) = lmask;
   1216 			width -= 2 * SFBCOPYBITS;
   1217 			while (width > 0) {
   1218 				p += SFBCOPYBYTESDONE;
   1219 				*(u_int32_t *)p = SFBCOPYALL1;
   1220 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
   1221 				width -= SFBCOPYBITS;
   1222 			}
   1223 			p += SFBCOPYBYTESDONE;
   1224 			*(u_int32_t *)p = rmask;
   1225 			*(u_int32_t *)(p + offset) = rmask;
   1226 
   1227 			p = (q += scanspan);
   1228 			width = w + align;
   1229 			height--;
   1230 		}
   1231 	}
   1232 	SFBMODE(sfb, MODE_SIMPLE);
   1233 }
   1234 
   1235 /*
   1236  * Erase lines.
   1237  */
   1238 void
   1239 sfb_eraserows(id, startrow, nrows, attr)
   1240 	void *id;
   1241 	int startrow, nrows;
   1242 	long attr;
   1243 {
   1244 	struct rasops_info *ri = id;
   1245 	caddr_t sfb, p;
   1246 	int scanspan, starty, height, width, align, w;
   1247 	u_int32_t lmask, rmask;
   1248 
   1249 	scanspan = ri->ri_stride;
   1250 	starty = ri->ri_font->fontheight * startrow;
   1251 	height = ri->ri_font->fontheight * nrows;
   1252 
   1253 	p = ri->ri_bits + starty * scanspan;
   1254 	align = (long)p & SFBALIGNMASK;
   1255 	p -= align;
   1256 	w = ri->ri_emuwidth;
   1257 	width = w + align;
   1258 	lmask = SFBSTIPPLEALL1 << align;
   1259 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
   1260 	sfb = ri->ri_hw;
   1261 
   1262 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
   1263 	SFBPLANEMASK(sfb, ~0);
   1264 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
   1265 	if (width <= SFBSTIPPLEBITS) {
   1266 		/* never happens */;
   1267 	}
   1268 	else {
   1269 		caddr_t q = p;
   1270 		while (height > 0) {
   1271 			*(u_int32_t *)p = lmask;
   1272 			WRITE_MB();
   1273 			width -= 2 * SFBSTIPPLEBITS;
   1274 			while (width > 0) {
   1275 				p += SFBSTIPPLEBYTESDONE;
   1276 				*(u_int32_t *)p = SFBSTIPPLEALL1;
   1277 				WRITE_MB();
   1278 				width -= SFBSTIPPLEBITS;
   1279 			}
   1280 			p += SFBSTIPPLEBYTESDONE;
   1281 			*(u_int32_t *)p = rmask;
   1282 			WRITE_MB();
   1283 
   1284 			p = (q += scanspan);
   1285 			width = w + align;
   1286 			height--;
   1287 		}
   1288 	}
   1289 	SFBMODE(sfb, MODE_SIMPLE);
   1290 }
   1291