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