main.c revision 66834
1264269Ssbruno/*- 2264269Ssbruno * Copyright (c) 1991-1997 S�ren Schmidt 3264269Ssbruno * All rights reserved. 4264269Ssbruno * 5264269Ssbruno * Redistribution and use in source and binary forms, with or without 6264269Ssbruno * modification, are permitted provided that the following conditions 7264269Ssbruno * are met: 8264269Ssbruno * 1. Redistributions of source code must retain the above copyright 9264269Ssbruno * notice, this list of conditions and the following disclaimer 10264269Ssbruno * in this position and unchanged. 11264269Ssbruno * 2. Redistributions in binary form must reproduce the above copyright 12264269Ssbruno * notice, this list of conditions and the following disclaimer in the 13264269Ssbruno * documentation and/or other materials provided with the distribution. 14264269Ssbruno * 3. The name of the author may not be used to endorse or promote products 15264269Ssbruno * derived from this software withough specific prior written permission 16264269Ssbruno * 17264269Ssbruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18264269Ssbruno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19264269Ssbruno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20264269Ssbruno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21264269Ssbruno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22264269Ssbruno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23264269Ssbruno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24264269Ssbruno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25264269Ssbruno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26264269Ssbruno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27264269Ssbruno * 28264269Ssbruno * $FreeBSD: head/lib/libvgl/main.c 66834 2000-10-08 21:34:00Z phk $ 29264269Ssbruno */ 30277155Swblock 31277155Swblock#include <stdio.h> 32264269Ssbruno#include <sys/types.h> 33264269Ssbruno#include <sys/signal.h> 34264269Ssbruno#include <sys/file.h> 35264269Ssbruno#include <sys/ioctl.h> 36264269Ssbruno#include <sys/mman.h> 37264269Ssbruno#include <sys/fbio.h> 38264269Ssbruno#include <sys/kbio.h> 39264269Ssbruno#include <sys/consio.h> 40266272Ssbruno#include "vgl.h" 41264269Ssbruno 42266272Ssbruno#define min(x, y) (((x) < (y)) ? (x) : (y)) 43264269Ssbruno#define max(x, y) (((x) > (y)) ? (x) : (y)) 44264269Ssbruno 45264269SsbrunoVGLBitmap *VGLDisplay; 46266272Ssbrunovideo_info_t VGLModeInfo; 47266272Ssbrunovideo_adapter_info_t VGLAdpInfo; 48266272Ssbrunobyte *VGLBuf; 49264269Ssbruno 50264269Ssbrunostatic int VGLMode; 51264269Ssbrunostatic int VGLOldMode; 52264269Ssbrunostatic size_t VGLBufSize; 53264269Ssbrunostatic byte *VGLMem = MAP_FAILED; 54264269Ssbrunostatic int VGLSwitchPending; 55264269Ssbrunostatic int VGLOnDisplay; 56264269Ssbrunostatic unsigned int VGLCurWindow; 57264269Ssbrunostatic int VGLInitDone = 0; 58264269Ssbruno 59264269Ssbrunovoid 60264269SsbrunoVGLEnd() 61264269Ssbruno{ 62264269Ssbrunostruct vt_mode smode; 63264269Ssbruno 64264269Ssbruno if (!VGLInitDone) 65264269Ssbruno return; 66264269Ssbruno VGLInitDone = 0; 67264269Ssbruno 68266272Ssbruno signal(SIGUSR1, SIG_IGN); 69266272Ssbruno 70266272Ssbruno if (VGLMem != MAP_FAILED) { 71266272Ssbruno VGLClear(VGLDisplay, 0); 72266272Ssbruno munmap(VGLMem, VGLAdpInfo.va_window_size); 73264269Ssbruno } 74264269Ssbruno 75264269Ssbruno if (VGLOldMode >= M_VESA_BASE) { 76264269Ssbruno /* ugly, but necessary */ 77264269Ssbruno ioctl(0, _IO('V', VGLOldMode - M_VESA_BASE), 0); 78264269Ssbruno if (VGLOldMode == M_VESA_800x600) { 79264269Ssbruno int size[3]; 80264269Ssbruno size[0] = 80; 81266272Ssbruno size[1] = 25; 82264269Ssbruno size[2] = 16; 83264269Ssbruno ioctl(0, KDRASTER, size); 84264269Ssbruno } 85264269Ssbruno } else { 86264269Ssbruno ioctl(0, _IO('S', VGLOldMode), 0); 87266272Ssbruno } 88266272Ssbruno ioctl(0, KDDISABIO, 0); 89266272Ssbruno ioctl(0, KDSETMODE, KD_TEXT); 90264269Ssbruno smode.mode = VT_AUTO; 91266272Ssbruno ioctl(0, VT_SETMODE, &smode); 92266272Ssbruno if (VGLBuf) 93264269Ssbruno free(VGLBuf); 94264269Ssbruno VGLBuf = NULL; 95266272Ssbruno free(VGLDisplay); 96264269Ssbruno VGLDisplay = NULL; 97264269Ssbruno VGLKeyboardEnd(); 98264269Ssbruno} 99266272Ssbruno 100264269Ssbrunostatic void 101264269SsbrunoVGLAbort() 102264269Ssbruno{ 103264269Ssbruno VGLEnd(); 104264269Ssbruno exit(0); 105264269Ssbruno} 106264269Ssbruno 107264269Ssbrunostatic void 108264269SsbrunoVGLSwitch() 109264269Ssbruno{ 110266272Ssbruno if (!VGLOnDisplay) 111264269Ssbruno VGLOnDisplay = 1; 112264269Ssbruno else 113264269Ssbruno VGLOnDisplay = 0; 114264269Ssbruno VGLSwitchPending = 1; 115266272Ssbruno signal(SIGUSR1, VGLSwitch); 116266272Ssbruno} 117266272Ssbruno 118264269Ssbrunoint 119264269SsbrunoVGLInit(int mode) 120264269Ssbruno{ 121266272Ssbruno struct vt_mode smode; 122266272Ssbruno int adptype; 123266272Ssbruno 124266272Ssbruno if (VGLInitDone) 125264269Ssbruno return -1; 126264269Ssbruno 127264269Ssbruno signal(SIGUSR1, VGLSwitch); 128266272Ssbruno signal(SIGINT, VGLAbort); 129264269Ssbruno signal(SIGTERM, VGLAbort); 130266272Ssbruno signal(SIGSEGV, VGLAbort); 131266272Ssbruno signal(SIGBUS, VGLAbort); 132266272Ssbruno 133264269Ssbruno VGLOnDisplay = 1; 134264269Ssbruno VGLSwitchPending = 0; 135264269Ssbruno 136264269Ssbruno if (ioctl(0, CONS_GET, &VGLOldMode) || ioctl(0, CONS_CURRENT, &adptype)) 137264269Ssbruno return -1; 138264269Ssbruno if (IOCGROUP(mode) == 'V') /* XXX: this is ugly */ 139264269Ssbruno VGLModeInfo.vi_mode = (mode & 0x0ff) + M_VESA_BASE; 140264269Ssbruno else 141264269Ssbruno VGLModeInfo.vi_mode = mode & 0x0ff; 142264269Ssbruno if (ioctl(0, CONS_MODEINFO, &VGLModeInfo)) /* FBIO_MODEINFO */ 143266272Ssbruno return -1; 144264269Ssbruno 145277155Swblock VGLDisplay = (VGLBitmap *)malloc(sizeof(VGLBitmap)); 146264269Ssbruno if (VGLDisplay == NULL) 147264269Ssbruno return -2; 148264269Ssbruno 149277155Swblock if (ioctl(0, KDENABIO, 0)) { 150277155Swblock free(VGLDisplay); 151277155Swblock return -3; 152277155Swblock } 153277155Swblock 154277155Swblock VGLInitDone = 1; 155264269Ssbruno 156264269Ssbruno /* 157277155Swblock * vi_mem_model specifies the memory model of the current video mode 158266272Ssbruno * in -CURRENT. 159266272Ssbruno */ 160266272Ssbruno switch (VGLModeInfo.vi_mem_model) { 161264269Ssbruno case V_INFO_MM_PLANAR: 162264269Ssbruno /* we can handle EGA/VGA planner modes only */ 163277155Swblock if (VGLModeInfo.vi_depth != 4 || VGLModeInfo.vi_planes != 4 164277155Swblock || (adptype != KD_EGA && adptype != KD_VGA)) { 165277155Swblock VGLEnd(); 166266272Ssbruno return -4; 167264269Ssbruno } 168277155Swblock VGLDisplay->Type = VIDBUF4; 169264269Ssbruno break; 170277155Swblock case V_INFO_MM_PACKED: 171266272Ssbruno /* we can do only 256 color packed modes */ 172264269Ssbruno if (VGLModeInfo.vi_depth != 8) { 173277155Swblock VGLEnd(); 174264269Ssbruno return -4; 175277155Swblock } 176266272Ssbruno VGLDisplay->Type = VIDBUF8; 177264269Ssbruno break; 178277155Swblock case V_INFO_MM_VGAX: 179264269Ssbruno VGLDisplay->Type = VIDBUF8X; 180277155Swblock break; 181266272Ssbruno default: 182264269Ssbruno VGLEnd(); 183277155Swblock return -4; 184277155Swblock } 185277155Swblock 186277155Swblock ioctl(0, VT_WAITACTIVE, 0); 187277155Swblock ioctl(0, KDSETMODE, KD_GRAPHICS); 188277155Swblock if (ioctl(0, mode, 0)) { 189277155Swblock VGLEnd(); 190277155Swblock return -5; 191277155Swblock } 192277155Swblock if (ioctl(0, CONS_ADPINFO, &VGLAdpInfo)) { /* FBIO_ADPINFO */ 193277155Swblock VGLEnd(); 194277155Swblock return -6; 195277155Swblock } 196277155Swblock 197277155Swblock /* 198277155Swblock * Calculate the shadow screen buffer size. In -CURRENT, va_buffer_size 199277155Swblock * always holds the entire frame buffer size, wheather it's in the linear 200277155Swblock * mode or windowed mode. 201277155Swblock * VGLBufSize = VGLAdpInfo.va_buffer_size; 202277155Swblock * In -STABLE, va_buffer_size holds the frame buffer size, only if 203277155Swblock * the linear frame buffer mode is supported. Otherwise the field is zero. 204277155Swblock * We shall calculate the minimal size in this case: 205277155Swblock * VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes 206277155Swblock * or 207277155Swblock * VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes; 208277155Swblock * Use whichever is larger. 209277155Swblock */ 210277155Swblock if (VGLAdpInfo.va_buffer_size != 0) 211277155Swblock VGLBufSize = VGLAdpInfo.va_buffer_size; 212277155Swblock else 213277155Swblock VGLBufSize = max(VGLAdpInfo.va_line_width*VGLModeInfo.vi_height, 214277155Swblock VGLAdpInfo.va_window_size)*VGLModeInfo.vi_planes; 215277155Swblock VGLBuf = malloc(VGLBufSize); 216277155Swblock if (VGLBuf == NULL) { 217277155Swblock VGLEnd(); 218277155Swblock return -7; 219277155Swblock } 220277155Swblock 221277155Swblock#ifdef LIBVGL_DEBUG 222277155Swblock fprintf(stderr, "VGLBufSize:0x%x\n", VGLBufSize); 223277155Swblock#endif 224277155Swblock 225277155Swblock /* see if we are in the windowed buffer mode or in the linear buffer mode */ 226277155Swblock if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) { 227277155Swblock if (VGLDisplay->Type == VIDBUF4) 228277155Swblock VGLDisplay->Type = VIDBUF4S; 229277155Swblock else if (VGLDisplay->Type == VIDBUF8) 230277155Swblock VGLDisplay->Type = VIDBUF8S; 231277155Swblock } 232277155Swblock 233277155Swblock VGLMode = mode; 234277155Swblock VGLCurWindow = 0; 235277155Swblock 236277155Swblock VGLDisplay->Xsize = VGLModeInfo.vi_width; 237277155Swblock VGLDisplay->Ysize = VGLModeInfo.vi_height; 238277155Swblock VGLDisplay->VXsize = VGLAdpInfo.va_line_width 239277155Swblock *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes); 240277155Swblock VGLDisplay->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width; 241277155Swblock VGLDisplay->Xorigin = 0; 242277155Swblock VGLDisplay->Yorigin = 0; 243277155Swblock 244277155Swblock VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE, 245277155Swblock MAP_FILE, 0, 0); 246277155Swblock if (VGLMem == MAP_FAILED) { 247277155Swblock VGLEnd(); 248277155Swblock return -7; 249277155Swblock } 250277155Swblock VGLDisplay->Bitmap = VGLMem; 251277155Swblock 252277155Swblock VGLSavePalette(); 253277155Swblock 254277155Swblock#ifdef LIBVGL_DEBUG 255277155Swblock fprintf(stderr, "va_line_width:%d\n", VGLAdpInfo.va_line_width); 256277155Swblock fprintf(stderr, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n", 257277155Swblock VGLDisplay->Xsize, VGLDisplay->Ysize, 258277155Swblock VGLDisplay->VXsize, VGLDisplay->VYsize); 259277155Swblock#endif 260277155Swblock 261277155Swblock smode.mode = VT_PROCESS; 262277155Swblock smode.waitv = 0; 263277155Swblock smode.relsig = SIGUSR1; 264277155Swblock smode.acqsig = SIGUSR1; 265277155Swblock smode.frsig = SIGINT; 266277155Swblock if (ioctl(0, VT_SETMODE, &smode)) { 267277155Swblock VGLEnd(); 268277155Swblock return -9; 269277155Swblock } 270277155Swblock VGLTextSetFontFile((byte*)0); 271277155Swblock VGLClear(VGLDisplay, 0); 272277155Swblock return 0; 273277155Swblock} 274277155Swblock 275277155Swblockvoid 276277155SwblockVGLCheckSwitch() 277277155Swblock{ 278277155Swblock while (VGLSwitchPending) { 279277155Swblock unsigned int offset; 280277155Swblock unsigned int len; 281277155Swblock int i; 282277155Swblock 283277155Swblock VGLSwitchPending = 0; 284277155Swblock if (VGLOnDisplay) { 285277155Swblock ioctl(0, KDENABIO, 0); 286277155Swblock ioctl(0, KDSETMODE, KD_GRAPHICS); 287264269Ssbruno ioctl(0, VGLMode, 0); 288266272Ssbruno VGLCurWindow = 0; 289277155Swblock VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE, 290277155Swblock MAP_FILE, 0, 0); 291264269Ssbruno 292264269Ssbruno /* XXX: what if mmap() has failed! */ 293264269Ssbruno VGLDisplay->Type = VIDBUF8; /* XXX */ 294264269Ssbruno switch (VGLModeInfo.vi_mem_model) { 295266272Ssbruno case V_INFO_MM_PLANAR: 296264269Ssbruno if (VGLModeInfo.vi_depth == 4 && VGLModeInfo.vi_planes == 4) { 297264269Ssbruno if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 298264269Ssbruno VGLDisplay->Type = VIDBUF4S; 299 else 300 VGLDisplay->Type = VIDBUF4; 301 } else { 302 /* shouldn't be happening */ 303 } 304 break; 305 case V_INFO_MM_PACKED: 306 if (VGLModeInfo.vi_depth == 8) { 307 if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) 308 VGLDisplay->Type = VIDBUF8S; 309 else 310 VGLDisplay->Type = VIDBUF8; 311 } else { 312 /* shouldn't be happening */ 313 } 314 break; 315 case V_INFO_MM_VGAX: 316 VGLDisplay->Type = VIDBUF8X; 317 break; 318 default: 319 /* shouldn't be happening */ 320 break; 321 } 322 323 VGLDisplay->Bitmap = VGLMem; 324 VGLDisplay->Xsize = VGLModeInfo.vi_width; 325 VGLDisplay->Ysize = VGLModeInfo.vi_height; 326 VGLSetVScreenSize(VGLDisplay, VGLDisplay->VXsize, VGLDisplay->VYsize); 327 VGLPanScreen(VGLDisplay, VGLDisplay->Xorigin, VGLDisplay->Yorigin); 328 switch (VGLDisplay->Type) { 329 case VIDBUF4S: 330 outb(0x3c6, 0xff); 331 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 332 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 333 for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes; 334 offset += len) { 335 VGLSetSegment(offset); 336 len = min(VGLBufSize/VGLModeInfo.vi_planes - offset, 337 VGLAdpInfo.va_window_size); 338 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 339 outb(0x3c4, 0x02); 340 outb(0x3c5, 0x01<<i); 341 bcopy(&VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset], 342 VGLMem, len); 343 } 344 } 345 break; 346 case VIDBUF4: 347 case VIDBUF8X: 348 outb(0x3c6, 0xff); 349 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 350 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 351 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 352 outb(0x3c4, 0x02); 353 outb(0x3c5, 0x01<<i); 354 bcopy(&VGLBuf[i*VGLAdpInfo.va_window_size], VGLMem, 355 VGLAdpInfo.va_window_size); 356 } 357 break; 358 case VIDBUF8: 359 case VIDBUF8S: 360 for (offset = 0; offset < VGLBufSize; offset += len) { 361 VGLSetSegment(offset); 362 len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size); 363 bcopy(&VGLBuf[offset], VGLMem, len); 364 } 365 break; 366 } 367 VGLRestorePalette(); 368 ioctl(0, VT_RELDISP, VT_ACKACQ); 369 } 370 else { 371 switch (VGLDisplay->Type) { 372 case VIDBUF4S: 373 for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes; 374 offset += len) { 375 VGLSetSegment(offset); 376 len = min(VGLBufSize/VGLModeInfo.vi_planes - offset, 377 VGLAdpInfo.va_window_size); 378 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 379 outb(0x3ce, 0x04); 380 outb(0x3cf, i); 381 bcopy(VGLMem, &VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset], 382 len); 383 } 384 } 385 break; 386 case VIDBUF4: 387 case VIDBUF8X: 388 /* 389 * NOTE: the saved buffer is NOT in the MEMBUF format which 390 * the ordinary memory bitmap object is stored in. XXX 391 */ 392 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 393 outb(0x3ce, 0x04); 394 outb(0x3cf, i); 395 bcopy(VGLMem, &VGLBuf[i*VGLAdpInfo.va_window_size], 396 VGLAdpInfo.va_window_size); 397 } 398 break; 399 case VIDBUF8: 400 case VIDBUF8S: 401 for (offset = 0; offset < VGLBufSize; offset += len) { 402 VGLSetSegment(offset); 403 len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size); 404 bcopy(VGLMem, &VGLBuf[offset], len); 405 } 406 break; 407 } 408 VGLMem = MAP_FAILED; 409 munmap(VGLDisplay->Bitmap, VGLAdpInfo.va_window_size); 410 ioctl(0, VGLOldMode, 0); 411 ioctl(0, KDSETMODE, KD_TEXT); 412 ioctl(0, KDDISABIO, 0); 413 ioctl(0, VT_RELDISP, VT_TRUE); 414 VGLDisplay->Bitmap = VGLBuf; 415 VGLDisplay->Type = MEMBUF; 416 VGLDisplay->Xsize = VGLDisplay->VXsize; 417 VGLDisplay->Ysize = VGLDisplay->VYsize; 418 while (!VGLOnDisplay) pause(); 419 } 420 } 421} 422 423int 424VGLSetSegment(unsigned int offset) 425{ 426 if (offset/VGLAdpInfo.va_window_size != VGLCurWindow) { 427 ioctl(0, CONS_SETWINORG, offset); /* FBIO_SETWINORG */ 428 VGLCurWindow = offset/VGLAdpInfo.va_window_size; 429 } 430 return (offset%VGLAdpInfo.va_window_size); 431} 432 433int 434VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize) 435{ 436 if (VXsize < object->Xsize || VYsize < object->Ysize) 437 return -1; 438 if (object->Type == MEMBUF) 439 return -1; 440 if (ioctl(0, FBIO_SETLINEWIDTH, &VXsize)) 441 return -1; 442 ioctl(0, CONS_ADPINFO, &VGLAdpInfo); /* FBIO_ADPINFO */ 443 object->VXsize = VGLAdpInfo.va_line_width 444 *8/(VGLModeInfo.vi_depth/VGLModeInfo.vi_planes); 445 object->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width; 446 if (VYsize < object->VYsize) 447 object->VYsize = VYsize; 448 449#ifdef LIBVGL_DEBUG 450 fprintf(stderr, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n", 451 object->Xsize, object->Ysize, object->VXsize, object->VYsize); 452#endif 453 454 return 0; 455} 456 457int 458VGLPanScreen(VGLBitmap *object, int x, int y) 459{ 460 video_display_start_t origin; 461 462 if (x < 0 || x + object->Xsize > object->VXsize 463 || y < 0 || y + object->Ysize > object->VYsize) 464 return -1; 465 if (object->Type == MEMBUF) 466 return 0; 467 origin.x = x; 468 origin.y = y; 469 if (ioctl(0, FBIO_SETDISPSTART, &origin)) 470 return -1; 471 object->Xorigin = x; 472 object->Yorigin = y; 473 474#ifdef LIBVGL_DEBUG 475 fprintf(stderr, "new origin: (%d, %d)\n", x, y); 476#endif 477 478 return 0; 479} 480