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