xref: /netbsd-src/sys/dev/sun/cgsix.c (revision 5aefcfdc06931dd97e76246d2fe0302f7b3fe094)
1 /*	$NetBSD: cgsix.c,v 1.4 2000/11/05 22:59:27 chs Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1993
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * This software was developed by the Computer Systems Engineering group
44  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
45  * contributed to Berkeley.
46  *
47  * All advertising materials mentioning features or use of this software
48  * must display the following acknowledgement:
49  *	This product includes software developed by the University of
50  *	California, Lawrence Berkeley Laboratory.
51  *
52  * Redistribution and use in source and binary forms, with or without
53  * modification, are permitted provided that the following conditions
54  * are met:
55  * 1. Redistributions of source code must retain the above copyright
56  *    notice, this list of conditions and the following disclaimer.
57  * 2. Redistributions in binary form must reproduce the above copyright
58  *    notice, this list of conditions and the following disclaimer in the
59  *    documentation and/or other materials provided with the distribution.
60  * 3. All advertising materials mentioning features or use of this software
61  *    must display the following acknowledgement:
62  *	This product includes software developed by the University of
63  *	California, Berkeley and its contributors.
64  * 4. Neither the name of the University nor the names of its contributors
65  *    may be used to endorse or promote products derived from this software
66  *    without specific prior written permission.
67  *
68  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
69  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
72  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78  * SUCH DAMAGE.
79  *
80  *	@(#)cgsix.c	8.4 (Berkeley) 1/21/94
81  */
82 
83 /*
84  * color display (cgsix) driver.
85  *
86  * Does not handle interrupts, even though they can occur.
87  *
88  * XXX should defer colormap updates to vertical retrace interrupts
89  */
90 
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/buf.h>
94 #include <sys/device.h>
95 #include <sys/ioctl.h>
96 #include <sys/malloc.h>
97 #include <sys/mman.h>
98 #include <sys/tty.h>
99 #include <sys/conf.h>
100 
101 #ifdef DEBUG
102 #include <sys/proc.h>
103 #include <sys/syslog.h>
104 #endif
105 
106 #include <uvm/uvm_extern.h>
107 
108 #include <machine/bus.h>
109 
110 #include <dev/sun/fbio.h>
111 #include <dev/sun/fbvar.h>
112 
113 #include <dev/sun/btreg.h>
114 #include <dev/sun/btvar.h>
115 #include <dev/sun/cgsixreg.h>
116 #include <dev/sun/cgsixvar.h>
117 #include <dev/sun/pfourreg.h>
118 
119 #ifdef RASTERCONSOLE
120 #include <dev/rasops/rasops.h>
121 #include <dev/wscons/wsconsio.h>
122 #endif
123 
124 #include <machine/conf.h>
125 
126 static void	cg6_unblank(struct device *);
127 
128 /* cdevsw prototypes */
129 cdev_decl(cgsix);
130 
131 extern struct cfdriver cgsix_cd;
132 
133 /* frame buffer generic driver */
134 static struct fbdriver cg6_fbdriver = {
135 	cg6_unblank, cgsixopen, cgsixclose, cgsixioctl, cgsixpoll, cgsixmmap
136 };
137 
138 static void cg6_reset (struct cgsix_softc *);
139 static void cg6_loadcmap (struct cgsix_softc *, int, int);
140 static void cg6_loadomap (struct cgsix_softc *);
141 static void cg6_setcursor (struct cgsix_softc *);/* set position */
142 static void cg6_loadcursor (struct cgsix_softc *);/* set shape */
143 
144 #ifdef RASTERCONSOLE
145 int cgsix_use_rasterconsole = 1;
146 
147 /*
148  * cg6 accelerated console routines.
149  *
150  * Note that buried in this code in several places is the assumption
151  * that pixels are exactly one byte wide.  Since this is cg6-specific
152  * code, this seems safe.  This assumption resides in things like the
153  * use of ri_emuwidth without messing around with ri_pelbytes, or the
154  * assumption that ri_font->fontwidth is the right thing to multiply
155  * character-cell counts by to get byte counts.
156  */
157 
158 /*
159  * Magic values for blitter
160  */
161 
162 /* Value for the alu register for screen-to-screen copies */
163 #define CG6_ALU_COPY	(						\
164 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
165 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
166 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
167 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
168 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
169 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
170 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
171 	| 0x0000cccc /* ALU = src */					\
172 )
173 
174 /* Value for the alu register for region fills */
175 #define CG6_ALU_FILL	(						\
176 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
177 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
178 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
179 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
180 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
181 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
182 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
183 	| 0x0000ff00 /* ALU = fg color */				\
184 )
185 
186 /* Value for the alu register for toggling an area */
187 #define CG6_ALU_FLIP	(						\
188 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
189 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
190 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
191 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
192 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
193 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
194 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
195 	| 0x00005555 /* ALU = ~dst */					\
196 )
197 
198 /*
199  * Wait for a blit to finish.
200  * 0x8000000 bit: function unknown; 0x20000000 bit: GX_BLT_INPROGRESS
201  */
202 #define CG6_BLIT_WAIT(fbc) do {						\
203 	while (((fbc)->fbc_blit & 0xa0000000) == 0xa0000000)		\
204 		/*EMPTY*/;						\
205 } while (0)
206 
207 /*
208  * Wait for a drawing operation to finish, or at least get queued.
209  * 0x8000000 bit: function unknown; 0x20000000 bit: GX_FULL
210  */
211 #define CG6_DRAW_WAIT(fbc) do {						\
212        	while (((fbc)->fbc_draw & 0xa0000000) == 0xa0000000)		\
213 		/*EMPTY*/;						\
214 } while (0)
215 
216 /*
217  * Wait for the whole engine to go idle.  This may not matter in our case;
218  * I'm not sure whether blits are actually queued or not.  It more likely
219  * is intended for lines and such that do get queued.
220  * 0x10000000 bit: GX_INPROGRESS
221  */
222 #define CG6_DRAIN(fbc) do {						\
223 	while ((fbc)->fbc_s & 0x10000000)				\
224 		/*EMPTY*/;						\
225 } while (0)
226 
227 static void
228 cg6_ras_copyrows(void *cookie, int src, int dst, int n)
229 {
230 	struct rasops_info *ri;
231 	volatile struct cg6_fbc *fbc;
232 
233 	ri = cookie;
234 	if (dst == src)
235 		return;
236 	if (src < 0) {
237 		n += src;
238 		src = 0;
239 	}
240 	if (src+n > ri->ri_rows)
241 		n = ri->ri_rows - src;
242 	if (dst < 0) {
243 		n += dst;
244 		dst = 0;
245 	}
246 	if (dst+n > ri->ri_rows)
247 		n = ri->ri_rows - dst;
248 	if (n <= 0)
249 		return;
250 	n *= ri->ri_font->fontheight;
251 	src *= ri->ri_font->fontheight;
252 	dst *= ri->ri_font->fontheight;
253 	fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc;
254 	fbc->fbc_clip = 0;
255 	fbc->fbc_s = 0;
256 	fbc->fbc_offx = 0;
257 	fbc->fbc_offy = 0;
258 	fbc->fbc_clipminx = 0;
259 	fbc->fbc_clipminy = 0;
260 	fbc->fbc_clipmaxx = ri->ri_width - 1;
261 	fbc->fbc_clipmaxy = ri->ri_height - 1;
262 	fbc->fbc_alu = CG6_ALU_COPY;
263 	fbc->fbc_x0 = ri->ri_xorigin;
264 	fbc->fbc_y0 = ri->ri_yorigin + src;
265 	fbc->fbc_x1 = ri->ri_xorigin + ri->ri_emuwidth - 1;
266 	fbc->fbc_y1 = ri->ri_yorigin + src + n - 1;
267 	fbc->fbc_x2 = ri->ri_xorigin;
268 	fbc->fbc_y2 = ri->ri_yorigin + dst;
269 	fbc->fbc_x3 = ri->ri_xorigin + ri->ri_emuwidth - 1;
270 	fbc->fbc_y3 = ri->ri_yorigin + dst + n - 1;
271 	CG6_BLIT_WAIT(fbc);
272 	CG6_DRAIN(fbc);
273 }
274 
275 static void
276 cg6_ras_copycols(void *cookie, int row, int src, int dst, int n)
277 {
278 	struct rasops_info *ri;
279 	volatile struct cg6_fbc *fbc;
280 
281 	ri = cookie;
282 	if (dst == src)
283 		return;
284 	if ((row < 0) || (row >= ri->ri_rows))
285 		return;
286 	if (src < 0) {
287 		n += src;
288 		src = 0;
289 	}
290 	if (src+n > ri->ri_cols)
291 		n = ri->ri_cols - src;
292 	if (dst < 0) {
293 		n += dst;
294 		dst = 0;
295 	}
296 	if (dst+n > ri->ri_cols)
297 		n = ri->ri_cols - dst;
298 	if (n <= 0)
299 		return;
300 	n *= ri->ri_font->fontwidth;
301 	src *= ri->ri_font->fontwidth;
302 	dst *= ri->ri_font->fontwidth;
303 	row *= ri->ri_font->fontheight;
304 	fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc;
305 	fbc->fbc_clip = 0;
306 	fbc->fbc_s = 0;
307 	fbc->fbc_offx = 0;
308 	fbc->fbc_offy = 0;
309 	fbc->fbc_clipminx = 0;
310 	fbc->fbc_clipminy = 0;
311 	fbc->fbc_clipmaxx = ri->ri_width - 1;
312 	fbc->fbc_clipmaxy = ri->ri_height - 1;
313 	fbc->fbc_alu = CG6_ALU_COPY;
314 	fbc->fbc_x0 = ri->ri_xorigin + src;
315 	fbc->fbc_y0 = ri->ri_yorigin + row;
316 	fbc->fbc_x1 = ri->ri_xorigin + src + n - 1;
317 	fbc->fbc_y1 = ri->ri_yorigin + row + ri->ri_font->fontheight - 1;
318 	fbc->fbc_x2 = ri->ri_xorigin + dst;
319 	fbc->fbc_y2 = ri->ri_yorigin + row;
320 	fbc->fbc_x3 = ri->ri_xorigin + dst + n - 1;
321 	fbc->fbc_y3 = ri->ri_yorigin + row + ri->ri_font->fontheight - 1;
322 	CG6_BLIT_WAIT(fbc);
323 	CG6_DRAIN(fbc);
324 }
325 
326 static void
327 cg6_ras_erasecols(void *cookie, int row, int col, int n, long int attr)
328 {
329 	struct rasops_info *ri;
330 	volatile struct cg6_fbc *fbc;
331 
332 	ri = cookie;
333 	if ((row < 0) || (row >= ri->ri_rows))
334 		return;
335 	if (col < 0) {
336 		n += col;
337 		col = 0;
338 	}
339 	if (col+n > ri->ri_cols)
340 		n = ri->ri_cols - col;
341 	if (n <= 0)
342 		return;
343 	n *= ri->ri_font->fontwidth;
344 	col *= ri->ri_font->fontwidth;
345 	row *= ri->ri_font->fontheight;
346 	fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc;
347 	fbc->fbc_clip = 0;
348 	fbc->fbc_s = 0;
349 	fbc->fbc_offx = 0;
350 	fbc->fbc_offy = 0;
351 	fbc->fbc_clipminx = 0;
352 	fbc->fbc_clipminy = 0;
353 	fbc->fbc_clipmaxx = ri->ri_width - 1;
354 	fbc->fbc_clipmaxy = ri->ri_height - 1;
355 	fbc->fbc_alu = CG6_ALU_FILL;
356 	fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xf];
357 	fbc->fbc_arecty = ri->ri_yorigin + row;
358 	fbc->fbc_arectx = ri->ri_xorigin + col;
359 	fbc->fbc_arecty = ri->ri_yorigin + row + ri->ri_font->fontheight - 1;
360 	fbc->fbc_arectx = ri->ri_xorigin + col + n - 1;
361 	CG6_DRAW_WAIT(fbc);
362 	CG6_DRAIN(fbc);
363 }
364 
365 static void
366 cg6_ras_eraserows(void *cookie, int row, int n, long int attr)
367 {
368 	struct rasops_info *ri;
369 	volatile struct cg6_fbc *fbc;
370 
371 	ri = cookie;
372 	if (row < 0) {
373 		n += row;
374 		row = 0;
375 	}
376 	if (row+n > ri->ri_rows)
377 		n = ri->ri_rows - row;
378 	if (n <= 0)
379 		return;
380 	fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc;
381 	fbc->fbc_clip = 0;
382 	fbc->fbc_s = 0;
383 	fbc->fbc_offx = 0;
384 	fbc->fbc_offy = 0;
385 	fbc->fbc_clipminx = 0;
386 	fbc->fbc_clipminy = 0;
387 	fbc->fbc_clipmaxx = ri->ri_width - 1;
388 	fbc->fbc_clipmaxy = ri->ri_height - 1;
389 	fbc->fbc_alu = CG6_ALU_FILL;
390 	fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xf];
391 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
392 		fbc->fbc_arecty = 0;
393 		fbc->fbc_arectx = 0;
394 		fbc->fbc_arecty = ri->ri_height - 1;
395 		fbc->fbc_arectx = ri->ri_width - 1;
396 	} else {
397 		row *= ri->ri_font->fontheight;
398 		fbc->fbc_arecty = ri->ri_yorigin + row;
399 		fbc->fbc_arectx = ri->ri_xorigin;
400 		fbc->fbc_arecty = ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1;
401 		fbc->fbc_arectx = ri->ri_xorigin + ri->ri_emuwidth - 1;
402 	}
403 	CG6_DRAW_WAIT(fbc);
404 	CG6_DRAIN(fbc);
405 }
406 
407 /*
408  * Really want something more like fg^bg here, but that would be more
409  * or less impossible to migrate to colors.  So we hope there's
410  * something not too inappropriate in the colormap...besides, it's what
411  * the non-accelerated code did. :-)
412  */
413 static void
414 cg6_ras_do_cursor(struct rasops_info *ri)
415 {
416 	volatile struct cg6_fbc *fbc;
417 	int row;
418 	int col;
419 
420 	row = ri->ri_crow * ri->ri_font->fontheight;
421 	col = ri->ri_ccol * ri->ri_font->fontwidth;
422 	fbc = ((struct cgsix_softc *)ri->ri_hw)->sc_fbc;
423 	fbc->fbc_clip = 0;
424 	fbc->fbc_s = 0;
425 	fbc->fbc_offx = 0;
426 	fbc->fbc_offy = 0;
427 	fbc->fbc_clipminx = 0;
428 	fbc->fbc_clipminy = 0;
429 	fbc->fbc_clipmaxx = ri->ri_width - 1;
430 	fbc->fbc_clipmaxy = ri->ri_height - 1;
431 	fbc->fbc_alu = CG6_ALU_FLIP;
432 	fbc->fbc_arecty = ri->ri_yorigin + row;
433 	fbc->fbc_arectx = ri->ri_xorigin + col;
434 	fbc->fbc_arecty = ri->ri_yorigin + row + ri->ri_font->fontheight - 1;
435 	fbc->fbc_arectx = ri->ri_xorigin + col + ri->ri_font->fontwidth - 1;
436 	CG6_DRAW_WAIT(fbc);
437 	CG6_DRAIN(fbc);
438 }
439 #endif /* RASTERCONSOLE */
440 
441 void
442 cg6attach(sc, name, isconsole)
443 	struct cgsix_softc *sc;
444 	char *name;
445 	int isconsole;
446 {
447 	struct fbdevice *fb = &sc->sc_fb;
448 
449 	fb->fb_driver = &cg6_fbdriver;
450 
451 	/* Don't have to map the pfour register on the cgsix. */
452 	fb->fb_pfour = NULL;
453 
454 	fb->fb_type.fb_cmsize = 256;
455 	fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
456 	printf(": %s, %d x %d", name,
457 	       fb->fb_type.fb_width, fb->fb_type.fb_height);
458 
459 	sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) &
460 			(FHC_REV_MASK >> FHC_REV_SHIFT);
461 
462 	printf(", rev %d", sc->sc_fhcrev);
463 
464 	/* reset cursor & frame buffer controls */
465 	cg6_reset(sc);
466 
467 	/* enable video */
468 	sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
469 
470 	if (isconsole) {
471 		printf(" (console)");
472 #ifdef RASTERCONSOLE
473 		if (cgsix_use_rasterconsole) {
474 			fbrcons_init(&sc->sc_fb);
475 			sc->sc_fb.fb_rinfo.ri_hw = sc;
476 			sc->sc_fb.fb_rinfo.ri_ops.copyrows = cg6_ras_copyrows;
477 			sc->sc_fb.fb_rinfo.ri_ops.copycols = cg6_ras_copycols;
478 			sc->sc_fb.fb_rinfo.ri_ops.erasecols = cg6_ras_erasecols;
479 			sc->sc_fb.fb_rinfo.ri_ops.eraserows = cg6_ras_eraserows;
480 			sc->sc_fb.fb_rinfo.ri_do_cursor = cg6_ras_do_cursor;
481 		}
482 #endif
483 	}
484 
485 	printf("\n");
486 	fb_attach(&sc->sc_fb, isconsole);
487 }
488 
489 
490 int
491 cgsixopen(dev, flags, mode, p)
492 	dev_t dev;
493 	int flags, mode;
494 	struct proc *p;
495 {
496 	int unit = minor(dev);
497 
498 	if (unit >= cgsix_cd.cd_ndevs || cgsix_cd.cd_devs[unit] == NULL)
499 		return (ENXIO);
500 	return (0);
501 }
502 
503 int
504 cgsixclose(dev, flags, mode, p)
505 	dev_t dev;
506 	int flags, mode;
507 	struct proc *p;
508 {
509 	struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
510 
511 	cg6_reset(sc);
512 
513 	/* (re-)initialize the default color map */
514 	bt_initcmap(&sc->sc_cmap, 256);
515 	cg6_loadcmap(sc, 0, 256);
516 
517 	return (0);
518 }
519 
520 int
521 cgsixioctl(dev, cmd, data, flags, p)
522 	dev_t dev;
523 	u_long cmd;
524 	caddr_t data;
525 	int flags;
526 	struct proc *p;
527 {
528 	struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
529 	u_int count;
530 	int v, error;
531 	union cursor_cmap tcm;
532 
533 	switch (cmd) {
534 
535 	case FBIOGTYPE:
536 		*(struct fbtype *)data = sc->sc_fb.fb_type;
537 		break;
538 
539 	case FBIOGATTR:
540 #define fba ((struct fbgattr *)data)
541 		fba->real_type = sc->sc_fb.fb_type.fb_type;
542 		fba->owner = 0;		/* XXX ??? */
543 		fba->fbtype = sc->sc_fb.fb_type;
544 		fba->sattr.flags = 0;
545 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
546 		fba->sattr.dev_specific[0] = -1;
547 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
548 		fba->emu_types[1] = -1;
549 #undef fba
550 		break;
551 
552 	case FBIOGETCMAP:
553 #define	p ((struct fbcmap *)data)
554 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
555 
556 	case FBIOPUTCMAP:
557 		/* copy to software map */
558 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
559 		if (error)
560 			return (error);
561 		/* now blast them into the chip */
562 		/* XXX should use retrace interrupt */
563 		cg6_loadcmap(sc, p->index, p->count);
564 #undef p
565 		break;
566 
567 	case FBIOGVIDEO:
568 		*(int *)data = sc->sc_blanked;
569 		break;
570 
571 	case FBIOSVIDEO:
572 		if (*(int *)data)
573 			cg6_unblank(&sc->sc_dev);
574 		else if (!sc->sc_blanked) {
575 			sc->sc_blanked = 1;
576 			sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN;
577 		}
578 		break;
579 
580 /* these are for both FBIOSCURSOR and FBIOGCURSOR */
581 #define p ((struct fbcursor *)data)
582 #define cc (&sc->sc_cursor)
583 
584 	case FBIOGCURSOR:
585 		/* do not quite want everything here... */
586 		p->set = FB_CUR_SETALL;	/* close enough, anyway */
587 		p->enable = cc->cc_enable;
588 		p->pos = cc->cc_pos;
589 		p->hot = cc->cc_hot;
590 		p->size = cc->cc_size;
591 
592 		/* begin ugh ... can we lose some of this crap?? */
593 		if (p->image != NULL) {
594 			count = cc->cc_size.y * 32 / NBBY;
595 			error = copyout((caddr_t)cc->cc_bits[1],
596 			    (caddr_t)p->image, count);
597 			if (error)
598 				return (error);
599 			error = copyout((caddr_t)cc->cc_bits[0],
600 			    (caddr_t)p->mask, count);
601 			if (error)
602 				return (error);
603 		}
604 		if (p->cmap.red != NULL) {
605 			error = bt_getcmap(&p->cmap,
606 			    (union bt_cmap *)&cc->cc_color, 2, 1);
607 			if (error)
608 				return (error);
609 		} else {
610 			p->cmap.index = 0;
611 			p->cmap.count = 2;
612 		}
613 		/* end ugh */
614 		break;
615 
616 	case FBIOSCURSOR:
617 		/*
618 		 * For setcmap and setshape, verify parameters, so that
619 		 * we do not get halfway through an update and then crap
620 		 * out with the software state screwed up.
621 		 */
622 		v = p->set;
623 		if (v & FB_CUR_SETCMAP) {
624 			/*
625 			 * This use of a temporary copy of the cursor
626 			 * colormap is not terribly efficient, but these
627 			 * copies are small (8 bytes)...
628 			 */
629 			tcm = cc->cc_color;
630 			error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2, 1);
631 			if (error)
632 				return (error);
633 		}
634 		if (v & FB_CUR_SETSHAPE) {
635 			if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32)
636 				return (EINVAL);
637 			count = p->size.y * 32 / NBBY;
638 			if (!uvm_useracc(p->image, count, B_READ) ||
639 			    !uvm_useracc(p->mask, count, B_READ))
640 				return (EFAULT);
641 		}
642 
643 		/* parameters are OK; do it */
644 		if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) {
645 			if (v & FB_CUR_SETCUR)
646 				cc->cc_enable = p->enable;
647 			if (v & FB_CUR_SETPOS)
648 				cc->cc_pos = p->pos;
649 			if (v & FB_CUR_SETHOT)
650 				cc->cc_hot = p->hot;
651 			cg6_setcursor(sc);
652 		}
653 		if (v & FB_CUR_SETCMAP) {
654 			cc->cc_color = tcm;
655 			cg6_loadomap(sc); /* XXX defer to vertical retrace */
656 		}
657 		if (v & FB_CUR_SETSHAPE) {
658 			cc->cc_size = p->size;
659 			count = p->size.y * 32 / NBBY;
660 			bzero((caddr_t)cc->cc_bits, sizeof cc->cc_bits);
661 			copyin(p->mask, (caddr_t)cc->cc_bits[0], count);
662 			copyin(p->image, (caddr_t)cc->cc_bits[1], count);
663 			cg6_loadcursor(sc);
664 		}
665 		break;
666 
667 #undef p
668 #undef cc
669 
670 	case FBIOGCURPOS:
671 		*(struct fbcurpos *)data = sc->sc_cursor.cc_pos;
672 		break;
673 
674 	case FBIOSCURPOS:
675 		sc->sc_cursor.cc_pos = *(struct fbcurpos *)data;
676 		cg6_setcursor(sc);
677 		break;
678 
679 	case FBIOGCURMAX:
680 		/* max cursor size is 32x32 */
681 		((struct fbcurpos *)data)->x = 32;
682 		((struct fbcurpos *)data)->y = 32;
683 		break;
684 
685 	default:
686 #ifdef DEBUG
687 		log(LOG_NOTICE, "cgsixioctl(0x%lx) (%s[%d])\n", cmd,
688 		    p->p_comm, p->p_pid);
689 #endif
690 		return (ENOTTY);
691 	}
692 	return (0);
693 }
694 
695 int
696 cgsixpoll(dev, events, p)
697 	dev_t dev;
698 	int events;
699 	struct proc *p;
700 {
701 
702 	return (seltrue(dev, events, p));
703 }
704 
705 /*
706  * Clean up hardware state (e.g., after bootup or after X crashes).
707  */
708 static void
709 cg6_reset(sc)
710 	struct cgsix_softc *sc;
711 {
712 	volatile struct cg6_tec_xxx *tec;
713 	int fhc;
714 	volatile struct bt_regs *bt;
715 
716 	/* hide the cursor, just in case */
717 	sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF;
718 
719 	/* turn off frobs in transform engine (makes X11 work) */
720 	tec = sc->sc_tec;
721 	tec->tec_mv = 0;
722 	tec->tec_clip = 0;
723 	tec->tec_vdc = 0;
724 
725 	/* take care of hardware bugs in old revisions */
726 	if (sc->sc_fhcrev < 5) {
727 		/*
728 		 * Keep current resolution; set cpu to 68020, set test
729 		 * window (size 1Kx1K), and for rev 1, disable dest cache.
730 		 */
731 		fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 |
732 		    FHC_TEST |
733 		    (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT);
734 		if (sc->sc_fhcrev < 2)
735 			fhc |= FHC_DST_DISABLE;
736 		*sc->sc_fhc = fhc;
737 	}
738 
739 	/* Enable cursor in Brooktree DAC. */
740 	bt = sc->sc_bt;
741 	bt->bt_addr = 0x06 << 24;
742 	bt->bt_ctrl |= 0x03 << 24;
743 }
744 
745 static void
746 cg6_setcursor(sc)
747 	struct cgsix_softc *sc;
748 {
749 
750 	/* we need to subtract the hot-spot value here */
751 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f)
752 	sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ?
753 	    ((COORD(x) << 16) | (COORD(y) & 0xffff)) :
754 	    (THC_CURSOFF << 16) | THC_CURSOFF;
755 #undef COORD
756 }
757 
758 static void
759 cg6_loadcursor(sc)
760 	struct cgsix_softc *sc;
761 {
762 	volatile struct cg6_thc *thc;
763 	u_int edgemask, m;
764 	int i;
765 
766 	/*
767 	 * Keep the top size.x bits.  Here we *throw out* the top
768 	 * size.x bits from an all-one-bits word, introducing zeros in
769 	 * the top size.x bits, then invert all the bits to get what
770 	 * we really wanted as our mask.  But this fails if size.x is
771 	 * 32---a sparc uses only the low 5 bits of the shift count---
772 	 * so we have to special case that.
773 	 */
774 	edgemask = ~0;
775 	if (sc->sc_cursor.cc_size.x < 32)
776 		edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x);
777 	thc = sc->sc_thc;
778 	for (i = 0; i < 32; i++) {
779 		m = sc->sc_cursor.cc_bits[0][i] & edgemask;
780 		thc->thc_cursmask[i] = m;
781 		thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i];
782 	}
783 }
784 
785 /*
786  * Load a subset of the current (new) colormap into the color DAC.
787  */
788 static void
789 cg6_loadcmap(sc, start, ncolors)
790 	struct cgsix_softc *sc;
791 	int start, ncolors;
792 {
793 	volatile struct bt_regs *bt;
794 	u_int *ip, i;
795 	int count;
796 
797 	ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)];	/* start/4 * 3 */
798 	count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
799 	bt = sc->sc_bt;
800 	bt->bt_addr = BT_D4M4(start) << 24;
801 	while (--count >= 0) {
802 		i = *ip++;
803 		/* hardware that makes one want to pound boards with hammers */
804 		bt->bt_cmap = i;
805 		bt->bt_cmap = i << 8;
806 		bt->bt_cmap = i << 16;
807 		bt->bt_cmap = i << 24;
808 	}
809 }
810 
811 /*
812  * Load the cursor (overlay `foreground' and `background') colors.
813  */
814 static void
815 cg6_loadomap(sc)
816 	struct cgsix_softc *sc;
817 {
818 	volatile struct bt_regs *bt;
819 	u_int i;
820 
821 	bt = sc->sc_bt;
822 	bt->bt_addr = 0x01 << 24;	/* set background color */
823 	i = sc->sc_cursor.cc_color.cm_chip[0];
824 	bt->bt_omap = i;		/* R */
825 	bt->bt_omap = i << 8;		/* G */
826 	bt->bt_omap = i << 16;		/* B */
827 
828 	bt->bt_addr = 0x03 << 24;	/* set foreground color */
829 	bt->bt_omap = i << 24;		/* R */
830 	i = sc->sc_cursor.cc_color.cm_chip[1];
831 	bt->bt_omap = i;		/* G */
832 	bt->bt_omap = i << 8;		/* B */
833 }
834 
835 static void
836 cg6_unblank(dev)
837 	struct device *dev;
838 {
839 	struct cgsix_softc *sc = (struct cgsix_softc *)dev;
840 
841 	if (sc->sc_blanked) {
842 		sc->sc_blanked = 0;
843 		sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
844 	}
845 }
846 
847 /* XXX the following should be moved to a "user interface" header */
848 /*
849  * Base addresses at which users can mmap() the various pieces of a cg6.
850  * Note that although the Brooktree color registers do not occupy 8K,
851  * the X server dies if we do not allow it to map 8K there (it just maps
852  * from 0x70000000 forwards, as a contiguous chunk).
853  */
854 #define	CG6_USER_FBC	0x70000000
855 #define	CG6_USER_TEC	0x70001000
856 #define	CG6_USER_BTREGS	0x70002000
857 #define	CG6_USER_FHC	0x70004000
858 #define	CG6_USER_THC	0x70005000
859 #define	CG6_USER_ROM	0x70006000
860 #define	CG6_USER_RAM	0x70016000
861 #define	CG6_USER_DHC	0x80000000
862 
863 struct mmo {
864 	u_long	mo_uaddr;	/* user (virtual) address */
865 	u_long	mo_size;	/* size, or 0 for video ram size */
866 	u_long	mo_physoff;	/* offset from sc_physadr */
867 };
868 
869 /*
870  * Return the address that would map the given device at the given
871  * offset, allowing for the given protection, or return -1 for error.
872  *
873  * XXX	needs testing against `demanding' applications (e.g., aviator)
874  */
875 paddr_t
876 cgsixmmap(dev, off, prot)
877 	dev_t dev;
878 	off_t off;
879 	int prot;
880 {
881 	struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)];
882 	struct mmo *mo;
883 	u_int u, sz;
884 	static struct mmo mmo[] = {
885 		{ CG6_USER_RAM, 0, CGSIX_RAM_OFFSET },
886 
887 		/* do not actually know how big most of these are! */
888 		{ CG6_USER_FBC, 1, CGSIX_FBC_OFFSET },
889 		{ CG6_USER_TEC, 1, CGSIX_TEC_OFFSET },
890 		{ CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET },
891 		{ CG6_USER_FHC, 1, CGSIX_FHC_OFFSET },
892 		{ CG6_USER_THC, sizeof(struct cg6_thc), CGSIX_THC_OFFSET },
893 		{ CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET },
894 		{ CG6_USER_DHC, 1, CGSIX_DHC_OFFSET },
895 	};
896 #define NMMO (sizeof mmo / sizeof *mmo)
897 
898 	if (off & PGOFSET)
899 		panic("cgsixmmap");
900 
901 	/*
902 	 * Entries with size 0 map video RAM (i.e., the size in fb data).
903 	 *
904 	 * Since we work in pages, the fact that the map offset table's
905 	 * sizes are sometimes bizarre (e.g., 1) is effectively ignored:
906 	 * one byte is as good as one page.
907 	 */
908 	for (mo = mmo; mo < &mmo[NMMO]; mo++) {
909 		if ((u_long)off < mo->mo_uaddr)
910 			continue;
911 		u = off - mo->mo_uaddr;
912 		sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size;
913 		if (u < sz) {
914 			bus_space_handle_t bh;
915 			if (bus_space_mmap(sc->sc_bustag,
916 					   sc->sc_btype,
917 					   sc->sc_paddr+u+mo->mo_physoff,
918 					   BUS_SPACE_MAP_LINEAR, &bh))
919 				return (-1);
920 
921 			return ((paddr_t)bh);
922 		}
923 	}
924 
925 #ifdef DEBUG
926 	{
927 	  struct proc *p = curproc;	/* XXX */
928 	  log(LOG_NOTICE, "cgsixmmap(0x%llx) (%s[%d])\n",
929 		(long long)off, p->p_comm, p->p_pid);
930 	}
931 #endif
932 	return (-1);	/* not a user-map offset */
933 }
934