xref: /netbsd-src/sys/arch/amiga/dev/amidisplaycc.c (revision ca453df649ce9db45b64d73678ba06cbccf9aa11)
1 /*	$NetBSD: amidisplaycc.c,v 1.23 2011/07/17 20:54:36 joerg Exp $ */
2 
3 /*-
4  * Copyright (c) 2000 Jukka Andberg.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: amidisplaycc.c,v 1.23 2011/07/17 20:54:36 joerg Exp $");
32 
33 /*
34  * wscons interface to amiga custom chips. Contains the necessary functions
35  * to render text on bitmapped screens. Uses the functions defined in
36  * grfabs_reg.h for display creation/destruction and low level setup.
37  *
38  * For each virtual terminal a new screen ('view') is allocated.
39  * Also one more is allocated for the mapped screen on demand.
40  */
41 
42 #include "amidisplaycc.h"
43 #include "grfcc.h"
44 #include "view.h"
45 #include "opt_amigaccgrf.h"
46 #include "kbd.h"
47 
48 #if NAMIDISPLAYCC>0
49 
50 #include <sys/param.h>
51 #include <sys/types.h>
52 #include <sys/device.h>
53 #include <sys/malloc.h>
54 #include <sys/systm.h>
55 
56 #include <sys/conf.h>
57 
58 #include <amiga/dev/grfabs_reg.h>
59 #include <amiga/dev/kbdvar.h>
60 #include <amiga/dev/viewioctl.h>
61 #include <amiga/amiga/device.h>
62 #include <dev/wscons/wsconsio.h>
63 #include <dev/rcons/raster.h>
64 #include <dev/wscons/wscons_raster.h>
65 #include <dev/wscons/wsdisplayvar.h>
66 #include <dev/cons.h>
67 #include <dev/wsfont/wsfont.h>
68 
69 /* These can be lowered if you are sure you dont need that much colors. */
70 #define MAXDEPTH 8
71 #define MAXROWS 128
72 
73 #define ADJUSTCOLORS
74 
75 #define MAXCOLORS (1<<MAXDEPTH)
76 
77 struct amidisplaycc_screen;
78 struct amidisplaycc_softc
79 {
80 	struct device dev;
81 
82 	struct amidisplaycc_screen  * currentscreen;
83 
84 	/* display turned on? */
85 	int       ison;
86 
87 	/* stuff relating to the mapped screen */
88 	view_t  * gfxview;
89 	int       gfxwidth;
90 	int       gfxheight;
91 	int       gfxdepth;
92 	int       gfxon;
93 };
94 
95 
96 /*
97  * Configuration stuff.
98  */
99 
100 static int  amidisplaycc_match(struct device *, struct cfdata *, void *);
101 static void amidisplaycc_attach(struct device *, struct device *, void *);
102 
103 CFATTACH_DECL(amidisplaycc, sizeof(struct amidisplaycc_softc),
104     amidisplaycc_match, amidisplaycc_attach, NULL, NULL);
105 
106 static int amidisplaycc_attached;
107 
108 cons_decl(amidisplaycc_);
109 
110 /* end of configuration stuff */
111 
112 /* private utility functions */
113 
114 static int amidisplaycc_setvideo(struct amidisplaycc_softc *, int);
115 
116 static int amidisplaycc_setemulcmap(struct amidisplaycc_screen *,
117 				    struct wsdisplay_cmap *);
118 
119 static int amidisplaycc_cmapioctl(view_t *, u_long, struct wsdisplay_cmap *);
120 static int amidisplaycc_setcmap(view_t *, struct wsdisplay_cmap *);
121 static int amidisplaycc_getcmap(view_t *, struct wsdisplay_cmap *);
122 static int amidisplaycc_gfxscreen(struct amidisplaycc_softc *, int);
123 
124 static int amidisplaycc_setfont(struct amidisplaycc_screen *, const char *);
125 static const struct wsdisplay_font * amidisplaycc_getbuiltinfont(void);
126 
127 static void dprintf(const char *fmt, ...);
128 
129 /* end of private utility functions */
130 
131 /* emulops for wscons */
132 void amidisplaycc_cursor(void *, int, int, int);
133 int amidisplaycc_mapchar(void *, int, unsigned int *);
134 void amidisplaycc_putchar(void *, int, int, u_int, long);
135 void amidisplaycc_copycols(void *, int, int, int, int);
136 void amidisplaycc_erasecols(void *, int, int, int, long);
137 void amidisplaycc_copyrows(void *, int, int, int);
138 void amidisplaycc_eraserows(void *, int, int, long);
139 int  amidisplaycc_allocattr(void *, int, int, int, long *);
140 /* end of emulops for wscons */
141 
142 
143 /* accessops for wscons */
144 int amidisplaycc_ioctl(void *, void *, u_long, void *, int, struct lwp *);
145 paddr_t amidisplaycc_mmap(void *, void *, off_t, int);
146 int amidisplaycc_alloc_screen(void *, const struct wsscreen_descr *, void **,
147 			      int *, int *, long *);
148 void amidisplaycc_free_screen( void *, void *);
149 int amidisplaycc_show_screen(void *, void *, int, void (*)(void *, int, int),
150 			     void *);
151 int amidisplaycc_load_font(void *, void *, struct wsdisplay_font *);
152 void amidisplaycc_pollc(void *, int);
153 /* end of accessops for wscons */
154 
155 /*
156  * These structures are passed to wscons, and they contain the
157  * display-specific callback functions.
158  */
159 
160 const struct wsdisplay_accessops amidisplaycc_accessops = {
161 	amidisplaycc_ioctl,
162 	amidisplaycc_mmap,
163 	amidisplaycc_alloc_screen,
164 	amidisplaycc_free_screen,
165 	amidisplaycc_show_screen,
166 	amidisplaycc_load_font,
167 	amidisplaycc_pollc
168 };
169 
170 const struct wsdisplay_emulops amidisplaycc_emulops = {
171 	amidisplaycc_cursor,
172 	amidisplaycc_mapchar,
173 	amidisplaycc_putchar,
174 	amidisplaycc_copycols,
175 	amidisplaycc_erasecols,
176 	amidisplaycc_copyrows,
177 	amidisplaycc_eraserows,
178 	amidisplaycc_allocattr
179 };
180 
181 /* add some of our own data to the wsscreen_descr */
182 struct amidisplaycc_screen_descr {
183 	struct wsscreen_descr  wsdescr;
184 	int                    depth;
185 };
186 
187 /*
188  * List of supported screenmodes. Almost anything can be given here.
189  */
190 
191 #define ADCC_SCREEN(name, width, height, depth, fontwidth, fontheight) \
192     /* CONSTCOND */ \
193     {{ \
194     name, \
195     width / fontwidth, \
196     height / fontheight, \
197     &amidisplaycc_emulops, fontwidth, fontheight, \
198     (depth > 1 ? WSSCREEN_WSCOLORS : 0) | WSSCREEN_REVERSE | \
199     WSSCREEN_HILIT | WSSCREEN_UNDERLINE }, \
200     depth }
201 
202 /*
203  * Screen types.
204  *
205  * The first in list is used for the console screen.
206  * A suitable screen mode is guessed for it by looking
207  * at the GRF_* options.
208  */
209 struct amidisplaycc_screen_descr amidisplaycc_screentab[] = {
210 	/* name, width, height, depth, fontwidth==8, fontheight */
211 
212 #if defined(GRF_PAL) && !defined(GRF_NTSC)
213 	ADCC_SCREEN("default", 640, 512, 3, 8, 8),
214 #else
215 	ADCC_SCREEN("default", 640, 400, 3, 8, 8),
216 #endif
217 	ADCC_SCREEN("80x50", 640, 400, 3, 8, 8),
218 	ADCC_SCREEN("80x40", 640, 400, 3, 8, 10),
219 	ADCC_SCREEN("80x25", 640, 400, 3, 8, 16),
220 	ADCC_SCREEN("80x24", 640, 192, 3, 8, 8),
221 
222 	ADCC_SCREEN("80x64", 640, 512, 3, 8, 8),
223 	ADCC_SCREEN("80x51", 640, 510, 3, 8, 10),
224 	ADCC_SCREEN("80x32", 640, 512, 3, 8, 16),
225 	ADCC_SCREEN("80x31", 640, 248, 3, 8, 8),
226 
227 	ADCC_SCREEN("640x400x1", 640, 400, 1, 8, 8),
228 	ADCC_SCREEN("640x400x2", 640, 400, 2, 8, 8),
229 	ADCC_SCREEN("640x400x3", 640, 400, 3, 8, 8),
230 
231 	ADCC_SCREEN("640x200x1", 640, 200, 1, 8, 8),
232 	ADCC_SCREEN("640x200x2", 640, 200, 2, 8, 8),
233 	ADCC_SCREEN("640x200x3", 640, 200, 3, 8, 8),
234 };
235 
236 #define ADCC_SCREENPTR(index) &amidisplaycc_screentab[index].wsdescr
237 const struct wsscreen_descr *amidisplaycc_screens[] = {
238 	ADCC_SCREENPTR(0),
239 	ADCC_SCREENPTR(1),
240 	ADCC_SCREENPTR(2),
241 	ADCC_SCREENPTR(3),
242 	ADCC_SCREENPTR(4),
243 	ADCC_SCREENPTR(5),
244 	ADCC_SCREENPTR(6),
245 	ADCC_SCREENPTR(7),
246 	ADCC_SCREENPTR(8),
247 	ADCC_SCREENPTR(9),
248 	ADCC_SCREENPTR(10),
249 	ADCC_SCREENPTR(11),
250 	ADCC_SCREENPTR(12),
251 	ADCC_SCREENPTR(13),
252 	ADCC_SCREENPTR(14),
253 };
254 
255 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0]))
256 
257 /*
258  * This structure also is passed to wscons. It contains pointers
259  * to the available display modes.
260  */
261 
262 const struct wsscreen_list amidisplaycc_screenlist = {
263 	sizeof(amidisplaycc_screens)/sizeof(amidisplaycc_screens[0]),
264 	amidisplaycc_screens
265 };
266 
267 /*
268  * Our own screen structure. One will be created for each screen.
269  */
270 
271 struct amidisplaycc_screen
272 {
273 	struct amidisplaycc_softc *device;
274 
275 	int       isconsole;
276 	int       isvisible;
277 	view_t  * view;
278 
279 	int       ncols;
280 	int       nrows;
281 
282 	int       cursorrow;
283 	int       cursorcol;
284 
285 	/* Active bitplanes for each character row. */
286 	int       rowmasks[MAXROWS];
287 
288 	/* Mapping of colors to screen colors. */
289 	int       colormap[MAXCOLORS];
290 
291 	/* Copies of display parameters for convenience */
292 	int       width;
293 	int       height;
294 	int       depth;
295 
296 	int       widthbytes; /* bytes_per_row           */
297 	int       linebytes;  /* widthbytes + row_mod    */
298 	int       rowbytes;   /* linebytes * fontheight  */
299 
300 	u_char  * planes[MAXDEPTH];
301 
302 	const struct wsdisplay_font  * wsfont;
303 	int                      wsfontcookie; /* if -1, builtin font */
304 	int                      fontwidth;
305 	int                      fontheight;
306 };
307 
308 typedef struct amidisplaycc_screen adccscr_t;
309 
310 /*
311  * Need one statically allocated screen for early init.
312  * The rest are mallocated when needed.
313  */
314 adccscr_t amidisplaycc_consolescreen;
315 
316 /*
317  * Default palettes for 2, 4 and 8 color emulation displays.
318  */
319 
320 /* black, grey */
321 static u_char pal2red[] = { 0x00, 0xaa };
322 static u_char pal2grn[] = { 0x00, 0xaa };
323 static u_char pal2blu[] = { 0x00, 0xaa };
324 
325 /* black, red, green, grey */
326 static u_char pal4red[] = { 0x00, 0xaa, 0x00, 0xaa };
327 static u_char pal4grn[] = { 0x00, 0x00, 0xaa, 0xaa };
328 static u_char pal4blu[] = { 0x00, 0x00, 0x00, 0xaa };
329 
330 /* black, red, green, brown, blue, magenta, cyan, grey */
331 static u_char pal8red[] = { 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa};
332 static u_char pal8grn[] = { 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa};
333 static u_char pal8blu[] = { 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa};
334 
335 static struct wsdisplay_cmap pal2 = { 0, 2, pal2red, pal2grn, pal2blu };
336 static struct wsdisplay_cmap pal4 = { 0, 4, pal4red, pal4grn, pal4blu };
337 static struct wsdisplay_cmap pal8 = { 0, 8, pal8red, pal8grn, pal8blu };
338 
339 #ifdef GRF_AGA
340 extern int aga_enable;
341 #else
342 static int aga_enable = 0;
343 #endif
344 
345 /*
346  * This gets called at console init to determine the priority of
347  * this console device.
348  *
349  * Of course pointers to this and other functions must present
350  * in constab[] in conf.c for this to work.
351  */
352 void
353 amidisplaycc_cnprobe(struct consdev *cd)
354 {
355 	cd->cn_pri = CN_INTERNAL;
356 
357 	/*
358 	 * Yeah, real nice. But if we win the console then the wscons system
359 	 * does the proper initialization.
360 	 */
361 	cd->cn_dev = NODEV;
362 }
363 
364 /*
365  * This gets called if this device is used as the console.
366  */
367 void
368 amidisplaycc_cninit(struct consdev  * cd)
369 {
370 	void  * cookie;
371 	long    attr;
372 	int     x;
373 	int     y;
374 
375 	/* Yeah, we got the console! */
376 
377 	/*
378 	 * This will do the basic stuff we also need.
379 	 */
380 	config_console();
381 
382 	grfcc_probe();
383 
384 #if NVIEW>0
385 	viewprobe();
386 #endif
387 
388 	/*
389 	 * Set up wscons to handle the details.
390 	 * It will then call us back when it needs something
391 	 * display-specific. It will also set up cn_tab properly,
392 	 * something which we failed to do at amidisplaycc_cnprobe().
393 	 */
394 
395 	/*
396 	 * The alloc_screen knows to allocate the first screen statically.
397 	 */
398 	amidisplaycc_alloc_screen(NULL, &amidisplaycc_screentab[0].wsdescr,
399 				  &cookie, &x, &y, &attr);
400 	wsdisplay_cnattach(&amidisplaycc_screentab[0].wsdescr,
401 			   cookie, x, y, attr);
402 
403 #if NKBD>0
404 	/* tell kbd device it is used as console keyboard */
405 	kbd_cnattach();
406 #endif
407 }
408 
409 static int
410 amidisplaycc_match(struct device *pdp, struct cfdata *cfp, void *auxp)
411 {
412 	char *name = auxp;
413 
414 	if (matchname("amidisplaycc", name) == 0)
415 		return (0);
416 
417 	/* Allow only one of us now. Not sure about that. */
418 	if (amidisplaycc_attached)
419 		return (0);
420 
421 	return 1;
422 }
423 
424 /* ARGSUSED */
425 static void
426 amidisplaycc_attach(struct device *pdp, struct device *dp, void *auxp)
427 {
428 	struct wsemuldisplaydev_attach_args    waa;
429 	struct amidisplaycc_softc            * adp;
430 
431 	amidisplaycc_attached = 1;
432 
433 	adp = (struct amidisplaycc_softc*)dp;
434 
435 	grfcc_probe();
436 
437 #if NVIEW>0
438 	viewprobe();
439 #endif
440 
441 	/*
442 	 * Attach only at real configuration time. Console init is done at
443 	 * the amidisplaycc_cninit function above.
444 	 */
445 	if (adp) {
446 		printf(": Amiga custom chip graphics %s",
447 		       aga_enable ? "(AGA)" : "");
448 
449 		if (amidisplaycc_consolescreen.isconsole) {
450 			adp->currentscreen = &amidisplaycc_consolescreen;
451 			printf(" (console)");
452 		} else
453 			adp->currentscreen = NULL;
454 
455 		printf("\n");
456 
457 		adp->ison = 1;
458 
459 		/*
460 		 * Mapped screen properties.
461 		 * Would need a way to configure.
462 		 */
463 		adp->gfxview = NULL;
464 		adp->gfxon = 0;
465 		adp->gfxwidth = amidisplaycc_screentab[0].wsdescr.ncols *
466 			amidisplaycc_screentab[0].wsdescr.fontwidth;
467 		adp->gfxheight = amidisplaycc_screentab[0].wsdescr.nrows *
468 			amidisplaycc_screentab[0].wsdescr.fontheight;
469 
470 		if (aga_enable)
471 			adp->gfxdepth = 8;
472 		else
473 			adp->gfxdepth = 4;
474 
475 		if (NELEMS(amidisplaycc_screentab) !=
476 		    NELEMS(amidisplaycc_screens))
477 			panic("invalid screen definitions");
478 
479 		waa.scrdata = &amidisplaycc_screenlist;
480 		waa.console = amidisplaycc_consolescreen.isconsole;
481 		waa.accessops = &amidisplaycc_accessops;
482 		waa.accesscookie = dp;
483 		config_found(dp, &waa, wsemuldisplaydevprint);
484 
485 		wsfont_init();
486 	}
487 }
488 
489 
490 /*
491  * Color, bgcolor and style are packed into one long attribute.
492  * These macros are used to create/split the attribute
493  */
494 
495 #define MAKEATTR(fg, bg, mode) (((fg)<<16) | ((bg)<<8) | (mode))
496 #define ATTRFG(attr) (((attr)>>16) & 255)
497 #define ATTRBG(attr) (((attr)>>8) & 255)
498 #define ATTRMO(attr) ((attr) & 255)
499 
500 /*
501  * Called by wscons to draw/clear the cursor.
502  * We do this by xorring the block to the screen.
503  *
504  * This simple implementation will break if the screen is modified
505  * under the cursor before clearing it.
506  */
507 void
508 amidisplaycc_cursor(void *screen, int on, int row, int col)
509 {
510 	adccscr_t  * scr;
511 	u_char     * dst;
512 	int  i;
513 
514 	scr = screen;
515 
516 	if (row < 0 || col < 0 || row >= scr->nrows || col >= scr->ncols)
517 		return;
518 
519 	/* was off, turning off again? */
520 	if (!on && scr->cursorrow == -1 && scr->cursorcol == -1)
521 		return;
522 
523 	/* was on, and turning on again? */
524 	if (on && scr->cursorrow >= 0 && scr->cursorcol >= 0)
525 	{
526 		/* clear from old location first */
527 		amidisplaycc_cursor (screen, 0, scr->cursorrow, scr->cursorcol);
528 	}
529 
530 	dst = scr->planes[0];
531 	dst += row * scr->rowbytes;
532 	dst += col;
533 
534 	if (on) {
535 		scr->cursorrow = row;
536 		scr->cursorcol = col;
537 	} else {
538 		scr->cursorrow = -1;
539 		scr->cursorcol = -1;
540 	}
541 
542 	for (i = scr->fontheight ; i > 0 ; i--) {
543 		*dst ^= 255;
544 		dst += scr->linebytes;
545 	}
546 }
547 
548 
549 /*
550  * This obviously does something important, don't ask me what.
551  */
552 int
553 amidisplaycc_mapchar(void *screen, int ch, unsigned int *chp)
554 {
555 	if (ch > 0 && ch < 256) {
556 		*chp = ch;
557 		return (5);
558 	}
559 	*chp = ' ';
560 	return (0);
561 }
562 
563 /*
564  * Write a character to screen with color / bgcolor / hilite(bold) /
565  * underline / reverse.
566  * Surely could be made faster but I'm not sure if its worth the
567  * effort as scrolling is at least a magnitude slower.
568  */
569 void
570 amidisplaycc_putchar(void *screen, int row, int col, u_int ch, long attr)
571 {
572 	adccscr_t  * scr;
573 	u_char     * dst;
574 	u_char     * font;
575 
576 	int         fontheight;
577 	u_int8_t  * fontreal;
578 	int         fontlow;
579 	int         fonthigh;
580 
581 	int     bmapoffset;
582 	int     linebytes;
583 	int     underline;
584 	int     fgcolor;
585 	int     bgcolor;
586 	int     plane;
587 	int     depth;
588 	int     mode;
589 	int     bold;
590 	u_char  f;
591 	int     j;
592 
593 	scr = screen;
594 
595 	if (row < 0 || col < 0 || row >= scr->nrows || col >= scr->ncols)
596 		return;
597 
598 	/* Extract the colors from the attribute */
599 	fgcolor = ATTRFG(attr);
600 	bgcolor = ATTRBG(attr);
601 	mode    = ATTRMO(attr);
602 
603 	/* Translate to screen colors */
604 	fgcolor = scr->colormap[fgcolor];
605 	bgcolor = scr->colormap[bgcolor];
606 
607 	if (mode & WSATTR_REVERSE) {
608 		j = fgcolor;
609 		fgcolor = bgcolor;
610 		bgcolor = j;
611 	}
612 
613 	bold      = (mode & WSATTR_HILIT) > 0;
614 	underline = (mode & WSATTR_UNDERLINE) > 0;
615 
616 	fontreal = scr->wsfont->data;
617 	fontlow  = scr->wsfont->firstchar;
618 	fonthigh = fontlow + scr->wsfont->numchars - 1;
619 
620 	fontheight = min(scr->fontheight, scr->wsfont->fontheight);
621 	depth      = scr->depth;
622 	linebytes  = scr->linebytes;
623 
624 	if (ch < fontlow || ch > fonthigh)
625 		ch = fontlow;
626 
627 	/* Find the location where the wanted char is in the font data */
628 	fontreal += scr->wsfont->fontheight * (ch - fontlow);
629 
630 	bmapoffset = row * scr->rowbytes + col;
631 
632 	scr->rowmasks[row] |= fgcolor | bgcolor;
633 
634 	for (plane = 0 ; plane < depth ; plane++) {
635 		dst = scr->planes[plane] + bmapoffset;
636 
637 		if (fgcolor & 1) {
638 			if (bgcolor & 1) {
639 				/* fg=on bg=on (fill) */
640 
641 				for (j = 0 ; j < fontheight ; j++) {
642 					*dst = 255;
643 					dst += linebytes;
644 				}
645 			} else {
646 				/* fg=on bg=off (normal) */
647 
648 				font = fontreal;
649 				for (j = 0 ; j < fontheight ; j++) {
650 					f = *(font++);
651 					f |= f >> bold;
652 					*dst = f;
653 					dst += linebytes;
654 				}
655 
656 				if (underline)
657 					*(dst - linebytes) = 255;
658 			}
659 		} else {
660 			if (bgcolor & 1) {
661 				/* fg=off bg=on (inverted) */
662 
663 				font = fontreal;
664 				for (j = 0 ; j < fontheight ; j++) {
665 					f = *(font++);
666 					f |= f >> bold;
667 					*dst = ~f;
668 					dst += linebytes;
669 				}
670 
671 				if (underline)
672 					*(dst - linebytes) = 0;
673 			} else {
674 				/* fg=off bg=off (clear) */
675 
676 				for (j = 0 ; j < fontheight ; j++) {
677 					*dst = 0;
678 					dst += linebytes;
679 				}
680 			}
681 		}
682 		fgcolor >>= 1;
683 		bgcolor >>= 1;
684 	}
685 }
686 
687 /*
688  * Copy characters on a row to another position on the same row.
689  */
690 
691 void
692 amidisplaycc_copycols(void *screen, int row, int srccol, int dstcol, int ncols)
693 {
694 	adccscr_t  * scr;
695 	u_char     * src;
696 	u_char     * dst;
697 
698 	int  bmapoffset;
699 	int  linebytes;
700 	int  depth;
701 	int  plane;
702 	int  i;
703 	int  j;
704 
705 	scr = screen;
706 
707 	if (srccol < 0 || srccol + ncols > scr->ncols ||
708 	    dstcol < 0 || dstcol + ncols > scr->ncols ||
709 	    row < 0 || row >= scr->nrows)
710 		return;
711 
712 	depth = scr->depth;
713 	linebytes = scr->linebytes;
714 	bmapoffset = row * scr->rowbytes;
715 
716 	for (plane = 0 ; plane < depth ; plane++) {
717 		src = scr->planes[plane] + bmapoffset;
718 
719 		for (j = 0 ; j < scr->fontheight ; j++) {
720 			dst = src;
721 
722 			if (srccol < dstcol) {
723 
724 				for (i = ncols - 1 ; i >= 0 ; i--)
725 					dst[dstcol + i] = src[srccol + i];
726 
727 			} else {
728 
729 				for (i = 0 ; i < ncols ; i++)
730 					dst[dstcol + i] = src[srccol + i];
731 
732 			}
733 			src += linebytes;
734 		}
735 	}
736 }
737 
738 /*
739  * Erase part of a row.
740  */
741 
742 void
743 amidisplaycc_erasecols(void *screen, int row, int startcol, int ncols,
744 		       long attr)
745 {
746 	adccscr_t  * scr;
747 	u_char     * dst;
748 
749 	int  bmapoffset;
750 	int  linebytes;
751 	int  bgcolor;
752 	int  depth;
753 	int  plane;
754 	int  fill;
755 	int  j;
756 
757 	scr = screen;
758 
759 	if (row < 0 || row >= scr->nrows ||
760 	    startcol < 0 || startcol + ncols > scr->ncols)
761 		return;
762 
763 	depth = scr->depth;
764 	linebytes = scr->linebytes;
765 	bmapoffset = row * scr->rowbytes + startcol;
766 
767 	/* Erase will be done using the set background color. */
768 	bgcolor = ATTRBG(attr);
769 	bgcolor = scr->colormap[bgcolor];
770 
771 	for(plane = 0 ; plane < depth ; plane++) {
772 
773 		fill = (bgcolor & 1) ? 255 : 0;
774 
775 		dst = scr->planes[plane] + bmapoffset;
776 
777 		for (j = 0 ; j < scr->fontheight ; j++) {
778 			memset(dst, fill, ncols);
779 			dst += linebytes;
780 		}
781 	}
782 }
783 
784 /*
785  * Copy a number of rows to another location on the screen.
786  * Combined with eraserows it can be used to perform operation
787  * also known as 'scrolling'.
788  */
789 
790 void
791 amidisplaycc_copyrows(void *screen, int srcrow, int dstrow, int nrows)
792 {
793 	adccscr_t  * scr;
794 	u_char     * src;
795 	u_char     * dst;
796 
797 	int  srcbmapoffset;
798 	int  dstbmapoffset;
799 	int  widthbytes;
800 	int  fontheight;
801 	int  linebytes;
802 	u_int copysize;
803 	int  rowdelta;
804 	int  rowbytes;
805 	int  srcmask;
806 	int  dstmask;
807 	int  bmdelta;
808 	int  depth;
809 	int  plane;
810 	int  i;
811 	int  j;
812 
813 	scr = screen;
814 
815 	if (srcrow < 0 || srcrow + nrows > scr->nrows ||
816 	    dstrow < 0 || dstrow + nrows > scr->nrows)
817 		return;
818 
819 	depth = scr->depth;
820 
821 	widthbytes = scr->widthbytes;
822 	rowbytes   = scr->rowbytes;
823 	linebytes  = scr->linebytes;
824 	fontheight = scr->fontheight;
825 
826 	srcbmapoffset = rowbytes * srcrow;
827 	dstbmapoffset = rowbytes * dstrow;
828 
829 	if (srcrow < dstrow) {
830 		/* Move data downwards, need to copy from down to up */
831 		bmdelta = -rowbytes;
832 		rowdelta = -1;
833 
834 		srcbmapoffset += rowbytes * (nrows - 1);
835 		srcrow += nrows - 1;
836 
837 		dstbmapoffset += rowbytes * (nrows - 1);
838 		dstrow += nrows - 1;
839 	} else {
840 		/* Move data upwards, copy up to down */
841 		bmdelta = rowbytes;
842 		rowdelta = 1;
843 	}
844 
845 	if (widthbytes == linebytes)
846 		copysize = rowbytes;
847 	else
848 		copysize = 0;
849 
850 	for (j = 0 ; j < nrows ; j++) {
851 		/* Need to copy only planes that have data on src or dst */
852 		srcmask = scr->rowmasks[srcrow];
853 		dstmask = scr->rowmasks[dstrow];
854 		scr->rowmasks[dstrow] = srcmask;
855 
856 		for (plane = 0 ; plane < depth ; plane++) {
857 
858 			if (srcmask & 1) {
859 				/*
860 				 * Source row has data on this
861 				 * plane, copy it.
862 				 */
863 
864 				src = scr->planes[plane] + srcbmapoffset;
865 				dst = scr->planes[plane] + dstbmapoffset;
866 
867 				if (copysize > 0) {
868 
869 					memcpy(dst, src, copysize);
870 
871 				} else {
872 
873 					/*
874 					 * Data not continuous,
875 					 * must do in pieces
876 					 */
877 					for (i=0 ; i < fontheight ; i++) {
878 						memcpy(dst, src, widthbytes);
879 
880 						src += linebytes;
881 						dst += linebytes;
882 					}
883 				}
884 			} else if (dstmask & 1) {
885 				/*
886 				 * Source plane is empty, but dest is not.
887 				 * so all we need to is clear it.
888 				 */
889 
890 				dst = scr->planes[plane] + dstbmapoffset;
891 
892 				if (copysize > 0) {
893 					/* Do it all */
894 					memset(dst, 0, copysize);
895 				} else {
896 					for (i = 0 ; i < fontheight ; i++) {
897 						memset(dst, 0, widthbytes);
898 						dst += linebytes;
899 					}
900 				}
901 			}
902 
903 			srcmask >>= 1;
904 			dstmask >>= 1;
905 		}
906 		srcbmapoffset += bmdelta;
907 		dstbmapoffset += bmdelta;
908 
909 		srcrow += rowdelta;
910 		dstrow += rowdelta;
911 	}
912 }
913 
914 /*
915  * Erase some rows.
916  */
917 
918 void
919 amidisplaycc_eraserows(void *screen, int row, int nrows, long attr)
920 {
921 	adccscr_t  * scr;
922 	u_char     * dst;
923 
924 	int  bmapoffset;
925 	int  fillsize;
926 	int  bgcolor;
927 	int  depth;
928 	int  plane;
929 	int  fill;
930 	int  j;
931 
932 	int  widthbytes;
933 	int  linebytes;
934 	int  rowbytes;
935 
936 
937 	scr = screen;
938 
939 	if (row < 0 || row + nrows > scr->nrows)
940 		return;
941 
942 	depth      = scr->depth;
943 	widthbytes = scr->widthbytes;
944 	linebytes  = scr->linebytes;
945 	rowbytes   = scr->rowbytes;
946 
947 	bmapoffset = row * rowbytes;
948 
949 	if (widthbytes == linebytes)
950 		fillsize = rowbytes * nrows;
951 	else
952 		fillsize = 0;
953 
954 	bgcolor = ATTRBG(attr);
955 	bgcolor = scr->colormap[bgcolor];
956 
957 	for (j = 0 ; j < nrows ; j++)
958 		scr->rowmasks[row+j] = bgcolor;
959 
960 	for (plane = 0 ; plane < depth ; plane++) {
961 		dst = scr->planes[plane] + bmapoffset;
962 		fill = (bgcolor & 1) ? 255 : 0;
963 
964 		if (fillsize > 0) {
965 			/* If the rows are continuous, write them all. */
966 			memset(dst, fill, fillsize);
967 		} else {
968 			for (j = 0 ; j < scr->fontheight * nrows ; j++) {
969 				memset(dst, fill, widthbytes);
970 				dst += linebytes;
971 			}
972 		}
973 		bgcolor >>= 1;
974 	}
975 }
976 
977 
978 /*
979  * Compose an attribute value from foreground color,
980  * background color, and flags.
981  */
982 int
983 amidisplaycc_allocattr(void *screen, int fg, int bg, int flags, long *attrp)
984 {
985 	adccscr_t  * scr;
986 	int          maxcolor;
987 	int          newfg;
988 	int          newbg;
989 
990 	scr = screen;
991 	maxcolor = (1 << scr->view->bitmap->depth) - 1;
992 
993 	/* Ensure the colors are displayable. */
994 	newfg = fg & maxcolor;
995 	newbg = bg & maxcolor;
996 
997 #ifdef ADJUSTCOLORS
998 	/*
999 	 * Hack for low-color screens, if background color is nonzero
1000 	 * but would be displayed as one, adjust it.
1001 	 */
1002 	if (bg > 0 && newbg == 0)
1003 		newbg = maxcolor;
1004 
1005 	/*
1006 	 * If foreground and background colors are different but would
1007 	 * display the same fix them by modifying the foreground.
1008 	 */
1009 	if (fg != bg && newfg == newbg) {
1010 		if (newbg > 0)
1011 			newfg = 0;
1012 		else
1013 			newfg = maxcolor;
1014 	}
1015 #endif
1016 	*attrp = MAKEATTR(newfg, newbg, flags);
1017 
1018 	return (0);
1019 }
1020 
1021 int
1022 amidisplaycc_ioctl(void *dp, void *vs, u_long cmd, void *data, int flag,
1023 	struct lwp *l)
1024 {
1025 	struct amidisplaycc_softc *adp;
1026 
1027 	adp = dp;
1028 
1029 	if (adp == NULL) {
1030 		printf("amidisplaycc_ioctl: adp==NULL\n");
1031 		return (EINVAL);
1032 	}
1033 
1034 #define UINTDATA (*(u_int*)data)
1035 #define INTDATA (*(int*)data)
1036 #define FBINFO (*(struct wsdisplay_fbinfo*)data)
1037 
1038 	switch (cmd)
1039 	{
1040 	case WSDISPLAYIO_GTYPE:
1041 		UINTDATA = WSDISPLAY_TYPE_AMIGACC;
1042 		return (0);
1043 
1044 	case WSDISPLAYIO_SVIDEO:
1045 		dprintf("amidisplaycc: WSDISPLAYIO_SVIDEO %s\n",
1046 			UINTDATA ? "On" : "Off");
1047 
1048 		return (amidisplaycc_setvideo(adp, UINTDATA));
1049 
1050 	case WSDISPLAYIO_GVIDEO:
1051 		dprintf("amidisplaycc: WSDISPLAYIO_GVIDEO\n");
1052 		UINTDATA = adp->ison ?
1053 		    WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF;
1054 
1055 		return (0);
1056 
1057 	case WSDISPLAYIO_SMODE:
1058 		if (INTDATA == WSDISPLAYIO_MODE_EMUL)
1059 			return amidisplaycc_gfxscreen(adp, 0);
1060 		if (INTDATA == WSDISPLAYIO_MODE_MAPPED)
1061 			return amidisplaycc_gfxscreen(adp, 1);
1062 		return (EINVAL);
1063 
1064 	case WSDISPLAYIO_GINFO:
1065 		FBINFO.width  = adp->gfxwidth;
1066 		FBINFO.height = adp->gfxheight;
1067 		FBINFO.depth  = adp->gfxdepth;
1068 		FBINFO.cmsize = 1 << FBINFO.depth;
1069 		return (0);
1070 
1071 	case WSDISPLAYIO_PUTCMAP:
1072 	case WSDISPLAYIO_GETCMAP:
1073 		return (amidisplaycc_cmapioctl(adp->gfxview,
1074 					       cmd,
1075 					       (struct wsdisplay_cmap*)data));
1076 	}
1077 
1078 	dprintf("amidisplaycc: unknown ioctl %lx (grp:'%c' num:%d)\n",
1079 		(long)cmd,
1080 		(char)((cmd&0xff00)>>8),
1081 		(int)(cmd&0xff));
1082 
1083 	return (EPASSTHROUGH);
1084 
1085 #undef UINTDATA
1086 #undef INTDATA
1087 #undef FBINFO
1088 }
1089 
1090 
1091 /*
1092  * Switch to either emulation (text) or mapped (graphics) mode
1093  * We keep an extra screen for mapped mode so it does not
1094  * interfere with emulation screens.
1095  *
1096  * Once the extra screen is created, it never goes away.
1097  */
1098 
1099 static int
1100 amidisplaycc_gfxscreen(struct amidisplaycc_softc *adp, int on)
1101 {
1102 	dimen_t  dimension;
1103 
1104 	dprintf("amidisplaycc: switching to %s mode.\n",
1105 		on ? "mapped" : "emul");
1106 
1107 	/* Current mode same as requested mode? */
1108 	if ( (on > 0) == (adp->gfxon > 0) )
1109 		return (0);
1110 
1111 	if (!on) {
1112 		/*
1113 		 * Switch away from mapped mode. If there is
1114 		 * a emulation screen, switch to it, otherwise
1115 		 * just try to hide the mapped screen.
1116 		 */
1117 		adp->gfxon = 0;
1118 		if (adp->currentscreen)
1119 			grf_display_view(adp->currentscreen->view);
1120 		else if (adp->gfxview)
1121 			grf_remove_view(adp->gfxview);
1122 
1123 		return (0);
1124 	}
1125 
1126 	/* switch to mapped mode then */
1127 
1128 	if (adp->gfxview == NULL) {
1129 		/* First time here, create the screen */
1130 
1131 		dimension.width = adp->gfxwidth;
1132 		dimension.height = adp->gfxheight;
1133 
1134 		dprintf("amidisplaycc: preparing mapped screen %dx%dx%d\n",
1135 			dimension.width,
1136 			dimension.height,
1137 			adp->gfxdepth);
1138 
1139 		adp->gfxview = grf_alloc_view(NULL,
1140 					      &dimension,
1141 					      adp->gfxdepth);
1142 	}
1143 
1144 	if (adp->gfxview) {
1145 		adp->gfxon = 1;
1146 
1147 		grf_display_view(adp->gfxview);
1148 	} else {
1149 		printf("amidisplaycc: failed to make mapped screen\n");
1150 		return (ENOMEM);
1151 	}
1152 	return (0);
1153 }
1154 
1155 /*
1156  * Map the graphics screen. It must have been created before
1157  * by switching to mapped mode by using an ioctl.
1158  */
1159 paddr_t
1160 amidisplaycc_mmap(void *dp, void *vs, off_t off, int prot)
1161 {
1162 	struct amidisplaycc_softc  * adp;
1163 	bmap_t                     * bm;
1164 	paddr_t                      rv;
1165 
1166 	adp = (struct amidisplaycc_softc*)dp;
1167 
1168 	/* Check we are in mapped mode */
1169 	if (adp->gfxon == 0 || adp->gfxview == NULL) {
1170 		dprintf("amidisplaycc_mmap: Not in mapped mode\n");
1171 		return (paddr_t)(-1);
1172 	}
1173 
1174 	/*
1175 	 * As we all know by now, we are mapping our special
1176 	 * screen here so our pretty text consoles are left
1177 	 * untouched.
1178 	 */
1179 
1180 	bm = adp->gfxview->bitmap;
1181 
1182 	/* Check that the offset is valid */
1183 	if (off < 0 || off >= bm->depth * bm->bytes_per_row * bm->rows) {
1184 		dprintf("amidisplaycc_mmap: Offset out of range\n");
1185 		return (paddr_t)(-1);
1186 	}
1187 
1188 	rv = (paddr_t)bm->hardware_address;
1189 	rv += off;
1190 
1191 	return (rv >> PGSHIFT);
1192 }
1193 
1194 
1195 /*
1196  * Create a new screen.
1197  * NULL dp signifies console and then memory is allocated statically
1198  * and the screen is automatically displayed.
1199  *
1200  * A font with suitable size is searched and if not found
1201  * the builtin 8x8 font is used.
1202  *
1203  * There are separate default palettes for 2, 4 and 8+ color
1204  * screens.
1205  */
1206 
1207 int
1208 amidisplaycc_alloc_screen(void *dp, const struct wsscreen_descr *screenp,
1209 			  void  **cookiep, int *curxp, int *curyp,
1210 			  long *defattrp)
1211 {
1212 	const struct amidisplaycc_screen_descr  * adccscreenp;
1213 	struct amidisplaycc_screen              * scr;
1214 	struct amidisplaycc_softc               * adp;
1215 	view_t                                  * view;
1216 
1217 	dimen_t  dimension;
1218 	int      fontheight;
1219 	int      fontwidth;
1220 	int      maxcolor;
1221 	int      depth;
1222 	int      i;
1223 	int      j;
1224 
1225 	adccscreenp = (const struct amidisplaycc_screen_descr *)screenp;
1226 	depth = adccscreenp->depth;
1227 
1228 	adp = dp;
1229 
1230 	maxcolor = (1 << depth) - 1;
1231 
1232 	/* Sanity checks because of fixed buffers */
1233 	if (depth > MAXDEPTH || maxcolor >= MAXCOLORS)
1234 		return (ENOMEM);
1235 	if (screenp->nrows > MAXROWS)
1236 		return (ENOMEM);
1237 
1238 	fontwidth = screenp->fontwidth;
1239 	fontheight = screenp->fontheight;
1240 
1241 	/*
1242 	 * The screen size is defined in characters.
1243 	 * Calculate the pixel size using the font size.
1244 	 */
1245 
1246 	dimension.width = screenp->ncols * fontwidth;
1247 	dimension.height = screenp->nrows * fontheight;
1248 
1249 	view = grf_alloc_view(NULL, &dimension, depth);
1250 	if (view == NULL)
1251 		return (ENOMEM);
1252 
1253 	/*
1254 	 * First screen gets the statically allocated console screen.
1255 	 * Others are allocated dynamically.
1256 	 */
1257 	if (adp == NULL) {
1258 		scr = &amidisplaycc_consolescreen;
1259 		if (scr->isconsole)
1260 			panic("more than one console?");
1261 
1262 		scr->isconsole = 1;
1263 	} else {
1264 		scr = malloc(sizeof(adccscr_t), M_DEVBUF, M_WAITOK|M_ZERO);
1265 	}
1266 
1267 	scr->view = view;
1268 
1269 	scr->ncols = screenp->ncols;
1270 	scr->nrows = screenp->nrows;
1271 
1272 	/* Copies of most used values */
1273 	scr->width  = dimension.width;
1274 	scr->height = dimension.height;
1275 	scr->depth  = depth;
1276 	scr->widthbytes = view->bitmap->bytes_per_row;
1277 	scr->linebytes  = scr->widthbytes + view->bitmap->row_mod;
1278 	scr->rowbytes   = scr->linebytes * fontheight;
1279 
1280 	scr->device = adp;
1281 
1282 
1283 	/*
1284 	 * Try to find a suitable font.
1285 	 * Avoid everything but the builtin font for console screen.
1286 	 * Builtin font is used if no other is found, even if it
1287 	 * has the wrong size.
1288 	 */
1289 
1290 	KASSERT(fontwidth == 8);
1291 
1292 	scr->wsfont       = NULL;
1293 	scr->wsfontcookie = -1;
1294 	scr->fontwidth    = fontwidth;
1295 	scr->fontheight   = fontheight;
1296 
1297 	if (adp)
1298 		amidisplaycc_setfont(scr, NULL);
1299 
1300 	if (scr->wsfont == NULL)
1301 	{
1302 		scr->wsfont = amidisplaycc_getbuiltinfont();
1303 		scr->wsfontcookie = -1;
1304 	}
1305 
1306 	KASSERT(scr->wsfont);
1307 	KASSERT(scr->wsfont->stride == 1);
1308 
1309 	for (i = 0 ; i < depth ; i++) {
1310 		scr->planes[i] = view->bitmap->plane[i];
1311 	}
1312 
1313 	for (i = 0 ; i < MAXROWS ; i++)
1314 		scr->rowmasks[i] = 0;
1315 
1316 	/* Simple one-to-one mapping for most colors */
1317 	for (i = 0 ; i < MAXCOLORS ; i++)
1318 		scr->colormap[i] = i;
1319 
1320 	/*
1321 	 * Arrange the most used pens to quickest colors.
1322 	 * The default color for given depth is (1<<depth)-1.
1323 	 * It is assumed it is used most and it is mapped to
1324 	 * color that can be drawn by writing data to one bitplane
1325 	 * only.
1326 	 * So map colors 3->2, 7->4, 15->8 and so on.
1327 	 */
1328 	for (i = 2 ; i < MAXCOLORS ; i *= 2) {
1329 		j = i * 2 - 1;
1330 
1331 		if (j < MAXCOLORS) {
1332 			scr->colormap[i] = j;
1333 			scr->colormap[j] = i;
1334 		}
1335 	}
1336 
1337 	/*
1338 	 * Set the default colormap.
1339 	 */
1340 	if (depth == 1)
1341 		amidisplaycc_setemulcmap(scr, &pal2);
1342 	else if (depth == 2)
1343 		amidisplaycc_setemulcmap(scr, &pal4);
1344 	else
1345 		amidisplaycc_setemulcmap(scr, &pal8);
1346 
1347 	*cookiep = scr;
1348 
1349 	/* cursor initially at top left */
1350 	scr->cursorrow = -1;
1351 	scr->cursorcol = -1;
1352 	*curxp = 0;
1353 	*curyp = 0;
1354 	amidisplaycc_cursor(scr, 1, *curxp, *curyp);
1355 
1356 	*defattrp = MAKEATTR(maxcolor, 0, 0);
1357 
1358 	/* Show the console automatically */
1359 	if (adp == NULL)
1360 		grf_display_view(scr->view);
1361 
1362 	if (adp) {
1363 		dprintf("amidisplaycc: allocated screen; %dx%dx%d; font=%s\n",
1364 			dimension.width,
1365 			dimension.height,
1366 			depth,
1367 			scr->wsfont->name);
1368 	}
1369 
1370 	return (0);
1371 }
1372 
1373 
1374 /*
1375  * Destroy a screen.
1376  */
1377 
1378 void
1379 amidisplaycc_free_screen(void *dp, void *screen)
1380 {
1381 	struct amidisplaycc_screen  * scr;
1382 	struct amidisplaycc_softc   * adp;
1383 
1384 	scr = screen;
1385 	adp = (struct amidisplaycc_softc*)dp;
1386 
1387 	if (scr == NULL)
1388 		return;
1389 
1390 	/* Free the used font */
1391 	if (scr->wsfont && scr->wsfontcookie != -1)
1392 		wsfont_unlock(scr->wsfontcookie);
1393 	scr->wsfont = NULL;
1394 	scr->wsfontcookie = -1;
1395 
1396 	if (adp->currentscreen == scr)
1397 		adp->currentscreen = NULL;
1398 
1399 	if (scr->view)
1400 		grf_free_view(scr->view);
1401 	scr->view = NULL;
1402 
1403 	/* Take care not to free the statically allocated console screen */
1404 	if (scr != &amidisplaycc_consolescreen) {
1405 		free(scr, M_DEVBUF);
1406 	}
1407 }
1408 
1409 /*
1410  * Switch to another vt. Switch is always made immediately.
1411  */
1412 
1413 /* ARGSUSED2 */
1414 int
1415 amidisplaycc_show_screen(void *dp, void *screen, int waitok,
1416 			 void (*cb) (void *, int, int), void *cbarg)
1417 {
1418 	adccscr_t *scr;
1419 	struct amidisplaycc_softc *adp;
1420 
1421 	adp = (struct amidisplaycc_softc*)dp;
1422 	scr = screen;
1423 
1424 	if (adp == NULL) {
1425 		dprintf("amidisplaycc_show_screen: adp==NULL\n");
1426 		return (EINVAL);
1427 	}
1428 	if (scr == NULL) {
1429 		dprintf("amidisplaycc_show_screen: scr==NULL\n");
1430 		return (EINVAL);
1431 	}
1432 
1433 	if (adp->gfxon) {
1434 		dprintf("amidisplaycc: Screen shift while in gfx mode?");
1435 		adp->gfxon = 0;
1436 	}
1437 
1438 	adp->currentscreen = scr;
1439 	adp->ison = 1;
1440 
1441 	grf_display_view(scr->view);
1442 
1443 	return (0);
1444 }
1445 
1446 /*
1447  * Load/set a font.
1448  *
1449  * Only setting is supported, as the wsfont pseudo-device can
1450  * handle the loading of fonts for us.
1451  */
1452 int
1453 amidisplaycc_load_font(void *dp, void *cookie, struct wsdisplay_font *font)
1454 {
1455 	struct amidisplaycc_softc   * adp;
1456 	struct amidisplaycc_screen  * scr;
1457 
1458 	adp = dp;
1459 	scr = cookie;
1460 
1461 	KASSERT(adp);
1462 	KASSERT(scr);
1463 	KASSERT(font);
1464 	KASSERT(font->name);
1465 
1466 	if (font->data)
1467 	{
1468 		/* request to load the font, not supported */
1469 		return (EINVAL);
1470 	}
1471 	else
1472 	{
1473 		/* request to use the given font on this screen */
1474 		return amidisplaycc_setfont(scr, font->name);
1475 	}
1476 }
1477 
1478 /*
1479  * Set display on/off.
1480  */
1481 static int
1482 amidisplaycc_setvideo(struct amidisplaycc_softc *adp, int mode)
1483 {
1484         view_t * view;
1485 
1486 	if (adp == NULL) {
1487 		dprintf("amidisplaycc_setvideo: adp==NULL\n");
1488 		return (EINVAL);
1489 	}
1490 	if (adp->currentscreen == NULL) {
1491 		dprintf("amidisplaycc_setvideo: adp->currentscreen==NULL\n");
1492 		return (EINVAL);
1493 	}
1494 
1495 	/* select graphics or emulation screen */
1496 	if (adp->gfxon && adp->gfxview)
1497 		view = adp->gfxview;
1498 	else
1499 		view = adp->currentscreen->view;
1500 
1501 	if (mode) {
1502 		/* on */
1503 
1504 		grf_display_view(view);
1505 		dprintf("amidisplaycc: video is now on\n");
1506 		adp->ison = 1;
1507 
1508 	} else {
1509 		/* off */
1510 
1511 		grf_remove_view(view);
1512 		dprintf("amidisplaycc: video is now off\n");
1513 		adp->ison = 0;
1514 	}
1515 
1516 	return (0);
1517 }
1518 
1519 /*
1520  * Handle the WSDISPLAY_[PUT/GET]CMAP ioctls.
1521  * Just handle the copying of data to/from userspace and
1522  * let the functions amidisplaycc_setcmap and amidisplaycc_putcmap
1523  * do the real work.
1524  */
1525 
1526 static int
1527 amidisplaycc_cmapioctl(view_t *view, u_long cmd, struct wsdisplay_cmap *cmap)
1528 {
1529 	struct wsdisplay_cmap  tmpcmap;
1530 	u_char                 cmred[MAXCOLORS];
1531 	u_char                 cmgrn[MAXCOLORS];
1532 	u_char                 cmblu[MAXCOLORS];
1533 
1534 	int                    err;
1535 
1536 	if (cmap->index >= MAXCOLORS ||
1537 	    cmap->count > MAXCOLORS ||
1538 	    cmap->index + cmap->count > MAXCOLORS)
1539 		return (EINVAL);
1540 
1541 	if (cmap->count == 0)
1542 		return (0);
1543 
1544 	tmpcmap.index = cmap->index;
1545 	tmpcmap.count = cmap->count;
1546 	tmpcmap.red   = cmred;
1547 	tmpcmap.green = cmgrn;
1548 	tmpcmap.blue  = cmblu;
1549 
1550 	if (cmd == WSDISPLAYIO_PUTCMAP) {
1551 		/* copy the color data to kernel space */
1552 
1553 		err = copyin(cmap->red, cmred, cmap->count);
1554 		if (err)
1555 			return (err);
1556 
1557 		err = copyin(cmap->green, cmgrn, cmap->count);
1558 		if (err)
1559 			return (err);
1560 
1561 		err = copyin(cmap->blue, cmblu, cmap->count);
1562 		if (err)
1563 			return (err);
1564 
1565 		return amidisplaycc_setcmap(view, &tmpcmap);
1566 
1567 	} else if (cmd == WSDISPLAYIO_GETCMAP) {
1568 
1569 		err = amidisplaycc_getcmap(view, &tmpcmap);
1570 		if (err)
1571 			return (err);
1572 
1573 		/* copy data to user space */
1574 
1575 		err = copyout(cmred, cmap->red, cmap->count);
1576 		if (err)
1577 			return (err);
1578 
1579 		err = copyout(cmgrn, cmap->green, cmap->count);
1580 		if (err)
1581 			return (err);
1582 
1583 		err = copyout(cmblu, cmap->blue, cmap->count);
1584 		if (err)
1585 			return (err);
1586 
1587 		return (0);
1588 
1589 	} else
1590 		return (EPASSTHROUGH);
1591 }
1592 
1593 /*
1594  * Set the palette of a emulation screen.
1595  * Here we do only color remapping and then call
1596  * amidisplaycc_setcmap to do the work.
1597  */
1598 
1599 static int
1600 amidisplaycc_setemulcmap(struct amidisplaycc_screen *scr,
1601 			 struct wsdisplay_cmap *cmap)
1602 {
1603 	struct wsdisplay_cmap  tmpcmap;
1604 
1605 	u_char                 red [MAXCOLORS];
1606 	u_char                 grn [MAXCOLORS];
1607 	u_char                 blu [MAXCOLORS];
1608 
1609 	int                    rc;
1610 	int                    i;
1611 
1612 	/*
1613 	 * Get old palette first.
1614 	 * Because of the color mapping going on in the emulation
1615 	 * screen the color range may not be contiguous in the real
1616 	 * palette.
1617 	 * So get the whole palette, insert the new colors
1618 	 * at the appropriate places and then set the whole
1619 	 * palette back.
1620 	 */
1621 
1622 	tmpcmap.index = 0;
1623 	tmpcmap.count = 1 << scr->depth;
1624 	tmpcmap.red   = red;
1625 	tmpcmap.green = grn;
1626 	tmpcmap.blue  = blu;
1627 
1628 	rc = amidisplaycc_getcmap(scr->view, &tmpcmap);
1629 	if (rc)
1630 		return (rc);
1631 
1632 	for (i = cmap->index ; i < cmap->index + cmap->count ; i++) {
1633 
1634 		tmpcmap.red   [ scr->colormap[ i ] ] = cmap->red   [ i ];
1635 		tmpcmap.green [ scr->colormap[ i ] ] = cmap->green [ i ];
1636 		tmpcmap.blue  [ scr->colormap[ i ] ] = cmap->blue  [ i ];
1637 	}
1638 
1639 	rc = amidisplaycc_setcmap(scr->view, &tmpcmap);
1640 	if (rc)
1641 		return (rc);
1642 
1643 	return (0);
1644 }
1645 
1646 
1647 /*
1648  * Set the colormap for the given screen.
1649  */
1650 
1651 static int
1652 amidisplaycc_setcmap(view_t *view, struct wsdisplay_cmap *cmap)
1653 {
1654 	u_long      cmentries [MAXCOLORS];
1655 
1656 	u_int       colors;
1657 	int         index;
1658 	int         count;
1659 	int         err;
1660 	colormap_t  cm;
1661 
1662 	if (view == NULL)
1663 		return (EINVAL);
1664 
1665 	if (!cmap || !cmap->red || !cmap->green || !cmap->blue) {
1666 		dprintf("amidisplaycc_setcmap: other==NULL\n");
1667 		return (EINVAL);
1668 	}
1669 
1670 	index  = cmap->index;
1671 	count  = cmap->count;
1672 	colors = (1 << view->bitmap->depth);
1673 
1674 	if (count > colors || index >= colors || index + count > colors)
1675 		return (EINVAL);
1676 
1677 	if (count == 0)
1678 		return (0);
1679 
1680 	cm.entry = cmentries;
1681 	cm.first = index;
1682 	cm.size  = count;
1683 
1684 	/*
1685 	 * Get the old colormap. We need to do this at least to know
1686 	 * how many bits to use with the color values.
1687 	 */
1688 
1689 	err = grf_get_colormap(view, &cm);
1690 	if (err)
1691 		return (err);
1692 
1693 	/*
1694 	 * The palette entries from wscons contain 8 bits per gun.
1695 	 * We need to convert them to the number of bits the view
1696 	 * expects. That is typically 4 or 8. Here we calculate the
1697 	 * conversion constants with which we divide the color values.
1698 	 */
1699 
1700 	if (cm.type == CM_COLOR) {
1701 		int c, green_div, blue_div, red_div;
1702 
1703 		red_div = 256 / (cm.red_mask + 1);
1704 		green_div = 256 / (cm.green_mask + 1);
1705 		blue_div = 256 / (cm.blue_mask + 1);
1706 
1707 		for (c = 0 ; c < count ; c++)
1708 			cm.entry[c + index] = MAKE_COLOR_ENTRY(
1709 				cmap->red[c] / red_div,
1710 				cmap->green[c] / green_div,
1711 				cmap->blue[c] / blue_div);
1712 
1713 	} else if (cm.type == CM_GREYSCALE) {
1714 		int c, grey_div;
1715 
1716 		grey_div = 256 / (cm.grey_mask + 1);
1717 
1718 		/* Generate grey from average of r-g-b (?) */
1719 		for (c = 0 ; c < count ; c++)
1720 			cm.entry[c + index] = MAKE_COLOR_ENTRY(
1721 				0,
1722 				0,
1723 				(cmap->red[c] +
1724 				 cmap->green[c] +
1725 				 cmap->blue[c]) / 3 / grey_div);
1726 	} else
1727 		return (EINVAL); /* Hmhh */
1728 
1729 	/*
1730 	 * Now we have a new colormap that contains all the entries. Set
1731 	 * it to the view.
1732 	 */
1733 
1734 	err = grf_use_colormap(view, &cm);
1735 	if (err)
1736 		return err;
1737 
1738 	return (0);
1739 }
1740 
1741 /*
1742  * Return the colormap of the given screen.
1743  */
1744 
1745 static int
1746 amidisplaycc_getcmap(view_t *view, struct wsdisplay_cmap *cmap)
1747 {
1748 	u_long      cmentries [MAXCOLORS];
1749 
1750 	u_int       colors;
1751 	int         index;
1752 	int         count;
1753 	int         err;
1754 	colormap_t  cm;
1755 
1756 	if (view == NULL)
1757 		return (EINVAL);
1758 
1759 	if (!cmap || !cmap->red || !cmap->green || !cmap->blue)
1760 		return (EINVAL);
1761 
1762 	index  = cmap->index;
1763 	count  = cmap->count;
1764 	colors = (1 << view->bitmap->depth);
1765 
1766 	if (count > colors || index >= colors || index + count > colors)
1767 		return (EINVAL);
1768 
1769 	if (count == 0)
1770 		return (0);
1771 
1772 	cm.entry = cmentries;
1773 	cm.first = index;
1774 	cm.size  = count;
1775 
1776 	err = grf_get_colormap(view, &cm);
1777 	if (err)
1778 		return (err);
1779 
1780 	/*
1781 	 * Copy color data to wscons-style structure. Translate to
1782 	 * 8 bits/gun from whatever resolution the color natively is.
1783 	 */
1784 	if (cm.type == CM_COLOR) {
1785 		int c, red_mul, green_mul, blue_mul;
1786 
1787 		red_mul   = 256 / (cm.red_mask + 1);
1788 		green_mul = 256 / (cm.green_mask + 1);
1789 		blue_mul  = 256 / (cm.blue_mask + 1);
1790 
1791 		for (c = 0 ; c < count ; c++) {
1792 			cmap->red[c] = red_mul *
1793 				CM_GET_RED(cm.entry[index+c]);
1794 			cmap->green[c] = green_mul *
1795 				CM_GET_GREEN(cm.entry[index+c]);
1796 			cmap->blue[c] = blue_mul *
1797 				CM_GET_BLUE(cm.entry[index+c]);
1798 		}
1799 	} else if (cm.type == CM_GREYSCALE) {
1800 		int c, grey_mul;
1801 
1802 		grey_mul = 256 / (cm.grey_mask + 1);
1803 
1804 		for (c = 0 ; c < count ; c++) {
1805 			cmap->red[c] = grey_mul *
1806 				CM_GET_GREY(cm.entry[index+c]);
1807 			cmap->green[c] = grey_mul *
1808 				CM_GET_GREY(cm.entry[index+c]);
1809 			cmap->blue[c] = grey_mul *
1810 				CM_GET_GREY(cm.entry[index+c]);
1811 		}
1812 	} else
1813 		return (EINVAL);
1814 
1815 	return (0);
1816 }
1817 
1818 /*
1819  * Find and set a font for the given screen.
1820  *
1821  * If fontname is given, a font with that name and suitable
1822  * size (determined by the screen) is searched for.
1823  * If fontname is NULL, a font with suitable size is searched.
1824  *
1825  * On success, the found font is assigned to the screen and possible
1826  * old font is freed.
1827  */
1828 static int
1829 amidisplaycc_setfont(struct amidisplaycc_screen *scr, const char *fontname)
1830 {
1831 	struct wsdisplay_font *wsfont;
1832 	int wsfontcookie;
1833 
1834 	KASSERT(scr);
1835 
1836 	wsfontcookie = wsfont_find(fontname,
1837 		scr->fontwidth,
1838 		scr->fontheight,
1839 		1,
1840 		WSDISPLAY_FONTORDER_L2R,
1841 		WSDISPLAY_FONTORDER_L2R);
1842 
1843 	if (wsfontcookie == -1)
1844 		return (EINVAL);
1845 
1846 	/* Suitable font found. Now lock it. */
1847 	if (wsfont_lock(wsfontcookie, &wsfont))
1848 		return (EINVAL);
1849 
1850 	KASSERT(wsfont);
1851 
1852 	if (scr->wsfont && scr->wsfontcookie != -1)
1853 		wsfont_unlock(scr->wsfontcookie);
1854 
1855 	scr->wsfont = wsfont;
1856 	scr->wsfontcookie = wsfontcookie;
1857 
1858 	return (0);
1859 }
1860 
1861 /*
1862  * Return a font that is guaranteed to exist.
1863  */
1864 static const struct wsdisplay_font *
1865 amidisplaycc_getbuiltinfont(void)
1866 {
1867 	static struct wsdisplay_font font;
1868 
1869 	extern unsigned char kernel_font_width_8x8;
1870 	extern unsigned char kernel_font_height_8x8;
1871 	extern unsigned char kernel_font_lo_8x8;
1872 	extern unsigned char kernel_font_hi_8x8;
1873 	extern unsigned char kernel_font_8x8[];
1874 
1875 	font.name = "kf8x8";
1876 	font.firstchar = kernel_font_lo_8x8;
1877 	font.numchars = kernel_font_hi_8x8 - kernel_font_lo_8x8 + 1;
1878 	font.fontwidth = kernel_font_width_8x8;
1879 	font.stride = 1;
1880 	font.fontheight = kernel_font_height_8x8;
1881 	font.data = kernel_font_8x8;
1882 
1883 	/* these values aren't really used for anything */
1884 	font.encoding = WSDISPLAY_FONTENC_ISO;
1885 	font.bitorder = WSDISPLAY_FONTORDER_KNOWN;
1886 	font.byteorder = WSDISPLAY_FONTORDER_KNOWN;
1887 
1888 	return &font;
1889 }
1890 
1891 /* ARGSUSED */
1892 void
1893 amidisplaycc_pollc(void *cookie, int on)
1894 {
1895 }
1896 
1897 /*
1898  * These dummy functions are here just so that we can compete of
1899  * the console at init.
1900  * If we win the console then the wscons system will provide the
1901  * real ones which in turn will call the apropriate wskbd device.
1902  * These should never be called.
1903  */
1904 
1905 /* ARGSUSED */
1906 void
1907 amidisplaycc_cnputc(dev_t cd, int ch)
1908 {
1909 }
1910 
1911 /* ARGSUSED */
1912 int
1913 amidisplaycc_cngetc(dev_t cd)
1914 {
1915 	return (0);
1916 }
1917 
1918 /* ARGSUSED */
1919 void
1920 amidisplaycc_cnpollc(dev_t cd, int on)
1921 {
1922 }
1923 
1924 
1925 /*
1926  * Prints stuff if DEBUG is turned on.
1927  */
1928 
1929 /* ARGSUSED */
1930 static void
1931 dprintf(const char *fmt, ...)
1932 {
1933 #ifdef DEBUG
1934 	va_list ap;
1935 
1936 	va_start(ap, fmt);
1937 	vprintf(fmt, ap);
1938 	va_end(ap);
1939 #endif
1940 }
1941 
1942 #endif /* AMIDISPLAYCC */
1943