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