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