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