Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / dev / misc / syscons / scvidctl.c
1 /*-
2  * Copyright (c) 1998 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The DragonFly Project
6  * by Sascha Wildner <saw@online.de>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer as
13  *    the first lines of this file unmodified.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
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  * $FreeBSD: src/sys/dev/syscons/scvidctl.c,v 1.19.2.2 2000/05/05 09:16:08 nyan Exp $
30  * $DragonFly: src/sys/dev/misc/syscons/scvidctl.c,v 1.6 2004/09/04 06:15:08 dillon Exp $
31  */
32
33 #include "opt_syscons.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/signalvar.h>
39 #include <sys/tty.h>
40 #include <sys/kernel.h>
41
42 #include <machine/console.h>
43
44 #include <dev/video/fb/fbreg.h>
45 #include "syscons.h"
46
47 SET_DECLARE(scrndr_set, const sc_renderer_t);
48
49 /* for compatibility with previous versions */
50 /* 3.0-RELEASE used the following structure */
51 typedef struct old_video_adapter {
52     int                 va_index;
53     int                 va_type;
54     int                 va_flags;
55 /* flag bits are the same as the -CURRENT
56 #define V_ADP_COLOR     (1<<0)
57 #define V_ADP_MODECHANGE (1<<1)
58 #define V_ADP_STATESAVE (1<<2)
59 #define V_ADP_STATELOAD (1<<3)
60 #define V_ADP_FONT      (1<<4)
61 #define V_ADP_PALETTE   (1<<5)
62 #define V_ADP_BORDER    (1<<6)
63 #define V_ADP_VESA      (1<<7)
64 */
65     int                 va_crtc_addr;
66     u_int               va_window;      /* virtual address */
67     size_t              va_window_size;
68     size_t              va_window_gran;
69     u_int               va_buffer;      /* virtual address */
70     size_t              va_buffer_size;
71     int                 va_initial_mode;
72     int                 va_initial_bios_mode;
73     int                 va_mode;
74 } old_video_adapter_t;
75
76 #define OLD_CONS_ADPINFO _IOWR('c', 101, old_video_adapter_t)
77
78 /* 3.1-RELEASE used the following structure */
79 typedef struct old_video_adapter_info {
80     int                 va_index;
81     int                 va_type;
82     char                va_name[16];
83     int                 va_unit;
84     int                 va_flags;
85     int                 va_io_base;
86     int                 va_io_size;
87     int                 va_crtc_addr;
88     int                 va_mem_base;
89     int                 va_mem_size;
90     u_int               va_window;      /* virtual address */
91     size_t              va_window_size;
92     size_t              va_window_gran;
93     u_int               va_buffer;;
94     size_t              va_buffer_size;
95     int                 va_initial_mode;
96     int                 va_initial_bios_mode;
97     int                 va_mode;
98     int                 va_line_width;
99 } old_video_adapter_info_t;
100
101 #define OLD_CONS_ADPINFO2 _IOWR('c', 101, old_video_adapter_info_t)
102
103 /* 3.0-RELEASE and 3.1-RELEASE used the following structure */
104 typedef struct old_video_info {
105     int                 vi_mode;
106     int                 vi_flags;
107 /* flag bits are the same as the -CURRENT
108 #define V_INFO_COLOR    (1<<0)
109 #define V_INFO_GRAPHICS (1<<1)
110 #define V_INFO_LINEAR   (1<<2)
111 #define V_INFO_VESA     (1<<3)
112 */
113     int                 vi_width;
114     int                 vi_height;
115     int                 vi_cwidth;
116     int                 vi_cheight;
117     int                 vi_depth;
118     int                 vi_planes;
119     u_int               vi_window;      /* physical address */
120     size_t              vi_window_size;
121     size_t              vi_window_gran;
122     u_int               vi_buffer;      /* physical address */
123     size_t              vi_buffer_size;
124 } old_video_info_t;
125
126 #define OLD_CONS_MODEINFO _IOWR('c', 102, old_video_info_t)
127 #define OLD_CONS_FINDMODE _IOWR('c', 103, old_video_info_t)
128
129 int
130 sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize,
131                  int fontsize)
132 {
133     video_info_t info;
134     u_char *font;
135     int prev_ysize;
136     int error;
137     int s;
138
139     if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info))
140         return ENODEV;
141
142     /* adjust argument values */
143     if (fontsize <= 0)
144         fontsize = info.vi_cheight;
145     if (fontsize < 14) {
146         fontsize = 8;
147 #ifndef SC_NO_FONT_LOADING
148         if (!(scp->sc->fonts_loaded & FONT_8))
149             return EINVAL;
150         font = scp->sc->font_8;
151 #else
152         font = NULL;
153 #endif
154     } else if (fontsize >= 16) {
155         fontsize = 16;
156 #ifndef SC_NO_FONT_LOADING
157         if (!(scp->sc->fonts_loaded & FONT_16))
158             return EINVAL;
159         font = scp->sc->font_16;
160 #else
161         font = NULL;
162 #endif
163     } else {
164         fontsize = 14;
165 #ifndef SC_NO_FONT_LOADING
166         if (!(scp->sc->fonts_loaded & FONT_14))
167             return EINVAL;
168         font = scp->sc->font_14;
169 #else
170         font = NULL;
171 #endif
172     }
173     if ((xsize <= 0) || (xsize > info.vi_width))
174         xsize = info.vi_width;
175     if ((ysize <= 0) || (ysize > info.vi_height))
176         ysize = info.vi_height;
177
178     /* stop screen saver, etc */
179     s = spltty();
180     if ((error = sc_clean_up(scp))) {
181         splx(s);
182         return error;
183     }
184
185     if (sc_render_match(scp, scp->sc->adp->va_name, 0) == NULL) {
186         splx(s);
187         return ENODEV;
188     }
189
190     /* set up scp */
191 #ifndef SC_NO_HISTORY
192     if (scp->history != NULL)
193         sc_hist_save(scp);
194 #endif
195     prev_ysize = scp->ysize;
196     /*
197      * This is a kludge to fend off scrn_update() while we
198      * muck around with scp. XXX
199      */
200     scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
201     scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE | MOUSE_VISIBLE);
202     scp->mode = mode;
203     scp->xsize = xsize;
204     scp->ysize = ysize;
205     scp->xoff = 0;
206     scp->yoff = 0;
207     scp->xpixel = scp->xsize*8;
208     scp->ypixel = scp->ysize*fontsize;
209     scp->font = font;
210     scp->font_size = fontsize;
211
212     /* allocate buffers */
213     sc_alloc_scr_buffer(scp, TRUE, TRUE);
214     sc_init_emulator(scp, NULL);
215 #ifndef SC_NO_CUTPASTE
216     sc_alloc_cut_buffer(scp, FALSE);
217 #endif
218 #ifndef SC_NO_HISTORY
219     sc_alloc_history_buffer(scp, 0, prev_ysize, FALSE);
220 #endif
221     splx(s);
222
223     if (scp == scp->sc->cur_scp)
224         set_mode(scp);
225     scp->status &= ~UNKNOWN_MODE;
226
227     if (tp == NULL)
228         return 0;
229     DPRINTF(5, ("ws_*size (%d,%d), size (%d,%d)\n",
230         tp->t_winsize.ws_col, tp->t_winsize.ws_row, scp->xsize, scp->ysize));
231     if (tp->t_winsize.ws_col != scp->xsize
232         || tp->t_winsize.ws_row != scp->ysize) {
233         tp->t_winsize.ws_col = scp->xsize;
234         tp->t_winsize.ws_row = scp->ysize;
235         pgsignal(tp->t_pgrp, SIGWINCH, 1);
236     }
237
238     return 0;
239 }
240
241 int
242 sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode)
243 {
244 #ifdef SC_NO_MODE_CHANGE
245     return ENODEV;
246 #else
247     video_info_t info;
248     int error;
249     int s;
250
251     if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, mode, &info))
252         return ENODEV;
253
254     /* stop screen saver, etc */
255     s = spltty();
256     if ((error = sc_clean_up(scp))) {
257         splx(s);
258         return error;
259     }
260
261     if (sc_render_match(scp, scp->sc->adp->va_name, GRAPHICS_MODE) == NULL) {
262         splx(s);
263         return ENODEV;
264     }
265
266     /* set up scp */
267     scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE | MOUSE_HIDDEN);
268     scp->status &= ~(PIXEL_MODE | MOUSE_VISIBLE);
269     scp->mode = mode;
270     /*
271      * Don't change xsize and ysize; preserve the previous vty
272      * and history buffers.
273      */
274     scp->xoff = 0;
275     scp->yoff = 0;
276     scp->xpixel = info.vi_width;
277     scp->ypixel = info.vi_height;
278     scp->font = NULL;
279     scp->font_size = 0;
280 #ifndef SC_NO_SYSMOUSE
281     /* move the mouse cursor at the center of the screen */
282     sc_mouse_move(scp, scp->xpixel / 2, scp->ypixel / 2);
283 #endif
284     sc_init_emulator(scp, NULL);
285     splx(s);
286
287     if (scp == scp->sc->cur_scp)
288         set_mode(scp);
289     /* clear_graphics();*/
290     scp->status &= ~UNKNOWN_MODE;
291
292     if (tp == NULL)
293         return 0;
294     if (tp->t_winsize.ws_xpixel != scp->xpixel
295         || tp->t_winsize.ws_ypixel != scp->ypixel) {
296         tp->t_winsize.ws_xpixel = scp->xpixel;
297         tp->t_winsize.ws_ypixel = scp->ypixel;
298         pgsignal(tp->t_pgrp, SIGWINCH, 1);
299     }
300
301     return 0;
302 #endif /* SC_NO_MODE_CHANGE */
303 }
304
305 int
306 sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, 
307                   int fontsize)
308 {
309 #ifndef SC_PIXEL_MODE
310     return ENODEV;
311 #else
312     video_info_t info;
313     u_char *font;
314     int prev_ysize;
315     int error;
316     int s;
317
318     if ((*vidsw[scp->sc->adapter]->get_info)(scp->sc->adp, scp->mode, &info))
319         return ENODEV;          /* this shouldn't happen */
320
321     /* adjust argument values */
322     if (fontsize <= 0)
323         fontsize = info.vi_cheight;
324     if (fontsize < 14) {
325         fontsize = 8;
326 #ifndef SC_NO_FONT_LOADING
327         if (!(scp->sc->fonts_loaded & FONT_8))
328             return EINVAL;
329         font = scp->sc->font_8;
330 #else
331         font = NULL;
332 #endif
333     } else if (fontsize >= 16) {
334         fontsize = 16;
335 #ifndef SC_NO_FONT_LOADING
336         if (!(scp->sc->fonts_loaded & FONT_16))
337             return EINVAL;
338         font = scp->sc->font_16;
339 #else
340         font = NULL;
341 #endif
342     } else {
343         fontsize = 14;
344 #ifndef SC_NO_FONT_LOADING
345         if (!(scp->sc->fonts_loaded & FONT_14))
346             return EINVAL;
347         font = scp->sc->font_14;
348 #else
349         font = NULL;
350 #endif
351     }
352     if (xsize <= 0)
353         xsize = info.vi_width/8;
354     if (ysize <= 0)
355         ysize = info.vi_height/fontsize;
356
357     if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize))
358         return EINVAL;
359
360     /*
361      * We currently support the following graphic modes:
362      *
363      * - 4 bpp planar modes whose memory size does not exceed 64K
364      * - 15, 16, 24 and 32 bpp linear modes
365      */
366
367     if (info.vi_mem_model == V_INFO_MM_PLANAR) {
368         if (info.vi_planes != 4)
369             return ENODEV;
370
371         /*
372          * A memory size >64K requires bank switching to access the entire
373          * screen. XXX
374          */
375
376         if (info.vi_width * info.vi_height / 8 > info.vi_window_size)
377             return ENODEV;
378     } else if (info.vi_mem_model == V_INFO_MM_DIRECT) {
379         if ((info.vi_depth != 15) && (info.vi_depth != 16) &&
380             (info.vi_depth != 24) && (info.vi_depth != 32))
381             return ENODEV;
382     } else
383         return ENODEV;
384
385     /* stop screen saver, etc */
386     s = spltty();
387     if ((error = sc_clean_up(scp))) {
388         splx(s);
389         return error;
390     }
391
392     if (sc_render_match(scp, scp->sc->adp->va_name, PIXEL_MODE) == NULL) {
393         splx(s);
394         return ENODEV;
395     }
396
397 #if 0
398     if (scp->tsw)
399         (*scp->tsw->te_term)(scp, scp->ts);
400     scp->tsw = NULL;
401     scp->ts = NULL;
402 #endif
403
404     /* set up scp */
405 #ifndef SC_NO_HISTORY
406     if (scp->history != NULL)
407         sc_hist_save(scp);
408 #endif
409     prev_ysize = scp->ysize;
410     scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN);
411     scp->status &= ~(GRAPHICS_MODE | MOUSE_VISIBLE);
412     scp->xsize = xsize;
413     scp->ysize = ysize;
414     scp->xoff = (scp->xpixel/8 - xsize)/2;
415     scp->yoff = (scp->ypixel/fontsize - ysize)/2;
416     scp->font = font;
417     scp->font_size = fontsize;
418
419     /* allocate buffers */
420     sc_alloc_scr_buffer(scp, TRUE, TRUE);
421     sc_init_emulator(scp, NULL);
422 #ifndef SC_NO_CUTPASTE
423     sc_alloc_cut_buffer(scp, FALSE);
424 #endif
425 #ifndef SC_NO_HISTORY
426     sc_alloc_history_buffer(scp, 0, prev_ysize, FALSE);
427 #endif
428     splx(s);
429
430     if (scp == scp->sc->cur_scp) {
431         sc_set_border(scp, scp->border);
432         sc_set_cursor_image(scp);
433     }
434
435     scp->status &= ~UNKNOWN_MODE;
436
437     if (tp == NULL)
438         return 0;
439     if (tp->t_winsize.ws_col != scp->xsize
440         || tp->t_winsize.ws_row != scp->ysize) {
441         tp->t_winsize.ws_col = scp->xsize;
442         tp->t_winsize.ws_row = scp->ysize;
443         pgsignal(tp->t_pgrp, SIGWINCH, 1);
444     }
445
446     return 0;
447 #endif /* SC_PIXEL_MODE */
448 }
449
450 #define fb_ioctl(a, c, d)               \
451         (((a) == NULL) ? ENODEV :       \
452                          (*vidsw[(a)->va_index]->ioctl)((a), (c), (caddr_t)(d)))
453
454 int
455 sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct thread *td)
456 {
457     scr_stat *scp;
458     video_adapter_t *adp;
459     video_info_t info;
460     video_adapter_info_t adp_info;
461     int error;
462     int s;
463
464     scp = SC_STAT(tp->t_dev);
465     if (scp == NULL)            /* tp == SC_MOUSE */
466         return ENOIOCTL;
467     adp = scp->sc->adp;
468     if (adp == NULL)            /* shouldn't happen??? */
469         return ENODEV;
470
471     switch (cmd) {
472
473     case CONS_CURRENTADP:       /* get current adapter index */
474     case FBIO_ADAPTER:
475         return fb_ioctl(adp, FBIO_ADAPTER, data);
476
477     case CONS_CURRENT:          /* get current adapter type */
478     case FBIO_ADPTYPE:
479         return fb_ioctl(adp, FBIO_ADPTYPE, data);
480
481     case OLD_CONS_ADPINFO:      /* adapter information (old interface) */
482         if (((old_video_adapter_t *)data)->va_index >= 0) {
483             adp = vid_get_adapter(((old_video_adapter_t *)data)->va_index);
484             if (adp == NULL)
485                 return ENODEV;
486         }
487         ((old_video_adapter_t *)data)->va_index = adp->va_index;
488         ((old_video_adapter_t *)data)->va_type = adp->va_type;
489         ((old_video_adapter_t *)data)->va_flags = adp->va_flags;
490         ((old_video_adapter_t *)data)->va_crtc_addr = adp->va_crtc_addr;
491         ((old_video_adapter_t *)data)->va_window = adp->va_window;
492         ((old_video_adapter_t *)data)->va_window_size = adp->va_window_size;
493         ((old_video_adapter_t *)data)->va_window_gran = adp->va_window_gran;
494         ((old_video_adapter_t *)data)->va_buffer = adp->va_buffer;
495         ((old_video_adapter_t *)data)->va_buffer_size = adp->va_buffer_size;
496         ((old_video_adapter_t *)data)->va_mode = adp->va_mode;
497         ((old_video_adapter_t *)data)->va_initial_mode = adp->va_initial_mode;
498         ((old_video_adapter_t *)data)->va_initial_bios_mode
499             = adp->va_initial_bios_mode;
500         return 0;
501
502     case OLD_CONS_ADPINFO2:     /* adapter information (yet another old I/F) */
503         adp_info.va_index = ((old_video_adapter_info_t *)data)->va_index;
504         if (adp_info.va_index >= 0) {
505             adp = vid_get_adapter(adp_info.va_index);
506             if (adp == NULL)
507                 return ENODEV;
508         }
509         error = fb_ioctl(adp, FBIO_ADPINFO, &adp_info);
510         if (error == 0)
511             bcopy(&adp_info, data, sizeof(old_video_adapter_info_t));
512         return error;
513
514     case CONS_ADPINFO:          /* adapter information */
515     case FBIO_ADPINFO:
516         if (((video_adapter_info_t *)data)->va_index >= 0) {
517             adp = vid_get_adapter(((video_adapter_info_t *)data)->va_index);
518             if (adp == NULL)
519                 return ENODEV;
520         }
521         return fb_ioctl(adp, FBIO_ADPINFO, data);
522
523     case CONS_GET:              /* get current video mode */
524     case FBIO_GETMODE:
525         *(int *)data = scp->mode;
526         return 0;
527
528 #ifndef SC_NO_MODE_CHANGE
529     case FBIO_SETMODE:          /* set video mode */
530         if (!(adp->va_flags & V_ADP_MODECHANGE))
531             return ENODEV;
532         info.vi_mode = *(int *)data;
533         error = fb_ioctl(adp, FBIO_MODEINFO, &info);
534         if (error)
535             return error;
536         if (info.vi_flags & V_INFO_GRAPHICS)
537             return sc_set_graphics_mode(scp, tp, *(int *)data);
538         else
539             return sc_set_text_mode(scp, tp, *(int *)data, 0, 0, 0);
540 #endif /* SC_NO_MODE_CHANGE */
541
542     case OLD_CONS_MODEINFO:     /* get mode information (old infterface) */
543         info.vi_mode = ((old_video_info_t *)data)->vi_mode;
544         error = fb_ioctl(adp, FBIO_MODEINFO, &info);
545         if (error == 0)
546             bcopy(&info, (old_video_info_t *)data, sizeof(old_video_info_t));
547         return error;
548
549     case CONS_MODEINFO:         /* get mode information */
550     case FBIO_MODEINFO:
551         return fb_ioctl(adp, FBIO_MODEINFO, data);
552
553     case OLD_CONS_FINDMODE:     /* find a matching video mode (old interface) */
554         bzero(&info, sizeof(info));
555         bcopy((old_video_info_t *)data, &info, sizeof(old_video_info_t));
556         error = fb_ioctl(adp, FBIO_FINDMODE, &info);
557         if (error == 0)
558             bcopy(&info, (old_video_info_t *)data, sizeof(old_video_info_t));
559         return error;
560
561     case CONS_FINDMODE:         /* find a matching video mode */
562     case FBIO_FINDMODE:
563         return fb_ioctl(adp, FBIO_FINDMODE, data);
564
565     case CONS_SETWINORG:        /* set frame buffer window origin */
566     case FBIO_SETWINORG:
567         if (scp != scp->sc->cur_scp)
568             return ENODEV;      /* XXX */
569         return fb_ioctl(adp, FBIO_SETWINORG, data);
570
571     case FBIO_GETWINORG:        /* get frame buffer window origin */
572         if (scp != scp->sc->cur_scp)
573             return ENODEV;      /* XXX */
574         return fb_ioctl(adp, FBIO_GETWINORG, data);
575
576     case FBIO_GETDISPSTART:
577     case FBIO_SETDISPSTART:
578     case FBIO_GETLINEWIDTH:
579     case FBIO_SETLINEWIDTH:
580         if (scp != scp->sc->cur_scp)
581             return ENODEV;      /* XXX */
582         return fb_ioctl(adp, cmd, data);
583
584     case FBIO_GETPALETTE:
585     case FBIO_SETPALETTE:
586     case FBIOPUTCMAP:
587     case FBIOGETCMAP:
588     case FBIOGTYPE:
589     case FBIOGATTR:
590     case FBIOSVIDEO:
591     case FBIOGVIDEO:
592     case FBIOSCURSOR:
593     case FBIOGCURSOR:
594     case FBIOSCURPOS:
595     case FBIOGCURPOS:
596     case FBIOGCURMAX:
597         if (scp != scp->sc->cur_scp)
598             return ENODEV;      /* XXX */
599         return fb_ioctl(adp, cmd, data);
600
601 #ifndef SC_NO_MODE_CHANGE
602     /* generic text modes */
603     case SW_TEXT_80x25: case SW_TEXT_80x30:
604     case SW_TEXT_80x43: case SW_TEXT_80x50:
605     case SW_TEXT_80x60:
606         /* FALL THROUGH */
607
608     /* VGA TEXT MODES */
609     case SW_VGA_C40x25:
610     case SW_VGA_C80x25: case SW_VGA_M80x25:
611     case SW_VGA_C80x30: case SW_VGA_M80x30:
612     case SW_VGA_C80x50: case SW_VGA_M80x50:
613     case SW_VGA_C80x60: case SW_VGA_M80x60:
614     case SW_VGA_C90x25: case SW_VGA_M90x25:
615     case SW_VGA_C90x30: case SW_VGA_M90x30:
616     case SW_VGA_C90x43: case SW_VGA_M90x43:
617     case SW_VGA_C90x50: case SW_VGA_M90x50:
618     case SW_VGA_C90x60: case SW_VGA_M90x60:
619     case SW_B40x25:     case SW_C40x25:
620     case SW_B80x25:     case SW_C80x25:
621     case SW_ENH_B40x25: case SW_ENH_C40x25:
622     case SW_ENH_B80x25: case SW_ENH_C80x25:
623     case SW_ENH_B80x43: case SW_ENH_C80x43:
624     case SW_EGAMONO80x25:
625
626 #ifdef PC98
627     /* PC98 TEXT MODES */
628     case SW_PC98_80x25:
629     case SW_PC98_80x30:
630 #endif
631         if (!(adp->va_flags & V_ADP_MODECHANGE))
632             return ENODEV;
633         return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0);
634
635     /* GRAPHICS MODES */
636     case SW_BG320:     case SW_BG640:
637     case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
638     case SW_CG640x350: case SW_ENH_CG640:
639     case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
640     case SW_VGA_MODEX:
641 #ifdef PC98
642     /* PC98 GRAPHICS MODES */
643     case SW_PC98_EGC640x400:    case SW_PC98_PEGC640x400:
644     case SW_PC98_PEGC640x480:
645 #endif
646         if (!(adp->va_flags & V_ADP_MODECHANGE))
647             return ENODEV;
648         return sc_set_graphics_mode(scp, tp, cmd & 0xff);
649 #endif /* SC_NO_MODE_CHANGE */
650
651     case KDSETMODE:             /* set current mode of this (virtual) console */
652         switch (*(int *)data) {
653         case KD_TEXT:           /* switch to TEXT (known) mode */
654             /*
655              * If scp->mode is of graphics modes, we don't know which
656              * text mode to switch back to...
657              */
658             if (scp->status & GRAPHICS_MODE)
659                 return EINVAL;
660             /* restore fonts & palette ! */
661 #if 0
662 #ifndef SC_NO_FONT_LOADING
663             if (ISFONTAVAIL(adp->va_flags) 
664                 && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
665                 /*
666                  * FONT KLUDGE
667                  * Don't load fonts for now... XXX
668                  */
669                 if (scp->sc->fonts_loaded & FONT_8)
670                     sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256);
671                 if (scp->sc->fonts_loaded & FONT_14)
672                     sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256);
673                 if (scp->sc->fonts_loaded & FONT_16)
674                     sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256);
675             }
676 #endif /* SC_NO_FONT_LOADING */
677 #endif
678
679 #ifndef SC_NO_PALETTE_LOADING
680             load_palette(adp, scp->sc->palette);
681 #endif
682
683 #ifndef PC98
684             /* move hardware cursor out of the way */
685             (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
686 #endif
687
688             /* FALL THROUGH */
689
690         case KD_TEXT1:          /* switch to TEXT (known) mode */
691             /*
692              * If scp->mode is of graphics modes, we don't know which
693              * text/pixel mode to switch back to...
694              */
695             if (scp->status & GRAPHICS_MODE)
696                 return EINVAL;
697             s = spltty();
698             if ((error = sc_clean_up(scp))) {
699                 splx(s);
700                 return error;
701             }
702 #ifndef PC98
703             scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
704             splx(s);
705             /* no restore fonts & palette */
706             if (scp == scp->sc->cur_scp)
707                 set_mode(scp);
708             sc_clear_screen(scp);
709             scp->status &= ~UNKNOWN_MODE;
710 #else /* PC98 */
711             scp->status &= ~UNKNOWN_MODE;
712             /* no restore fonts & palette */
713             if (scp == scp->sc->cur_scp)
714                 set_mode(scp);
715             sc_clear_screen(scp);
716             splx(s);
717 #endif /* PC98 */
718             return 0;
719
720 #ifdef SC_PIXEL_MODE
721         case KD_PIXEL:          /* pixel (raster) display */
722             if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
723                 return EINVAL;
724             if (scp->status & GRAPHICS_MODE)
725                 return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, 
726                                          scp->font_size);
727             s = spltty();
728             if ((error = sc_clean_up(scp))) {
729                 splx(s);
730                 return error;
731             }
732             scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN);
733             splx(s);
734             if (scp == scp->sc->cur_scp) {
735                 set_mode(scp);
736 #ifndef SC_NO_PALETTE_LOADING
737                 load_palette(adp, scp->sc->palette);
738 #endif
739             }
740             sc_clear_screen(scp);
741             scp->status &= ~UNKNOWN_MODE;
742             return 0;
743 #endif /* SC_PIXEL_MODE */
744
745         case KD_GRAPHICS:       /* switch to GRAPHICS (unknown) mode */
746             s = spltty();
747             if ((error = sc_clean_up(scp))) {
748                 splx(s);
749                 return error;
750             }
751             scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
752             splx(s);
753 #ifdef PC98
754             if (scp == scp->sc->cur_scp)
755                 set_mode(scp);
756 #endif
757             return 0;
758
759         default:
760             return EINVAL;
761         }
762         /* NOT REACHED */
763
764 #ifdef SC_PIXEL_MODE
765     case KDRASTER:              /* set pixel (raster) display mode */
766         if (ISUNKNOWNSC(scp) || ISTEXTSC(scp))
767             return ENODEV;
768         return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], 
769                                  ((int *)data)[2]);
770 #endif /* SC_PIXEL_MODE */
771
772     case KDGETMODE:             /* get current mode of this (virtual) console */
773         /* 
774          * From the user program's point of view, KD_PIXEL is the same 
775          * as KD_TEXT... 
776          */
777         *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT;
778         return 0;
779
780     case KDSBORDER:             /* set border color of this (virtual) console */
781         scp->border = *data;
782         if (scp == scp->sc->cur_scp)
783             sc_set_border(scp, scp->border);
784         return 0;
785     }
786
787     return ENOIOCTL;
788 }
789
790 static LIST_HEAD(, sc_renderer) sc_rndr_list = 
791         LIST_HEAD_INITIALIZER(sc_rndr_list);
792
793 int
794 sc_render_add(sc_renderer_t *rndr)
795 {
796         LIST_INSERT_HEAD(&sc_rndr_list, rndr, link);
797         return 0;
798 }
799
800 int
801 sc_render_remove(sc_renderer_t *rndr)
802 {
803         /*
804         LIST_REMOVE(rndr, link);
805         */
806         return EBUSY;   /* XXX */
807 }
808
809 sc_rndr_sw_t
810 *sc_render_match(scr_stat *scp, char *name, int mode)
811 {
812         const sc_renderer_t **list;
813         const sc_renderer_t *p;
814
815         if (!LIST_EMPTY(&sc_rndr_list)) {
816                 LIST_FOREACH(p, &sc_rndr_list, link) {
817                         if ((strcmp(p->name, name) == 0)
818                                 && (mode == p->mode)) {
819                                 scp->status &=
820                                     ~(VR_CURSOR_ON | VR_CURSOR_BLINK);
821                                 return p->rndrsw;
822                         }
823                 }
824         } else {
825                 SET_FOREACH(list, scrndr_set) {
826                         p = *list;
827                         if ((strcmp(p->name, name) == 0)
828                                 && (mode == p->mode)) {
829                                 scp->status &=
830                                     ~(VR_CURSOR_ON | VR_CURSOR_BLINK);
831                                 return p->rndrsw;
832                         }
833                 }
834         }
835
836         return NULL;
837 }