scvidctl.c revision 42831
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.6 1999/01/11 03:18:26 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#ifdef __i386__ 41#include <machine/apm_bios.h> 42#endif 43#include <machine/console.h> 44 45#include <dev/fb/fbreg.h> 46#include <dev/syscons/syscons.h> 47 48/* for compatibility with previous versions */ 49typedef struct old_video_adapter { 50 int va_index; 51 int va_type; 52 int va_flags; 53#define V_ADP_COLOR (1<<0) 54#define V_ADP_MODECHANGE (1<<1) 55#define V_ADP_STATESAVE (1<<2) 56#define V_ADP_STATELOAD (1<<3) 57#define V_ADP_FONT (1<<4) 58#define V_ADP_PALETTE (1<<5) 59#define V_ADP_BORDER (1<<6) 60#define V_ADP_VESA (1<<7) 61 int va_crtc_addr; 62 u_int va_window; /* virtual address */ 63 size_t va_window_size; 64 size_t va_window_gran; 65 u_int va_buffer; /* virtual address */ 66 size_t va_buffer_size; 67 int va_initial_mode; 68 int va_initial_bios_mode; 69 int va_mode; 70} old_video_adapter_t; 71 72#define OLD_CONS_ADPINFO _IOWR('c', 101, old_video_adapter_t) 73 74/* variables */ 75extern scr_stat *cur_console; 76extern int fonts_loaded; 77extern int sc_history_size; 78extern u_char palette[]; 79 80int 81sc_set_text_mode(scr_stat *scp, struct tty *tp, int mode, int xsize, int ysize, 82 int fontsize) 83{ 84 video_info_t info; 85 int error; 86 int s; 87 int i; 88 89 if ((*vidsw[scp->ad]->get_info)(scp->adp, mode, &info)) 90 return ENODEV; 91 92 /* adjust argument values */ 93 if (fontsize <= 0) 94 fontsize = info.vi_cheight; 95 if (fontsize < 14) { 96 fontsize = 8; 97 if (!(fonts_loaded & FONT_8)) 98 return EINVAL; 99 } else if (fontsize >= 16) { 100 fontsize = 16; 101 if (!(fonts_loaded & FONT_16)) 102 return EINVAL; 103 } else { 104 fontsize = 14; 105 if (!(fonts_loaded & FONT_14)) 106 return EINVAL; 107 } 108 if ((xsize <= 0) || (xsize > info.vi_width)) 109 xsize = info.vi_width; 110 if ((ysize <= 0) || (ysize > info.vi_height)) 111 ysize = info.vi_height; 112 113 /* stop screen saver, etc */ 114 s = spltty(); 115 if ((error = sc_clean_up(scp))) { 116 splx(s); 117 return error; 118 } 119 120 /* set up scp */ 121 if (scp->history != NULL) 122 i = imax(scp->history_size / scp->xsize 123 - imax(sc_history_size, scp->ysize), 0); 124 else 125 i = 0; 126 /* 127 * This is a kludge to fend off scrn_update() while we 128 * muck around with scp. XXX 129 */ 130 scp->status |= UNKNOWN_MODE; 131 scp->status &= ~(GRAPHICS_MODE | PIXEL_MODE); 132 scp->mode = mode; 133 scp->font_size = fontsize; 134 scp->xsize = xsize; 135 scp->ysize = ysize; 136 scp->xoff = 0; 137 scp->yoff = 0; 138 scp->xpixel = scp->xsize*8; 139 scp->ypixel = scp->ysize*fontsize; 140 141 /* allocate buffers */ 142 sc_alloc_scr_buffer(scp, TRUE, TRUE); 143 if (ISMOUSEAVAIL(scp->adp->va_flags)) 144 sc_alloc_cut_buffer(scp, FALSE); 145 sc_alloc_history_buffer(scp, sc_history_size, i, FALSE); 146 splx(s); 147 148 if (scp == cur_console) 149 set_mode(scp); 150 scp->status &= ~UNKNOWN_MODE; 151 152 if (tp == NULL) 153 return 0; 154 if (tp->t_winsize.ws_col != scp->xsize 155 || tp->t_winsize.ws_row != scp->ysize) { 156 tp->t_winsize.ws_col = scp->xsize; 157 tp->t_winsize.ws_row = scp->ysize; 158 pgsignal(tp->t_pgrp, SIGWINCH, 1); 159 } 160 161 return 0; 162} 163 164int 165sc_set_graphics_mode(scr_stat *scp, struct tty *tp, int mode) 166{ 167 video_info_t info; 168 int error; 169 int s; 170 171 if ((*vidsw[scp->ad]->get_info)(scp->adp, mode, &info)) 172 return ENODEV; 173 174 /* stop screen saver, etc */ 175 s = spltty(); 176 if ((error = sc_clean_up(scp))) { 177 splx(s); 178 return error; 179 } 180 181 /* set up scp */ 182 scp->status |= (UNKNOWN_MODE | GRAPHICS_MODE); 183 scp->status &= ~PIXEL_MODE; 184 scp->mode = mode; 185 scp->xoff = 0; 186 scp->yoff = 0; 187 scp->xpixel = info.vi_width; 188 scp->ypixel = info.vi_height; 189 scp->xsize = info.vi_width/8; 190 scp->ysize = info.vi_height/info.vi_cheight; 191 scp->font_size = FONT_NONE; 192 /* move the mouse cursor at the center of the screen */ 193 sc_move_mouse(scp, scp->xpixel / 2, scp->ypixel / 2); 194 splx(s); 195 196 if (scp == cur_console) 197 set_mode(scp); 198 /* clear_graphics();*/ 199 scp->status &= ~UNKNOWN_MODE; 200 201 if (tp == NULL) 202 return 0; 203 if (tp->t_winsize.ws_xpixel != scp->xpixel 204 || tp->t_winsize.ws_ypixel != scp->ypixel) { 205 tp->t_winsize.ws_xpixel = scp->xpixel; 206 tp->t_winsize.ws_ypixel = scp->ypixel; 207 pgsignal(tp->t_pgrp, SIGWINCH, 1); 208 } 209 210 return 0; 211} 212 213int 214sc_set_pixel_mode(scr_stat *scp, struct tty *tp, int xsize, int ysize, 215 int fontsize) 216{ 217 video_info_t info; 218 int error; 219 int s; 220 int i; 221 222 if ((*vidsw[scp->ad]->get_info)(scp->adp, scp->mode, &info)) 223 return ENODEV; /* this shouldn't happen */ 224 225#ifdef SC_VIDEO_DEBUG 226 if (scp->scr_buf != NULL) { 227 printf("set_pixel_mode(): mode:%x, col:%d, row:%d, font:%d\n", 228 scp->mode, xsize, ysize, fontsize); 229 } 230#endif 231 232 /* adjust argument values */ 233 if ((fontsize <= 0) || (fontsize == FONT_NONE)) 234 fontsize = info.vi_cheight; 235 if (fontsize < 14) { 236 fontsize = 8; 237 if (!(fonts_loaded & FONT_8)) 238 return EINVAL; 239 } else if (fontsize >= 16) { 240 fontsize = 16; 241 if (!(fonts_loaded & FONT_16)) 242 return EINVAL; 243 } else { 244 fontsize = 14; 245 if (!(fonts_loaded & FONT_14)) 246 return EINVAL; 247 } 248 if (xsize <= 0) 249 xsize = info.vi_width/8; 250 if (ysize <= 0) 251 ysize = info.vi_height/fontsize; 252 253#ifdef SC_VIDEO_DEBUG 254 if (scp->scr_buf != NULL) { 255 printf("set_pixel_mode(): mode:%x, col:%d, row:%d, font:%d\n", 256 scp->mode, xsize, ysize, fontsize); 257 printf("set_pixel_mode(): window:%x, %dx%d, xoff:%d, yoff:%d\n", 258 scp->adp->va_window, info.vi_width, info.vi_height, 259 (info.vi_width/8 - xsize)/2, 260 (info.vi_height/fontsize - ysize)/2); 261 } 262#endif 263 264 if ((info.vi_width < xsize*8) || (info.vi_height < ysize*fontsize)) 265 return EINVAL; 266 267 /* only 16 color, 4 plane modes are supported XXX */ 268 if ((info.vi_depth != 4) || (info.vi_planes != 4)) 269 return ENODEV; 270 271 /* 272 * set_pixel_mode() currently does not support video modes whose 273 * memory size is larger than 64K. Because such modes require 274 * bank switching to access the entire screen. XXX 275 */ 276 if (info.vi_width*info.vi_height/8 > info.vi_window_size) 277 return ENODEV; 278 279 /* stop screen saver, etc */ 280 s = spltty(); 281 if ((error = sc_clean_up(scp))) { 282 splx(s); 283 return error; 284 } 285 286 /* set up scp */ 287 if (scp->history != NULL) 288 i = imax(scp->history_size / scp->xsize 289 - imax(sc_history_size, scp->ysize), 0); 290 else 291 i = 0; 292 scp->status |= (UNKNOWN_MODE | PIXEL_MODE); 293 scp->status &= ~(GRAPHICS_MODE | MOUSE_ENABLED); 294 scp->xsize = xsize; 295 scp->ysize = ysize; 296 scp->font_size = fontsize; 297 scp->xoff = (scp->xpixel/8 - xsize)/2; 298 scp->yoff = (scp->ypixel/fontsize - ysize)/2; 299 300 /* allocate buffers */ 301 sc_alloc_scr_buffer(scp, TRUE, TRUE); 302 if (ISMOUSEAVAIL(scp->adp->va_flags)) 303 sc_alloc_cut_buffer(scp, FALSE); 304 sc_alloc_history_buffer(scp, sc_history_size, i, FALSE); 305 splx(s); 306 307 if (scp == cur_console) 308 set_border(scp, scp->border); 309 310 scp->status &= ~UNKNOWN_MODE; 311 312#ifdef SC_VIDEO_DEBUG 313 printf("set_pixel_mode(): status:%x\n", scp->status); 314#endif 315 316 if (tp == NULL) 317 return 0; 318 if (tp->t_winsize.ws_col != scp->xsize 319 || tp->t_winsize.ws_row != scp->ysize) { 320 tp->t_winsize.ws_col = scp->xsize; 321 tp->t_winsize.ws_row = scp->ysize; 322 pgsignal(tp->t_pgrp, SIGWINCH, 1); 323 } 324 325 return 0; 326} 327 328int 329sc_vid_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p) 330{ 331 scr_stat *scp; 332 int error; 333 int s; 334 335 scp = sc_get_scr_stat(tp->t_dev); 336 337 switch (cmd) { 338 339 case CONS_CURRENT: /* get current adapter type */ 340 if (scp->adp == NULL) 341 return ENODEV; 342 *(int *)data = scp->adp->va_type; 343 return 0; 344 345 case CONS_CURRENTADP: /* get current adapter index */ 346 *(int *)data = scp->ad; 347 return 0; 348 349 case OLD_CONS_ADPINFO: /* adapter information */ 350 if (scp->adp == NULL) 351 return ENODEV; 352 ((old_video_adapter_t *)data)->va_index = scp->adp->va_index; 353 ((old_video_adapter_t *)data)->va_type = scp->adp->va_type; 354 ((old_video_adapter_t *)data)->va_flags = scp->adp->va_flags; 355 ((old_video_adapter_t *)data)->va_crtc_addr = scp->adp->va_crtc_addr; 356 ((old_video_adapter_t *)data)->va_window = scp->adp->va_window; 357 ((old_video_adapter_t *)data)->va_window_size 358 = scp->adp->va_window_size; 359 ((old_video_adapter_t *)data)->va_window_gran 360 = scp->adp->va_window_gran; 361 ((old_video_adapter_t *)data)->va_buffer = scp->adp->va_buffer; 362 ((old_video_adapter_t *)data)->va_buffer_size 363 = scp->adp->va_buffer_size; 364 ((old_video_adapter_t *)data)->va_mode = scp->adp->va_mode; 365 ((old_video_adapter_t *)data)->va_initial_mode 366 = scp->adp->va_initial_mode; 367 ((old_video_adapter_t *)data)->va_initial_bios_mode 368 = scp->adp->va_initial_bios_mode; 369 return 0; 370 371 case CONS_ADPINFO: /* adapter information */ 372 if (scp->adp == NULL) 373 return ENODEV; 374 ((video_adapter_info_t *)data)->va_index = scp->adp->va_index; 375 ((video_adapter_info_t *)data)->va_type = scp->adp->va_type; 376 bcopy(scp->adp->va_name, ((video_adapter_info_t *)data)->va_name, 377 imin(strlen(scp->adp->va_name) + 1, 378 sizeof(((video_adapter_info_t *)data)->va_name))); 379 ((video_adapter_info_t *)data)->va_unit = scp->adp->va_unit; 380 ((video_adapter_info_t *)data)->va_flags = scp->adp->va_flags; 381 ((video_adapter_info_t *)data)->va_io_base = scp->adp->va_io_base; 382 ((video_adapter_info_t *)data)->va_io_size = scp->adp->va_io_size; 383 ((video_adapter_info_t *)data)->va_crtc_addr = scp->adp->va_crtc_addr; 384 ((video_adapter_info_t *)data)->va_mem_base = scp->adp->va_mem_base; 385 ((video_adapter_info_t *)data)->va_mem_size = scp->adp->va_mem_size; 386 ((video_adapter_info_t *)data)->va_window = scp->adp->va_window; 387 ((video_adapter_info_t *)data)->va_window_size 388 = scp->adp->va_window_size; 389 ((video_adapter_info_t *)data)->va_window_gran 390 = scp->adp->va_window_gran; 391 ((video_adapter_info_t *)data)->va_buffer = scp->adp->va_buffer; 392 ((video_adapter_info_t *)data)->va_buffer_size 393 = scp->adp->va_buffer_size; 394 ((video_adapter_info_t *)data)->va_mode = scp->adp->va_mode; 395 ((video_adapter_info_t *)data)->va_mode_flags = scp->adp->va_mode_flags; 396 ((video_adapter_info_t *)data)->va_initial_mode 397 = scp->adp->va_initial_mode; 398 ((video_adapter_info_t *)data)->va_initial_bios_mode 399 = scp->adp->va_initial_bios_mode; 400 return 0; 401 402 case CONS_GET: /* get current video mode */ 403 *(int *)data = scp->mode; 404 return 0; 405 406 case CONS_MODEINFO: /* get mode information */ 407 return ((*vidsw[scp->ad]->get_info)(scp->adp, 408 ((video_info_t *)data)->vi_mode, (video_info_t *)data) 409 ? ENODEV : 0); 410 411 case CONS_FINDMODE: /* find a matching video mode */ 412 return ((*vidsw[scp->ad]->query_mode)(scp->adp, (video_info_t *)data) 413 ? ENODEV : 0); 414 415 case CONS_SETWINORG: 416 return ((*vidsw[scp->ad]->set_win_org)(scp->adp, *(u_int *)data) 417 ? ENODEV : 0); 418 419 /* generic text modes */ 420 case SW_TEXT_80x25: case SW_TEXT_80x30: 421 case SW_TEXT_80x43: case SW_TEXT_80x50: 422 case SW_TEXT_80x60: 423 /* FALL THROUGH */ 424 425 /* VGA TEXT MODES */ 426 case SW_VGA_C40x25: 427 case SW_VGA_C80x25: case SW_VGA_M80x25: 428 case SW_VGA_C80x30: case SW_VGA_M80x30: 429 case SW_VGA_C80x50: case SW_VGA_M80x50: 430 case SW_VGA_C80x60: case SW_VGA_M80x60: 431 case SW_B40x25: case SW_C40x25: 432 case SW_B80x25: case SW_C80x25: 433 case SW_ENH_B40x25: case SW_ENH_C40x25: 434 case SW_ENH_B80x25: case SW_ENH_C80x25: 435 case SW_ENH_B80x43: case SW_ENH_C80x43: 436 case SW_EGAMONO80x25: 437 438#ifdef PC98 439 /* PC98 TEXT MODES */ 440 case SW_PC98_80x25: 441 case SW_PC98_80x30: 442#endif 443 if (!(scp->adp->va_flags & V_ADP_MODECHANGE)) 444 return ENODEV; 445 return sc_set_text_mode(scp, tp, cmd & 0xff, 0, 0, 0); 446 447 /* GRAPHICS MODES */ 448 case SW_BG320: case SW_BG640: 449 case SW_CG320: case SW_CG320_D: case SW_CG640_E: 450 case SW_CG640x350: case SW_ENH_CG640: 451 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320: 452 case SW_VGA_MODEX: 453 if (!(scp->adp->va_flags & V_ADP_MODECHANGE)) 454 return ENODEV; 455 return sc_set_graphics_mode(scp, tp, cmd & 0xff); 456 457 case KDSETMODE: /* set current mode of this (virtual) console */ 458 switch (*(int *)data) { 459 case KD_TEXT: /* switch to TEXT (known) mode */ 460 /* 461 * If scp->mode is of graphics modes, we don't know which 462 * text mode to switch back to... 463 */ 464 if (scp->status & GRAPHICS_MODE) 465 return EINVAL; 466 /* restore fonts & palette ! */ 467#if 0 468 if (ISFONTAVAIL(scp->adp->va_flags) 469 && !(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) 470 /* 471 * FONT KLUDGE 472 * Don't load fonts for now... XXX 473 */ 474 if (fonts_loaded & FONT_8) 475 copy_font(scp, LOAD, 8, font_8); 476 if (fonts_loaded & FONT_14) 477 copy_font(scp, LOAD, 14, font_14); 478 if (fonts_loaded & FONT_16) 479 copy_font(scp, LOAD, 16, font_16); 480 } 481#endif 482 load_palette(scp->adp, palette); 483 484 /* move hardware cursor out of the way */ 485 (*vidsw[scp->ad]->set_hw_cursor)(scp->adp, -1, -1); 486 487 /* FALL THROUGH */ 488 489 case KD_TEXT1: /* switch to TEXT (known) mode */ 490 /* 491 * If scp->mode is of graphics modes, we don't know which 492 * text/pixel mode to switch back to... 493 */ 494 if (scp->status & GRAPHICS_MODE) 495 return EINVAL; 496 s = spltty(); 497 if ((error = sc_clean_up(scp))) { 498 splx(s); 499 return error; 500 } 501#ifndef PC98 502 scp->status |= UNKNOWN_MODE; 503 splx(s); 504 /* no restore fonts & palette */ 505 if (scp == cur_console) 506 set_mode(scp); 507 sc_clear_screen(scp); 508 scp->status &= ~UNKNOWN_MODE; 509#else /* PC98 */ 510 scp->status &= ~UNKNOWN_MODE; 511 /* no restore fonts & palette */ 512 if (scp == cur_console) 513 set_mode(scp); 514 sc_clear_screen(scp); 515 splx(s); 516#endif /* PC98 */ 517 return 0; 518 519 case KD_PIXEL: /* pixel (raster) display */ 520 if (!(scp->status & (GRAPHICS_MODE | PIXEL_MODE))) 521 return EINVAL; 522 if (scp->status & GRAPHICS_MODE) 523 return sc_set_pixel_mode(scp, tp, scp->xsize, scp->ysize, 524 scp->font_size); 525 s = spltty(); 526 if ((error = sc_clean_up(scp))) { 527 splx(s); 528 return error; 529 } 530 scp->status |= (UNKNOWN_MODE | PIXEL_MODE); 531 splx(s); 532 if (scp == cur_console) { 533 set_mode(scp); 534 load_palette(scp->adp, palette); 535 } 536 sc_clear_screen(scp); 537 scp->status &= ~UNKNOWN_MODE; 538 return 0; 539 540 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */ 541 s = spltty(); 542 if ((error = sc_clean_up(scp))) { 543 splx(s); 544 return error; 545 } 546 scp->status |= UNKNOWN_MODE; 547 splx(s); 548#ifdef PC98 549 if (scp == cur_console) 550 set_mode(scp); 551#endif 552 return 0; 553 554 default: 555 return EINVAL; 556 } 557 /* NOT REACHED */ 558 559 case KDRASTER: /* set pixel (raster) display mode */ 560 if (ISUNKNOWNSC(scp) || ISTEXTSC(scp)) 561 return ENODEV; 562 return sc_set_pixel_mode(scp, tp, ((int *)data)[0], ((int *)data)[1], 563 ((int *)data)[2]); 564 565 case KDGETMODE: /* get current mode of this (virtual) console */ 566 /* 567 * From the user program's point of view, KD_PIXEL is the same 568 * as KD_TEXT... 569 */ 570 *data = ISGRAPHSC(scp) ? KD_GRAPHICS : KD_TEXT; 571 return 0; 572 573 case KDSBORDER: /* set border color of this (virtual) console */ 574 scp->border = *data; 575 if (scp == cur_console) 576 set_border(scp, scp->border); 577 return 0; 578 } 579 580 return ENOIOCTL; 581} 582 583#endif /* NSC > 0 */ 584