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