scvidctl.c revision 39742
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.3 1998/09/25 11:55:46 yokota 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[];
52extern int sc_flags;
53
54int
55sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize,
56		 int fontsize)
57{
58    video_adapter_t *adp;
59    video_info_t info;
60    int error;
61    int s;
62    int i;
63
64    if ((*biosvidsw.get_info)(scp->adp, mode, &info))
65	return ENODEV;
66    adp = get_adapter(scp);
67
68    /* adjust argument values */
69    if (fontsize <= 0)
70	fontsize = info.vi_cheight;
71    if (fontsize < 14) {
72	fontsize = 8;
73	if (!(fonts_loaded & FONT_8))
74	    return EINVAL;
75    } else if (fontsize >= 16) {
76	fontsize = 16;
77	if (!(fonts_loaded & FONT_16))
78	    return EINVAL;
79    } else {
80	fontsize = 14;
81	if (!(fonts_loaded & FONT_14))
82	    return EINVAL;
83    }
84    if ((xsize <= 0) || (xsize > info.vi_width))
85	xsize = info.vi_width;
86    if ((ysize <= 0) || (ysize > info.vi_height))
87	ysize = info.vi_height;
88
89    /* stop screen saver, etc */
90    s = spltty();
91    if ((error = sc_clean_up(scp))) {
92	splx(s);
93	return error;
94    }
95
96    /* set up scp */
97    if (scp->history != NULL)
98	i = imax(scp->history_size / scp->xsize
99		 - imax(sc_history_size, scp->ysize), 0);
100    else
101	i = 0;
102    /*
103     * This is a kludge to fend off scrn_update() while we
104     * muck around with scp. XXX
105     */
106    scp->status |= UNKNOWN_MODE;
107    scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE);
108    scp->mode = mode;
109    scp->font_size = fontsize;
110    scp->xsize = xsize;
111    scp->ysize = ysize;
112    scp->xpixel = scp->xsize*8;
113    scp->ypixel = scp->ysize*fontsize;
114
115    /* allocate buffers */
116    sc_alloc_scr_buffer(scp, TRUE, TRUE);
117    if (ISMOUSEAVAIL(adp->va_flags))
118	sc_alloc_cut_buffer(scp, FALSE);
119    sc_alloc_history_buffer(scp, sc_history_size, i, FALSE);
120    splx(s);
121
122    if (scp == cur_console)
123	set_mode(scp);
124    scp->status &= ~UNKNOWN_MODE;
125    if (ISTEXTSC(scp) && (sc_flags & CHAR_CURSOR))
126	set_destructive_cursor(scp);
127
128    if (tp == NULL)
129	return 0;
130    if (tp->t_winsize.ws_col != scp->xsize
131	|| tp->t_winsize.ws_row != scp->ysize) {
132	tp->t_winsize.ws_col = scp->xsize;
133	tp->t_winsize.ws_row = scp->ysize;
134	pgsignal(tp->t_pgrp, SIGWINCH, 1);
135    }
136
137    return 0;
138}
139
140int
141sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode)
142{
143    video_adapter_t *adp;
144    video_info_t info;
145    int error;
146    int s;
147
148    if ((*biosvidsw.get_info)(scp->adp, mode, &info))
149	return ENODEV;
150    adp = get_adapter(scp);
151
152    /* stop screen saver, etc */
153    s = spltty();
154    if ((error = sc_clean_up(scp))) {
155	splx(s);
156	return error;
157    }
158
159    /* set up scp */
160    scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE);
161    scp->status &= ~PIXEL_MODE;
162    scp->mode = mode;
163    scp->xpixel = info.vi_width;
164    scp->ypixel = info.vi_height;
165    scp->xsize = info.vi_width/8;
166    scp->ysize = info.vi_height/info.vi_cheight;
167    scp->font_size = FONT_NONE;
168    /* move the mouse cursor at the center of the screen */
169    sc_move_mouse(scp, scp->xpixel / 2, scp->ypixel / 2);
170    splx(s);
171
172    if (scp == cur_console)
173	set_mode(scp);
174    /* clear_graphics();*/
175    scp->status &= ~UNKNOWN_MODE;
176
177    if (tp == NULL)
178	return 0;
179    if (tp->t_winsize.ws_xpixel != scp->xpixel
180	|| tp->t_winsize.ws_ypixel != scp->ypixel) {
181	tp->t_winsize.ws_xpixel = scp->xpixel;
182	tp->t_winsize.ws_ypixel = scp->ypixel;
183	pgsignal(tp->t_pgrp, SIGWINCH, 1);
184    }
185
186    return 0;
187}
188
189int
190sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize,
191		  int fontsize)
192{
193    video_adapter_t *adp;
194    video_info_t info;
195    int error;
196    int s;
197    int i;
198
199    if ((*biosvidsw.get_info)(scp->adp, scp->mode, &info))
200	return ENODEV;		/* this shouldn't happen */
201    adp = get_adapter(scp);
202
203#ifdef SC_VIDEO_DEBUG
204    if (scp->scr_buf != NULL) {
205	printf("set_pixel_mode(): mode:%x, col:%d, row:%d, font:%d\n",
206	       scp->mode, xsize, ysize, fontsize);
207    }
208#endif
209
210    /* adjust argument values */
211    if ((fontsize <= 0) || (fontsize == FONT_NONE))
212	fontsize = info.vi_cheight;
213    if (fontsize < 14) {
214	fontsize = 8;
215	if (!(fonts_loaded & FONT_8))
216	    return EINVAL;
217    } else if (fontsize >= 16) {
218	fontsize = 16;
219	if (!(fonts_loaded & FONT_16))
220	    return EINVAL;
221    } else {
222	fontsize = 14;
223	if (!(fonts_loaded & FONT_14))
224	    return EINVAL;
225    }
226    if (xsize <= 0)
227	xsize = info.vi_width/8;
228    if (ysize <= 0)
229	ysize = info.vi_height/fontsize;
230
231#ifdef SC_VIDEO_DEBUG
232    if (scp->scr_buf != NULL) {
233	printf("set_pixel_mode(): mode:%x, col:%d, row:%d, font:%d\n",
234	       scp->mode, xsize, ysize, fontsize);
235	printf("set_pixel_mode(): window:%x, %dx%d, xoff:%d, yoff:%d\n",
236	       adp->va_window, info.vi_width, info.vi_height,
237	       (info.vi_width/8 - xsize)/2,
238	       (info.vi_height/fontsize - ysize)/2);
239    }
240#endif
241
242    if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize))
243	return EINVAL;
244
245    /* only 16 color, 4 plane modes are supported XXX */
246    if ((info.vi_depth != 4) || (info.vi_planes != 4))
247	return ENODEV;
248
249    /*
250     * set_pixel_mode() currently does not support video modes whose
251     * memory size is larger than 64K. Because such modes require
252     * bank switching to access the entire screen. XXX
253     */
254    if (info.vi_width*info.vi_height/8 > info.vi_window_size*1024)
255	return ENODEV;
256
257    /* stop screen saver, etc */
258    s = spltty();
259    if ((error = sc_clean_up(scp))) {
260	splx(s);
261	return error;
262    }
263
264    /* set up scp */
265    if (scp->history != NULL)
266	i = imax(scp->history_size / scp->xsize
267		 - imax(sc_history_size, scp->ysize), 0);
268    else
269	i = 0;
270    scp->status |= (UNKNOWN_MODE | PIXEL_MODE);
271    scp->status &= ~(GRAPHICS_MODE | MOUSE_ENABLED);
272    scp->xsize = xsize;
273    scp->ysize = ysize;
274    scp->font_size = fontsize;
275    scp->xoff = (scp->xpixel/8 - xsize)/2;
276    scp->yoff = (scp->ypixel/fontsize - ysize)/2;
277
278    /* allocate buffers */
279    sc_alloc_scr_buffer(scp, TRUE, TRUE);
280    if (ISMOUSEAVAIL(adp->va_flags))
281	sc_alloc_cut_buffer(scp, FALSE);
282    sc_alloc_history_buffer(scp, sc_history_size, i, FALSE);
283    splx(s);
284
285    if (scp == cur_console)
286	set_border(scp, scp->border);
287
288    scp->status &= ~UNKNOWN_MODE;
289
290#ifdef SC_VIDEO_DEBUG
291    printf("set_pixel_mode(): status:%x\n", scp->status);
292#endif
293
294    if (tp == NULL)
295	return 0;
296    if (tp->t_winsize.ws_col != scp->xsize
297	|| tp->t_winsize.ws_row != scp->ysize) {
298	tp->t_winsize.ws_col = scp->xsize;
299	tp->t_winsize.ws_row = scp->ysize;
300	pgsignal(tp->t_pgrp, SIGWINCH, 1);
301    }
302
303    return 0;
304}
305
306int
307sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p)
308{
309    scr_stat *scp;
310    video_adapter_t *adp;
311    int error;
312    int s;
313
314    scp = sc_get_scr_stat(tp->t_dev);
315
316    switch (cmd) {
317
318    case CONS_CURRENT:  	/* get current adapter type */
319	adp = get_adapter(scp);
320	*(int *)data = adp->va_type;
321	return 0;
322
323    case CONS_CURRENTADP:	/* get current adapter index */
324	*(int *)data = scp->adp;
325	return 0;
326
327    case CONS_ADPINFO:		/* adapter information */
328	adp = (*biosvidsw.adapter)(((video_adapter_t *)data)->va_index);
329	if (adp == NULL)
330	    return ENODEV;
331	bcopy(adp, data, sizeof(*adp));
332	return 0;
333
334    case CONS_GET:      	/* get current video mode */
335	*(int *)data = scp->mode;
336	return 0;
337
338    case CONS_MODEINFO:		/* get mode information */
339	return ((*biosvidsw.get_info)(scp->adp,
340		    ((video_info_t *)data)->vi_mode, (video_info_t *)data)
341		? ENODEV : 0);
342
343    case CONS_FINDMODE:		/* find a matching video mode */
344	return ((*biosvidsw.query_mode)(scp->adp, (video_info_t *)data)
345		? ENODEV : 0);
346
347    case CONS_SETWINORG:
348	return ((*biosvidsw.set_win_org)(scp->adp, *(u_int *)data)
349		   ? ENODEV : 0);
350
351    /* generic text modes */
352    case SW_TEXT_80x25:	case SW_TEXT_80x30:
353    case SW_TEXT_80x43: case SW_TEXT_80x50:
354    case SW_TEXT_80x60:
355	/* FALL THROUGH */
356
357    /* VGA TEXT MODES */
358    case SW_VGA_C40x25:
359    case SW_VGA_C80x25: case SW_VGA_M80x25:
360    case SW_VGA_C80x30: case SW_VGA_M80x30:
361    case SW_VGA_C80x50: case SW_VGA_M80x50:
362    case SW_VGA_C80x60: case SW_VGA_M80x60:
363    case SW_B40x25:     case SW_C40x25:
364    case SW_B80x25:     case SW_C80x25:
365    case SW_ENH_B40x25: case SW_ENH_C40x25:
366    case SW_ENH_B80x25: case SW_ENH_C80x25:
367    case SW_ENH_B80x43: case SW_ENH_C80x43:
368    case SW_EGAMONO80x25:
369	adp = get_adapter(scp);
370	if (!(adp->va_flags & V_ADP_MODECHANGE))
371 	    return ENODEV;
372	return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0);
373
374    /* GRAPHICS MODES */
375    case SW_BG320:     case SW_BG640:
376    case SW_CG320:     case SW_CG320_D:   case SW_CG640_E:
377    case SW_CG640x350: case SW_ENH_CG640:
378    case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
379    case SW_VGA_MODEX:
380	adp = get_adapter(scp);
381	if (!(adp->va_flags & V_ADP_MODECHANGE))
382	    return ENODEV;
383	return sc_set_graphics_mode(scp, tp, cmd & 0xff);
384
385    case KDSETMODE:     	/* set current mode of this (virtual) console */
386	switch (*data) {
387	case KD_TEXT:   	/* switch to TEXT (known) mode */
388	    /*
389	     * If scp->mode is of graphics modes, we don't know which
390	     * text mode to switch back to...
391	     */
392	    if (scp->status & GRAPHICS_MODE)
393		return EINVAL;
394	    /* restore fonts & palette ! */
395#if 0
396	    adp = get_adapter(scp);
397	    if (ISFONTAVAIL(adp->va_flags)
398		&& !(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
399		/*
400		 * FONT KLUDGE
401		 * Don't load fonts for now... XXX
402		 */
403		if (fonts_loaded & FONT_8)
404		    copy_font(scp, LOAD, 8, font_8);
405		if (fonts_loaded & FONT_14)
406		    copy_font(scp, LOAD, 14, font_14);
407		if (fonts_loaded & FONT_16)
408		    copy_font(scp, LOAD, 16, font_16);
409	    }
410#endif
411	    load_palette(scp, palette);
412
413	    /* move hardware cursor out of the way */
414	    (*biosvidsw.set_hw_cursor)(scp->adp, -1, -1);
415
416	    /* FALL THROUGH */
417
418	case KD_TEXT1:  	/* switch to TEXT (known) mode */
419	    /*
420	     * If scp->mode is of graphics modes, we don't know which
421	     * text/pixel mode to switch back to...
422	     */
423	    if (scp->status & GRAPHICS_MODE)
424		return EINVAL;
425	    s = spltty();
426	    if ((error = sc_clean_up(scp))) {
427		splx(s);
428		return error;
429	    }
430	    scp->status |= UNKNOWN_MODE;
431	    splx(s);
432	    /* no restore fonts & palette */
433	    if (scp == cur_console)
434		set_mode(scp);
435	    sc_clear_screen(scp);
436	    scp->status &= ~UNKNOWN_MODE;
437	    return 0;
438
439	case KD_PIXEL:		/* pixel (raster) display */
440	    if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE)))
441		return EINVAL;
442	    if (scp->status & GRAPHICS_MODE)
443		return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize,
444					 scp->font_size);
445	    s = spltty();
446	    if ((error = sc_clean_up(scp))) {
447		splx(s);
448		return error;
449	    }
450	    scp->status |= (UNKNOWN_MODE | PIXEL_MODE);
451	    splx(s);
452	    if (scp == cur_console) {
453		set_mode(scp);
454		load_palette(scp, palette);
455	    }
456	    sc_clear_screen(scp);
457	    scp->status &= ~UNKNOWN_MODE;
458	    return 0;
459
460	case KD_GRAPHICS:	/* switch to GRAPHICS (unknown) mode */
461	    s = spltty();
462	    if ((error = sc_clean_up(scp))) {
463		splx(s);
464		return error;
465	    }
466	    scp->status |= UNKNOWN_MODE;
467	    splx(s);
468	    return 0;
469
470	default:
471	    return EINVAL;
472	}
473	/* NOT REACHED */
474
475    case KDRASTER:		/* set pixel (raster) display mode */
476	if (ISUNKNOWNSC(scp) || ISTEXTSC(scp))
477	    return ENODEV;
478	return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1],
479				 ((int *)data)[2]);
480
481    case KDGETMODE:     	/* get current mode of this (virtual) console */
482	/*
483	 * From the user program's point of view, KD_PIXEL is the same
484	 * as KD_TEXT...
485	 */
486	*data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT;
487	return 0;
488
489    case KDSBORDER:     	/* set border color of this (virtual) console */
490	scp->border = *data;
491	if (scp == cur_console)
492	    set_border(cur_console, scp->border);
493	return 0;
494    }
495
496    return ENOIOCTL;
497}
498
499#endif /* NSC > 0 */
500