xref: /freebsd/sys/dev/syscons/scvidctl.c (revision 0640d357f29fb1c0daaaffadd0416c5981413afd)
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 
48 extern scr_stat *cur_console;
49 extern int fonts_loaded;
50 extern int sc_history_size;
51 extern u_char palette[];
52 
53 int
54 sc_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 
137 int
138 sc_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 
186 int
187 sc_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 
303 int
304 sc_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