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