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