xref: /freebsd/sys/dev/syscons/scvidctl.c (revision 56e53cb8ef000c3ef72337a4095987a932cdedef)
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 }
869