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