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