main.c revision 70991
1/*- 2 * Copyright (c) 1991-1997 S�ren Schmidt 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 * in this position and unchanged. 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 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD: head/lib/libvgl/main.c 70991 2001-01-13 11:30:17Z nsouch $ 29 */ 30 31#include <stdio.h> 32#include <sys/types.h> 33#include <sys/signal.h> 34#include <sys/file.h> 35#include <sys/ioctl.h> 36#include <sys/mman.h> 37#include <sys/fbio.h> 38#include <sys/kbio.h> 39#include <sys/consio.h> 40#include "vgl.h" 41 42/* XXX Direct Color 24bits modes unsupported */ 43 44#define min(x, y) (((x) < (y)) ? (x) : (y)) 45#define max(x, y) (((x) > (y)) ? (x) : (y)) 46 47VGLBitmap *VGLDisplay; 48video_info_t VGLModeInfo; 49video_adapter_info_t VGLAdpInfo; 50byte *VGLBuf; 51 52static int VGLMode; 53static int VGLOldMode; 54static size_t VGLBufSize; 55static byte *VGLMem = MAP_FAILED; 56static int VGLSwitchPending; 57static int VGLOnDisplay; 58static unsigned int VGLCurWindow; 59static int VGLInitDone = 0; 60 61void 62VGLEnd() 63{ 64struct vt_mode smode; 65 66 if (!VGLInitDone) 67 return; 68 VGLInitDone = 0; 69 70 signal(SIGUSR1, SIG_IGN); 71 72 if (VGLMem != MAP_FAILED) { 73 VGLClear(VGLDisplay, 0); 74 munmap(VGLMem, VGLAdpInfo.va_window_size); 75 } 76 77 if (VGLOldMode >= M_VESA_BASE) { 78 /* ugly, but necessary */ 79 ioctl(0, _IO('V', VGLOldMode - M_VESA_BASE), 0); 80 if (VGLOldMode == M_VESA_800x600) { 81 int size[3]; 82 size[0] = 80; 83 size[1] = 25; 84 size[2] = 16; 85 ioctl(0, KDRASTER, size); 86 } 87 } else { 88 ioctl(0, _IO('S', VGLOldMode), 0); 89 } 90 ioctl(0, KDDISABIO, 0); 91 ioctl(0, KDSETMODE, KD_TEXT); 92 smode.mode = VT_AUTO; 93 ioctl(0, VT_SETMODE, &smode); 94 if (VGLBuf) 95 free(VGLBuf); 96 VGLBuf = NULL; 97 free(VGLDisplay); 98 VGLDisplay = NULL; 99 VGLKeyboardEnd(); 100} 101 102static void 103VGLAbort() 104{ 105 VGLEnd(); 106 exit(0); 107} 108 109static void 110VGLSwitch() 111{ 112 if (!VGLOnDisplay) 113 VGLOnDisplay = 1; 114 else 115 VGLOnDisplay = 0; 116 VGLSwitchPending = 1; 117 signal(SIGUSR1, VGLSwitch); 118} 119 120int 121VGLInit(int mode) 122{ 123 struct vt_mode smode; 124 int adptype; 125 126 if (VGLInitDone) 127 return -1; 128 129 signal(SIGUSR1, VGLSwitch); 130 signal(SIGINT, VGLAbort); 131 signal(SIGTERM, VGLAbort); 132 signal(SIGSEGV, VGLAbort); 133 signal(SIGBUS, VGLAbort); 134 135 VGLOnDisplay = 1; 136 VGLSwitchPending = 0; 137 138 if (ioctl(0, CONS_GET, &VGLOldMode) || ioctl(0, CONS_CURRENT, &adptype)) 139 return -1; 140 if (IOCGROUP(mode) == 'V') /* XXX: this is ugly */ 141 VGLModeInfo.vi_mode = (mode & 0x0ff) + M_VESA_BASE; 142 else 143 VGLModeInfo.vi_mode = mode & 0x0ff; 144 if (ioctl(0, CONS_MODEINFO, &VGLModeInfo)) /* FBIO_MODEINFO */ 145 return -1; 146 147 VGLDisplay = (VGLBitmap *)malloc(sizeof(VGLBitmap)); 148 if (VGLDisplay == NULL) 149 return -2; 150 151 if (ioctl(0, KDENABIO, 0)) { 152 free(VGLDisplay); 153 return -3; 154 } 155 156 VGLInitDone = 1; 157 158 /* 159 * vi_mem_model specifies the memory model of the current video mode 160 * in -CURRENT. 161 */ 162 switch (VGLModeInfo.vi_mem_model) { 163 case V_INFO_MM_PLANAR: 164 /* we can handle EGA/VGA planner modes only */ 165 if (VGLModeInfo.vi_depth != 4 || VGLModeInfo.vi_planes != 4 166 || (adptype != KD_EGA && adptype != KD_VGA)) { 167 VGLEnd(); 168 return -4; 169 } 170 VGLDisplay->Type = VIDBUF4; 171 break; 172 case V_INFO_MM_PACKED: 173 /* we can do only 256 color packed modes */ 174 if (VGLModeInfo.vi_depth != 8) { 175 VGLEnd(); 176 return -4; 177 } 178 VGLDisplay->Type = VIDBUF8; 179 break; 180 case V_INFO_MM_VGAX: 181 VGLDisplay->Type = VIDBUF8X; 182 break; 183 case V_INFO_MM_DIRECT: 184 VGLDisplay->PixelBytes = VGLModeInfo.vi_pixel_size; 185 switch (VGLDisplay->PixelBytes) { 186 case 2: 187 VGLDisplay->Type = VIDBUF16; 188 break; 189#if notyet 190 case 3: 191 VGLDisplay->Type = VIDBUF24; 192 break; 193#endif 194 case 4: 195 VGLDisplay->Type = VIDBUF32; 196 break; 197 default: 198 VGLEnd(); 199 return -4; 200 } 201 break; 202 default: 203 VGLEnd(); 204 return -4; 205 } 206 207 ioctl(0, VT_WAITACTIVE, 0); 208 ioctl(0, KDSETMODE, KD_GRAPHICS); 209 if (ioctl(0, mode, 0)) { 210 VGLEnd(); 211 return -5; 212 } 213 if (ioctl(0, CONS_ADPINFO, &VGLAdpInfo)) { /* FBIO_ADPINFO */ 214 VGLEnd(); 215 return -6; 216 } 217 218 /* 219 * Calculate the shadow screen buffer size. In -CURRENT, va_buffer_size 220 * always holds the entire frame buffer size, wheather it's in the linear 221 * mode or windowed mode. 222 * VGLBufSize = VGLAdpInfo.va_buffer_size; 223 * In -STABLE, va_buffer_size holds the frame buffer size, only if 224 * the linear frame buffer mode is supported. Otherwise the field is zero. 225 * We shall calculate the minimal size in this case: 226 * VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes 227 * or 228 * VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes; 229 * Use whichever is larger. 230 */ 231 if (VGLAdpInfo.va_buffer_size != 0) 232 VGLBufSize = VGLAdpInfo.va_buffer_size; 233 else 234 VGLBufSize = max(VGLAdpInfo.va_line_width*VGLModeInfo.vi_height, 235 VGLAdpInfo.va_window_size)*VGLModeInfo.vi_planes; 236 VGLBuf = malloc(VGLBufSize); 237 if (VGLBuf == NULL) { 238 VGLEnd(); 239 return -7; 240 } 241 242#ifdef LIBVGL_DEBUG 243 fprintf(stderr, "VGLBufSize:0x%x\n", VGLBufSize); 244#endif 245 246 /* see if we are in the windowed buffer mode or in the linear buffer mode */ 247 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) { 248 switch (VGLDisplay->Type) { 249 case VIDBUF4: 250 VGLDisplay->Type = VIDBUF4S; 251 break; 252 case VIDBUF8: 253 VGLDisplay->Type = VIDBUF8S; 254 break; 255 case VIDBUF16: 256 VGLDisplay->Type = VIDBUF16S; 257 break; 258 case VIDBUF24: 259 VGLDisplay->Type = VIDBUF24S; 260 break; 261 case VIDBUF32: 262 VGLDisplay->Type = VIDBUF32S; 263 break; 264 default: 265 VGLEnd(); 266 return -8; 267 } 268 } 269 270 VGLMode = mode; 271 VGLCurWindow = 0; 272 273 VGLDisplay->Xsize = VGLModeInfo.vi_width; 274 VGLDisplay->Ysize = VGLModeInfo.vi_height; 275 VGLDisplay->VXsize = VGLAdpInfo.va_line_width 276 *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes); 277 VGLDisplay->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width; 278 VGLDisplay->Xorigin = 0; 279 VGLDisplay->Yorigin = 0; 280 281 VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE, 282 MAP_FILE, 0, 0); 283 if (VGLMem == MAP_FAILED) { 284 VGLEnd(); 285 return -7; 286 } 287 VGLDisplay->Bitmap = VGLMem; 288 289 VGLSavePalette(); 290 291#ifdef LIBVGL_DEBUG 292 fprintf(stderr, "va_line_width:%d\n", VGLAdpInfo.va_line_width); 293 fprintf(stderr, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n", 294 VGLDisplay->Xsize, VGLDisplay->Ysize, 295 VGLDisplay->VXsize, VGLDisplay->VYsize); 296#endif 297 298 smode.mode = VT_PROCESS; 299 smode.waitv = 0; 300 smode.relsig = SIGUSR1; 301 smode.acqsig = SIGUSR1; 302 smode.frsig = SIGINT; 303 if (ioctl(0, VT_SETMODE, &smode)) { 304 VGLEnd(); 305 return -9; 306 } 307 VGLTextSetFontFile((byte*)0); 308 VGLClear(VGLDisplay, 0); 309 return 0; 310} 311 312void 313VGLCheckSwitch() 314{ 315 while (VGLSwitchPending) { 316 unsigned int offset; 317 unsigned int len; 318 int i; 319 320 VGLSwitchPending = 0; 321 if (VGLOnDisplay) { 322 ioctl(0, KDENABIO, 0); 323 ioctl(0, KDSETMODE, KD_GRAPHICS); 324 ioctl(0, VGLMode, 0); 325 VGLCurWindow = 0; 326 VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE, 327 MAP_FILE, 0, 0); 328 329 /* XXX: what if mmap() has failed! */ 330 VGLDisplay->Type = VIDBUF8; /* XXX */ 331 switch (VGLModeInfo.vi_mem_model) { 332 case V_INFO_MM_PLANAR: 333 if (VGLModeInfo.vi_depth == 4 && VGLModeInfo.vi_planes == 4) { 334 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 335 VGLDisplay->Type = VIDBUF4S; 336 else 337 VGLDisplay->Type = VIDBUF4; 338 } else { 339 /* shouldn't be happening */ 340 } 341 break; 342 case V_INFO_MM_PACKED: 343 if (VGLModeInfo.vi_depth == 8) { 344 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 345 VGLDisplay->Type = VIDBUF8S; 346 else 347 VGLDisplay->Type = VIDBUF8; 348 } 349 break; 350 case V_INFO_MM_VGAX: 351 VGLDisplay->Type = VIDBUF8X; 352 break; 353 case V_INFO_MM_DIRECT: 354 switch (VGLModeInfo.vi_pixel_size) { 355 case 2: 356 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 357 VGLDisplay->Type = VIDBUF16S; 358 else 359 VGLDisplay->Type = VIDBUF16; 360 break; 361 case 3: 362 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 363 VGLDisplay->Type = VIDBUF24S; 364 else 365 VGLDisplay->Type = VIDBUF24; 366 break; 367 case 4: 368 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 369 VGLDisplay->Type = VIDBUF32S; 370 else 371 VGLDisplay->Type = VIDBUF32; 372 break; 373 default: 374 /* shouldn't be happening */ 375 break; 376 } 377 default: 378 /* shouldn't be happening */ 379 break; 380 } 381 382 VGLDisplay->Bitmap = VGLMem; 383 VGLDisplay->Xsize = VGLModeInfo.vi_width; 384 VGLDisplay->Ysize = VGLModeInfo.vi_height; 385 VGLSetVScreenSize(VGLDisplay, VGLDisplay->VXsize, VGLDisplay->VYsize); 386 VGLPanScreen(VGLDisplay, VGLDisplay->Xorigin, VGLDisplay->Yorigin); 387 switch (VGLDisplay->Type) { 388 case VIDBUF4S: 389 outb(0x3c6, 0xff); 390 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 391 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 392 for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes; 393 offset += len) { 394 VGLSetSegment(offset); 395 len = min(VGLBufSize/VGLModeInfo.vi_planes - offset, 396 VGLAdpInfo.va_window_size); 397 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 398 outb(0x3c4, 0x02); 399 outb(0x3c5, 0x01<<i); 400 bcopy(&VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset], 401 VGLMem, len); 402 } 403 } 404 break; 405 case VIDBUF4: 406 case VIDBUF8X: 407 outb(0x3c6, 0xff); 408 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 409 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 410 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 411 outb(0x3c4, 0x02); 412 outb(0x3c5, 0x01<<i); 413 bcopy(&VGLBuf[i*VGLAdpInfo.va_window_size], VGLMem, 414 VGLAdpInfo.va_window_size); 415 } 416 break; 417 case VIDBUF8: 418 case VIDBUF8S: 419 case VIDBUF16: 420 case VIDBUF16S: 421 case VIDBUF24: 422 case VIDBUF24S: 423 case VIDBUF32: 424 case VIDBUF32S: 425 for (offset = 0; offset < VGLBufSize; offset += len) { 426 VGLSetSegment(offset); 427 len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size); 428 bcopy(&VGLBuf[offset], VGLMem, len); 429 } 430 break; 431 } 432 VGLRestorePalette(); 433 ioctl(0, VT_RELDISP, VT_ACKACQ); 434 } 435 else { 436 switch (VGLDisplay->Type) { 437 case VIDBUF4S: 438 for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes; 439 offset += len) { 440 VGLSetSegment(offset); 441 len = min(VGLBufSize/VGLModeInfo.vi_planes - offset, 442 VGLAdpInfo.va_window_size); 443 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 444 outb(0x3ce, 0x04); 445 outb(0x3cf, i); 446 bcopy(VGLMem, &VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset], 447 len); 448 } 449 } 450 break; 451 case VIDBUF4: 452 case VIDBUF8X: 453 /* 454 * NOTE: the saved buffer is NOT in the MEMBUF format which 455 * the ordinary memory bitmap object is stored in. XXX 456 */ 457 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 458 outb(0x3ce, 0x04); 459 outb(0x3cf, i); 460 bcopy(VGLMem, &VGLBuf[i*VGLAdpInfo.va_window_size], 461 VGLAdpInfo.va_window_size); 462 } 463 break; 464 case VIDBUF8: 465 case VIDBUF8S: 466 case VIDBUF16: 467 case VIDBUF16S: 468 case VIDBUF24: 469 case VIDBUF24S: 470 case VIDBUF32: 471 case VIDBUF32S: 472 for (offset = 0; offset < VGLBufSize; offset += len) { 473 VGLSetSegment(offset); 474 len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size); 475 bcopy(VGLMem, &VGLBuf[offset], len); 476 } 477 break; 478 } 479 VGLMem = MAP_FAILED; 480 munmap(VGLDisplay->Bitmap, VGLAdpInfo.va_window_size); 481 ioctl(0, VGLOldMode, 0); 482 ioctl(0, KDSETMODE, KD_TEXT); 483 ioctl(0, KDDISABIO, 0); 484 ioctl(0, VT_RELDISP, VT_TRUE); 485 VGLDisplay->Bitmap = VGLBuf; 486 VGLDisplay->Type = MEMBUF; 487 VGLDisplay->Xsize = VGLDisplay->VXsize; 488 VGLDisplay->Ysize = VGLDisplay->VYsize; 489 while (!VGLOnDisplay) pause(); 490 } 491 } 492} 493 494int 495VGLSetSegment(unsigned int offset) 496{ 497 if (offset/VGLAdpInfo.va_window_size != VGLCurWindow) { 498 ioctl(0, CONS_SETWINORG, offset); /* FBIO_SETWINORG */ 499 VGLCurWindow = offset/VGLAdpInfo.va_window_size; 500 } 501 return (offset%VGLAdpInfo.va_window_size); 502} 503 504int 505VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize) 506{ 507 if (VXsize < object->Xsize || VYsize < object->Ysize) 508 return -1; 509 if (object->Type == MEMBUF) 510 return -1; 511 if (ioctl(0, FBIO_SETLINEWIDTH, &VXsize)) 512 return -1; 513 ioctl(0, CONS_ADPINFO, &VGLAdpInfo); /* FBIO_ADPINFO */ 514 object->VXsize = VGLAdpInfo.va_line_width 515 *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes); 516 object->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width; 517 if (VYsize < object->VYsize) 518 object->VYsize = VYsize; 519 520#ifdef LIBVGL_DEBUG 521 fprintf(stderr, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n", 522 object->Xsize, object->Ysize, object->VXsize, object->VYsize); 523#endif 524 525 return 0; 526} 527 528int 529VGLPanScreen(VGLBitmap *object, int x, int y) 530{ 531 video_display_start_t origin; 532 533 if (x < 0 || x + object->Xsize > object->VXsize 534 || y < 0 || y + object->Ysize > object->VYsize) 535 return -1; 536 if (object->Type == MEMBUF) 537 return 0; 538 origin.x = x; 539 origin.y = y; 540 if (ioctl(0, FBIO_SETDISPSTART, &origin)) 541 return -1; 542 object->Xorigin = x; 543 object->Yorigin = y; 544 545#ifdef LIBVGL_DEBUG 546 fprintf(stderr, "new origin: (%d, %d)\n", x, y); 547#endif 548 549 return 0; 550} 551