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