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