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