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