Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / vbe / vbeModes.c
CommitLineData
a09e091a
JB
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 XNFasprintf(&pMode->name, "%dx%d",
360 pMode->HDisplay, pMode->VDisplay);
361 }
362 }
363 pMode = pMode->next;
364 } while (pMode);
365}
366
367/*
368 * Go through the monitor modes and selecting the best set of
369 * parameters for each BIOS mode. Note: This is only supported in
370 * VBE version 3.0 or later.
371 */
372void
373VBESetModeParameters(ScrnInfoPtr pScrn, vbeInfoPtr pVbe)
374{
375 DisplayModePtr pMode;
376 VbeModeInfoData *data;
377
378 pMode = pScrn->modes;
379 do {
380 DisplayModePtr p, best = NULL;
381 ModeStatus status;
382
383 for (p = pScrn->monitor->Modes; p != NULL; p = p->next) {
384 if ((p->HDisplay != pMode->HDisplay) ||
385 (p->VDisplay != pMode->VDisplay) ||
386 (p->Flags & (V_INTERLACE | V_DBLSCAN | V_CLKDIV2)))
387 continue;
388 /* XXX could support the various V_ flags */
389 status = xf86CheckModeForMonitor(p, pScrn->monitor);
390 if (status != MODE_OK)
391 continue;
392 if (!best || (p->Clock > best->Clock))
393 best = p;
394 }
395
396 if (best) {
397 int clock;
398
399 data = (VbeModeInfoData *) pMode->Private;
400 pMode->HSync = (float) best->Clock * 1000.0 / best->HTotal + 0.5;
401 pMode->VRefresh = pMode->HSync / best->VTotal + 0.5;
402 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
403 "Attempting to use %dHz refresh for mode \"%s\" (%x)\n",
404 (int) pMode->VRefresh, pMode->name, data->mode);
405 data->block = calloc(sizeof(VbeCRTCInfoBlock), 1);
406 data->block->HorizontalTotal = best->HTotal;
407 data->block->HorizontalSyncStart = best->HSyncStart;
408 data->block->HorizontalSyncEnd = best->HSyncEnd;
409 data->block->VerticalTotal = best->VTotal;
410 data->block->VerticalSyncStart = best->VSyncStart;
411 data->block->VerticalSyncEnd = best->VSyncEnd;
412 data->block->Flags = ((best->Flags & V_NHSYNC) ? CRTC_NHSYNC : 0) |
413 ((best->Flags & V_NVSYNC) ? CRTC_NVSYNC : 0);
414 data->block->PixelClock = best->Clock * 1000;
415 /* XXX May not have this. */
416 clock = VBEGetPixelClock(pVbe, data->mode, data->block->PixelClock);
417 DebugF("Setting clock %.2fMHz, closest is %.2fMHz\n",
418 (double) data->block->PixelClock / 1000000.0,
419 (double) clock / 1000000.0);
420 if (clock)
421 data->block->PixelClock = clock;
422 data->mode |= (1 << 11);
423 data->block->RefreshRate = ((double) (data->block->PixelClock) /
424 (double) (best->HTotal *
425 best->VTotal)) * 100;
426 }
427 pMode = pMode->next;
428 } while (pMode != pScrn->modes);
429}
430
431/*
432 * These wrappers are to allow (temporary) funtionality divergences.
433 */
434int
435VBEValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
436 char **modeNames, ClockRangePtr clockRanges,
437 int *linePitches, int minPitch, int maxPitch, int pitchInc,
438 int minHeight, int maxHeight, int virtualX, int virtualY,
439 int apertureSize, LookupModeFlags strategy)
440{
441 return xf86ValidateModes(scrp, availModes, modeNames, clockRanges,
442 linePitches, minPitch, maxPitch, pitchInc,
443 minHeight, maxHeight, virtualX, virtualY,
444 apertureSize, strategy);
445}
446
447void
448VBEPrintModes(ScrnInfoPtr scrp)
449{
450 xf86PrintModes(scrp);
451}