scvidctl.c revision 39858
1/*-
2 * Copyright (c) 1998 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer as
10 *    the first lines of this file unmodified.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $Id: scvidctl.c,v 1.4 1998/09/29 02:00:56 ache Exp $
27 */
28
29#include "sc.h"
30#include "opt_syscons.h"
31
32#if NSC > 0
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/signalvar.h>
37#include <sys/tty.h>
38#include <sys/kernel.h>
39
40#include <machine/apm_bios.h>
41#include <machine/console.h>
42
43#include <i386/isa/videoio.h>
44#include <i386/isa/syscons.h>
45
46/* video ioctl */
47
48extern scr_stat *cur_console;
49extern int fonts_loaded;
50extern int sc_history_size;
51extern u_char palette[];
52
53int
54sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize,
55		 int fontsize)
56{
57    video_adapter_t *adp;
58    video_info_t info;
59    int error;
60    int s;
61    int i;
62
63    if ((*biosvidsw.get_info)(scp->adp, mode, &info))
64	return ENODEV;
65    adp = get_adapter(scp);
66
67    /* adjust argument values */
68    if (fontsize <= 0)
69	fontsize = info.vi_cheight;
70    if (fontsize < 14) {
71	fontsize = 8;
72	if (!(fonts_loaded & FONT_8))
73	    return EINVAL;
74    } else if (fontsize >= 16) {
75	fontsize = 16;
76	if (!(fonts_loaded & FONT_16))
77	    return EINVAL;
78    } else {
79	fontsize = 14;
80	if (!(fonts_loaded & FONT_14))
81	    return EINVAL;
82    }
83    if ((xsize <= 0) || (xsize > info.vi_width))
84	xsize = info.vi_width;
85    if ((ysize <= 0) || (ysize > info.vi_height))
86	ysize = info.vi_height;
87
88    /* stop screen saver, etc */
89    s = spltty();
90    if ((error = sc_clean_up(scp))) {
91	splx(s);
92	return error;
93    }
94
95    /* set up scp */
96    if (scp->history != NULL)
97	i = imax(scp->history_size / scp->xsize
98		 - imax(sc_history_size, scp->ysize), 0);
99    else
100	i = 0;
101    /*
102     * This is a kludge to fend off scrn_update() while we
103     * muck around with scp. XXX
104     */
105    scp->status |= UNKNOWN_MODE;
106    scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
107    scp->mode = mode;
108    scp->font_size = fontsize;
109    scp->xsize = xsize;
110    scp->ysize = ysize;
111    scp->xpixel = scp->xsize*8;
112    scp->ypixel = scp->ysize*fontsize;
113
114    /* allocate buffers */
115    sc_alloc_scr_buffer(scp, TRUE, TRUE);
116    if (ISMOUSEAVAIL(adp->va_flags))
117	sc_alloc_cut_buffer(scp, FALSE);
118    sc_alloc_history_buffer(scp, sc_history_size, i, FALSE);
119    splx(s);
120
121    if (scp == cur_console)
122	set_mode(scp);
123    scp->status &= ~UNKNOWN_MODE;
124
125    if (tp == NULL)
126	return 0;
127    if (tp->t_winsize.ws_col != scp->xsize
128	|| tp->t_winsize.ws_row != scp->ysize) {
129	tp->t_winsize.ws_col = scp->xsize;
130	tp->t_winsize.ws_row = scp->ysize;
131	pgsignal(tp->t_pgrp, SIGWINCH, 1);
132    }
133
134    return 0;
135}
136
137int
138sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode)
139{
140    video_adapter_t *adp;
141    video_info_t info;
142    int error;
143    int s;
144
145    if ((*biosvidsw.get_info)(scp->adp, mode, &info))
146	return ENODEV;
147    adp = get_adapter(scp);
148
149    /* stop screen saver, etc */
150    s = spltty();
151    if ((error = sc_clean_up(scp))) {
152	splx(s);
153	return error;
154    }
155
156    /* set up scp */
157    scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE);
158    scp->status &= ~PIXEL_MODE;
159    scp->mode = mode;
160    scp->xpixel = info.vi_width;
161    scp->ypixel = info.vi_height;
162    scp->xsize = info.vi_width/8;
163    scp->ysize = info.vi_height/info.vi_cheight;
164    scp->font_size = FONT_NONE;
165    /* move the mouse cursor at the center of the screen */
166    sc_move_mouse(scp, scp->xpixel / 2, scp->ypixel / 2);
167    splx(s);
168
169    if (scp == cur_console)
170	set_mode(scp);
171    /* clear_graphics();*/
172    scp->status &= ~UNKNOWN_MODE;
173
174    if (tp == NULL)
175	return 0;
176    if (tp->t_winsize.ws_xpixel != scp->xpixel
177	|| tp->t_winsize.ws_ypixel != scp->ypixel) {
178	tp->t_winsize.ws_xpixel = scp->xpixel;
179	tp->t_winsize.ws_ypixel = scp->ypixel;
180	pgsignal(tp->t_pgrp, SIGWINCH, 1);
181    }
182
183    return 0;
184}
185
186int
187sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize,
188		  int fontsize)
189{
190    video_adapter_t *adp;
191    video_info_t info;
192    int error;
193    int s;
194    int i;
195
196    if ((*biosvidsw.get_info)(scp->adp, scp->mode, &info))
197	return ENODEV;		/* this shouldn't happen */
198    adp = get_adapter(scp);
199
200#ifdef SC_VIDEO_DEBUG
201    if (scp->scr_buf != NULL) {
202	printf("set_pixel_mode(): mode:%x, col:%d, row:%d, font:%d\n",
203	       scp->mode, xsize, ysize, fontsize);
204    }
205#endif
206
207    /* adjust argument values */
208    if ((fontsize <= 0) || (fontsize == FONT_NONE))
209	fontsize = info.vi_cheight;
210    if (fontsize < 14) {
211	fontsize = 8;
212	if (!(fonts_loaded & FONT_8))
213	    return EINVAL;
214    } else if (fontsize >= 16) {
215	fontsize = 16;
216	if (!(fonts_loaded & FONT_16))
217	    return EINVAL;
218    } else {
219	fontsize = 14;
220	if (!(fonts_loaded & FONT_14))
221	    return EINVAL;
222    }
223    if (xsize <= 0)
224	xsize = info.vi_width/8;
225    if (ysize <= 0)
226	ysize = info.vi_height/fontsize;
227
228#ifdef SC_VIDEO_DEBUG
229    if (scp->scr_buf != NULL) {
230	printf("set_pixel_mode(): mode:%x, col:%d, row:%d, font:%d\n",
231	       scp->mode, xsize, ysize, fontsize);
232	printf("set_pixel_mode(): window:%x, %dx%d, xoff:%d, yoff:%d\n",
233	       adp->va_window, info.vi_width, info.vi_height,
234	       (info.vi_width/8 - xsize)/2,
235	       (info.vi_height/fontsize - ysize)/2);
236    }
237#endif
238
239    if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize))
240	return EINVAL;
241
242    /* only 16 color, 4 plane modes are supported XXX */
243    if ((info.vi_depth != 4) || (info.vi_planes != 4))
244	return ENODEV;
245
246    /*
247     * set_pixel_mode() currently does not support video modes whose
248     * memory size is larger than 64K. Because such modes require
249     * bank switching to access the entire screen. XXX
250     */
251    if (info.vi_width*info.vi_height/8 > info.vi_window_size)
252	return ENODEV;
253
254    /* stop screen saver, etc */
255    s = spltty();
256    if ((error = sc_clean_up(scp))) {
257	splx(s);
258	return error;
259    }
260
261    /* set up scp */
262    if (scp->history != NULL)
263	i = imax(scp->history_size / scp->xsize
264		 - imax(sc_history_size, scp->ysize), 0);
265    else
266	i = 0;
267    scp->status |= (UNKNOWN_MODE | PIXEL_MODE);
268    scp->status &= ~(GRAPHICS_MODE | MOUSE_ENABLED);
269    scp->xsize = xsize;
270    scp->ysize = ysize;
271    scp->font_size = fontsize;
272    scp->xoff = (scp->xpixel/8 - xsize)/2;
273    scp->yoff = (scp->ypixel/fontsize - ysize)/2;
274
275    /* allocate buffers */
276    sc_alloc_scr_buffer(scp, TRUE, TRUE);
277    if (ISMOUSEAVAIL(adp->va_flags))
278	sc_alloc_cut_buffer(scp, FALSE);
279    sc_alloc_history_buffer(scp, sc_history_size, i, FALSE);
280    splx(s);
281
282    if (scp == cur_console)
283	set_border(scp, scp->border);
284
285    scp->status &= ~UNKNOWN_MODE;
286
287#ifdef SC_VIDEO_DEBUG
288    printf("set_pixel_mode(): status:%x\n", scp->status);
289#endif
290
291    if (tp == NULL)
292	return 0;
293    if (tp->t_winsize.ws_col != scp->xsize
294	|| tp->t_winsize.ws_row != scp->ysize) {
295	tp->t_winsize.ws_col = scp->xsize;
296	tp->t_winsize.ws_row = scp->ysize;
297	pgsignal(tp->t_pgrp, SIGWINCH, 1);
298    }
299
300    return 0;
301}
302
303int
304sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
305{
306    scr_stat *scp;
307    video_adapter_t *adp;
308    int error;
309    int s;
310
311    scp = sc_get_scr_stat(tp->t_dev);
312
313    switch (cmd) {
314
315    case CONS_CURRENT:  	/* get current adapter type */
316	adp = get_adapter(scp);
317	*(int *)data = adp->va_type;
318	return 0;
319
320    case CONS_CURRENTADP:	/* get current adapter index */
321	*(int *)data = scp->adp;
322	return 0;
323
324    case CONS_ADPINFO:		/* adapter information */
325	adp = (*biosvidsw.adapter)(((video_adapter_t *)data)->va_index);
326	if (adp == NULL)
327	    return ENODEV;
328	bcopy(adp, data, sizeof(*adp));
329	return 0;
330
331    case CONS_GET:      	/* get current video mode */
332	*(int *)data = scp->mode;
333	return 0;
334
335    case CONS_MODEINFO:		/* get mode information */
336	return ((*biosvidsw.get_info)(scp->adp,
337		    ((video_info_t *)data)->vi_mode, (video_info_t *)data)
338		? ENODEV : 0);
339
340    case CONS_FINDMODE:		/* find a matching video mode */
341	return ((*biosvidsw.query_mode)(scp->adp, (video_info_t *)data)
342		? ENODEV : 0);
343
344    case CONS_SETWINORG:
345	return ((*biosvidsw.set_win_org)(scp->adp, *(u_int *)data)
346		   ? ENODEV : 0);
347
348    /* generic text modes */
349    case SW_TEXT_80x25:	case SW_TEXT_80x30:
350    case SW_TEXT_80x43: case SW_TEXT_80x50:
351    case SW_TEXT_80x60:
352	/* FALL THROUGH */
353
354    /* VGA TEXT MODES */
355    case SW_VGA_C40x25:
356    case SW_VGA_C80x25: case SW_VGA_M80x25:
357    case SW_VGA_C80x30: case SW_VGA_M80x30:
358    case SW_VGA_C80x50: case SW_VGA_M80x50:
359    case SW_VGA_C80x60: case SW_VGA_M80x60:
360    case SW_B40x25:     case SW_C40x25:
361    case SW_B80x25:     case SW_C80x25:
362    case SW_ENH_B40x25: case SW_ENH_C40x25:
363    case SW_ENH_B80x25: case SW_ENH_C80x25:
364    case SW_ENH_B80x43: case SW_ENH_C80x43:
365    case SW_EGAMONO80x25:
366	adp = get_adapter(scp);
367	if (!(adp->va_flags & V_ADP_MODECHANGE))
368 	    return ENODEV;
369	return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0);
370
371    /* GRAPHICS MODES */
372    case SW_BG320:     case SW_BG640:
373    case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
374    case SW_CG640x350: case SW_ENH_CG640:
375    case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
376    case SW_VGA_MODEX:
377	adp = get_adapter(scp);
378	if (!(adp->va_flags & V_ADP_MODECHANGE))
379	    return ENODEV;
380	return sc_set_graphics_mode(scp, tp, cmd & 0xff);
381
382    case KDSETMODE:     	/* set current mode of this (virtual) console */
383	switch (*(int *)data) {
384	case KD_TEXT:   	/* switch to TEXT (known) mode */
385	    /*
386	     * If scp->mode is of graphics modes, we don't know which
387	     * text mode to switch back to...
388	     */
389	    if (scp->status & GRAPHICS_MODE)
390		return EINVAL;
391	    /* restore fonts & palette ! */
392#if 0
393	    adp = get_adapter(scp);
394	    if (ISFONTAVAIL(adp->va_flags)
395		&& !(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
396		/*
397		 * FONT KLUDGE
398		 * Don't load fonts for now... XXX
399		 */
400		if (fonts_loaded & FONT_8)
401		    copy_font(scp, LOAD, 8, font_8);
402		if (fonts_loaded & FONT_14)
403		    copy_font(scp, LOAD, 14, font_14);
404		if (fonts_loaded & FONT_16)
405		    copy_font(scp, LOAD, 16, font_16);
406	    }
407#endif
408	    load_palette(scp, palette);
409
410	    /* move hardware cursor out of the way */
411	    (*biosvidsw.set_hw_cursor)(scp->adp, -1, -1);
412
413	    /* FALL THROUGH */
414
415	case KD_TEXT1:  	/* switch to TEXT (known) mode */
416	    /*
417	     * If scp->mode is of graphics modes, we don't know which
418	     * text/pixel mode to switch back to...
419	     */
420	    if (scp->status & GRAPHICS_MODE)
421		return EINVAL;
422	    s = spltty();
423	    if ((error = sc_clean_up(scp))) {
424		splx(s);
425		return error;
426	    }
427	    scp->status |= UNKNOWN_MODE;
428	    splx(s);
429	    /* no restore fonts & palette */
430	    if (scp == cur_console)
431		set_mode(scp);
432	    sc_clear_screen(scp);
433	    scp->status &= ~UNKNOWN_MODE;
434	    return 0;
435
436	case KD_PIXEL:		/* pixel (raster) display */
437	    if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
438		return EINVAL;
439	    if (scp->status & GRAPHICS_MODE)
440		return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize,
441					 scp->font_size);
442	    s = spltty();
443	    if ((error = sc_clean_up(scp))) {
444		splx(s);
445		return error;
446	    }
447	    scp->status |= (UNKNOWN_MODE | PIXEL_MODE);
448	    splx(s);
449	    if (scp == cur_console) {
450		set_mode(scp);
451		load_palette(scp, palette);
452	    }
453	    sc_clear_screen(scp);
454	    scp->status &= ~UNKNOWN_MODE;
455	    return 0;
456
457	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
458	    s = spltty();
459	    if ((error = sc_clean_up(scp))) {
460		splx(s);
461		return error;
462	    }
463	    scp->status |= UNKNOWN_MODE;
464	    splx(s);
465	    return 0;
466
467	default:
468	    return EINVAL;
469	}
470	/* NOT REACHED */
471
472    case KDRASTER:		/* set pixel (raster) display mode */
473	if (ISUNKNOWNSC(scp) || ISTEXTSC(scp))
474	    return ENODEV;
475	return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1],
476				 ((int *)data)[2]);
477
478    case KDGETMODE:     	/* get current mode of this (virtual) console */
479	/*
480	 * From the user program's point of view, KD_PIXEL is the same
481	 * as KD_TEXT...
482	 */
483	*data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT;
484	return 0;
485
486    case KDSBORDER:     	/* set border color of this (virtual) console */
487	scp->border = *data;
488	if (scp == cur_console)
489	    set_border(cur_console, scp->border);
490	return 0;
491    }
492
493    return ENOIOCTL;
494}
495
496#endif /* NSC > 0 */
497