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