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