1#define DEBUG_VERB 2 2/* 3 * Copyright © 2002 David Dawes 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Except as contained in this notice, the name of the author(s) shall 24 * not be used in advertising or otherwise to promote the sale, use or other 25 * dealings in this Software without prior written authorization from 26 * the author(s). 27 * 28 * Authors: David Dawes <dawes@xfree86.org> 29 * 30 */ 31 32#ifdef HAVE_XORG_CONFIG_H 33#include <xorg-config.h> 34#endif 35 36#include <stdio.h> 37#include <string.h> 38 39#include "xf86.h" 40#include "vbe.h" 41#include "vbeModes.h" 42 43static int 44GetDepthFlag(vbeInfoPtr pVbe, int id) 45{ 46 VbeModeInfoBlock *mode; 47 int bpp; 48 49 if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) 50 return 0; 51 52 if (VBE_MODE_USABLE(mode, 0)) { 53 int depth; 54 55 if (VBE_MODE_COLOR(mode)) { 56 depth = mode->RedMaskSize + mode->GreenMaskSize + 57 mode->BlueMaskSize; 58 } 59 else { 60 depth = 1; 61 } 62 bpp = mode->BitsPerPixel; 63 VBEFreeModeInfo(mode); 64 mode = NULL; 65 switch (depth) { 66 case 1: 67 return V_DEPTH_1; 68 case 4: 69 return V_DEPTH_4; 70 case 8: 71 return V_DEPTH_8; 72 case 15: 73 return V_DEPTH_15; 74 case 16: 75 return V_DEPTH_16; 76 case 24: 77 switch (bpp) { 78 case 24: 79 return V_DEPTH_24_24; 80 case 32: 81 return V_DEPTH_24_32; 82 } 83 } 84 } 85 if (mode) 86 VBEFreeModeInfo(mode); 87 return 0; 88} 89 90/* 91 * Find supported mode depths. 92 */ 93int 94VBEFindSupportedDepths(vbeInfoPtr pVbe, VbeInfoBlock * vbe, int *flags24, 95 int modeTypes) 96{ 97 int i = 0; 98 int depths = 0; 99 100 if (modeTypes & V_MODETYPE_VBE) { 101 while (vbe->VideoModePtr[i] != 0xffff) { 102 depths |= GetDepthFlag(pVbe, vbe->VideoModePtr[i++]); 103 } 104 } 105 106 /* 107 * XXX This possibly only works with VBE 3.0 and later. 108 */ 109 if (modeTypes & V_MODETYPE_VGA) { 110 for (i = 0; i < 0x7F; i++) { 111 depths |= GetDepthFlag(pVbe, i); 112 } 113 } 114 115 if (flags24) { 116 if (depths & V_DEPTH_24_24) 117 *flags24 |= Support24bppFb; 118 if (depths & V_DEPTH_24_32) 119 *flags24 |= Support32bppFb; 120 } 121 122 return depths; 123} 124 125static DisplayModePtr 126CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock * vbe, int id, 127 int flags) 128{ 129 CARD16 major; 130 VbeModeInfoBlock *mode; 131 DisplayModePtr pMode; 132 VbeModeInfoData *data; 133 Bool modeOK = FALSE; 134 135 major = (unsigned) (vbe->VESAVersion >> 8); 136 137 if ((mode = VBEGetModeInfo(pVbe, id)) == NULL) 138 return NULL; 139 140 /* Does the mode match the depth/bpp? */ 141 /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */ 142 if (VBE_MODE_USABLE(mode, flags) && 143 ((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) || 144 (mode->BitsPerPixel > 8 && 145 (mode->RedMaskSize + mode->GreenMaskSize + 146 mode->BlueMaskSize) == pScrn->depth && 147 mode->BitsPerPixel == pScrn->bitsPerPixel) || 148 (mode->BitsPerPixel == 15 && pScrn->depth == 15) || 149 (mode->BitsPerPixel <= 8 && 150 mode->BitsPerPixel == pScrn->bitsPerPixel))) { 151 modeOK = TRUE; 152 xf86ErrorFVerb(DEBUG_VERB, "*"); 153 } 154 155 xf86ErrorFVerb(DEBUG_VERB, 156 "Mode: %x (%dx%d)\n", id, mode->XResolution, 157 mode->YResolution); 158 xf86ErrorFVerb(DEBUG_VERB, " ModeAttributes: 0x%x\n", 159 mode->ModeAttributes); 160 xf86ErrorFVerb(DEBUG_VERB, " WinAAttributes: 0x%x\n", 161 mode->WinAAttributes); 162 xf86ErrorFVerb(DEBUG_VERB, " WinBAttributes: 0x%x\n", 163 mode->WinBAttributes); 164 xf86ErrorFVerb(DEBUG_VERB, " WinGranularity: %d\n", 165 mode->WinGranularity); 166 xf86ErrorFVerb(DEBUG_VERB, " WinSize: %d\n", mode->WinSize); 167 xf86ErrorFVerb(DEBUG_VERB, 168 " WinASegment: 0x%x\n", mode->WinASegment); 169 xf86ErrorFVerb(DEBUG_VERB, 170 " WinBSegment: 0x%x\n", mode->WinBSegment); 171 xf86ErrorFVerb(DEBUG_VERB, 172 " WinFuncPtr: 0x%lx\n", (unsigned long) mode->WinFuncPtr); 173 xf86ErrorFVerb(DEBUG_VERB, 174 " BytesPerScanline: %d\n", mode->BytesPerScanline); 175 xf86ErrorFVerb(DEBUG_VERB, " XResolution: %d\n", mode->XResolution); 176 xf86ErrorFVerb(DEBUG_VERB, " YResolution: %d\n", mode->YResolution); 177 xf86ErrorFVerb(DEBUG_VERB, " XCharSize: %d\n", mode->XCharSize); 178 xf86ErrorFVerb(DEBUG_VERB, " YCharSize: %d\n", mode->YCharSize); 179 xf86ErrorFVerb(DEBUG_VERB, 180 " NumberOfPlanes: %d\n", mode->NumberOfPlanes); 181 xf86ErrorFVerb(DEBUG_VERB, 182 " BitsPerPixel: %d\n", mode->BitsPerPixel); 183 xf86ErrorFVerb(DEBUG_VERB, 184 " NumberOfBanks: %d\n", mode->NumberOfBanks); 185 xf86ErrorFVerb(DEBUG_VERB, " MemoryModel: %d\n", mode->MemoryModel); 186 xf86ErrorFVerb(DEBUG_VERB, " BankSize: %d\n", mode->BankSize); 187 xf86ErrorFVerb(DEBUG_VERB, 188 " NumberOfImages: %d\n", mode->NumberOfImages); 189 xf86ErrorFVerb(DEBUG_VERB, " RedMaskSize: %d\n", mode->RedMaskSize); 190 xf86ErrorFVerb(DEBUG_VERB, 191 " RedFieldPosition: %d\n", mode->RedFieldPosition); 192 xf86ErrorFVerb(DEBUG_VERB, 193 " GreenMaskSize: %d\n", mode->GreenMaskSize); 194 xf86ErrorFVerb(DEBUG_VERB, 195 " GreenFieldPosition: %d\n", mode->GreenFieldPosition); 196 xf86ErrorFVerb(DEBUG_VERB, 197 " BlueMaskSize: %d\n", mode->BlueMaskSize); 198 xf86ErrorFVerb(DEBUG_VERB, 199 " BlueFieldPosition: %d\n", mode->BlueFieldPosition); 200 xf86ErrorFVerb(DEBUG_VERB, 201 " RsvdMaskSize: %d\n", mode->RsvdMaskSize); 202 xf86ErrorFVerb(DEBUG_VERB, 203 " RsvdFieldPosition: %d\n", mode->RsvdFieldPosition); 204 xf86ErrorFVerb(DEBUG_VERB, 205 " DirectColorModeInfo: %d\n", mode->DirectColorModeInfo); 206 if (major >= 2) { 207 xf86ErrorFVerb(DEBUG_VERB, 208 " PhysBasePtr: 0x%lx\n", 209 (unsigned long) mode->PhysBasePtr); 210 if (major >= 3) { 211 xf86ErrorFVerb(DEBUG_VERB, 212 " LinBytesPerScanLine: %d\n", 213 mode->LinBytesPerScanLine); 214 xf86ErrorFVerb(DEBUG_VERB, " BnkNumberOfImagePages: %d\n", 215 mode->BnkNumberOfImagePages); 216 xf86ErrorFVerb(DEBUG_VERB, " LinNumberOfImagePages: %d\n", 217 mode->LinNumberOfImagePages); 218 xf86ErrorFVerb(DEBUG_VERB, " LinRedMaskSize: %d\n", 219 mode->LinRedMaskSize); 220 xf86ErrorFVerb(DEBUG_VERB, " LinRedFieldPosition: %d\n", 221 mode->LinRedFieldPosition); 222 xf86ErrorFVerb(DEBUG_VERB, " LinGreenMaskSize: %d\n", 223 mode->LinGreenMaskSize); 224 xf86ErrorFVerb(DEBUG_VERB, " LinGreenFieldPosition: %d\n", 225 mode->LinGreenFieldPosition); 226 xf86ErrorFVerb(DEBUG_VERB, " LinBlueMaskSize: %d\n", 227 mode->LinBlueMaskSize); 228 xf86ErrorFVerb(DEBUG_VERB, " LinBlueFieldPosition: %d\n", 229 mode->LinBlueFieldPosition); 230 xf86ErrorFVerb(DEBUG_VERB, " LinRsvdMaskSize: %d\n", 231 mode->LinRsvdMaskSize); 232 xf86ErrorFVerb(DEBUG_VERB, " LinRsvdFieldPosition: %d\n", 233 mode->LinRsvdFieldPosition); 234 xf86ErrorFVerb(DEBUG_VERB, " MaxPixelClock: %ld\n", 235 (unsigned long) mode->MaxPixelClock); 236 } 237 } 238 239 if (!modeOK) { 240 VBEFreeModeInfo(mode); 241 return NULL; 242 } 243 pMode = xnfcalloc(sizeof(DisplayModeRec), 1); 244 245 pMode->status = MODE_OK; 246 pMode->type = M_T_BUILTIN; 247 248 /* for adjust frame */ 249 pMode->HDisplay = mode->XResolution; 250 pMode->VDisplay = mode->YResolution; 251 252 data = xnfcalloc(sizeof(VbeModeInfoData), 1); 253 data->mode = id; 254 data->data = mode; 255 pMode->PrivSize = sizeof(VbeModeInfoData); 256 pMode->Private = (INT32 *) data; 257 pMode->next = NULL; 258 return pMode; 259} 260 261/* 262 * Check the available BIOS modes, and extract those that match the 263 * requirements into the modePool. Note: modePool is a NULL-terminated 264 * list. 265 */ 266 267DisplayModePtr 268VBEGetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock * vbe, 269 int modeTypes) 270{ 271 DisplayModePtr pMode, p = NULL, modePool = NULL; 272 int i = 0; 273 274 if (modeTypes & V_MODETYPE_VBE) { 275 while (vbe->VideoModePtr[i] != 0xffff) { 276 int id = vbe->VideoModePtr[i++]; 277 278 if ((pMode = CheckMode(pScrn, pVbe, vbe, id, modeTypes)) != NULL) { 279 ModeStatus status = MODE_OK; 280 281 /* Check the mode against a specified virtual size (if any) */ 282 if (pScrn->display->virtualX > 0 && 283 pMode->HDisplay > pScrn->display->virtualX) { 284 status = MODE_VIRTUAL_X; 285 } 286 if (pScrn->display->virtualY > 0 && 287 pMode->VDisplay > pScrn->display->virtualY) { 288 status = MODE_VIRTUAL_Y; 289 } 290 if (status != MODE_OK) { 291 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 292 "Not using mode \"%dx%d\" (%s)\n", 293 pMode->HDisplay, pMode->VDisplay, 294 xf86ModeStatusToString(status)); 295 } 296 else { 297 if (p == NULL) { 298 modePool = pMode; 299 } 300 else { 301 p->next = pMode; 302 } 303 pMode->prev = NULL; 304 p = pMode; 305 } 306 } 307 } 308 } 309 if (modeTypes & V_MODETYPE_VGA) { 310 for (i = 0; i < 0x7F; i++) { 311 if ((pMode = CheckMode(pScrn, pVbe, vbe, i, modeTypes)) != NULL) { 312 ModeStatus status = MODE_OK; 313 314 /* Check the mode against a specified virtual size (if any) */ 315 if (pScrn->display->virtualX > 0 && 316 pMode->HDisplay > pScrn->display->virtualX) { 317 status = MODE_VIRTUAL_X; 318 } 319 if (pScrn->display->virtualY > 0 && 320 pMode->VDisplay > pScrn->display->virtualY) { 321 status = MODE_VIRTUAL_Y; 322 } 323 if (status != MODE_OK) { 324 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 325 "Not using mode \"%dx%d\" (%s)\n", 326 pMode->HDisplay, pMode->VDisplay, 327 xf86ModeStatusToString(status)); 328 } 329 else { 330 if (p == NULL) { 331 modePool = pMode; 332 } 333 else { 334 p->next = pMode; 335 } 336 pMode->prev = NULL; 337 p = pMode; 338 } 339 } 340 } 341 } 342 return modePool; 343} 344 345void 346VBESetModeNames(DisplayModePtr pMode) 347{ 348 if (!pMode) 349 return; 350 351 do { 352 if (!pMode->name) { 353 /* Catch "bad" modes. */ 354 if (pMode->HDisplay > 10000 || pMode->HDisplay < 0 || 355 pMode->VDisplay > 10000 || pMode->VDisplay < 0) { 356 pMode->name = strdup("BADMODE"); 357 } 358 else { 359 char *tmp; 360 XNFasprintf(&tmp, "%dx%d", 361 pMode->HDisplay, pMode->VDisplay); 362 pMode->name = tmp; 363 } 364 } 365 pMode = pMode->next; 366 } while (pMode); 367} 368 369/* 370 * Go through the monitor modes and selecting the best set of 371 * parameters for each BIOS mode. Note: This is only supported in 372 * VBE version 3.0 or later. 373 */ 374void 375VBESetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe) 376{ 377 DisplayModePtr pMode; 378 VbeModeInfoData *data; 379 380 pMode = pScrn->modes; 381 do { 382 DisplayModePtr p, best = NULL; 383 ModeStatus status; 384 385 for (p = pScrn->monitor->Modes; p != NULL; p = p->next) { 386 if ((p->HDisplay != pMode->HDisplay) || 387 (p->VDisplay != pMode->VDisplay) || 388 (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2))) 389 continue; 390 /* XXX could support the various V_ flags */ 391 status = xf86CheckModeForMonitor(p, pScrn->monitor); 392 if (status != MODE_OK) 393 continue; 394 if (!best || (p->Clock > best->Clock)) 395 best = p; 396 } 397 398 if (best) { 399 int clock; 400 401 data = (VbeModeInfoData *) pMode->Private; 402 pMode->HSync = (float) best->Clock * 1000.0 / best->HTotal + 0.5; 403 pMode->VRefresh = pMode->HSync / best->VTotal + 0.5; 404 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 405 "Attempting to use %dHz refresh for mode \"%s\" (%x)\n", 406 (int) pMode->VRefresh, pMode->name, data->mode); 407 data->block = calloc(sizeof(VbeCRTCInfoBlock), 1); 408 data->block->HorizontalTotal = best->HTotal; 409 data->block->HorizontalSyncStart = best->HSyncStart; 410 data->block->HorizontalSyncEnd = best->HSyncEnd; 411 data->block->VerticalTotal = best->VTotal; 412 data->block->VerticalSyncStart = best->VSyncStart; 413 data->block->VerticalSyncEnd = best->VSyncEnd; 414 data->block->Flags = ((best->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) | 415 ((best->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0); 416 data->block->PixelClock = best->Clock * 1000; 417 /* XXX May not have this. */ 418 clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock); 419 DebugF("Setting clock %.2fMHz, closest is %.2fMHz\n", 420 (double) data->block->PixelClock / 1000000.0, 421 (double) clock / 1000000.0); 422 if (clock) 423 data->block->PixelClock = clock; 424 data->mode |= (1 << 11); 425 data->block->RefreshRate = ((double) (data->block->PixelClock) / 426 (double) (best->HTotal * 427 best->VTotal)) * 100; 428 } 429 pMode = pMode->next; 430 } while (pMode != pScrn->modes); 431} 432 433/* 434 * These wrappers are to allow (temporary) functionality divergences. 435 */ 436int 437VBEValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes, 438 const char **modeNames, ClockRangePtr clockRanges, 439 int *linePitches, int minPitch, int maxPitch, int pitchInc, 440 int minHeight, int maxHeight, int virtualX, int virtualY, 441 int apertureSize, LookupModeFlags strategy) 442{ 443 return xf86ValidateModes(scrp, availModes, modeNames, clockRanges, 444 linePitches, minPitch, maxPitch, pitchInc, 445 minHeight, maxHeight, virtualX, virtualY, 446 apertureSize, strategy); 447} 448 449void 450VBEPrintModes(ScrnInfoPtr scrp) 451{ 452 xf86PrintModes(scrp); 453} 454