xref: /freebsd/sys/dev/syscons/scvidctl.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
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 
51 extern scr_stat *cur_console;
52 extern u_short *Crtat;
53 extern int fonts_loaded;
54 extern int sc_history_size;
55 extern u_char palette[];
56 
57 int
58 sc_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 
141 int
142 sc_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 
190 int
191 sc_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 
293 int
294 sc_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