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