1 2/* 3 * XFree86 vbe module 4 * Copyright 2000 Egbert Eich 5 * 6 * The mode query/save/set/restore functions from the vesa driver 7 * have been moved here. 8 * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com) 9 * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br> 10 */ 11 12#ifdef HAVE_XORG_CONFIG_H 13#include <xorg-config.h> 14#endif 15 16#include <string.h> 17 18#include "xf86.h" 19#include "xf86Modes.h" 20#include "vbe.h" 21#include <X11/extensions/dpmsconst.h> 22 23#define VERSION(x) VBE_VERSION_MAJOR(x),VBE_VERSION_MINOR(x) 24 25#if X_BYTE_ORDER == X_LITTLE_ENDIAN 26#define B_O16(x) (x) 27#define B_O32(x) (x) 28#else 29#define B_O16(x) ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8)) 30#define B_O32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \ 31 | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24)) 32#endif 33#define L_ADD(x) (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00) 34 35#define FARP(p) (((unsigned)(p & 0xffff0000) >> 12) | (p & 0xffff)) 36#define R16(v) ((v) & 0xffff) 37 38static unsigned char * vbeReadEDID(vbeInfoPtr pVbe); 39static Bool vbeProbeDDC(vbeInfoPtr pVbe); 40 41static const char vbeVersionString[] = "VBE2"; 42 43vbeInfoPtr 44VBEInit(xf86Int10InfoPtr pInt, int entityIndex) 45{ 46 return VBEExtendedInit(pInt, entityIndex, 0); 47} 48 49vbeInfoPtr 50VBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags) 51{ 52 int RealOff; 53 pointer page = NULL; 54 ScrnInfoPtr pScrn = xf86FindScreenForEntity(entityIndex); 55 vbeControllerInfoPtr vbe = NULL; 56 Bool init_int10 = FALSE; 57 vbeInfoPtr vip = NULL; 58 int screen; 59 60 if (!pScrn) return NULL; 61 screen = pScrn->scrnIndex; 62 63 if (!pInt) { 64 if (!xf86LoadSubModule(pScrn, "int10")) 65 goto error; 66 67 xf86DrvMsg(screen,X_INFO,"initializing int10\n"); 68 pInt = xf86ExtendedInitInt10(entityIndex,Flags); 69 if (!pInt) 70 goto error; 71 init_int10 = TRUE; 72 } 73 74 page = xf86Int10AllocPages(pInt,1,&RealOff); 75 if (!page) goto error; 76 vbe = (vbeControllerInfoPtr) page; 77 memcpy(vbe->VbeSignature,vbeVersionString,4); 78 79 pInt->ax = 0x4F00; 80 pInt->es = SEG_ADDR(RealOff); 81 pInt->di = SEG_OFF(RealOff); 82 pInt->num = 0x10; 83 84 xf86ExecX86int10(pInt); 85 86 if ((pInt->ax & 0xff) != 0x4f) { 87 xf86DrvMsgVerb(screen,X_INFO,3,"VESA BIOS not detected\n"); 88 goto error; 89 } 90 91 switch (pInt->ax & 0xff00) { 92 case 0: 93 xf86DrvMsg(screen,X_INFO,"VESA BIOS detected\n"); 94 break; 95 case 0x100: 96 xf86DrvMsg(screen,X_INFO,"VESA BIOS function failed\n"); 97 goto error; 98 case 0x200: 99 xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported\n"); 100 goto error; 101 case 0x300: 102 xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported in current mode\n"); 103 goto error; 104 default: 105 xf86DrvMsg(screen,X_INFO,"Invalid\n"); 106 goto error; 107 } 108 109 xf86DrvMsgVerb(screen, X_INFO, 4, 110 "VbeVersion is %d, OemStringPtr is 0x%08lx,\n" 111 "\tOemVendorNamePtr is 0x%08lx, OemProductNamePtr is 0x%08lx,\n" 112 "\tOemProductRevPtr is 0x%08lx\n", 113 vbe->VbeVersion, (unsigned long)vbe->OemStringPtr, 114 (unsigned long)vbe->OemVendorNamePtr, 115 (unsigned long)vbe->OemProductNamePtr, 116 (unsigned long)vbe->OemProductRevPtr); 117 118 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Version %i.%i\n", 119 VERSION(vbe->VbeVersion)); 120 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Total Mem: %i kB\n", 121 vbe->TotalMem * 64); 122 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM: %s\n", 123 (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemStringPtr))); 124 125 if (B_O16(vbe->VbeVersion) >= 0x200) { 126 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Software Rev: %i.%i\n", 127 VERSION(vbe->OemSoftwareRev)); 128 if (vbe->OemVendorNamePtr) 129 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Vendor: %s\n", 130 (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemVendorNamePtr))); 131 if (vbe->OemProductNamePtr) 132 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product: %s\n", 133 (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductNamePtr))); 134 if (vbe->OemProductRevPtr) 135 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product Rev: %s\n", 136 (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductRevPtr))); 137 } 138 vip = (vbeInfoPtr)xnfalloc(sizeof(vbeInfoRec)); 139 vip->version = B_O16(vbe->VbeVersion); 140 vip->pInt10 = pInt; 141 vip->ddc = DDC_UNCHECKED; 142 vip->memory = page; 143 vip->real_mode_base = RealOff; 144 vip->num_pages = 1; 145 vip->init_int10 = init_int10; 146 147 return vip; 148 149 error: 150 if (page) 151 xf86Int10FreePages(pInt, page, 1); 152 if (init_int10) 153 xf86FreeInt10(pInt); 154 return NULL; 155} 156 157void 158vbeFree(vbeInfoPtr pVbe) 159{ 160 if (!pVbe) 161 return; 162 163 xf86Int10FreePages(pVbe->pInt10,pVbe->memory,pVbe->num_pages); 164 /* If we have initalized int10 we ought to free it, too */ 165 if (pVbe->init_int10) 166 xf86FreeInt10(pVbe->pInt10); 167 free(pVbe); 168 return; 169} 170 171static Bool 172vbeProbeDDC(vbeInfoPtr pVbe) 173{ 174 char *ddc_level; 175 int screen = pVbe->pInt10->scrnIndex; 176 177 if (pVbe->ddc == DDC_NONE) 178 return FALSE; 179 if (pVbe->ddc != DDC_UNCHECKED) 180 return TRUE; 181 182 pVbe->pInt10->ax = 0x4F15; 183 pVbe->pInt10->bx = 0; 184 pVbe->pInt10->cx = 0; 185 pVbe->pInt10->es = 0; 186 pVbe->pInt10->di = 0; 187 pVbe->pInt10->num = 0x10; 188 189 xf86ExecX86int10(pVbe->pInt10); 190 191 if ((pVbe->pInt10->ax & 0xff) != 0x4f) { 192 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC not supported\n"); 193 pVbe->ddc = DDC_NONE; 194 return FALSE; 195 } 196 197 switch ((pVbe->pInt10->ax >> 8) & 0xff) { 198 case 0: 199 xf86DrvMsg(screen,X_INFO,"VESA VBE DDC supported\n"); 200 switch (pVbe->pInt10->bx & 0x3) { 201 case 0: 202 ddc_level = " none"; 203 pVbe->ddc = DDC_NONE; 204 break; 205 case 1: 206 ddc_level = " 1"; 207 pVbe->ddc = DDC_1; 208 break; 209 case 2: 210 ddc_level = " 2"; 211 pVbe->ddc = DDC_2; 212 break; 213 case 3: 214 ddc_level = " 1 + 2"; 215 pVbe->ddc = DDC_1_2; 216 break; 217 default: 218 ddc_level = ""; 219 pVbe->ddc = DDC_NONE; 220 break; 221 } 222 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Level%s\n",ddc_level); 223 if (pVbe->pInt10->bx & 0x4) { 224 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Screen blanked" 225 "for data transfer\n"); 226 pVbe->ddc_blank = TRUE; 227 } else 228 pVbe->ddc_blank = FALSE; 229 230 xf86DrvMsgVerb(screen,X_INFO,3, 231 "VESA VBE DDC transfer in appr. %x sec.\n", 232 (pVbe->pInt10->bx >> 8) & 0xff); 233 } 234 235 return TRUE; 236} 237 238typedef enum { 239 VBEOPT_NOVBE, 240 VBEOPT_NODDC 241} VBEOpts; 242 243static const OptionInfoRec VBEOptions[] = { 244 { VBEOPT_NOVBE, "NoVBE", OPTV_BOOLEAN, {0}, FALSE }, 245 { VBEOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE }, 246 { -1, NULL, OPTV_NONE, {0}, FALSE }, 247}; 248 249static unsigned char * 250vbeReadEDID(vbeInfoPtr pVbe) 251{ 252 int RealOff = pVbe->real_mode_base; 253 pointer page = pVbe->memory; 254 unsigned char *tmp = NULL; 255 Bool novbe = FALSE; 256 Bool noddc = FALSE; 257 int screen = pVbe->pInt10->scrnIndex; 258 OptionInfoPtr options; 259 260 if (!page) return NULL; 261 262 options = xnfalloc(sizeof(VBEOptions)); 263 (void)memcpy(options, VBEOptions, sizeof(VBEOptions)); 264 xf86ProcessOptions(screen, xf86Screens[screen]->options, options); 265 xf86GetOptValBool(options, VBEOPT_NOVBE, &novbe); 266 xf86GetOptValBool(options, VBEOPT_NODDC, &noddc); 267 free(options); 268 if (novbe || noddc) return NULL; 269 270 if (!vbeProbeDDC(pVbe)) goto error; 271 272 memset(page,0,sizeof(vbeInfoPtr)); 273 strcpy(page,vbeVersionString); 274 275 pVbe->pInt10->ax = 0x4F15; 276 pVbe->pInt10->bx = 0x01; 277 pVbe->pInt10->cx = 0; 278 pVbe->pInt10->dx = 0; 279 pVbe->pInt10->es = SEG_ADDR(RealOff); 280 pVbe->pInt10->di = SEG_OFF(RealOff); 281 pVbe->pInt10->num = 0x10; 282 283 xf86ExecX86int10(pVbe->pInt10); 284 285 if ((pVbe->pInt10->ax & 0xff) != 0x4f) { 286 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC invalid\n"); 287 goto error; 288 } 289 switch (pVbe->pInt10->ax & 0xff00) { 290 case 0x0: 291 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read successfully\n"); 292 tmp = (unsigned char *)xnfalloc(128); 293 memcpy(tmp,page,128); 294 break; 295 case 0x100: 296 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read failed\n"); 297 break; 298 default: 299 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC unkown failure %i\n", 300 pVbe->pInt10->ax & 0xff00); 301 break; 302 } 303 304 error: 305 return tmp; 306} 307 308xf86MonPtr 309vbeDoEDID(vbeInfoPtr pVbe, pointer pDDCModule) 310{ 311 xf86MonPtr pMonitor; 312 pointer pModule; 313 unsigned char *DDC_data = NULL; 314 315 if (!pVbe) return NULL; 316 if (pVbe->version < 0x200) 317 return NULL; 318 319 if (!(pModule = pDDCModule)) { 320 pModule = 321 xf86LoadSubModule(xf86Screens[pVbe->pInt10->scrnIndex], "ddc"); 322 if (!pModule) 323 return NULL; 324 } 325 326 DDC_data = vbeReadEDID(pVbe); 327 328 if (!DDC_data) 329 return NULL; 330 331 pMonitor = xf86InterpretEDID(pVbe->pInt10->scrnIndex, DDC_data); 332 333 if (!pDDCModule) 334 xf86UnloadSubModule(pModule); 335 return pMonitor; 336} 337 338#define GET_UNALIGNED2(x) \ 339 ((*(CARD16*)(x)) | (*(((CARD16*)(x) + 1))) << 16) 340 341VbeInfoBlock * 342VBEGetVBEInfo(vbeInfoPtr pVbe) 343{ 344 VbeInfoBlock *block = NULL; 345 int i, pStr, pModes; 346 char *str; 347 CARD16 major, *modes; 348 349 memset(pVbe->memory, 0, sizeof(VbeInfoBlock)); 350 351 /* 352 Input: 353 AH := 4Fh Super VGA support 354 AL := 00h Return Super VGA information 355 ES:DI := Pointer to buffer 356 357 Output: 358 AX := status 359 (All other registers are preserved) 360 */ 361 362 ((char*)pVbe->memory)[0] = 'V'; 363 ((char*)pVbe->memory)[1] = 'B'; 364 ((char*)pVbe->memory)[2] = 'E'; 365 ((char*)pVbe->memory)[3] = '2'; 366 367 pVbe->pInt10->num = 0x10; 368 pVbe->pInt10->ax = 0x4f00; 369 pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); 370 pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); 371 xf86ExecX86int10(pVbe->pInt10); 372 373 if (R16(pVbe->pInt10->ax) != 0x4f) 374 return NULL; 375 376 block = calloc(sizeof(VbeInfoBlock), 1); 377 block->VESASignature[0] = ((char*)pVbe->memory)[0]; 378 block->VESASignature[1] = ((char*)pVbe->memory)[1]; 379 block->VESASignature[2] = ((char*)pVbe->memory)[2]; 380 block->VESASignature[3] = ((char*)pVbe->memory)[3]; 381 382 block->VESAVersion = *(CARD16*)(((char*)pVbe->memory) + 4); 383 major = (unsigned)block->VESAVersion >> 8; 384 385 pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 6)); 386 str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); 387 block->OEMStringPtr = strdup(str); 388 389 block->Capabilities[0] = ((char*)pVbe->memory)[10]; 390 block->Capabilities[1] = ((char*)pVbe->memory)[11]; 391 block->Capabilities[2] = ((char*)pVbe->memory)[12]; 392 block->Capabilities[3] = ((char*)pVbe->memory)[13]; 393 394 pModes = GET_UNALIGNED2((((char*)pVbe->memory) + 14)); 395 modes = xf86int10Addr(pVbe->pInt10, FARP(pModes)); 396 i = 0; 397 while (modes[i] != 0xffff) 398 i++; 399 block->VideoModePtr = malloc(sizeof(CARD16) * (i + 1)); 400 memcpy(block->VideoModePtr, modes, sizeof(CARD16) * i); 401 block->VideoModePtr[i] = 0xffff; 402 403 block->TotalMemory = *(CARD16*)(((char*)pVbe->memory) + 18); 404 405 if (major < 2) 406 memcpy(&block->OemSoftwareRev, ((char*)pVbe->memory) + 20, 236); 407 else { 408 block->OemSoftwareRev = *(CARD16*)(((char*)pVbe->memory) + 20); 409 pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 22)); 410 str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); 411 block->OemVendorNamePtr = strdup(str); 412 pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 26)); 413 str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); 414 block->OemProductNamePtr = strdup(str); 415 pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 30)); 416 str = xf86int10Addr(pVbe->pInt10, FARP(pStr)); 417 block->OemProductRevPtr = strdup(str); 418 memcpy(&block->Reserved, ((char*)pVbe->memory) + 34, 222); 419 memcpy(&block->OemData, ((char*)pVbe->memory) + 256, 256); 420 } 421 422 return block; 423} 424 425void 426VBEFreeVBEInfo(VbeInfoBlock *block) 427{ 428 free(block->OEMStringPtr); 429 free(block->VideoModePtr); 430 if (((unsigned)block->VESAVersion >> 8) >= 2) { 431 free(block->OemVendorNamePtr); 432 free(block->OemProductNamePtr); 433 free(block->OemProductRevPtr); 434 } 435 free(block); 436} 437 438Bool 439VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock *block) 440{ 441 /* 442 Input: 443 AH := 4Fh Super VGA support 444 AL := 02h Set Super VGA video mode 445 BX := Video mode 446 D0-D8 := Mode number 447 D9-D10 := Reserved (must be 0) 448 D11 := 0 Use current default refresh rate 449 := 1 Use user specified CRTC values for refresh rate 450 D12-13 Reserved for VBE/AF (must be 0) 451 D14 := 0 Use windowed frame buffer model 452 := 1 Use linear/flat frame buffer model 453 D15 := 0 Clear video memory 454 := 1 Don't clear video memory 455 ES:DI := Pointer to VbeCRTCInfoBlock structure 456 457 Output: AX = Status 458 (All other registers are preserved) 459 */ 460 pVbe->pInt10->num = 0x10; 461 pVbe->pInt10->ax = 0x4f02; 462 pVbe->pInt10->bx = mode; 463 if (block) { 464 pVbe->pInt10->bx |= 1 << 11; 465 memcpy(pVbe->memory, block, sizeof(VbeCRTCInfoBlock)); 466 pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); 467 pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); 468 } else 469 pVbe->pInt10->bx &= ~(1 << 11); 470 471 xf86ExecX86int10(pVbe->pInt10); 472 473 return (R16(pVbe->pInt10->ax) == 0x4f); 474} 475 476Bool 477VBEGetVBEMode(vbeInfoPtr pVbe, int *mode) 478{ 479 /* 480 Input: 481 AH := 4Fh Super VGA support 482 AL := 03h Return current video mode 483 484 Output: 485 AX := Status 486 BX := Current video mode 487 (All other registers are preserved) 488 */ 489 pVbe->pInt10->num = 0x10; 490 pVbe->pInt10->ax = 0x4f03; 491 492 xf86ExecX86int10(pVbe->pInt10); 493 494 if (R16(pVbe->pInt10->ax) == 0x4f) { 495 *mode = R16(pVbe->pInt10->bx); 496 497 return TRUE; 498 } 499 500 return FALSE; 501} 502 503VbeModeInfoBlock * 504VBEGetModeInfo(vbeInfoPtr pVbe, int mode) 505{ 506 VbeModeInfoBlock *block = NULL; 507 508 memset(pVbe->memory, 0, sizeof(VbeModeInfoBlock)); 509 510 /* 511 Input: 512 AH := 4Fh Super VGA support 513 AL := 01h Return Super VGA mode information 514 CX := Super VGA video mode 515 (mode number must be one of those returned by Function 0) 516 ES:DI := Pointer to buffer 517 518 Output: 519 AX := status 520 (All other registers are preserved) 521 */ 522 pVbe->pInt10->num = 0x10; 523 pVbe->pInt10->ax = 0x4f01; 524 pVbe->pInt10->cx = mode; 525 pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); 526 pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); 527 xf86ExecX86int10(pVbe->pInt10); 528 if (R16(pVbe->pInt10->ax) != 0x4f) 529 return NULL; 530 531 block = malloc(sizeof(VbeModeInfoBlock)); 532 if (block) 533 memcpy(block, pVbe->memory, sizeof(*block)); 534 535 return block; 536} 537 538void 539VBEFreeModeInfo(VbeModeInfoBlock *block) 540{ 541 free(block); 542} 543 544Bool 545VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function, 546 pointer *memory, int *size, int *real_mode_pages) 547{ 548 /* 549 Input: 550 AH := 4Fh Super VGA support 551 AL := 04h Save/restore Super VGA video state 552 DL := 00h Return save/restore state buffer size 553 CX := Requested states 554 D0 = Save/restore video hardware state 555 D1 = Save/restore video BIOS data state 556 D2 = Save/restore video DAC state 557 D3 = Save/restore Super VGA state 558 559 Output: 560 AX = Status 561 BX = Number of 64-byte blocks to hold the state buffer 562 (All other registers are preserved) 563 564 565 Input: 566 AH := 4Fh Super VGA support 567 AL := 04h Save/restore Super VGA video state 568 DL := 01h Save Super VGA video state 569 CX := Requested states (see above) 570 ES:BX := Pointer to buffer 571 572 Output: 573 AX := Status 574 (All other registers are preserved) 575 576 577 Input: 578 AH := 4Fh Super VGA support 579 AL := 04h Save/restore Super VGA video state 580 DL := 02h Restore Super VGA video state 581 CX := Requested states (see above) 582 ES:BX := Pointer to buffer 583 584 Output: 585 AX := Status 586 (All other registers are preserved) 587 */ 588 589 if ((pVbe->version & 0xff00) > 0x100) { 590 int screen = pVbe->pInt10->scrnIndex; 591 if (function == MODE_QUERY || 592 (function == MODE_SAVE && !*memory)) { 593 /* Query amount of memory to save state */ 594 595 pVbe->pInt10->num = 0x10; 596 pVbe->pInt10->ax = 0x4f04; 597 pVbe->pInt10->dx = 0; 598 pVbe->pInt10->cx = 0x000f; 599 xf86ExecX86int10(pVbe->pInt10); 600 if (R16(pVbe->pInt10->ax) != 0x4f) 601 return FALSE; 602 603 if (function == MODE_SAVE) { 604 int npages = (R16(pVbe->pInt10->bx) * 64) / 4096 + 1; 605 if ((*memory = xf86Int10AllocPages(pVbe->pInt10, npages, 606 real_mode_pages)) == NULL) { 607 xf86DrvMsg(screen, X_ERROR, 608 "Cannot allocate memory to save SVGA state.\n"); 609 return FALSE; 610 } 611 } 612 *size = pVbe->pInt10->bx * 64; 613 } 614 615 /* Save/Restore Super VGA state */ 616 if (function != MODE_QUERY) { 617 618 if (!*memory) return FALSE; 619 pVbe->pInt10->num = 0x10; 620 pVbe->pInt10->ax = 0x4f04; 621 switch (function) { 622 case MODE_SAVE: 623 pVbe->pInt10->dx = 1; 624 break; 625 case MODE_RESTORE: 626 pVbe->pInt10->dx = 2; 627 break; 628 case MODE_QUERY: 629 return FALSE; 630 } 631 pVbe->pInt10->cx = 0x000f; 632 633 pVbe->pInt10->es = SEG_ADDR(*real_mode_pages); 634 pVbe->pInt10->bx = SEG_OFF(*real_mode_pages); 635 xf86ExecX86int10(pVbe->pInt10); 636 return (R16(pVbe->pInt10->ax) == 0x4f); 637 638 } 639 } 640 return TRUE; 641} 642 643Bool 644VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window) 645{ 646 /* 647 Input: 648 AH := 4Fh Super VGA support 649 AL := 05h 650 651 Output: 652 */ 653 pVbe->pInt10->num = 0x10; 654 pVbe->pInt10->ax = 0x4f05; 655 pVbe->pInt10->bx = window; 656 pVbe->pInt10->dx = iBank; 657 xf86ExecX86int10(pVbe->pInt10); 658 659 if (R16(pVbe->pInt10->ax) != 0x4f) 660 return FALSE; 661 662 return TRUE; 663} 664 665Bool 666VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command, 667 int width, int *pixels, int *bytes, int *max) 668{ 669 if (command < SCANWID_SET || command > SCANWID_GET_MAX) 670 return FALSE; 671 672 /* 673 Input: 674 AX := 4F06h VBE Set/Get Logical Scan Line Length 675 BL := 00h Set Scan Line Length in Pixels 676 := 01h Get Scan Line Length 677 := 02h Set Scan Line Length in Bytes 678 := 03h Get Maximum Scan Line Length 679 CX := If BL=00h Desired Width in Pixels 680 If BL=02h Desired Width in Bytes 681 (Ignored for Get Functions) 682 683 Output: 684 AX := VBE Return Status 685 BX := Bytes Per Scan Line 686 CX := Actual Pixels Per Scan Line 687 (truncated to nearest complete pixel) 688 DX := Maximum Number of Scan Lines 689 */ 690 691 pVbe->pInt10->num = 0x10; 692 pVbe->pInt10->ax = 0x4f06; 693 pVbe->pInt10->bx = command; 694 if (command == SCANWID_SET || command == SCANWID_SET_BYTES) 695 pVbe->pInt10->cx = width; 696 xf86ExecX86int10(pVbe->pInt10); 697 698 if (R16(pVbe->pInt10->ax) != 0x4f) 699 return FALSE; 700 701 if (command == SCANWID_GET || command == SCANWID_GET_MAX) { 702 if (pixels) 703 *pixels = R16(pVbe->pInt10->cx); 704 if (bytes) 705 *bytes = R16(pVbe->pInt10->bx); 706 if (max) 707 *max = R16(pVbe->pInt10->dx); 708 } 709 710 return TRUE; 711} 712 713Bool 714VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace) 715{ 716 pVbe->pInt10->num = 0x10; 717 pVbe->pInt10->ax = 0x4f07; 718 pVbe->pInt10->bx = wait_retrace ? 0x80 : 0x00; 719 pVbe->pInt10->cx = x; 720 pVbe->pInt10->dx = y; 721 xf86ExecX86int10(pVbe->pInt10); 722 723 if (R16(pVbe->pInt10->ax) != 0x4f) 724 return FALSE; 725 726 return TRUE; 727} 728 729Bool 730VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y) 731{ 732 pVbe->pInt10->num = 0x10; 733 pVbe->pInt10->ax = 0x4f07; 734 pVbe->pInt10->bx = 0x01; 735 xf86ExecX86int10(pVbe->pInt10); 736 737 if (R16(pVbe->pInt10->ax) != 0x4f) 738 return FALSE; 739 740 *x = pVbe->pInt10->cx; 741 *y = pVbe->pInt10->dx; 742 743 return TRUE; 744} 745 746int 747VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits) 748{ 749 /* 750 Input: 751 AX := 4F08h VBE Set/Get Palette Format 752 BL := 00h Set DAC Palette Format 753 := 01h Get DAC Palette Format 754 BH := Desired bits of color per primary 755 (Set DAC Palette Format only) 756 757 Output: 758 AX := VBE Return Status 759 BH := Current number of bits of color per primary 760 */ 761 762 pVbe->pInt10->num = 0x10; 763 pVbe->pInt10->ax = 0x4f08; 764 if (!bits) 765 pVbe->pInt10->bx = 0x01; 766 else 767 pVbe->pInt10->bx = (bits & 0x00ff) << 8; 768 xf86ExecX86int10(pVbe->pInt10); 769 770 if (R16(pVbe->pInt10->ax) != 0x4f) 771 return 0; 772 773 return (bits != 0 ? bits : (pVbe->pInt10->bx >> 8) & 0x00ff); 774} 775 776CARD32 * 777VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num, 778 CARD32 *data, Bool secondary, Bool wait_retrace) 779{ 780 /* 781 Input: 782 (16-bit) 783 AX := 4F09h VBE Load/Unload Palette Data 784 BL := 00h Set Palette Data 785 := 01h Get Palette Data 786 := 02h Set Secondary Palette Data 787 := 03h Get Secondary Palette Data 788 := 80h Set Palette Data during Vertical Retrace 789 CX := Number of palette registers to update (to a maximum of 256) 790 DX := First of the palette registers to update (start) 791 ES:DI := Table of palette values (see below for format) 792 793 Output: 794 AX := VBE Return Status 795 796 797 Input: 798 (32-bit) 799 BL := 00h Set Palette Data 800 := 80h Set Palette Data during Vertical Retrace 801 CX := Number of palette registers to update (to a maximum of 256) 802 DX := First of the palette registers to update (start) 803 ES:EDI := Table of palette values (see below for format) 804 DS := Selector for memory mapped registers 805 */ 806 807 pVbe->pInt10->num = 0x10; 808 pVbe->pInt10->ax = 0x4f09; 809 if (!secondary) 810 pVbe->pInt10->bx = set && wait_retrace ? 0x80 : set ? 0 : 1; 811 else 812 pVbe->pInt10->bx = set ? 2 : 3; 813 pVbe->pInt10->cx = num; 814 pVbe->pInt10->dx = first; 815 pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base); 816 pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base); 817 if (set) 818 memcpy(pVbe->memory, data, num * sizeof(CARD32)); 819 xf86ExecX86int10(pVbe->pInt10); 820 821 if (R16(pVbe->pInt10->ax) != 0x4f) 822 return NULL; 823 824 if (set) 825 return data; 826 827 data = malloc(num * sizeof(CARD32)); 828 memcpy(data, pVbe->memory, num * sizeof(CARD32)); 829 830 return data; 831} 832 833VBEpmi * 834VBEGetVBEpmi(vbeInfoPtr pVbe) 835{ 836 VBEpmi *pmi; 837 838 /* 839 Input: 840 AH := 4Fh Super VGA support 841 AL := 0Ah Protected Mode Interface 842 BL := 00h Return Protected Mode Table 843 844 Output: 845 AX := Status 846 ES := Real Mode Segment of Table 847 DI := Offset of Table 848 CX := Lenght of Table including protected mode code in bytes (for copying purposes) 849 (All other registers are preserved) 850 */ 851 852 pVbe->pInt10->num = 0x10; 853 pVbe->pInt10->ax = 0x4f0a; 854 pVbe->pInt10->bx = 0; 855 pVbe->pInt10->di = 0; 856 xf86ExecX86int10(pVbe->pInt10); 857 858 if (R16(pVbe->pInt10->ax) != 0x4f) 859 return NULL; 860 861 pmi = malloc(sizeof(VBEpmi)); 862 pmi->seg_tbl = R16(pVbe->pInt10->es); 863 pmi->tbl_off = R16(pVbe->pInt10->di); 864 pmi->tbl_len = R16(pVbe->pInt10->cx); 865 866 return pmi; 867} 868 869#if 0 870vbeModeInfoPtr 871VBEBuildVbeModeList(vbeInfoPtr pVbe, VbeInfoBlock *vbe) 872{ 873 vbeModeInfoPtr ModeList = NULL; 874 875 int i = 0; 876 while (vbe->VideoModePtr[i] != 0xffff) { 877 vbeModeInfoPtr m; 878 VbeModeInfoBlock *mode; 879 int id = vbe->VideoModePtr[i++]; 880 int bpp; 881 882 if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) 883 continue; 884 885 bpp = mode->BitsPerPixel; 886 887 m = xnfcalloc(sizeof(vbeModeInfoRec),1); 888 m->width = mode->XResolution; 889 m->height = mode->YResolution; 890 m->bpp = bpp; 891 m->n = id; 892 m->next = ModeList; 893 894 xf86DrvMsgVerb(pVbe->pInt10->scrnIndex, X_PROBED, 3, 895 "BIOS reported VESA mode 0x%x: x:%i y:%i bpp:%i\n", 896 m->n, m->width, m->height, m->bpp); 897 898 ModeList = m; 899 900 VBEFreeModeInfo(mode); 901 } 902 return ModeList; 903} 904 905unsigned short 906VBECalcVbeModeIndex(vbeModeInfoPtr m, DisplayModePtr mode, int bpp) 907{ 908 while (m) { 909 if (bpp == m->bpp 910 && mode->HDisplay == m->width 911 && mode->VDisplay == m->height) 912 return m->n; 913 m = m->next; 914 } 915 return 0; 916} 917#endif 918 919void 920VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr, 921 vbeSaveRestoreFunction function) 922{ 923 Bool SaveSucc = FALSE; 924 925 if (VBE_VERSION_MAJOR(pVbe->version) > 1 926 && (function == MODE_SAVE || vbe_sr->pstate)) { 927 if (function == MODE_RESTORE) 928 memcpy(vbe_sr->state, vbe_sr->pstate, vbe_sr->stateSize); 929 ErrorF("VBESaveRestore\n"); 930 if ((VBESaveRestore(pVbe,function, 931 (pointer)&vbe_sr->state, 932 &vbe_sr->stateSize,&vbe_sr->statePage))) { 933 if (function == MODE_SAVE) { 934 SaveSucc = TRUE; 935 vbe_sr->stateMode = -1; /* invalidate */ 936 /* don't rely on the memory not being touched */ 937 if (vbe_sr->pstate == NULL) 938 vbe_sr->pstate = malloc(vbe_sr->stateSize); 939 memcpy(vbe_sr->pstate, vbe_sr->state, vbe_sr->stateSize); 940 } 941 ErrorF("VBESaveRestore done with success\n"); 942 return; 943 } 944 ErrorF("VBESaveRestore done\n"); 945 } 946 947 if (function == MODE_SAVE && !SaveSucc) 948 (void)VBEGetVBEMode(pVbe, &vbe_sr->stateMode); 949 950 if (function == MODE_RESTORE && vbe_sr->stateMode != -1) 951 VBESetVBEMode(pVbe, vbe_sr->stateMode, NULL); 952 953} 954 955int 956VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock) 957{ 958 /* 959 Input: 960 AX := 4F0Bh VBE Get Pixel Clock 961 BL := 00h Get Pixel Clock 962 ECX := pixel clock in units of Hz 963 DX := mode number 964 965 Output: 966 AX := VBE Return Status 967 ECX := Closest pixel clock 968 */ 969 970 pVbe->pInt10->num = 0x10; 971 pVbe->pInt10->ax = 0x4f0b; 972 pVbe->pInt10->bx = 0x00; 973 pVbe->pInt10->cx = clock; 974 pVbe->pInt10->dx = mode; 975 xf86ExecX86int10(pVbe->pInt10); 976 977 if (R16(pVbe->pInt10->ax) != 0x4f) 978 return 0; 979 980 return pVbe->pInt10->cx; 981} 982 983Bool 984VBEDPMSSet(vbeInfoPtr pVbe, int mode) 985{ 986 /* 987 Input: 988 AX := 4F10h DPMS 989 BL := 01h Set Display Power State 990 BH := requested power state 991 992 Output: 993 AX := VBE Return Status 994 */ 995 996 pVbe->pInt10->num = 0x10; 997 pVbe->pInt10->ax = 0x4f10; 998 pVbe->pInt10->bx = 0x01; 999 switch (mode) { 1000 case DPMSModeOn: 1001 break; 1002 case DPMSModeStandby: 1003 pVbe->pInt10->bx |= 0x100; 1004 break; 1005 case DPMSModeSuspend: 1006 pVbe->pInt10->bx |= 0x200; 1007 break; 1008 case DPMSModeOff: 1009 pVbe->pInt10->bx |= 0x400; 1010 break; 1011 } 1012 xf86ExecX86int10(pVbe->pInt10); 1013 return (R16(pVbe->pInt10->ax) == 0x4f); 1014} 1015 1016void 1017VBEInterpretPanelID(int scrnIndex, struct vbePanelID *data) 1018{ 1019 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 1020 DisplayModePtr mode; 1021 const float PANEL_HZ = 60.0; 1022 1023 if (!data) 1024 return; 1025 1026 xf86DrvMsg(scrnIndex, X_INFO, "PanelID returned panel resolution %dx%d\n", 1027 data->hsize, data->vsize); 1028 1029 if (pScrn->monitor->nHsync || pScrn->monitor->nVrefresh) 1030 return; 1031 1032 if (data->hsize < 320 || data->vsize < 240) { 1033 xf86DrvMsg(scrnIndex, X_INFO, "...which I refuse to believe\n"); 1034 return; 1035 } 1036 1037 mode = xf86CVTMode(data->hsize, data->vsize, PANEL_HZ, 1, 0); 1038 1039 pScrn->monitor->nHsync = 1; 1040 pScrn->monitor->hsync[0].lo = 29.37; 1041 pScrn->monitor->hsync[0].hi = (float)mode->Clock / (float)mode->HTotal; 1042 pScrn->monitor->nVrefresh = 1; 1043 pScrn->monitor->vrefresh[0].lo = 56.0; 1044 pScrn->monitor->vrefresh[0].hi = 1045 (float)mode->Clock*1000.0 / (float)mode->HTotal / (float)mode->VTotal; 1046 1047 if (pScrn->monitor->vrefresh[0].hi < 59.47) 1048 pScrn->monitor->vrefresh[0].hi = 59.47; 1049 1050 free(mode); 1051} 1052 1053struct vbePanelID * 1054VBEReadPanelID(vbeInfoPtr pVbe) 1055{ 1056 int RealOff = pVbe->real_mode_base; 1057 pointer page = pVbe->memory; 1058 void *tmp = NULL; 1059 int screen = pVbe->pInt10->scrnIndex; 1060 1061 pVbe->pInt10->ax = 0x4F11; 1062 pVbe->pInt10->bx = 0x01; 1063 pVbe->pInt10->cx = 0; 1064 pVbe->pInt10->dx = 0; 1065 pVbe->pInt10->es = SEG_ADDR(RealOff); 1066 pVbe->pInt10->di = SEG_OFF(RealOff); 1067 pVbe->pInt10->num = 0x10; 1068 1069 xf86ExecX86int10(pVbe->pInt10); 1070 1071 if ((pVbe->pInt10->ax & 0xff) != 0x4f) { 1072 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n"); 1073 goto error; 1074 } 1075 1076 switch (pVbe->pInt10->ax & 0xff00) { 1077 case 0x0: 1078 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n"); 1079 tmp = xnfalloc(32); 1080 memcpy(tmp, page, 32); 1081 break; 1082 case 0x100: 1083 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n"); 1084 break; 1085 default: 1086 xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n", 1087 pVbe->pInt10->ax & 0xff00); 1088 break; 1089 } 1090 1091error: 1092 return tmp; 1093} 1094