scvidctl.c revision 81039
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 * $FreeBSD: head/sys/dev/syscons/scvidctl.c 81039 2001-08-02 11:26:30Z yokota $
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    case FBIO_BLANK:
585	if (scp != scp->sc->cur_scp)
586	    return ENODEV;	/* XXX */
587	return fb_ioctl(adp, cmd, data);
588
589#ifndef SC_NO_MODE_CHANGE
590    /* generic text modes */
591    case SW_TEXT_80x25:	case SW_TEXT_80x30:
592    case SW_TEXT_80x43: case SW_TEXT_80x50:
593    case SW_TEXT_80x60:
594	/* FALL THROUGH */
595
596    /* VGA TEXT MODES */
597    case SW_VGA_C40x25:
598    case SW_VGA_C80x25: case SW_VGA_M80x25:
599    case SW_VGA_C80x30: case SW_VGA_M80x30:
600    case SW_VGA_C80x50: case SW_VGA_M80x50:
601    case SW_VGA_C80x60: case SW_VGA_M80x60:
602    case SW_VGA_C90x25: case SW_VGA_M90x25:
603    case SW_VGA_C90x30: case SW_VGA_M90x30:
604    case SW_VGA_C90x43: case SW_VGA_M90x43:
605    case SW_VGA_C90x50: case SW_VGA_M90x50:
606    case SW_VGA_C90x60: case SW_VGA_M90x60:
607    case SW_B40x25:     case SW_C40x25:
608    case SW_B80x25:     case SW_C80x25:
609    case SW_ENH_B40x25: case SW_ENH_C40x25:
610    case SW_ENH_B80x25: case SW_ENH_C80x25:
611    case SW_ENH_B80x43: case SW_ENH_C80x43:
612    case SW_EGAMONO80x25:
613
614#ifdef PC98
615    /* PC98 TEXT MODES */
616    case SW_PC98_80x25:
617    case SW_PC98_80x30:
618#endif
619	if (!(adp->va_flags & V_ADP_MODECHANGE))
620 	    return ENODEV;
621	return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0);
622
623    /* GRAPHICS MODES */
624    case SW_BG320:     case SW_BG640:
625    case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
626    case SW_CG640x350: case SW_ENH_CG640:
627    case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
628    case SW_VGA_MODEX:
629#ifdef PC98
630    /* PC98 GRAPHICS MODES */
631    case SW_PC98_EGC640x400:	case SW_PC98_PEGC640x400:
632    case SW_PC98_PEGC640x480:
633#endif
634	if (!(adp->va_flags & V_ADP_MODECHANGE))
635	    return ENODEV;
636	return sc_set_graphics_mode(scp, tp, cmd & 0xff);
637#endif /* SC_NO_MODE_CHANGE */
638
639    case KDSETMODE:     	/* set current mode of this (virtual) console */
640	switch (*(int *)data) {
641	case KD_TEXT:   	/* switch to TEXT (known) mode */
642	    /*
643	     * If scp->mode is of graphics modes, we don't know which
644	     * text mode to switch back to...
645	     */
646	    if (scp->status & GRAPHICS_MODE)
647		return EINVAL;
648	    /* restore fonts & palette ! */
649#if 0
650#ifndef SC_NO_FONT_LOADING
651	    if (ISFONTAVAIL(adp->va_flags)
652		&& !(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
653		/*
654		 * FONT KLUDGE
655		 * Don't load fonts for now... XXX
656		 */
657		if (scp->sc->fonts_loaded & FONT_8)
658		    sc_load_font(scp, 0, 8, scp->sc->font_8, 0, 256);
659		if (scp->sc->fonts_loaded & FONT_14)
660		    sc_load_font(scp, 0, 14, scp->sc->font_14, 0, 256);
661		if (scp->sc->fonts_loaded & FONT_16)
662		    sc_load_font(scp, 0, 16, scp->sc->font_16, 0, 256);
663	    }
664#endif /* SC_NO_FONT_LOADING */
665#endif
666
667#ifndef SC_NO_PALETTE_LOADING
668	    load_palette(adp, scp->sc->palette);
669#endif
670
671#ifndef PC98
672	    /* move hardware cursor out of the way */
673	    (*vidsw[adp->va_index]->set_hw_cursor)(adp, -1, -1);
674#endif
675
676	    /* FALL THROUGH */
677
678	case KD_TEXT1:  	/* switch to TEXT (known) mode */
679	    /*
680	     * If scp->mode is of graphics modes, we don't know which
681	     * text/pixel mode to switch back to...
682	     */
683	    if (scp->status & GRAPHICS_MODE)
684		return EINVAL;
685	    s = spltty();
686	    if ((error = sc_clean_up(scp))) {
687		splx(s);
688		return error;
689	    }
690#ifndef PC98
691	    scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
692	    splx(s);
693	    /* no restore fonts & palette */
694	    if (scp == scp->sc->cur_scp)
695		set_mode(scp);
696	    sc_clear_screen(scp);
697	    scp->status &= ~UNKNOWN_MODE;
698#else /* PC98 */
699	    scp->status &= ~UNKNOWN_MODE;
700	    /* no restore fonts & palette */
701	    if (scp == scp->sc->cur_scp)
702		set_mode(scp);
703	    sc_clear_screen(scp);
704	    splx(s);
705#endif /* PC98 */
706	    return 0;
707
708#ifdef SC_PIXEL_MODE
709	case KD_PIXEL:		/* pixel (raster) display */
710	    if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
711		return EINVAL;
712	    if (scp->status & GRAPHICS_MODE)
713		return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize,
714					 scp->font_size);
715	    s = spltty();
716	    if ((error = sc_clean_up(scp))) {
717		splx(s);
718		return error;
719	    }
720	    scp->status |= (UNKNOWN_MODE | PIXEL_MODE | MOUSE_HIDDEN);
721	    splx(s);
722	    if (scp == scp->sc->cur_scp) {
723		set_mode(scp);
724#ifndef SC_NO_PALETTE_LOADING
725		load_palette(adp, scp->sc->palette);
726#endif
727	    }
728	    sc_clear_screen(scp);
729	    scp->status &= ~UNKNOWN_MODE;
730	    return 0;
731#endif /* SC_PIXEL_MODE */
732
733	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
734	    s = spltty();
735	    if ((error = sc_clean_up(scp))) {
736		splx(s);
737		return error;
738	    }
739	    scp->status |= UNKNOWN_MODE | MOUSE_HIDDEN;
740	    splx(s);
741#ifdef PC98
742	    if (scp == scp->sc->cur_scp)
743		set_mode(scp);
744#endif
745	    return 0;
746
747	default:
748	    return EINVAL;
749	}
750	/* NOT REACHED */
751
752#ifdef SC_PIXEL_MODE
753    case KDRASTER:		/* set pixel (raster) display mode */
754	if (ISUNKNOWNSC(scp) || ISTEXTSC(scp))
755	    return ENODEV;
756	return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1],
757				 ((int *)data)[2]);
758#endif /* SC_PIXEL_MODE */
759
760    case KDGETMODE:     	/* get current mode of this (virtual) console */
761	/*
762	 * From the user program's point of view, KD_PIXEL is the same
763	 * as KD_TEXT...
764	 */
765	*data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT;
766	return 0;
767
768    case KDSBORDER:     	/* set border color of this (virtual) console */
769	scp->border = *data;
770	if (scp == scp->sc->cur_scp)
771	    sc_set_border(scp, scp->border);
772	return 0;
773    }
774
775    return ENOIOCTL;
776}
777
778static LIST_HEAD(, sc_renderer) sc_rndr_list =
779	LIST_HEAD_INITIALIZER(sc_rndr_list);
780
781int
782sc_render_add(sc_renderer_t *rndr)
783{
784	LIST_INSERT_HEAD(&sc_rndr_list, rndr, link);
785	return 0;
786}
787
788int
789sc_render_remove(sc_renderer_t *rndr)
790{
791	/*
792	LIST_REMOVE(rndr, link);
793	*/
794	return EBUSY;	/* XXX */
795}
796
797sc_rndr_sw_t
798*sc_render_match(scr_stat *scp, char *name, int mode)
799{
800	const sc_renderer_t **list;
801	const sc_renderer_t *p;
802
803	if (!LIST_EMPTY(&sc_rndr_list)) {
804		LIST_FOREACH(p, &sc_rndr_list, link) {
805			if ((strcmp(p->name, name) == 0)
806				&& (mode == p->mode)) {
807				scp->status &=
808				    ~(VR_CURSOR_ON | VR_CURSOR_BLINK);
809				return p->rndrsw;
810			}
811		}
812	} else {
813		SET_FOREACH(list, scrndr_set) {
814			p = *list;
815			if ((strcmp(p->name, name) == 0)
816				&& (mode == p->mode)) {
817				scp->status &=
818				    ~(VR_CURSOR_ON | VR_CURSOR_BLINK);
819				return p->rndrsw;
820			}
821		}
822	}
823
824	return NULL;
825}
826