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