xref: /netbsd-src/sys/dev/sun/cgsix.c (revision ce2c90c7c172d95d2402a5b3d96d8f8e6d138a21)
1 /*	$NetBSD: cgsix.c,v 1.31 2006/04/15 17:48:24 jmmv Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1993
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * This software was developed by the Computer Systems Engineering group
44  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
45  * contributed to Berkeley.
46  *
47  * All advertising materials mentioning features or use of this software
48  * must display the following acknowledgement:
49  *	This product includes software developed by the University of
50  *	California, Lawrence Berkeley Laboratory.
51  *
52  * Redistribution and use in source and binary forms, with or without
53  * modification, are permitted provided that the following conditions
54  * are met:
55  * 1. Redistributions of source code must retain the above copyright
56  *    notice, this list of conditions and the following disclaimer.
57  * 2. Redistributions in binary form must reproduce the above copyright
58  *    notice, this list of conditions and the following disclaimer in the
59  *    documentation and/or other materials provided with the distribution.
60  * 3. Neither the name of the University nor the names of its contributors
61  *    may be used to endorse or promote products derived from this software
62  *    without specific prior written permission.
63  *
64  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74  * SUCH DAMAGE.
75  *
76  *	@(#)cgsix.c	8.4 (Berkeley) 1/21/94
77  */
78 
79 /*
80  * color display (cgsix) driver.
81  *
82  * Does not handle interrupts, even though they can occur.
83  *
84  * XXX should defer colormap updates to vertical retrace interrupts
85  */
86 
87 #include <sys/cdefs.h>
88 __KERNEL_RCSID(0, "$NetBSD: cgsix.c,v 1.31 2006/04/15 17:48:24 jmmv Exp $");
89 
90 #include <sys/param.h>
91 #include <sys/systm.h>
92 #include <sys/buf.h>
93 #include <sys/device.h>
94 #include <sys/ioctl.h>
95 #include <sys/malloc.h>
96 #include <sys/mman.h>
97 #include <sys/tty.h>
98 #include <sys/conf.h>
99 
100 #ifdef DEBUG
101 #include <sys/proc.h>
102 #include <sys/syslog.h>
103 #endif
104 
105 #include <uvm/uvm_extern.h>
106 
107 #include <machine/bus.h>
108 
109 #include <dev/sun/fbio.h>
110 #include <dev/sun/fbvar.h>
111 
112 #include <dev/sun/btreg.h>
113 #include <dev/sun/btvar.h>
114 #include <dev/sun/pfourreg.h>
115 
116 #include <dev/wscons/wsconsio.h>
117 #include <dev/wsfont/wsfont.h>
118 #include <dev/rasops/rasops.h>
119 
120 #include "opt_wsemul.h"
121 #include "rasops_glue.h"
122 
123 #include <dev/sun/cgsixreg.h>
124 #include <dev/sun/cgsixvar.h>
125 
126 static void	cg6_unblank(struct device *);
127 
128 extern struct cfdriver cgsix_cd;
129 
130 dev_type_open(cgsixopen);
131 dev_type_close(cgsixclose);
132 dev_type_ioctl(cgsixioctl);
133 dev_type_mmap(cgsixmmap);
134 
135 const struct cdevsw cgsix_cdevsw = {
136 	cgsixopen, cgsixclose, noread, nowrite, cgsixioctl,
137 	nostop, notty, nopoll, cgsixmmap, nokqfilter,
138 };
139 
140 /* frame buffer generic driver */
141 static struct fbdriver cg6_fbdriver = {
142 	cg6_unblank, cgsixopen, cgsixclose, cgsixioctl, nopoll, cgsixmmap,
143 	nokqfilter
144 };
145 
146 static void cg6_reset (struct cgsix_softc *);
147 static void cg6_loadcmap (struct cgsix_softc *, int, int);
148 static void cg6_loadomap (struct cgsix_softc *);
149 static void cg6_setcursor (struct cgsix_softc *);/* set position */
150 static void cg6_loadcursor (struct cgsix_softc *);/* set shape */
151 
152 #if NWSDISPLAY > 0
153 static void cg6_setup_palette(struct cgsix_softc *);
154 
155 struct wsscreen_descr cgsix_defaultscreen = {
156 	"std",
157 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
158 	NULL,		/* textops */
159 	8, 16,	/* font width/height */
160 	WSSCREEN_WSCOLORS	/* capabilities */
161 };
162 
163 static int 	cgsix_ioctl(void *, void *, u_long, caddr_t, int, struct lwp *);
164 static paddr_t	cgsix_mmap(void *, void *, off_t, int);
165 void		cgsix_init_screen(struct cgsix_softc *, struct cg6_screen *,
166 			int, long *);
167 
168 static int 	cgsix_alloc_screen(void *, const struct wsscreen_descr *,
169 				void **, int *, int *, long *);
170 static void 	cgsix_free_screen(void *, void *);
171 static int 	cgsix_show_screen(void *, void *, int,
172 				void (*) (void *, int, int), void *);
173 void	cgsix_switch_screen(struct cgsix_softc *);
174 void	cgsix_restore_screen(struct cg6_screen *, const struct wsscreen_descr *, 		u_int16_t *);
175 void	cgsix_clearscreen(struct cgsix_softc *);
176 void 	cgsix_setup_mono(struct cgsix_softc *, int, int, int, int, uint32_t,
177 		uint32_t);
178 void 	cgsix_feed_line(struct cgsix_softc *, int, uint8_t *);
179 void 	cgsix_rectfill(struct cgsix_softc *, int, int, int, int, uint32_t);
180 
181 int	cgsix_putcmap(struct cgsix_softc *, struct wsdisplay_cmap *);
182 int	cgsix_getcmap(struct cgsix_softc *, struct wsdisplay_cmap *);
183 void	cgsix_putchar(void *, int, int, u_int, long);
184 void	cgsix_cursor(void *, int, int, int);
185 
186 
187 struct wsdisplay_accessops cgsix_accessops = {
188 	cgsix_ioctl,
189 	cgsix_mmap,
190 	cgsix_alloc_screen,
191 	cgsix_free_screen,
192 	cgsix_show_screen,
193 	NULL, 	/* load_font */
194 	NULL,	/* pollc */
195 	NULL	/* scroll */
196 };
197 
198 const struct wsscreen_descr *_cgsix_scrlist[] = {
199 	&cgsix_defaultscreen
200 };
201 
202 struct wsscreen_list cgsix_screenlist = {
203 	sizeof(_cgsix_scrlist) / sizeof(struct wsscreen_descr *),
204 	_cgsix_scrlist
205 };
206 
207 
208 extern const u_char rasops_cmap[768];
209 
210 #endif /* NWSDISPLAY > 0 */
211 
212 #if (NWSDISPLAY > 0) || defined(RASTERCONSOLE)
213 void	cg6_invert(struct cgsix_softc *, int, int, int, int);
214 
215 /* need this for both cases because ri_hw points to it */
216 static struct cg6_screen cg6_console_screen;
217 #endif
218 
219 #ifdef RASTERCONSOLE
220 int cgsix_use_rasterconsole = 1;
221 #endif
222 
223 /*
224  * cg6 accelerated console routines.
225  *
226  * Note that buried in this code in several places is the assumption
227  * that pixels are exactly one byte wide.  Since this is cg6-specific
228  * code, this seems safe.  This assumption resides in things like the
229  * use of ri_emuwidth without messing around with ri_pelbytes, or the
230  * assumption that ri_font->fontwidth is the right thing to multiply
231  * character-cell counts by to get byte counts.
232  */
233 
234 /*
235  * Magic values for blitter
236  */
237 
238 /* Values for the mode register */
239 #define CG6_MODE	(						\
240 	  0x00200000 /* GX_BLIT_SRC */					\
241 	| 0x00020000 /* GX_MODE_COLOR8 */				\
242 	| 0x00008000 /* GX_DRAW_RENDER */				\
243 	| 0x00002000 /* GX_BWRITE0_ENABLE */				\
244 	| 0x00001000 /* GX_BWRITE1_DISABLE */				\
245 	| 0x00000200 /* GX_BREAD_0 */					\
246 	| 0x00000080 /* GX_BDISP_0 */					\
247 )
248 #define CG6_MODE_MASK	(						\
249 	  0x00300000 /* GX_BLIT_ALL */					\
250 	| 0x00060000 /* GX_MODE_ALL */					\
251 	| 0x00018000 /* GX_DRAW_ALL */					\
252 	| 0x00006000 /* GX_BWRITE0_ALL */				\
253 	| 0x00001800 /* GX_BWRITE1_ALL */				\
254 	| 0x00000600 /* GX_BREAD_ALL */					\
255 	| 0x00000180 /* GX_BDISP_ALL */					\
256 )
257 
258 /* Value for the alu register for screen-to-screen copies */
259 #define CG6_ALU_COPY	(						\
260 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
261 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
262 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
263 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
264 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
265 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
266 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
267 	| 0x0000cccc /* ALU = src */					\
268 )
269 
270 /* Value for the alu register for region fills */
271 #define CG6_ALU_FILL	(						\
272 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
273 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
274 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
275 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
276 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
277 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
278 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
279 	| 0x0000ff00 /* ALU = fg color */				\
280 )
281 
282 /* Value for the alu register for toggling an area */
283 #define CG6_ALU_FLIP	(						\
284 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
285 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
286 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
287 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
288 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
289 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
290 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
291 	| 0x00005555 /* ALU = ~dst */					\
292 )
293 
294 /*
295  * Wait for a blit to finish.
296  * 0x8000000 bit: function unknown; 0x20000000 bit: GX_BLT_INPROGRESS
297  */
298 #define CG6_BLIT_WAIT(fbc) do {						\
299 	while (((fbc)->fbc_blit & 0xa0000000) == 0xa0000000)		\
300 		/*EMPTY*/;						\
301 } while (0)
302 
303 /*
304  * Wait for a drawing operation to finish, or at least get queued.
305  * 0x8000000 bit: function unknown; 0x20000000 bit: GX_FULL
306  */
307 #define CG6_DRAW_WAIT(fbc) do {						\
308        	while (((fbc)->fbc_draw & 0xa0000000) == 0xa0000000)		\
309 		/*EMPTY*/;						\
310 } while (0)
311 
312 /*
313  * Wait for the whole engine to go idle.  This may not matter in our case;
314  * I'm not sure whether blits are actually queued or not.  It more likely
315  * is intended for lines and such that do get queued.
316  * 0x10000000 bit: GX_INPROGRESS
317  */
318 #define CG6_DRAIN(fbc) do {						\
319 	while ((fbc)->fbc_s & 0x10000000)				\
320 		/*EMPTY*/;						\
321 } while (0)
322 
323 #if (NWSDISPLAY > 0) || defined(RASTERCONSOLE)
324 static void cg6_ras_init(struct cgsix_softc *);
325 static void cg6_ras_copyrows(void *, int, int, int);
326 static void cg6_ras_copycols(void *, int, int, int, int);
327 static void cg6_ras_erasecols(void *, int, int, int, long int);
328 static void cg6_ras_eraserows(void *, int, int, long int);
329 #if defined(RASTERCONSOLE) && defined(CG6_BLIT_CURSOR)
330 static void cg6_ras_do_cursor(struct rasops_info *);
331 #endif
332 static void
333 cg6_ras_init(struct cgsix_softc *sc)
334 {
335 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
336 
337 	CG6_DRAIN(fbc);
338 	fbc->fbc_mode &= ~CG6_MODE_MASK;
339 	fbc->fbc_mode |= CG6_MODE;
340 }
341 
342 static void
343 cg6_ras_copyrows(void *cookie, int src, int dst, int n)
344 {
345 	struct rasops_info *ri=cookie;
346 	struct cg6_screen *scr=ri->ri_hw;
347 	struct cgsix_softc *sc=scr->sc;
348 
349 #if NWSDISPLAY > 0
350 	int from, to, len;
351 
352 	from = ri->ri_cols * src;
353 	to = ri->ri_cols * dst;
354 	len = ri->ri_cols * n;
355 
356 	memmove(&scr->attrs[to], &scr->attrs[from], len * sizeof(long));
357 	memmove(&scr->chars[to], &scr->chars[from], len * sizeof(uint16_t));
358 
359 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
360 #endif
361 		volatile struct cg6_fbc *fbc = sc->sc_fbc;
362 
363 		if (dst == src)
364 			return;
365 		if (src < 0) {
366 			n += src;
367 			src = 0;
368 		}
369 		if (src+n > ri->ri_rows)
370 			n = ri->ri_rows - src;
371 		if (dst < 0) {
372 			n += dst;
373 			dst = 0;
374 		}
375 		if (dst+n > ri->ri_rows)
376 			n = ri->ri_rows - dst;
377 		if (n <= 0)
378 			return;
379 		n *= ri->ri_font->fontheight;
380 		src *= ri->ri_font->fontheight;
381 		dst *= ri->ri_font->fontheight;
382 		fbc->fbc_clip = 0;
383 		fbc->fbc_s = 0;
384 		fbc->fbc_offx = 0;
385 		fbc->fbc_offy = 0;
386 		fbc->fbc_clipminx = 0;
387 		fbc->fbc_clipminy = 0;
388 		fbc->fbc_clipmaxx = ri->ri_width - 1;
389 		fbc->fbc_clipmaxy = ri->ri_height - 1;
390 		fbc->fbc_alu = CG6_ALU_COPY;
391 		fbc->fbc_x0 = ri->ri_xorigin;
392 		fbc->fbc_y0 = ri->ri_yorigin + src;
393 		fbc->fbc_x1 = ri->ri_xorigin + ri->ri_emuwidth - 1;
394 		fbc->fbc_y1 = ri->ri_yorigin + src + n - 1;
395 		fbc->fbc_x2 = ri->ri_xorigin;
396 		fbc->fbc_y2 = ri->ri_yorigin + dst;
397 		fbc->fbc_x3 = ri->ri_xorigin + ri->ri_emuwidth - 1;
398 		fbc->fbc_y3 = ri->ri_yorigin + dst + n - 1;
399 		CG6_BLIT_WAIT(fbc);
400 		CG6_DRAIN(fbc);
401 #if NWSDISPLAY > 0
402 	}
403 #endif
404 }
405 
406 static void
407 cg6_ras_copycols(void *cookie, int row, int src, int dst, int n)
408 {
409 	struct rasops_info *ri=cookie;
410 	struct cg6_screen *scr=ri->ri_hw;
411 	struct cgsix_softc *sc=scr->sc;
412 
413 #if NWSDISPLAY > 0
414 	int from, to;
415 
416 	from = src + row * ri->ri_cols;
417 	to = dst + row * ri->ri_cols;
418 
419 	memmove(&scr->attrs[to], &scr->attrs[from], n * sizeof(long));
420 	memmove(&scr->chars[to], &scr->chars[from], n * sizeof(uint16_t));
421 
422 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
423 #endif
424 		volatile struct cg6_fbc *fbc = sc->sc_fbc;
425 
426 		if (dst == src)
427 			return;
428 		if ((row < 0) || (row >= ri->ri_rows))
429 			return;
430 		if (src < 0) {
431 			n += src;
432 			src = 0;
433 		}
434 		if (src+n > ri->ri_cols)
435 			n = ri->ri_cols - src;
436 		if (dst < 0) {
437 			n += dst;
438 			dst = 0;
439 		}
440 		if (dst+n > ri->ri_cols)
441 			n = ri->ri_cols - dst;
442 		if (n <= 0)
443 			return;
444 		n *= ri->ri_font->fontwidth;
445 		src *= ri->ri_font->fontwidth;
446 		dst *= ri->ri_font->fontwidth;
447 		row *= ri->ri_font->fontheight;
448 		fbc->fbc_clip = 0;
449 		fbc->fbc_s = 0;
450 		fbc->fbc_offx = 0;
451 		fbc->fbc_offy = 0;
452 		fbc->fbc_clipminx = 0;
453 		fbc->fbc_clipminy = 0;
454 		fbc->fbc_clipmaxx = ri->ri_width - 1;
455 		fbc->fbc_clipmaxy = ri->ri_height - 1;
456 		fbc->fbc_alu = CG6_ALU_COPY;
457 		fbc->fbc_x0 = ri->ri_xorigin + src;
458 		fbc->fbc_y0 = ri->ri_yorigin + row;
459 		fbc->fbc_x1 = ri->ri_xorigin + src + n - 1;
460 		fbc->fbc_y1 = ri->ri_yorigin + row +
461 		    ri->ri_font->fontheight - 1;
462 		fbc->fbc_x2 = ri->ri_xorigin + dst;
463 		fbc->fbc_y2 = ri->ri_yorigin + row;
464 		fbc->fbc_x3 = ri->ri_xorigin + dst + n - 1;
465 		fbc->fbc_y3 = ri->ri_yorigin + row +
466 		    ri->ri_font->fontheight - 1;
467 		CG6_BLIT_WAIT(fbc);
468 		CG6_DRAIN(fbc);
469 #if NWSDISPLAY > 0
470 	}
471 #endif
472 }
473 
474 static void
475 cg6_ras_erasecols(void *cookie, int row, int col, int n, long int attr)
476 {
477 	struct rasops_info *ri=cookie;
478 	struct cg6_screen *scr=ri->ri_hw;
479 	struct cgsix_softc *sc=scr->sc;
480 
481 #if NWSDISPLAY > 0
482 	int start, end, i;
483 
484 	start = col + row * ri->ri_cols;
485 	end = start + n;
486 
487 	for (i = start; i < end; i++) {
488 		scr->attrs[i] = attr;
489 		scr->chars[i] = 0x20;
490 	}
491 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
492 #endif
493 		volatile struct cg6_fbc *fbc = sc->sc_fbc;
494 
495 		if ((row < 0) || (row >= ri->ri_rows))
496 			return;
497 		if (col < 0) {
498 			n += col;
499 			col = 0;
500 		}
501 		if (col+n > ri->ri_cols)
502 			n = ri->ri_cols - col;
503 		if (n <= 0)
504 			return;
505 		n *= ri->ri_font->fontwidth;
506 		col *= ri->ri_font->fontwidth;
507 		row *= ri->ri_font->fontheight;
508 		fbc->fbc_clip = 0;
509 		fbc->fbc_s = 0;
510 		fbc->fbc_offx = 0;
511 		fbc->fbc_offy = 0;
512 		fbc->fbc_clipminx = 0;
513 		fbc->fbc_clipminy = 0;
514 		fbc->fbc_clipmaxx = ri->ri_width - 1;
515 		fbc->fbc_clipmaxy = ri->ri_height - 1;
516 		fbc->fbc_alu = CG6_ALU_FILL;
517 		fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xff];
518 		fbc->fbc_arecty = ri->ri_yorigin + row;
519 		fbc->fbc_arectx = ri->ri_xorigin + col;
520 		fbc->fbc_arecty = ri->ri_yorigin + row +
521 		    ri->ri_font->fontheight - 1;
522 		fbc->fbc_arectx = ri->ri_xorigin + col + n - 1;
523 		CG6_DRAW_WAIT(fbc);
524 		CG6_DRAIN(fbc);
525 #if NWSDISPLAY > 0
526 	}
527 #endif
528 }
529 
530 static void
531 cg6_ras_eraserows(void *cookie, int row, int n, long int attr)
532 {
533 	struct rasops_info *ri=cookie;
534 	struct cg6_screen *scr=ri->ri_hw;
535 	struct cgsix_softc *sc=scr->sc;
536 
537 #if NWSDISPLAY > 0
538 	int start, end, i;
539 
540 	start = ri->ri_cols*row;
541 	end = ri->ri_cols * (row + n);
542 
543 	for (i = start; i < end; i++) {
544 		scr->attrs[i] = attr;
545 		scr->chars[i] = 0x20;
546 	}
547 
548 	if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
549 #endif
550 		volatile struct cg6_fbc *fbc = sc->sc_fbc;
551 
552 		if (row < 0) {
553 			n += row;
554 			row = 0;
555 		}
556 		if (row+n > ri->ri_rows)
557 			n = ri->ri_rows - row;
558 		if (n <= 0)
559 			return;
560 		fbc->fbc_clip = 0;
561 		fbc->fbc_s = 0;
562 		fbc->fbc_offx = 0;
563 		fbc->fbc_offy = 0;
564 		fbc->fbc_clipminx = 0;
565 		fbc->fbc_clipminy = 0;
566 		fbc->fbc_clipmaxx = ri->ri_width - 1;
567 		fbc->fbc_clipmaxy = ri->ri_height - 1;
568 		fbc->fbc_alu = CG6_ALU_FILL;
569 		fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xff];
570 		if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
571 			fbc->fbc_arecty = 0;
572 			fbc->fbc_arectx = 0;
573 			fbc->fbc_arecty = ri->ri_height - 1;
574 			fbc->fbc_arectx = ri->ri_width - 1;
575 		} else {
576 			row *= ri->ri_font->fontheight;
577 			fbc->fbc_arecty = ri->ri_yorigin + row;
578 			fbc->fbc_arectx = ri->ri_xorigin;
579 			fbc->fbc_arecty = ri->ri_yorigin + row +
580 			    (n * ri->ri_font->fontheight) - 1;
581 			fbc->fbc_arectx = ri->ri_xorigin + ri->ri_emuwidth - 1;
582 		}
583 		CG6_DRAW_WAIT(fbc);
584 		CG6_DRAIN(fbc);
585 #if NWSDISPLAY > 0
586 	}
587 #endif
588 }
589 
590 #if defined(RASTERCONSOLE) && defined(CG6_BLIT_CURSOR)
591 /*
592  * Really want something more like fg^bg here, but that would be more
593  * or less impossible to migrate to colors.  So we hope there's
594  * something not too inappropriate in the colormap...besides, it's what
595  * the non-accelerated code did. :-)
596  */
597 static void
598 cg6_ras_do_cursor(struct rasops_info *ri)
599 {
600 	struct cg6_screen *scr = ri->ri_hw;
601 	struct cgsix_softc *sc = scr->sc;
602 	int row, col;
603 
604 	row = ri->ri_crow * ri->ri_font->fontheight;
605 	col = ri->ri_ccol * ri->ri_font->fontwidth;
606 	cg6_invert(sc, ri->ri_xorigin + col,ri->ri_yorigin +
607 	    row, ri->ri_font->fontwidth, ri->ri_font->fontheight);
608 }
609 #endif	/* RASTERCONSOLE */
610 
611 #endif	/* (NWSDISPLAY > 0) || defined(RASTERCONSOLE) */
612 
613 void
614 cg6attach(struct cgsix_softc *sc, const char *name, int isconsole)
615 {
616 	struct fbdevice *fb = &sc->sc_fb;
617 #if NWSDISPLAY > 0
618 	struct wsemuldisplaydev_attach_args aa;
619 	struct rasops_info *ri = &cg6_console_screen.ri;
620 	unsigned long defattr;
621 #endif
622 
623 	fb->fb_driver = &cg6_fbdriver;
624 
625 	/* Don't have to map the pfour register on the cgsix. */
626 	fb->fb_pfour = NULL;
627 
628 	fb->fb_type.fb_cmsize = 256;
629 	fb->fb_type.fb_size = sc->sc_ramsize;
630 	/*fb->fb_type.fb_height * fb->fb_linebytes;*/
631 	printf(": %s, %d x %d", name,
632 	       fb->fb_type.fb_width, fb->fb_type.fb_height);
633 	if(sc->sc_fhc) {
634 		sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) &
635 			(FHC_REV_MASK >> FHC_REV_SHIFT);
636 	} else
637 		sc->sc_fhcrev=-1;
638 	printf(", rev %d", sc->sc_fhcrev);
639 
640 	/* reset cursor & frame buffer controls */
641 	cg6_reset(sc);
642 
643 	/* enable video */
644 	sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
645 
646 	if (isconsole) {
647 		printf(" (console)");
648 
649 /* this is the old console attachment stuff - sparc still needs it */
650 #ifdef RASTERCONSOLE
651 		if (cgsix_use_rasterconsole) {
652 			fbrcons_init(&sc->sc_fb);
653 			/*
654 			 * we don't use the screen struct but keep it here to
655 			 * avoid ugliness in the cg6_ras_* functions
656 			 */
657 			cg6_console_screen.sc = sc;
658 			sc->sc_fb.fb_rinfo.ri_hw = &cg6_console_screen;
659 			sc->sc_fb.fb_rinfo.ri_ops.copyrows = cg6_ras_copyrows;
660 			sc->sc_fb.fb_rinfo.ri_ops.copycols = cg6_ras_copycols;
661 			sc->sc_fb.fb_rinfo.ri_ops.erasecols = cg6_ras_erasecols;
662 			sc->sc_fb.fb_rinfo.ri_ops.eraserows = cg6_ras_eraserows;
663 #ifdef CG6_BLIT_CURSOR
664 			sc->sc_fb.fb_rinfo.ri_do_cursor = cg6_ras_do_cursor;
665 #endif
666 			cg6_ras_init(sc);
667 		}
668 #endif
669 	}
670 	printf("\n");
671 
672 	fb_attach(&sc->sc_fb, isconsole);
673 	sc->sc_width = fb->fb_type.fb_width;
674 	sc->sc_stride = fb->fb_type.fb_width;
675 	sc->sc_height = fb->fb_type.fb_height;
676 
677 	printf("%s: framebuffer size: %d MB\n", sc->sc_dev.dv_xname,
678 	    sc->sc_ramsize >> 20);
679 
680 #if NWSDISPLAY
681 	/* setup rasops and so on for wsdisplay */
682 	wsfont_init();
683 	cg6_ras_init(sc);
684 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
685 	sc->sc_bg = WS_DEFAULT_BG;
686 
687 	LIST_INIT(&sc->screens);
688 	sc->active = NULL;
689 	sc->currenttype = &cgsix_defaultscreen;
690 	callout_init(&sc->switch_callout);
691 
692 	if(isconsole) {
693 		/* we mess with cg6_console_screen only once */
694 		cgsix_init_screen(sc, &cg6_console_screen, 1, &defattr);
695 		cgsix_defaultscreen.textops = &ri->ri_ops;
696 		cgsix_defaultscreen.capabilities = ri->ri_caps;
697 		cgsix_defaultscreen.nrows = ri->ri_rows;
698 		cgsix_defaultscreen.ncols = ri->ri_cols;
699 		cg6_console_screen.active = 1;
700 		sc->active = &cg6_console_screen;
701 		wsdisplay_cnattach(&cgsix_defaultscreen, ri, 0, 0, defattr);
702 	} else {
703 		/*
704 		 * we're not the console so we just clear the screen and don't
705 		 * set up any sort of text display
706 		 */
707 		if (cgsix_defaultscreen.textops == NULL) {
708 			/*
709 			 * ugly, but...
710 			 * we want the console settings to win, so we only
711 			 * touch anything when we find an untouched screen
712 			 * definition. In this case we fill it from fb to
713 			 * avoid problems in case no cgsix is the console
714 			 */
715 			ri = &sc->sc_fb.fb_rinfo;
716 			cgsix_defaultscreen.textops = &ri->ri_ops;
717 			cgsix_defaultscreen.capabilities = ri->ri_caps;
718 			cgsix_defaultscreen.nrows = ri->ri_rows;
719 			cgsix_defaultscreen.ncols = ri->ri_cols;
720 		}
721 		sc->active = NULL;
722 		cgsix_clearscreen(sc);
723 	}
724 
725 	cg6_setup_palette(sc);
726 
727 	aa.scrdata = &cgsix_screenlist;
728 	aa.console = isconsole;
729 	aa.accessops = &cgsix_accessops;
730 	aa.accesscookie = sc;
731 	config_found(&sc->sc_dev, &aa, wsemuldisplaydevprint);
732 #else
733 	bt_initcmap(&sc->sc_cmap, 256);
734 	cg6_loadcmap(sc, 0, 256);
735 
736 #endif
737 
738 }
739 
740 
741 int
742 cgsixopen(dev_t dev, int flags, int mode, struct lwp *l)
743 {
744 	int unit = minor(dev);
745 
746 	if (unit >= cgsix_cd.cd_ndevs || cgsix_cd.cd_devs[unit] == NULL)
747 		return ENXIO;
748 	return 0;
749 }
750 
751 int
752 cgsixclose(dev_t dev, int flags, int mode, struct lwp *l)
753 {
754 	struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
755 
756 	cg6_reset(sc);
757 
758 #if NWSDISPLAY > 0
759 	cg6_setup_palette(sc);
760 #else
761 	/* (re-)initialize the default color map */
762 	bt_initcmap(&sc->sc_cmap, 256);
763 
764 	cg6_loadcmap(sc, 0, 256);
765 #endif
766 
767 	return 0;
768 }
769 
770 int
771 cgsixioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct lwp *l)
772 {
773 	struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
774 	union cursor_cmap tcm;
775 	uint32_t image[32], mask[32];
776 	u_int count;
777 	int v, error;
778 
779 #ifdef CGSIX_DEBUG
780 	printf("cgsixioctl(%ld)\n",cmd);
781 #endif
782 
783 	switch (cmd) {
784 
785 	case FBIOGTYPE:
786 		*(struct fbtype *)data = sc->sc_fb.fb_type;
787 		break;
788 
789 	case FBIOGATTR:
790 #define fba ((struct fbgattr *)data)
791 		fba->real_type = sc->sc_fb.fb_type.fb_type;
792 		fba->owner = 0;		/* XXX ??? */
793 		fba->fbtype = sc->sc_fb.fb_type;
794 		fba->sattr.flags = 0;
795 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
796 		fba->sattr.dev_specific[0] = -1;
797 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
798 		fba->emu_types[1] = -1;
799 #undef fba
800 		break;
801 
802 	case FBIOGETCMAP:
803 #define	p ((struct fbcmap *)data)
804 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
805 
806 	case FBIOPUTCMAP:
807 		/* copy to software map */
808 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
809 		if (error)
810 			return error;
811 		/* now blast them into the chip */
812 		/* XXX should use retrace interrupt */
813 		cg6_loadcmap(sc, p->index, p->count);
814 #undef p
815 		break;
816 
817 	case FBIOGVIDEO:
818 		*(int *)data = sc->sc_blanked;
819 		break;
820 
821 	case FBIOSVIDEO:
822 		if (*(int *)data)
823 			cg6_unblank(&sc->sc_dev);
824 		else if (!sc->sc_blanked) {
825 			sc->sc_blanked = 1;
826 			sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN;
827 		}
828 		break;
829 
830 /* these are for both FBIOSCURSOR and FBIOGCURSOR */
831 #define p ((struct fbcursor *)data)
832 #define cc (&sc->sc_cursor)
833 
834 	case FBIOGCURSOR:
835 		/* do not quite want everything here... */
836 		p->set = FB_CUR_SETALL;	/* close enough, anyway */
837 		p->enable = cc->cc_enable;
838 		p->pos = cc->cc_pos;
839 		p->hot = cc->cc_hot;
840 		p->size = cc->cc_size;
841 
842 		/* begin ugh ... can we lose some of this crap?? */
843 		if (p->image != NULL) {
844 			count = cc->cc_size.y * 32 / NBBY;
845 			error = copyout(cc->cc_bits[1], p->image, count);
846 			if (error)
847 				return error;
848 			error = copyout(cc->cc_bits[0], p->mask, count);
849 			if (error)
850 				return error;
851 		}
852 		if (p->cmap.red != NULL) {
853 			error = bt_getcmap(&p->cmap,
854 			    (union bt_cmap *)&cc->cc_color, 2, 1);
855 			if (error)
856 				return error;
857 		} else {
858 			p->cmap.index = 0;
859 			p->cmap.count = 2;
860 		}
861 		/* end ugh */
862 		break;
863 
864 	case FBIOSCURSOR:
865 		/*
866 		 * For setcmap and setshape, verify parameters, so that
867 		 * we do not get halfway through an update and then crap
868 		 * out with the software state screwed up.
869 		 */
870 		v = p->set;
871 		if (v & FB_CUR_SETCMAP) {
872 			/*
873 			 * This use of a temporary copy of the cursor
874 			 * colormap is not terribly efficient, but these
875 			 * copies are small (8 bytes)...
876 			 */
877 			tcm = cc->cc_color;
878 			error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2,
879 			    1);
880 			if (error)
881 				return error;
882 		}
883 		if (v & FB_CUR_SETSHAPE) {
884 			if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32)
885 				return EINVAL;
886 			count = p->size.y * 32 / NBBY;
887 			error = copyin(p->image, image, count);
888 			if (error)
889 				return error;
890 			error = copyin(p->mask, mask, count);
891 			if (error)
892 				return error;
893 		}
894 
895 		/* parameters are OK; do it */
896 		if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) {
897 			if (v & FB_CUR_SETCUR)
898 				cc->cc_enable = p->enable;
899 			if (v & FB_CUR_SETPOS)
900 				cc->cc_pos = p->pos;
901 			if (v & FB_CUR_SETHOT)
902 				cc->cc_hot = p->hot;
903 			cg6_setcursor(sc);
904 		}
905 		if (v & FB_CUR_SETCMAP) {
906 			cc->cc_color = tcm;
907 			cg6_loadomap(sc); /* XXX defer to vertical retrace */
908 		}
909 		if (v & FB_CUR_SETSHAPE) {
910 			cc->cc_size = p->size;
911 			count = p->size.y * 32 / NBBY;
912 			memset(cc->cc_bits, 0, sizeof cc->cc_bits);
913 			memcpy(cc->cc_bits[1], image, count);
914 			memcpy(cc->cc_bits[0], mask, count);
915 			cg6_loadcursor(sc);
916 		}
917 		break;
918 
919 #undef p
920 #undef cc
921 
922 	case FBIOGCURPOS:
923 		*(struct fbcurpos *)data = sc->sc_cursor.cc_pos;
924 		break;
925 
926 	case FBIOSCURPOS:
927 		sc->sc_cursor.cc_pos = *(struct fbcurpos *)data;
928 		cg6_setcursor(sc);
929 		break;
930 
931 	case FBIOGCURMAX:
932 		/* max cursor size is 32x32 */
933 		((struct fbcurpos *)data)->x = 32;
934 		((struct fbcurpos *)data)->y = 32;
935 		break;
936 
937 	default:
938 #ifdef DEBUG
939 		log(LOG_NOTICE, "cgsixioctl(0x%lx) (%s[%d])\n", cmd,
940 		    l->l_proc->p_comm, l->l_proc->p_pid);
941 #endif
942 		return ENOTTY;
943 	}
944 	return 0;
945 }
946 
947 /*
948  * Clean up hardware state (e.g., after bootup or after X crashes).
949  */
950 static void
951 cg6_reset(struct cgsix_softc *sc)
952 {
953 	volatile struct cg6_tec_xxx *tec;
954 	int fhc;
955 	volatile struct bt_regs *bt;
956 
957 	/* hide the cursor, just in case */
958 	sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF;
959 
960 	/* turn off frobs in transform engine (makes X11 work) */
961 	tec = sc->sc_tec;
962 	tec->tec_mv = 0;
963 	tec->tec_clip = 0;
964 	tec->tec_vdc = 0;
965 
966 	/* take care of hardware bugs in old revisions */
967 	if (sc->sc_fhcrev < 5) {
968 		/*
969 		 * Keep current resolution; set CPU to 68020, set test
970 		 * window (size 1Kx1K), and for rev 1, disable dest cache.
971 		 */
972 		fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 |
973 		    FHC_TEST |
974 		    (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT);
975 		if (sc->sc_fhcrev < 2)
976 			fhc |= FHC_DST_DISABLE;
977 		*sc->sc_fhc = fhc;
978 	}
979 
980 	/* Enable cursor in Brooktree DAC. */
981 	bt = sc->sc_bt;
982 	bt->bt_addr = 0x06 << 24;
983 	bt->bt_ctrl |= 0x03 << 24;
984 }
985 
986 static void
987 cg6_setcursor(struct cgsix_softc *sc)
988 {
989 
990 	/* we need to subtract the hot-spot value here */
991 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f)
992 	sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ?
993 	    ((COORD(x) << 16) | (COORD(y) & 0xffff)) :
994 	    (THC_CURSOFF << 16) | THC_CURSOFF;
995 #undef COORD
996 }
997 
998 static void
999 cg6_loadcursor(struct cgsix_softc *sc)
1000 {
1001 	volatile struct cg6_thc *thc;
1002 	u_int edgemask, m;
1003 	int i;
1004 
1005 	/*
1006 	 * Keep the top size.x bits.  Here we *throw out* the top
1007 	 * size.x bits from an all-one-bits word, introducing zeros in
1008 	 * the top size.x bits, then invert all the bits to get what
1009 	 * we really wanted as our mask.  But this fails if size.x is
1010 	 * 32---a sparc uses only the low 5 bits of the shift count---
1011 	 * so we have to special case that.
1012 	 */
1013 	edgemask = ~0;
1014 	if (sc->sc_cursor.cc_size.x < 32)
1015 		edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x);
1016 	thc = sc->sc_thc;
1017 	for (i = 0; i < 32; i++) {
1018 		m = sc->sc_cursor.cc_bits[0][i] & edgemask;
1019 		thc->thc_cursmask[i] = m;
1020 		thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i];
1021 	}
1022 }
1023 
1024 /*
1025  * Load a subset of the current (new) colormap into the color DAC.
1026  */
1027 static void
1028 cg6_loadcmap(struct cgsix_softc *sc, int start, int ncolors)
1029 {
1030 	volatile struct bt_regs *bt;
1031 	u_int *ip, i;
1032 	int count;
1033 
1034 	ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)];	/* start/4 * 3 */
1035 	count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
1036 	bt = sc->sc_bt;
1037 	bt->bt_addr = BT_D4M4(start) << 24;
1038 	while (--count >= 0) {
1039 		i = *ip++;
1040 		/* hardware that makes one want to pound boards with hammers */
1041 		bt->bt_cmap = i;
1042 		bt->bt_cmap = i << 8;
1043 		bt->bt_cmap = i << 16;
1044 		bt->bt_cmap = i << 24;
1045 	}
1046 }
1047 
1048 /*
1049  * Load the cursor (overlay `foreground' and `background') colors.
1050  */
1051 static void
1052 cg6_loadomap(struct cgsix_softc *sc)
1053 {
1054 	volatile struct bt_regs *bt;
1055 	u_int i;
1056 
1057 	bt = sc->sc_bt;
1058 	bt->bt_addr = 0x01 << 24;	/* set background color */
1059 	i = sc->sc_cursor.cc_color.cm_chip[0];
1060 	bt->bt_omap = i;		/* R */
1061 	bt->bt_omap = i << 8;		/* G */
1062 	bt->bt_omap = i << 16;		/* B */
1063 
1064 	bt->bt_addr = 0x03 << 24;	/* set foreground color */
1065 	bt->bt_omap = i << 24;		/* R */
1066 	i = sc->sc_cursor.cc_color.cm_chip[1];
1067 	bt->bt_omap = i;		/* G */
1068 	bt->bt_omap = i << 8;		/* B */
1069 }
1070 
1071 static void
1072 cg6_unblank(struct device *dev)
1073 {
1074 	struct cgsix_softc *sc = (struct cgsix_softc *)dev;
1075 
1076 	if (sc->sc_blanked) {
1077 		sc->sc_blanked = 0;
1078 		sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
1079 	}
1080 }
1081 
1082 /* XXX the following should be moved to a "user interface" header */
1083 /*
1084  * Base addresses at which users can mmap() the various pieces of a cg6.
1085  * Note that although the Brooktree color registers do not occupy 8K,
1086  * the X server dies if we do not allow it to map 8K there (it just maps
1087  * from 0x70000000 forwards, as a contiguous chunk).
1088  */
1089 #define	CG6_USER_FBC	0x70000000
1090 #define	CG6_USER_TEC	0x70001000
1091 #define	CG6_USER_BTREGS	0x70002000
1092 #define	CG6_USER_FHC	0x70004000
1093 #define	CG6_USER_THC	0x70005000
1094 #define	CG6_USER_ROM	0x70006000
1095 #define	CG6_USER_RAM	0x70016000
1096 #define	CG6_USER_DHC	0x80000000
1097 
1098 struct mmo {
1099 	u_long	mo_uaddr;	/* user (virtual) address */
1100 	u_long	mo_size;	/* size, or 0 for video ram size */
1101 	u_long	mo_physoff;	/* offset from sc_physadr */
1102 };
1103 
1104 /*
1105  * Return the address that would map the given device at the given
1106  * offset, allowing for the given protection, or return -1 for error.
1107  *
1108  * XXX	needs testing against `demanding' applications (e.g., aviator)
1109  */
1110 paddr_t
1111 cgsixmmap(dev_t dev, off_t off, int prot)
1112 {
1113 	struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
1114 	struct mmo *mo;
1115 	u_int u, sz;
1116 	static struct mmo mmo[] = {
1117 		{ CG6_USER_RAM, 0, CGSIX_RAM_OFFSET },
1118 
1119 		/* do not actually know how big most of these are! */
1120 		{ CG6_USER_FBC, 1, CGSIX_FBC_OFFSET },
1121 		{ CG6_USER_TEC, 1, CGSIX_TEC_OFFSET },
1122 		{ CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET },
1123 		{ CG6_USER_FHC, 1, CGSIX_FHC_OFFSET },
1124 		{ CG6_USER_THC, sizeof(struct cg6_thc), CGSIX_THC_OFFSET },
1125 		{ CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET },
1126 		{ CG6_USER_DHC, 1, CGSIX_DHC_OFFSET },
1127 	};
1128 #define NMMO (sizeof mmo / sizeof *mmo)
1129 
1130 	if (off & PGOFSET)
1131 		panic("cgsixmmap");
1132 
1133 	/*
1134 	 * Entries with size 0 map video RAM (i.e., the size in fb data).
1135 	 *
1136 	 * Since we work in pages, the fact that the map offset table's
1137 	 * sizes are sometimes bizarre (e.g., 1) is effectively ignored:
1138 	 * one byte is as good as one page.
1139 	 */
1140 	for (mo = mmo; mo < &mmo[NMMO]; mo++) {
1141 		if ((u_long)off < mo->mo_uaddr)
1142 			continue;
1143 		u = off - mo->mo_uaddr;
1144 		sz = mo->mo_size ? mo->mo_size :
1145 		    sc->sc_ramsize/*sc_fb.fb_type.fb_size*/;
1146 		if (u < sz) {
1147 			return (bus_space_mmap(sc->sc_bustag,
1148 				sc->sc_paddr, u+mo->mo_physoff,
1149 				prot, BUS_SPACE_MAP_LINEAR));
1150 		}
1151 	}
1152 
1153 #ifdef DEBUG
1154 	{
1155 	  struct proc *p = curlwp->l_proc;	/* XXX */
1156 	  log(LOG_NOTICE, "cgsixmmap(0x%llx) (%s[%d])\n",
1157 		(long long)off, p->p_comm, p->p_pid);
1158 	}
1159 #endif
1160 	return -1;	/* not a user-map offset */
1161 }
1162 
1163 #if NWSDISPLAY > 0
1164 
1165 static void
1166 cg6_setup_palette(struct cgsix_softc *sc)
1167 {
1168 	int i, j;
1169 
1170 	j = 0;
1171 	for (i = 0; i < 256; i++) {
1172 		sc->sc_cmap.cm_map[i][0] = rasops_cmap[j];
1173 		j++;
1174 		sc->sc_cmap.cm_map[i][1] = rasops_cmap[j];
1175 		j++;
1176 		sc->sc_cmap.cm_map[i][2] = rasops_cmap[j];
1177 		j++;
1178 	}
1179 	cg6_loadcmap(sc, 0, 256);
1180 }
1181 
1182 int
1183 cgsix_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
1184 	struct lwp *l)
1185 {
1186 	/* we'll probably need to add more stuff here */
1187 	struct cgsix_softc *sc = v;
1188 	struct wsdisplay_fbinfo *wdf;
1189 	struct rasops_info *ri = &sc->sc_fb.fb_rinfo;
1190 	struct cg6_screen *ms = sc->active;
1191 #ifdef CGSIX_DEBUG
1192 	printf("cgsix_ioctl(%ld)\n",cmd);
1193 #endif
1194 	switch (cmd) {
1195 		case WSDISPLAYIO_GTYPE:
1196 			*(u_int *)data = WSDISPLAY_TYPE_SUNTCX;
1197 			return 0;
1198 		case WSDISPLAYIO_GINFO:
1199 			wdf = (void *)data;
1200 			wdf->height = ri->ri_height;
1201 			wdf->width = ri->ri_width;
1202 			wdf->depth = ri->ri_depth;
1203 			wdf->cmsize = 256;
1204 			return 0;
1205 
1206 		case WSDISPLAYIO_GETCMAP:
1207 			return cgsix_getcmap(sc,
1208 			    (struct wsdisplay_cmap *)data);
1209 		case WSDISPLAYIO_PUTCMAP:
1210 			return cgsix_putcmap(sc,
1211 			    (struct wsdisplay_cmap *)data);
1212 
1213 		case WSDISPLAYIO_SMODE:
1214 			{
1215 				int new_mode = *(int*)data;
1216 				if (new_mode != sc->sc_mode)
1217 				{
1218 					sc->sc_mode = new_mode;
1219 					if(new_mode == WSDISPLAYIO_MODE_EMUL)
1220 					{
1221 						cg6_reset(sc);
1222 						cg6_ras_init(sc);
1223 						/* restore the screen content */
1224 						cgsix_restore_screen(ms,
1225 						    ms->type, ms->chars);
1226 						/*
1227 						 * because X likes to bork up
1228 						 * our colour map
1229 						 */
1230 						cg6_setup_palette(sc);									/* and draw the cursor */
1231 						cgsix_cursor(ms, ms->cursoron,
1232 						    ms->cursorrow,
1233 						    ms->cursorcol);
1234 					}
1235 				}
1236 			}
1237 	}
1238 	return EPASSTHROUGH;
1239 }
1240 
1241 paddr_t
1242 cgsix_mmap(void *v, void *vs, off_t offset, int prot)
1243 {
1244 	struct cgsix_softc *sc = v;
1245 	if(offset<sc->sc_ramsize) {
1246 		return bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
1247 		    CGSIX_RAM_OFFSET+offset, prot, BUS_SPACE_MAP_LINEAR);
1248 	}
1249 	/* I'm not at all sure this is the right thing to do */
1250 	return cgsixmmap(0, offset, prot); /* assume minor dev 0 for now */
1251 }
1252 
1253 int
1254 cgsix_putcmap(struct cgsix_softc *sc, struct wsdisplay_cmap *cm)
1255 {
1256 	u_int index = cm->index;
1257 	u_int count = cm->count;
1258 	int error,i;
1259 	if (index >= 256 || count > 256 || index + count > 256)
1260 		return EINVAL;
1261 
1262 	for (i = 0; i < count; i++)
1263 	{
1264 		error = copyin(&cm->red[i],
1265 		    &sc->sc_cmap.cm_map[index + i][0], 1);
1266 		if (error)
1267 			return error;
1268 		error = copyin(&cm->green[i],
1269 		    &sc->sc_cmap.cm_map[index + i][1],
1270 		    1);
1271 		if (error)
1272 			return error;
1273 		error = copyin(&cm->blue[i],
1274 		    &sc->sc_cmap.cm_map[index + i][2], 1);
1275 		if (error)
1276 			return error;
1277 	}
1278 	cg6_loadcmap(sc, index, count);
1279 
1280 	return 0;
1281 }
1282 
1283 int
1284 cgsix_getcmap(struct cgsix_softc *sc, struct wsdisplay_cmap *cm)
1285 {
1286 	u_int index = cm->index;
1287 	u_int count = cm->count;
1288 	int error,i;
1289 
1290 	if (index >= 256 || count > 256 || index + count > 256)
1291 		return EINVAL;
1292 
1293 	for (i = 0; i < count; i++)
1294 	{
1295 		error = copyout(&sc->sc_cmap.cm_map[index + i][0],
1296 		    &cm->red[i], 1);
1297 		if (error)
1298 			return error;
1299 		error = copyout(&sc->sc_cmap.cm_map[index + i][1],
1300 		    &cm->green[i], 1);
1301 		if (error)
1302 			return error;
1303 		error = copyout(&sc->sc_cmap.cm_map[index + i][2],
1304 		    &cm->blue[i], 1);
1305 		if (error)
1306 			return error;
1307 	}
1308 
1309 	return 0;
1310 }
1311 
1312 void
1313 cgsix_init_screen(struct cgsix_softc *sc, struct cg6_screen *scr,
1314     int existing, long *defattr)
1315 {
1316 	struct rasops_info *ri = &scr->ri;
1317 	int cnt;
1318 	scr->sc = sc;
1319 	/*scr->type = type;*/
1320 	scr->cursorcol = 0;
1321 	scr->cursorrow = 0;
1322 	scr->cursordrawn = 0;
1323 
1324 	ri->ri_depth = 8;
1325 	ri->ri_width = sc->sc_width;
1326 	ri->ri_height = sc->sc_height;
1327 	ri->ri_stride = sc->sc_stride;
1328 	ri->ri_flg = RI_CENTER;
1329 
1330 	ri->ri_bits = sc->sc_fb.fb_pixels;
1331 
1332 	rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
1333 	ri->ri_caps=WSSCREEN_WSCOLORS;
1334 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
1335 		    sc->sc_width / ri->ri_font->fontwidth);
1336 	ri->ri_ops.allocattr(ri, 0, 0, 0, defattr);
1337 
1338 	cnt = ri->ri_rows * ri->ri_cols;
1339 	/*
1340 	 * we allocate both chars and attributes in one chunk, attributes first
1341 	 * because they have the (potentially) bigger alignment
1342 	 */
1343 	scr->attrs = (long *)malloc(cnt * (sizeof(long) + sizeof(uint16_t)),
1344 	    M_DEVBUF, M_WAITOK);
1345 	scr->chars = (uint16_t *)&scr->attrs[cnt];
1346 
1347 	/* enable acceleration */
1348 	ri->ri_hw = scr;
1349 	ri->ri_ops.copyrows = cg6_ras_copyrows;
1350 	ri->ri_ops.copycols = cg6_ras_copycols;
1351 	ri->ri_ops.eraserows = cg6_ras_eraserows;
1352 	ri->ri_ops.erasecols = cg6_ras_erasecols;
1353 	ri->ri_ops.cursor = cgsix_cursor;
1354 	ri->ri_ops.putchar = cgsix_putchar;
1355 	if (existing) {
1356 		scr->active = 1;
1357 	} else {
1358 		scr->active = 0;
1359 	}
1360 
1361 	cg6_ras_eraserows(&scr->ri, 0, ri->ri_rows, *defattr);
1362 
1363 	LIST_INSERT_HEAD(&sc->screens, scr, next);
1364 }
1365 
1366 int
1367 cgsix_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1368     int *curxp, int *curyp, long *defattrp)
1369 {
1370 	struct cgsix_softc *sc = v;
1371 	struct cg6_screen *scr;
1372 
1373 	scr = malloc(sizeof(struct cg6_screen), M_DEVBUF, M_WAITOK|M_ZERO);
1374 	cgsix_init_screen(sc, scr, 0, defattrp);
1375 
1376 	if (sc->active == NULL) {
1377 		scr->active = 1;
1378 		sc->active = scr;
1379 		sc->currenttype = type;
1380 	}
1381 
1382 	*cookiep = scr;
1383 	*curxp = scr->cursorcol;
1384 	*curyp = scr->cursorrow;
1385 	return 0;
1386 }
1387 
1388 void
1389 cgsix_free_screen(void *v, void *cookie)
1390 {
1391 	struct cgsix_softc *sc = v;
1392 	struct cg6_screen *scr = cookie;
1393 
1394 	LIST_REMOVE(scr, next);
1395 	if (scr != &cg6_console_screen) {
1396 		free(scr->attrs, M_DEVBUF);
1397 		free(scr, M_DEVBUF);
1398 	} else
1399 		panic("cgsix_free_screen: console");
1400 
1401 	if (sc->active == scr)
1402 		sc->active = 0;
1403 }
1404 
1405 int
1406 cgsix_show_screen(void *v, void *cookie, int waitok,
1407     void (*cb)(void *, int, int), void *cbarg)
1408 {
1409 	struct cgsix_softc *sc = v;
1410 	struct cg6_screen *scr, *oldscr;
1411 
1412 	scr = cookie;
1413 	oldscr = sc->active;
1414 	if (scr == oldscr)
1415 		return 0;
1416 
1417 	sc->wanted = scr;
1418 	sc->switchcb = cb;
1419 	sc->switchcbarg = cbarg;
1420 	if (cb) {
1421 		callout_reset(&sc->switch_callout, 0,
1422 		    (void(*)(void *))cgsix_switch_screen, sc);
1423 		return EAGAIN;
1424 	}
1425 
1426 	cgsix_switch_screen(sc);
1427 	return 0;
1428 }
1429 
1430 void
1431 cgsix_switch_screen(struct cgsix_softc *sc)
1432 {
1433 	struct cg6_screen *scr, *oldscr;
1434 
1435 	scr = sc->wanted;
1436 	if (!scr) {
1437 		printf("cgsix_switch_screen: disappeared\n");
1438 		(*sc->switchcb)(sc->switchcbarg, EIO, 0);
1439 		return;
1440 	}
1441 	oldscr = sc->active; /* can be NULL! */
1442 #ifdef DIAGNOSTIC
1443 	if (oldscr) {
1444 		if (!oldscr->active)
1445 			panic("cgsix_switch_screen: not active");
1446 	}
1447 #endif
1448 	if (scr == oldscr)
1449 		return;
1450 
1451 #ifdef DIAGNOSTIC
1452 	if (scr->active)
1453 		panic("cgsix_switch_screen: active");
1454 #endif
1455 
1456 	if (oldscr)
1457 		oldscr->active = 0;
1458 #ifdef notyet
1459 	if (sc->currenttype != type) {
1460 		cgsix_set_screentype(sc, type);
1461 		sc->currenttype = type;
1462 	}
1463 #endif
1464 
1465 	/* Clear the entire screen. */
1466 
1467 	scr->active = 1;
1468 	cgsix_restore_screen(scr, &cgsix_defaultscreen, scr->chars);
1469 
1470 	sc->active = scr;
1471 
1472 	scr->ri.ri_ops.cursor(scr, scr->cursoron, scr->cursorrow,
1473 	    scr->cursorcol);
1474 
1475 	sc->wanted = 0;
1476 	if (sc->switchcb)
1477 		(*sc->switchcb)(sc->switchcbarg, 0, 0);
1478 }
1479 
1480 void
1481 cgsix_restore_screen(struct cg6_screen *scr,
1482     const struct wsscreen_descr *type, u_int16_t *mem)
1483 {
1484 	int i, j, offset = 0;
1485 	uint16_t *charptr = scr->chars;
1486 	long *attrptr = scr->attrs;
1487 
1488 	cgsix_clearscreen(scr->sc);
1489 	for (i = 0; i < scr->ri.ri_rows; i++) {
1490 		for (j = 0; j < scr->ri.ri_cols; j++) {
1491 			cgsix_putchar(scr, i, j, charptr[offset],
1492 			    attrptr[offset]);
1493 			offset++;
1494 		}
1495 	}
1496 	scr->cursordrawn = 0;
1497 }
1498 
1499 void
1500 cgsix_rectfill(struct cgsix_softc *sc, int xs, int ys, int wi, int he,
1501     uint32_t col)
1502 {
1503 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1504 
1505 	CG6_DRAIN(fbc);
1506 	fbc->fbc_clip = 0;
1507 	fbc->fbc_s = 0;
1508 	fbc->fbc_offx = 0;
1509 	fbc->fbc_offy = 0;
1510 	fbc->fbc_clipminx = 0;
1511 	fbc->fbc_clipminy = 0;
1512 	fbc->fbc_clipmaxx = sc->sc_width - 1;
1513 	fbc->fbc_clipmaxy = sc->sc_height - 1;
1514 	fbc->fbc_alu = CG6_ALU_FILL;
1515 	fbc->fbc_fg = col;
1516 	fbc->fbc_arecty = ys;
1517 	fbc->fbc_arectx = xs;
1518 	fbc->fbc_arecty = ys + he - 1;
1519 	fbc->fbc_arectx = xs + wi - 1;
1520 	CG6_DRAW_WAIT(fbc);
1521 }
1522 
1523 void
1524 cgsix_setup_mono(struct cgsix_softc *sc, int x, int y, int wi, int he,
1525     uint32_t fg, uint32_t bg)
1526 {
1527 	volatile struct cg6_fbc *fbc=sc->sc_fbc;
1528 	CG6_DRAIN(fbc);
1529 	fbc->fbc_x0 = x;
1530 	fbc->fbc_x1  =x + wi - 1;
1531 	fbc->fbc_y0 = y;
1532 	fbc->fbc_incx = 0;
1533 	fbc->fbc_incy = 1;
1534 	fbc->fbc_fg = fg;
1535 	fbc->fbc_bg = bg;
1536 	fbc->fbc_mode = 0x00140000;	/* nosrc, color1 */
1537 	fbc->fbc_alu = 0x0800fc30;	/* colour expansion, solid bg */
1538 	sc->sc_mono_width = wi;
1539 	/* now feed the data into the chip */
1540 }
1541 
1542 void
1543 cgsix_feed_line(struct cgsix_softc *sc, int count, uint8_t *data)
1544 {
1545 	int i;
1546 	uint32_t latch, res = 0, shift;
1547 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1548 
1549 	if (sc->sc_mono_width > 32) {
1550 		/* ARGH! */
1551 	} else
1552 	{
1553 		shift = 24;
1554 		for (i = 0; i < count; i++) {
1555 			latch = data[i];
1556 			res |= latch << shift;
1557 			shift -= 8;
1558 		}
1559 		fbc->fbc_font = res;
1560 	}
1561 }
1562 
1563 void
1564 cgsix_putchar(void *cookie, int row, int col, u_int c, long attr)
1565 {
1566 	struct rasops_info *ri=cookie;
1567 	struct cg6_screen *scr=ri->ri_hw;
1568 	struct cgsix_softc *sc=scr->sc;
1569 	int pos;
1570 
1571 	if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
1572 	    (col < ri->ri_cols)) {
1573 		pos = col + row * ri->ri_cols;
1574 		scr->attrs[pos] = attr;
1575 		scr->chars[pos] = c;
1576 
1577 		if ((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1578 			/*cgsix_sync(sc);*/
1579 			int fg, bg, uc, i;
1580 			uint8_t *data;
1581 			int x, y, wi, he;
1582 			volatile struct cg6_fbc *fbc = sc->sc_fbc;
1583 
1584 			wi = ri->ri_font->fontwidth;
1585 			he = ri->ri_font->fontheight;
1586 
1587 			if (!CHAR_IN_FONT(c, ri->ri_font))
1588 				return;
1589 			bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff];
1590 			fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff];
1591 			x = ri->ri_xorigin + col * wi;
1592 			y = ri->ri_yorigin + row * he;
1593 			if (c == 0x20) {
1594 				cgsix_rectfill(sc, x, y, wi, he, bg);
1595 			} else {
1596 				uc = c-ri->ri_font->firstchar;
1597 				data = (uint8_t *)ri->ri_font->data + uc *
1598 				    ri->ri_fontscale;
1599 
1600 				cgsix_setup_mono(sc, x, y, wi, 1, fg, bg);
1601 				for (i = 0; i < he; i++) {
1602 					cgsix_feed_line(sc, ri->ri_font->stride,
1603 					    data);
1604 					data += ri->ri_font->stride;
1605 				}
1606 				/* put the chip back to normal */
1607 				fbc->fbc_incy = 0;
1608 				/* nosrc, color8 */
1609 				fbc->fbc_mode = 0x00120000;
1610 				fbc->fbc_mode &= ~CG6_MODE_MASK;
1611 				fbc->fbc_mode |= CG6_MODE;
1612 			}
1613 		}
1614 	}
1615 }
1616 
1617 void
1618 cgsix_cursor(void *cookie, int on, int row, int col)
1619 {
1620 	struct rasops_info *ri=cookie;
1621 	struct cg6_screen *scr=ri->ri_hw;
1622 	struct cgsix_softc *sc=scr->sc;
1623 	int x, y, wi, he;
1624 
1625 	wi = ri->ri_font->fontwidth;
1626 	he = ri->ri_font->fontheight;
1627 
1628 	if((scr->active) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
1629 		x = scr->cursorcol * wi + ri->ri_xorigin;
1630 		y = scr->cursorrow * he + ri->ri_yorigin;
1631 		if(scr->cursordrawn) {
1632 			cg6_invert(sc, x, y, wi, he);
1633 			scr->cursordrawn = 0;
1634 		}
1635 		scr->cursorrow = row;
1636 		scr->cursorcol = col;
1637 		if((scr->cursoron = on) != 0)
1638 		{
1639 			x = scr->cursorcol * wi + ri->ri_xorigin;
1640 			y = scr->cursorrow * he + ri->ri_yorigin;
1641 			cg6_invert(sc, x, y, wi, he);
1642 			scr->cursordrawn = 1;
1643 		}
1644 	} else {
1645 		scr->cursoron = on;
1646 		scr->cursorrow = row;
1647 		scr->cursorcol = col;
1648 		scr->cursordrawn = 0;
1649 	}
1650 }
1651 
1652 void
1653 cgsix_clearscreen(struct cgsix_softc *sc)
1654 {
1655 	struct rasops_info *ri=&cg6_console_screen.ri;
1656 
1657 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1658 		volatile struct cg6_fbc *fbc = sc->sc_fbc;
1659 
1660 		CG6_DRAIN(fbc);
1661 		fbc->fbc_clip = 0;
1662 		fbc->fbc_s = 0;
1663 		fbc->fbc_offx = 0;
1664 		fbc->fbc_offy = 0;
1665 		fbc->fbc_clipminx = 0;
1666 		fbc->fbc_clipminy = 0;
1667 		fbc->fbc_clipmaxx = ri->ri_width - 1;
1668 		fbc->fbc_clipmaxy = ri->ri_height - 1;
1669 		fbc->fbc_alu = CG6_ALU_FILL;
1670 		fbc->fbc_fg = ri->ri_devcmap[sc->sc_bg];
1671 		fbc->fbc_arectx = 0;
1672 		fbc->fbc_arecty = 0;
1673 		fbc->fbc_arectx = ri->ri_width - 1;
1674 		fbc->fbc_arecty = ri->ri_height - 1;
1675 		CG6_DRAW_WAIT(fbc);
1676 	}
1677 }
1678 
1679 #endif /* NWSDISPLAY > 0 */
1680 
1681 #if (NWSDISPLAY > 0) || defined(RASTERCONSOLE)
1682 void
1683 cg6_invert(struct cgsix_softc *sc, int x, int y, int wi, int he)
1684 {
1685 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1686 	struct rasops_info *ri = &cg6_console_screen.ri;
1687 
1688 	CG6_DRAIN(fbc);
1689 	fbc->fbc_clip = 0;
1690 	fbc->fbc_s = 0;
1691 	fbc->fbc_offx = 0;
1692 	fbc->fbc_offy = 0;
1693 	fbc->fbc_clipminx = 0;
1694 	fbc->fbc_clipminy = 0;
1695 	fbc->fbc_clipmaxx = ri->ri_width - 1;
1696 	fbc->fbc_clipmaxy = ri->ri_height - 1;
1697 	fbc->fbc_alu = CG6_ALU_FLIP;
1698 	fbc->fbc_arecty = y;
1699 	fbc->fbc_arectx = x;
1700 	fbc->fbc_arecty = y + he - 1;
1701 	fbc->fbc_arectx = x + wi - 1;
1702 	CG6_DRAW_WAIT(fbc);
1703 }
1704 
1705 #endif
1706