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