xref: /dragonfly/sys/dev/misc/syscons/scvidctl.c (revision c9f721c2)
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 }
838