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