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