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