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	} else {
59	    depth = 1;
60	}
61	bpp = mode->BitsPerPixel;
62	VBEFreeModeInfo(mode);
63	mode = NULL;
64	switch (depth) {
65	case 1:
66	    return V_DEPTH_1;
67	case 4:
68	    return V_DEPTH_4;
69	case 8:
70	    return V_DEPTH_8;
71	case 15:
72	    return V_DEPTH_15;
73	case 16:
74	    return V_DEPTH_16;
75	case 24:
76	    switch (bpp) {
77	    case 24:
78		return V_DEPTH_24_24;
79	    case 32:
80		return V_DEPTH_24_32;
81	    }
82	}
83    }
84    if (mode)
85	VBEFreeModeInfo(mode);
86    return 0;
87}
88
89/*
90 * Find supported mode depths.
91 */
92int
93VBEFindSupportedDepths(vbeInfoPtr pVbe, VbeInfoBlock *vbe, int *flags24,
94			int modeTypes)
95{
96    int i = 0;
97    int depths = 0;
98
99    if (modeTypes & V_MODETYPE_VBE) {
100	while (vbe->VideoModePtr[i] != 0xffff) {
101	    depths |= GetDepthFlag(pVbe, vbe->VideoModePtr[i++]);
102	}
103    }
104
105    /*
106     * XXX This possibly only works with VBE 3.0 and later.
107     */
108    if (modeTypes & V_MODETYPE_VGA) {
109	for (i = 0; i < 0x7F; i++) {
110	    depths |= GetDepthFlag(pVbe, i);
111	}
112    }
113
114    if (flags24) {
115	if (depths & V_DEPTH_24_24)
116	    *flags24 |= Support24bppFb;
117	if (depths & V_DEPTH_24_32)
118	    *flags24 |= Support32bppFb;
119    }
120
121    return depths;
122}
123
124static DisplayModePtr
125CheckMode(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe, int id,
126	  int flags)
127{
128    CARD16 major;
129    VbeModeInfoBlock *mode;
130    DisplayModePtr pMode;
131    VbeModeInfoData *data;
132    Bool modeOK = FALSE;
133
134    major = (unsigned)(vbe->VESAVersion >> 8);
135
136    if ((mode = VBEGetModeInfo(pVbe, id)) == NULL)
137	return NULL;
138
139    /* Does the mode match the depth/bpp? */
140    /* Some BIOS's set BitsPerPixel to 15 instead of 16 for 15/16 */
141    if (VBE_MODE_USABLE(mode, flags) &&
142	((pScrn->bitsPerPixel == 1 && !VBE_MODE_COLOR(mode)) ||
143	 (mode->BitsPerPixel > 8 &&
144	  (mode->RedMaskSize + mode->GreenMaskSize +
145	   mode->BlueMaskSize) == pScrn->depth &&
146	  mode->BitsPerPixel == pScrn->bitsPerPixel) ||
147	 (mode->BitsPerPixel == 15 && pScrn->depth == 15) ||
148	 (mode->BitsPerPixel <= 8 &&
149	  mode->BitsPerPixel == pScrn->bitsPerPixel))) {
150	modeOK = TRUE;
151	xf86ErrorFVerb(DEBUG_VERB, "*");
152    }
153
154    xf86ErrorFVerb(DEBUG_VERB,
155	    "Mode: %x (%dx%d)\n", id, mode->XResolution, mode->YResolution);
156    xf86ErrorFVerb(DEBUG_VERB,
157	    "	ModeAttributes: 0x%x\n", mode->ModeAttributes);
158    xf86ErrorFVerb(DEBUG_VERB,
159	    "	WinAAttributes: 0x%x\n", mode->WinAAttributes);
160    xf86ErrorFVerb(DEBUG_VERB,
161	    "	WinBAttributes: 0x%x\n", mode->WinBAttributes);
162    xf86ErrorFVerb(DEBUG_VERB,
163	    "	WinGranularity: %d\n", mode->WinGranularity);
164    xf86ErrorFVerb(DEBUG_VERB,
165	    "	WinSize: %d\n", mode->WinSize);
166    xf86ErrorFVerb(DEBUG_VERB,
167	    "	WinASegment: 0x%x\n", mode->WinASegment);
168    xf86ErrorFVerb(DEBUG_VERB,
169	    "	WinBSegment: 0x%x\n", mode->WinBSegment);
170    xf86ErrorFVerb(DEBUG_VERB,
171	    "	WinFuncPtr: 0x%lx\n", (unsigned long)mode->WinFuncPtr);
172    xf86ErrorFVerb(DEBUG_VERB,
173	    "	BytesPerScanline: %d\n", mode->BytesPerScanline);
174    xf86ErrorFVerb(DEBUG_VERB,
175	    "	XResolution: %d\n", mode->XResolution);
176    xf86ErrorFVerb(DEBUG_VERB,
177	    "	YResolution: %d\n", mode->YResolution);
178    xf86ErrorFVerb(DEBUG_VERB,
179	    "	XCharSize: %d\n", mode->XCharSize);
180    xf86ErrorFVerb(DEBUG_VERB,
181           "	YCharSize: %d\n", mode->YCharSize);
182    xf86ErrorFVerb(DEBUG_VERB,
183	    "	NumberOfPlanes: %d\n", mode->NumberOfPlanes);
184    xf86ErrorFVerb(DEBUG_VERB,
185	    "	BitsPerPixel: %d\n", mode->BitsPerPixel);
186    xf86ErrorFVerb(DEBUG_VERB,
187	    "	NumberOfBanks: %d\n", mode->NumberOfBanks);
188    xf86ErrorFVerb(DEBUG_VERB,
189	    "	MemoryModel: %d\n", mode->MemoryModel);
190    xf86ErrorFVerb(DEBUG_VERB,
191	    "	BankSize: %d\n", mode->BankSize);
192    xf86ErrorFVerb(DEBUG_VERB,
193	    "	NumberOfImages: %d\n", mode->NumberOfImages);
194    xf86ErrorFVerb(DEBUG_VERB,
195	    "	RedMaskSize: %d\n", mode->RedMaskSize);
196    xf86ErrorFVerb(DEBUG_VERB,
197	    "	RedFieldPosition: %d\n", mode->RedFieldPosition);
198    xf86ErrorFVerb(DEBUG_VERB,
199	    "	GreenMaskSize: %d\n", mode->GreenMaskSize);
200    xf86ErrorFVerb(DEBUG_VERB,
201	    "	GreenFieldPosition: %d\n", mode->GreenFieldPosition);
202    xf86ErrorFVerb(DEBUG_VERB,
203	    "	BlueMaskSize: %d\n", mode->BlueMaskSize);
204    xf86ErrorFVerb(DEBUG_VERB,
205	    "	BlueFieldPosition: %d\n", mode->BlueFieldPosition);
206    xf86ErrorFVerb(DEBUG_VERB,
207	    "	RsvdMaskSize: %d\n", mode->RsvdMaskSize);
208    xf86ErrorFVerb(DEBUG_VERB,
209	    "	RsvdFieldPosition: %d\n", mode->RsvdFieldPosition);
210    xf86ErrorFVerb(DEBUG_VERB,
211	    "	DirectColorModeInfo: %d\n", mode->DirectColorModeInfo);
212    if (major >= 2) {
213	xf86ErrorFVerb(DEBUG_VERB,
214		"	PhysBasePtr: 0x%lx\n",
215		(unsigned long)mode->PhysBasePtr);
216	if (major >= 3) {
217	    xf86ErrorFVerb(DEBUG_VERB,
218		    "	LinBytesPerScanLine: %d\n", mode->LinBytesPerScanLine);
219	    xf86ErrorFVerb(DEBUG_VERB,
220		    "	BnkNumberOfImagePages: %d\n", mode->BnkNumberOfImagePages);
221	    xf86ErrorFVerb(DEBUG_VERB,
222		    "	LinNumberOfImagePages: %d\n", mode->LinNumberOfImagePages);
223	    xf86ErrorFVerb(DEBUG_VERB,
224		    "	LinRedMaskSize: %d\n", mode->LinRedMaskSize);
225	    xf86ErrorFVerb(DEBUG_VERB,
226		    "	LinRedFieldPosition: %d\n", mode->LinRedFieldPosition);
227	    xf86ErrorFVerb(DEBUG_VERB,
228		    "	LinGreenMaskSize: %d\n", mode->LinGreenMaskSize);
229	    xf86ErrorFVerb(DEBUG_VERB,
230		    "	LinGreenFieldPosition: %d\n", mode->LinGreenFieldPosition);
231	    xf86ErrorFVerb(DEBUG_VERB,
232		    "	LinBlueMaskSize: %d\n", mode->LinBlueMaskSize);
233	    xf86ErrorFVerb(DEBUG_VERB,
234		    "	LinBlueFieldPosition: %d\n", mode->LinBlueFieldPosition);
235	    xf86ErrorFVerb(DEBUG_VERB,
236		    "	LinRsvdMaskSize: %d\n", mode->LinRsvdMaskSize);
237	    xf86ErrorFVerb(DEBUG_VERB,
238		    "	LinRsvdFieldPosition: %d\n", mode->LinRsvdFieldPosition);
239	    xf86ErrorFVerb(DEBUG_VERB,
240		    "	MaxPixelClock: %ld\n", (unsigned long)mode->MaxPixelClock);
241	}
242    }
243
244    if (!modeOK) {
245	VBEFreeModeInfo(mode);
246	return NULL;
247    }
248    pMode = xnfcalloc(sizeof(DisplayModeRec), 1);
249
250    pMode->status = MODE_OK;
251    pMode->type = M_T_BUILTIN;
252
253    /* for adjust frame */
254    pMode->HDisplay = mode->XResolution;
255    pMode->VDisplay = mode->YResolution;
256
257    data = xnfcalloc(sizeof(VbeModeInfoData), 1);
258    data->mode = id;
259    data->data = mode;
260    pMode->PrivSize = sizeof(VbeModeInfoData);
261    pMode->Private = (INT32*)data;
262    pMode->next = NULL;
263    return pMode;
264}
265
266/*
267 * Check the available BIOS modes, and extract those that match the
268 * requirements into the modePool.  Note: modePool is a NULL-terminated
269 * list.
270 */
271
272DisplayModePtr
273VBEGetModePool(ScrnInfoPtr pScrn, vbeInfoPtr pVbe, VbeInfoBlock *vbe,
274	       int modeTypes)
275{
276    DisplayModePtr pMode, p = NULL, modePool = NULL;
277    int i = 0;
278
279    if (modeTypes & V_MODETYPE_VBE) {
280	while (vbe->VideoModePtr[i] != 0xffff) {
281	    int id = vbe->VideoModePtr[i++];
282
283	    if ((pMode = CheckMode(pScrn, pVbe, vbe, id, modeTypes)) != NULL) {
284		ModeStatus status = MODE_OK;
285
286		/* Check the mode against a specified virtual size (if any) */
287		if (pScrn->display->virtualX > 0 &&
288		    pMode->HDisplay > pScrn->display->virtualX) {
289		    status = MODE_VIRTUAL_X;
290		}
291		if (pScrn->display->virtualY > 0 &&
292		    pMode->VDisplay > pScrn->display->virtualY) {
293		    status = MODE_VIRTUAL_Y;
294		}
295		if (status != MODE_OK) {
296		     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
297				"Not using mode \"%dx%d\" (%s)\n",
298				pMode->HDisplay, pMode->VDisplay,
299				xf86ModeStatusToString(status));
300		} else {
301		    if (p == NULL) {
302			modePool = pMode;
303		    } else {
304			p->next = pMode;
305		    }
306		    pMode->prev = NULL;
307		    p = pMode;
308		}
309	    }
310	}
311    }
312    if (modeTypes & V_MODETYPE_VGA) {
313	for (i = 0; i < 0x7F; i++) {
314	    if ((pMode = CheckMode(pScrn, pVbe, vbe, i, modeTypes)) != NULL) {
315		ModeStatus status = MODE_OK;
316
317		/* Check the mode against a specified virtual size (if any) */
318		if (pScrn->display->virtualX > 0 &&
319		    pMode->HDisplay > pScrn->display->virtualX) {
320		    status = MODE_VIRTUAL_X;
321		}
322		if (pScrn->display->virtualY > 0 &&
323		    pMode->VDisplay > pScrn->display->virtualY) {
324		    status = MODE_VIRTUAL_Y;
325		}
326		if (status != MODE_OK) {
327		     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
328				"Not using mode \"%dx%d\" (%s)\n",
329				pMode->HDisplay, pMode->VDisplay,
330				xf86ModeStatusToString(status));
331		} else {
332		    if (p == NULL) {
333			modePool = pMode;
334		    } else {
335			p->next = pMode;
336		    }
337		    pMode->prev = NULL;
338		    p = pMode;
339		}
340	    }
341	}
342    }
343    return modePool;
344}
345
346void
347VBESetModeNames(DisplayModePtr pMode)
348{
349    if (!pMode)
350	return;
351
352    do {
353	if (!pMode->name) {
354	    /* Catch "bad" modes. */
355	    if (pMode->HDisplay > 10000 || pMode->HDisplay < 0 ||
356		pMode->VDisplay > 10000 || pMode->VDisplay < 0) {
357		pMode->name = strdup("BADMODE");
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 * best->VTotal)) * 100;
425	}
426	pMode = pMode->next;
427    } while (pMode != pScrn->modes);
428}
429
430/*
431 * These wrappers are to allow (temporary) funtionality divergences.
432 */
433int
434VBEValidateModes(ScrnInfoPtr scrp, DisplayModePtr availModes,
435		  const char **modeNames, ClockRangePtr clockRanges,
436		  int *linePitches, int minPitch, int maxPitch, int pitchInc,
437		  int minHeight, int maxHeight, int virtualX, int virtualY,
438		  int apertureSize, LookupModeFlags strategy)
439{
440    return xf86ValidateModes(scrp, availModes, modeNames, clockRanges,
441			     linePitches, minPitch, maxPitch, pitchInc,
442			     minHeight, maxHeight, virtualX, virtualY,
443			     apertureSize, strategy);
444}
445
446void
447VBEPrintModes(ScrnInfoPtr scrp)
448{
449    xf86PrintModes(scrp);
450}
451
452