1706f2543Smrg
2706f2543Smrg/*
3706f2543Smrg *                   XFree86 vbe module
4706f2543Smrg *               Copyright 2000 Egbert Eich
5706f2543Smrg *
6706f2543Smrg * The mode query/save/set/restore functions from the vesa driver
7706f2543Smrg * have been moved here.
8706f2543Smrg * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
9706f2543Smrg * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
10706f2543Smrg */
11706f2543Smrg
12706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
13706f2543Smrg#include <xorg-config.h>
14706f2543Smrg#endif
15706f2543Smrg
16706f2543Smrg#include <string.h>
17706f2543Smrg
18706f2543Smrg#include "xf86.h"
19706f2543Smrg#include "xf86Modes.h"
20706f2543Smrg#include "vbe.h"
21706f2543Smrg#include <X11/extensions/dpmsconst.h>
22706f2543Smrg
23706f2543Smrg#define VERSION(x) VBE_VERSION_MAJOR(x),VBE_VERSION_MINOR(x)
24706f2543Smrg
25706f2543Smrg#if X_BYTE_ORDER == X_LITTLE_ENDIAN
26706f2543Smrg#define B_O16(x)  (x)
27706f2543Smrg#define B_O32(x)  (x)
28706f2543Smrg#else
29706f2543Smrg#define B_O16(x)  ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8))
30706f2543Smrg#define B_O32(x)  ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \
31706f2543Smrg                  | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))
32706f2543Smrg#endif
33706f2543Smrg#define L_ADD(x)  (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00)
34706f2543Smrg
35706f2543Smrg#define FARP(p)		(((unsigned)(p & 0xffff0000) >> 12) | (p & 0xffff))
36706f2543Smrg#define R16(v)		((v) & 0xffff)
37706f2543Smrg
38706f2543Smrgstatic unsigned char * vbeReadEDID(vbeInfoPtr pVbe);
39706f2543Smrgstatic Bool vbeProbeDDC(vbeInfoPtr pVbe);
40706f2543Smrg
41706f2543Smrgstatic const char vbeVersionString[] = "VBE2";
42706f2543Smrg
43706f2543SmrgvbeInfoPtr
44706f2543SmrgVBEInit(xf86Int10InfoPtr pInt, int entityIndex)
45706f2543Smrg{
46706f2543Smrg    return VBEExtendedInit(pInt, entityIndex, 0);
47706f2543Smrg}
48706f2543Smrg
49706f2543SmrgvbeInfoPtr
50706f2543SmrgVBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags)
51706f2543Smrg{
52706f2543Smrg    int RealOff;
53706f2543Smrg    pointer page = NULL;
54706f2543Smrg    ScrnInfoPtr pScrn = xf86FindScreenForEntity(entityIndex);
55706f2543Smrg    vbeControllerInfoPtr vbe = NULL;
56706f2543Smrg    Bool init_int10 = FALSE;
57706f2543Smrg    vbeInfoPtr vip = NULL;
58706f2543Smrg    int screen;
59706f2543Smrg
60706f2543Smrg    if (!pScrn) return NULL;
61706f2543Smrg    screen = pScrn->scrnIndex;
62706f2543Smrg
63706f2543Smrg    if (!pInt) {
64706f2543Smrg	if (!xf86LoadSubModule(pScrn, "int10"))
65706f2543Smrg	    goto error;
66706f2543Smrg
67706f2543Smrg	xf86DrvMsg(screen,X_INFO,"initializing int10\n");
68706f2543Smrg	pInt = xf86ExtendedInitInt10(entityIndex,Flags);
69706f2543Smrg	if (!pInt)
70706f2543Smrg	    goto error;
71706f2543Smrg	init_int10 = TRUE;
72706f2543Smrg    }
73706f2543Smrg
74706f2543Smrg    page = xf86Int10AllocPages(pInt,1,&RealOff);
75706f2543Smrg    if (!page) goto error;
76706f2543Smrg    vbe = (vbeControllerInfoPtr) page;
77706f2543Smrg    memcpy(vbe->VbeSignature,vbeVersionString,4);
78706f2543Smrg
79706f2543Smrg    pInt->ax = 0x4F00;
80706f2543Smrg    pInt->es = SEG_ADDR(RealOff);
81706f2543Smrg    pInt->di = SEG_OFF(RealOff);
82706f2543Smrg    pInt->num = 0x10;
83706f2543Smrg
84706f2543Smrg    xf86ExecX86int10(pInt);
85706f2543Smrg
86706f2543Smrg    if ((pInt->ax & 0xff) != 0x4f) {
87706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA BIOS not detected\n");
88706f2543Smrg	goto error;
89706f2543Smrg    }
90706f2543Smrg
91706f2543Smrg    switch (pInt->ax & 0xff00) {
92706f2543Smrg    case 0:
93706f2543Smrg	xf86DrvMsg(screen,X_INFO,"VESA BIOS detected\n");
94706f2543Smrg	break;
95706f2543Smrg    case 0x100:
96706f2543Smrg	xf86DrvMsg(screen,X_INFO,"VESA BIOS function failed\n");
97706f2543Smrg	goto error;
98706f2543Smrg    case 0x200:
99706f2543Smrg	xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported\n");
100706f2543Smrg	goto error;
101706f2543Smrg    case 0x300:
102706f2543Smrg	xf86DrvMsg(screen,X_INFO,"VESA BIOS not supported in current mode\n");
103706f2543Smrg	goto error;
104706f2543Smrg    default:
105706f2543Smrg	xf86DrvMsg(screen,X_INFO,"Invalid\n");
106706f2543Smrg	goto error;
107706f2543Smrg    }
108706f2543Smrg
109706f2543Smrg    xf86DrvMsgVerb(screen, X_INFO, 4,
110706f2543Smrg		"VbeVersion is %d, OemStringPtr is 0x%08lx,\n"
111706f2543Smrg		"\tOemVendorNamePtr is 0x%08lx, OemProductNamePtr is 0x%08lx,\n"
112706f2543Smrg		"\tOemProductRevPtr is 0x%08lx\n",
113706f2543Smrg		vbe->VbeVersion, (unsigned long)vbe->OemStringPtr,
114706f2543Smrg		(unsigned long)vbe->OemVendorNamePtr,
115706f2543Smrg		(unsigned long)vbe->OemProductNamePtr,
116706f2543Smrg		(unsigned long)vbe->OemProductRevPtr);
117706f2543Smrg
118706f2543Smrg    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Version %i.%i\n",
119706f2543Smrg		   VERSION(vbe->VbeVersion));
120706f2543Smrg    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE Total Mem: %i kB\n",
121706f2543Smrg		   vbe->TotalMem * 64);
122706f2543Smrg    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM: %s\n",
123706f2543Smrg		   (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemStringPtr)));
124706f2543Smrg
125706f2543Smrg    if (B_O16(vbe->VbeVersion) >= 0x200) {
126706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Software Rev: %i.%i\n",
127706f2543Smrg		    VERSION(vbe->OemSoftwareRev));
128706f2543Smrg	if (vbe->OemVendorNamePtr)
129706f2543Smrg	    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Vendor: %s\n",
130706f2543Smrg		    (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemVendorNamePtr)));
131706f2543Smrg	if (vbe->OemProductNamePtr)
132706f2543Smrg	    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product: %s\n",
133706f2543Smrg		    (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductNamePtr)));
134706f2543Smrg	if (vbe->OemProductRevPtr)
135706f2543Smrg	    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE OEM Product Rev: %s\n",
136706f2543Smrg		    (CARD8*)xf86int10Addr(pInt,L_ADD(vbe->OemProductRevPtr)));
137706f2543Smrg    }
138706f2543Smrg    vip = (vbeInfoPtr)xnfalloc(sizeof(vbeInfoRec));
139706f2543Smrg    vip->version = B_O16(vbe->VbeVersion);
140706f2543Smrg    vip->pInt10 = pInt;
141706f2543Smrg    vip->ddc = DDC_UNCHECKED;
142706f2543Smrg    vip->memory = page;
143706f2543Smrg    vip->real_mode_base = RealOff;
144706f2543Smrg    vip->num_pages = 1;
145706f2543Smrg    vip->init_int10 = init_int10;
146706f2543Smrg
147706f2543Smrg    return vip;
148706f2543Smrg
149706f2543Smrg error:
150706f2543Smrg    if (page)
151706f2543Smrg	xf86Int10FreePages(pInt, page, 1);
152706f2543Smrg    if (init_int10)
153706f2543Smrg	xf86FreeInt10(pInt);
154706f2543Smrg    return NULL;
155706f2543Smrg}
156706f2543Smrg
157706f2543Smrgvoid
158706f2543SmrgvbeFree(vbeInfoPtr pVbe)
159706f2543Smrg{
160706f2543Smrg    if (!pVbe)
161706f2543Smrg	return;
162706f2543Smrg
163706f2543Smrg    xf86Int10FreePages(pVbe->pInt10,pVbe->memory,pVbe->num_pages);
164706f2543Smrg    /* If we have initalized int10 we ought to free it, too */
165706f2543Smrg    if (pVbe->init_int10)
166706f2543Smrg	xf86FreeInt10(pVbe->pInt10);
167706f2543Smrg    free(pVbe);
168706f2543Smrg    return;
169706f2543Smrg}
170706f2543Smrg
171706f2543Smrgstatic Bool
172706f2543SmrgvbeProbeDDC(vbeInfoPtr pVbe)
173706f2543Smrg{
174706f2543Smrg    char *ddc_level;
175706f2543Smrg    int screen = pVbe->pInt10->scrnIndex;
176706f2543Smrg
177706f2543Smrg    if (pVbe->ddc == DDC_NONE)
178706f2543Smrg	return FALSE;
179706f2543Smrg    if (pVbe->ddc != DDC_UNCHECKED)
180706f2543Smrg	return TRUE;
181706f2543Smrg
182706f2543Smrg    pVbe->pInt10->ax = 0x4F15;
183706f2543Smrg    pVbe->pInt10->bx = 0;
184706f2543Smrg    pVbe->pInt10->cx = 0;
185706f2543Smrg    pVbe->pInt10->es = 0;
186706f2543Smrg    pVbe->pInt10->di = 0;
187706f2543Smrg    pVbe->pInt10->num = 0x10;
188706f2543Smrg
189706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
190706f2543Smrg
191706f2543Smrg    if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
192706f2543Smrg        xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC not supported\n");
193706f2543Smrg	pVbe->ddc = DDC_NONE;
194706f2543Smrg	return FALSE;
195706f2543Smrg    }
196706f2543Smrg
197706f2543Smrg    switch ((pVbe->pInt10->ax >> 8) & 0xff) {
198706f2543Smrg    case 0:
199706f2543Smrg	xf86DrvMsg(screen,X_INFO,"VESA VBE DDC supported\n");
200706f2543Smrg	switch (pVbe->pInt10->bx & 0x3) {
201706f2543Smrg	case 0:
202706f2543Smrg  	    ddc_level = " none";
203706f2543Smrg	    pVbe->ddc = DDC_NONE;
204706f2543Smrg	    break;
205706f2543Smrg	case 1:
206706f2543Smrg  	    ddc_level = " 1";
207706f2543Smrg	    pVbe->ddc = DDC_1;
208706f2543Smrg	    break;
209706f2543Smrg	case 2:
210706f2543Smrg  	    ddc_level = " 2";
211706f2543Smrg	    pVbe->ddc = DDC_2;
212706f2543Smrg	    break;
213706f2543Smrg	case 3:
214706f2543Smrg  	    ddc_level = " 1 + 2";
215706f2543Smrg	    pVbe->ddc = DDC_1_2;
216706f2543Smrg	    break;
217706f2543Smrg	default:
218706f2543Smrg 	    ddc_level = "";
219706f2543Smrg	    pVbe->ddc = DDC_NONE;
220706f2543Smrg	    break;
221706f2543Smrg	}
222706f2543Smrg  	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Level%s\n",ddc_level);
223706f2543Smrg  	if (pVbe->pInt10->bx & 0x4) {
224706f2543Smrg    	    xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC Screen blanked"
225706f2543Smrg    			"for data transfer\n");
226706f2543Smrg    	    pVbe->ddc_blank = TRUE;
227706f2543Smrg    	}  else
228706f2543Smrg    	    pVbe->ddc_blank = FALSE;
229706f2543Smrg
230706f2543Smrg  	xf86DrvMsgVerb(screen,X_INFO,3,
231706f2543Smrg		       "VESA VBE DDC transfer in appr. %x sec.\n",
232706f2543Smrg		       (pVbe->pInt10->bx >> 8) & 0xff);
233706f2543Smrg    }
234706f2543Smrg
235706f2543Smrg    return TRUE;
236706f2543Smrg}
237706f2543Smrg
238706f2543Smrgtypedef enum {
239706f2543Smrg  VBEOPT_NOVBE,
240706f2543Smrg    VBEOPT_NODDC
241706f2543Smrg} VBEOpts;
242706f2543Smrg
243706f2543Smrgstatic const OptionInfoRec VBEOptions[] = {
244706f2543Smrg    { VBEOPT_NOVBE,	"NoVBE",	OPTV_BOOLEAN,	{0},	FALSE },
245706f2543Smrg    { VBEOPT_NODDC,	"NoDDC",	OPTV_BOOLEAN,	{0},	FALSE },
246706f2543Smrg    { -1,		NULL,		OPTV_NONE,	{0},	FALSE },
247706f2543Smrg};
248706f2543Smrg
249706f2543Smrgstatic unsigned char *
250706f2543SmrgvbeReadEDID(vbeInfoPtr pVbe)
251706f2543Smrg{
252706f2543Smrg    int RealOff = pVbe->real_mode_base;
253706f2543Smrg    pointer page = pVbe->memory;
254706f2543Smrg    unsigned char *tmp = NULL;
255706f2543Smrg    Bool novbe = FALSE;
256706f2543Smrg    Bool noddc = FALSE;
257706f2543Smrg    int screen = pVbe->pInt10->scrnIndex;
258706f2543Smrg    OptionInfoPtr options;
259706f2543Smrg
260706f2543Smrg    if (!page) return NULL;
261706f2543Smrg
262706f2543Smrg    options = xnfalloc(sizeof(VBEOptions));
263706f2543Smrg    (void)memcpy(options, VBEOptions, sizeof(VBEOptions));
264706f2543Smrg    xf86ProcessOptions(screen, xf86Screens[screen]->options, options);
265706f2543Smrg    xf86GetOptValBool(options, VBEOPT_NOVBE, &novbe);
266706f2543Smrg    xf86GetOptValBool(options, VBEOPT_NODDC, &noddc);
267706f2543Smrg    free(options);
268706f2543Smrg    if (novbe || noddc) return NULL;
269706f2543Smrg
270706f2543Smrg    if (!vbeProbeDDC(pVbe)) goto error;
271706f2543Smrg
272706f2543Smrg    memset(page,0,sizeof(vbeInfoPtr));
273706f2543Smrg    strcpy(page,vbeVersionString);
274706f2543Smrg
275706f2543Smrg    pVbe->pInt10->ax = 0x4F15;
276706f2543Smrg    pVbe->pInt10->bx = 0x01;
277706f2543Smrg    pVbe->pInt10->cx = 0;
278706f2543Smrg    pVbe->pInt10->dx = 0;
279706f2543Smrg    pVbe->pInt10->es = SEG_ADDR(RealOff);
280706f2543Smrg    pVbe->pInt10->di = SEG_OFF(RealOff);
281706f2543Smrg    pVbe->pInt10->num = 0x10;
282706f2543Smrg
283706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
284706f2543Smrg
285706f2543Smrg    if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
286706f2543Smrg        xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC invalid\n");
287706f2543Smrg	goto error;
288706f2543Smrg    }
289706f2543Smrg    switch (pVbe->pInt10->ax & 0xff00) {
290706f2543Smrg    case 0x0:
291706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read successfully\n");
292706f2543Smrg  	tmp = (unsigned char *)xnfalloc(128);
293706f2543Smrg  	memcpy(tmp,page,128);
294706f2543Smrg	break;
295706f2543Smrg    case 0x100:
296706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC read failed\n");
297706f2543Smrg	break;
298706f2543Smrg    default:
299706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE DDC unkown failure %i\n",
300706f2543Smrg		       pVbe->pInt10->ax & 0xff00);
301706f2543Smrg	break;
302706f2543Smrg    }
303706f2543Smrg
304706f2543Smrg error:
305706f2543Smrg    return tmp;
306706f2543Smrg}
307706f2543Smrg
308706f2543Smrgxf86MonPtr
309706f2543SmrgvbeDoEDID(vbeInfoPtr pVbe, pointer pDDCModule)
310706f2543Smrg{
311706f2543Smrg    xf86MonPtr    pMonitor;
312706f2543Smrg    pointer       pModule;
313706f2543Smrg    unsigned char *DDC_data = NULL;
314706f2543Smrg
315706f2543Smrg    if (!pVbe) return NULL;
316706f2543Smrg    if (pVbe->version < 0x200)
317706f2543Smrg	return NULL;
318706f2543Smrg
319706f2543Smrg    if (!(pModule = pDDCModule)) {
320706f2543Smrg	pModule =
321706f2543Smrg	    xf86LoadSubModule(xf86Screens[pVbe->pInt10->scrnIndex], "ddc");
322706f2543Smrg	if (!pModule)
323706f2543Smrg	    return NULL;
324706f2543Smrg    }
325706f2543Smrg
326706f2543Smrg    DDC_data = vbeReadEDID(pVbe);
327706f2543Smrg
328706f2543Smrg    if (!DDC_data)
329706f2543Smrg	return NULL;
330706f2543Smrg
331706f2543Smrg    pMonitor = xf86InterpretEDID(pVbe->pInt10->scrnIndex, DDC_data);
332706f2543Smrg
333706f2543Smrg    if (!pDDCModule)
334706f2543Smrg        xf86UnloadSubModule(pModule);
335706f2543Smrg    return pMonitor;
336706f2543Smrg}
337706f2543Smrg
338706f2543Smrg#define GET_UNALIGNED2(x) \
339706f2543Smrg            ((*(CARD16*)(x)) | (*(((CARD16*)(x) + 1))) << 16)
340706f2543Smrg
341706f2543SmrgVbeInfoBlock *
342706f2543SmrgVBEGetVBEInfo(vbeInfoPtr pVbe)
343706f2543Smrg{
344706f2543Smrg    VbeInfoBlock *block = NULL;
345706f2543Smrg    int i, pStr, pModes;
346706f2543Smrg    char *str;
347706f2543Smrg    CARD16 major, *modes;
348706f2543Smrg
349706f2543Smrg    memset(pVbe->memory, 0, sizeof(VbeInfoBlock));
350706f2543Smrg
351706f2543Smrg    /*
352706f2543Smrg    Input:
353706f2543Smrg	AH    := 4Fh	Super VGA support
354706f2543Smrg	AL    := 00h	Return Super VGA information
355706f2543Smrg	ES:DI := Pointer to buffer
356706f2543Smrg
357706f2543Smrg    Output:
358706f2543Smrg	AX    := status
359706f2543Smrg	(All other registers are preserved)
360706f2543Smrg     */
361706f2543Smrg
362706f2543Smrg    ((char*)pVbe->memory)[0] = 'V';
363706f2543Smrg    ((char*)pVbe->memory)[1] = 'B';
364706f2543Smrg    ((char*)pVbe->memory)[2] = 'E';
365706f2543Smrg    ((char*)pVbe->memory)[3] = '2';
366706f2543Smrg
367706f2543Smrg    pVbe->pInt10->num = 0x10;
368706f2543Smrg    pVbe->pInt10->ax = 0x4f00;
369706f2543Smrg    pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
370706f2543Smrg    pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
371706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
372706f2543Smrg
373706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
374706f2543Smrg	return NULL;
375706f2543Smrg
376706f2543Smrg    block = calloc(sizeof(VbeInfoBlock), 1);
377706f2543Smrg    block->VESASignature[0] = ((char*)pVbe->memory)[0];
378706f2543Smrg    block->VESASignature[1] = ((char*)pVbe->memory)[1];
379706f2543Smrg    block->VESASignature[2] = ((char*)pVbe->memory)[2];
380706f2543Smrg    block->VESASignature[3] = ((char*)pVbe->memory)[3];
381706f2543Smrg
382706f2543Smrg    block->VESAVersion = *(CARD16*)(((char*)pVbe->memory) + 4);
383706f2543Smrg    major = (unsigned)block->VESAVersion >> 8;
384706f2543Smrg
385706f2543Smrg    pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 6));
386706f2543Smrg    str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
387706f2543Smrg    block->OEMStringPtr = strdup(str);
388706f2543Smrg
389706f2543Smrg    block->Capabilities[0] = ((char*)pVbe->memory)[10];
390706f2543Smrg    block->Capabilities[1] = ((char*)pVbe->memory)[11];
391706f2543Smrg    block->Capabilities[2] = ((char*)pVbe->memory)[12];
392706f2543Smrg    block->Capabilities[3] = ((char*)pVbe->memory)[13];
393706f2543Smrg
394706f2543Smrg    pModes = GET_UNALIGNED2((((char*)pVbe->memory) + 14));
395706f2543Smrg    modes = xf86int10Addr(pVbe->pInt10, FARP(pModes));
396706f2543Smrg    i = 0;
397706f2543Smrg    while (modes[i] != 0xffff)
398706f2543Smrg	i++;
399706f2543Smrg    block->VideoModePtr = malloc(sizeof(CARD16) * (i + 1));
400706f2543Smrg    memcpy(block->VideoModePtr, modes, sizeof(CARD16) * i);
401706f2543Smrg    block->VideoModePtr[i] = 0xffff;
402706f2543Smrg
403706f2543Smrg    block->TotalMemory = *(CARD16*)(((char*)pVbe->memory) + 18);
404706f2543Smrg
405706f2543Smrg    if (major < 2)
406706f2543Smrg	memcpy(&block->OemSoftwareRev, ((char*)pVbe->memory) + 20, 236);
407706f2543Smrg    else {
408706f2543Smrg	block->OemSoftwareRev = *(CARD16*)(((char*)pVbe->memory) + 20);
409706f2543Smrg	pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 22));
410706f2543Smrg	str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
411706f2543Smrg	block->OemVendorNamePtr = strdup(str);
412706f2543Smrg	pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 26));
413706f2543Smrg	str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
414706f2543Smrg	block->OemProductNamePtr = strdup(str);
415706f2543Smrg	pStr = GET_UNALIGNED2((((char*)pVbe->memory) + 30));
416706f2543Smrg	str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
417706f2543Smrg	block->OemProductRevPtr = strdup(str);
418706f2543Smrg	memcpy(&block->Reserved, ((char*)pVbe->memory) + 34, 222);
419706f2543Smrg	memcpy(&block->OemData, ((char*)pVbe->memory) + 256, 256);
420706f2543Smrg    }
421706f2543Smrg
422706f2543Smrg    return block;
423706f2543Smrg}
424706f2543Smrg
425706f2543Smrgvoid
426706f2543SmrgVBEFreeVBEInfo(VbeInfoBlock *block)
427706f2543Smrg{
428706f2543Smrg    free(block->OEMStringPtr);
429706f2543Smrg    free(block->VideoModePtr);
430706f2543Smrg    if (((unsigned)block->VESAVersion >> 8) >= 2) {
431706f2543Smrg	free(block->OemVendorNamePtr);
432706f2543Smrg	free(block->OemProductNamePtr);
433706f2543Smrg	free(block->OemProductRevPtr);
434706f2543Smrg    }
435706f2543Smrg    free(block);
436706f2543Smrg}
437706f2543Smrg
438706f2543SmrgBool
439706f2543SmrgVBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock *block)
440706f2543Smrg{
441706f2543Smrg    /*
442706f2543Smrg    Input:
443706f2543Smrg	AH    := 4Fh	Super VGA support
444706f2543Smrg	AL    := 02h	Set Super VGA video mode
445706f2543Smrg	BX    := Video mode
446706f2543Smrg	    D0-D8  := Mode number
447706f2543Smrg	    D9-D10 := Reserved (must be 0)
448706f2543Smrg	    D11    := 0 Use current default refresh rate
449706f2543Smrg		   := 1 Use user specified CRTC values for refresh rate
450706f2543Smrg	    D12-13	Reserved for VBE/AF (must be 0)
451706f2543Smrg	    D14    := 0 Use windowed frame buffer model
452706f2543Smrg		   := 1 Use linear/flat frame buffer model
453706f2543Smrg	    D15    := 0 Clear video memory
454706f2543Smrg		   := 1 Don't clear video memory
455706f2543Smrg	ES:DI := Pointer to VbeCRTCInfoBlock structure
456706f2543Smrg
457706f2543Smrg    Output: AX = Status
458706f2543Smrg	(All other registers are preserved)
459706f2543Smrg    */
460706f2543Smrg    pVbe->pInt10->num = 0x10;
461706f2543Smrg    pVbe->pInt10->ax = 0x4f02;
462706f2543Smrg    pVbe->pInt10->bx = mode;
463706f2543Smrg    if (block) {
464706f2543Smrg	pVbe->pInt10->bx |= 1 << 11;
465706f2543Smrg	memcpy(pVbe->memory, block, sizeof(VbeCRTCInfoBlock));
466706f2543Smrg	pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
467706f2543Smrg	pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
468706f2543Smrg    } else
469706f2543Smrg	pVbe->pInt10->bx &= ~(1 << 11);
470706f2543Smrg
471706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
472706f2543Smrg
473706f2543Smrg    return (R16(pVbe->pInt10->ax) == 0x4f);
474706f2543Smrg}
475706f2543Smrg
476706f2543SmrgBool
477706f2543SmrgVBEGetVBEMode(vbeInfoPtr pVbe, int *mode)
478706f2543Smrg{
479706f2543Smrg    /*
480706f2543Smrg    Input:
481706f2543Smrg	AH := 4Fh	Super VGA support
482706f2543Smrg	AL := 03h	Return current video mode
483706f2543Smrg
484706f2543Smrg    Output:
485706f2543Smrg	AX := Status
486706f2543Smrg	BX := Current video mode
487706f2543Smrg	(All other registers are preserved)
488706f2543Smrg    */
489706f2543Smrg    pVbe->pInt10->num = 0x10;
490706f2543Smrg    pVbe->pInt10->ax = 0x4f03;
491706f2543Smrg
492706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
493706f2543Smrg
494706f2543Smrg    if (R16(pVbe->pInt10->ax) == 0x4f) {
495706f2543Smrg	*mode = R16(pVbe->pInt10->bx);
496706f2543Smrg
497706f2543Smrg	return TRUE;
498706f2543Smrg    }
499706f2543Smrg
500706f2543Smrg    return FALSE;
501706f2543Smrg}
502706f2543Smrg
503706f2543SmrgVbeModeInfoBlock *
504706f2543SmrgVBEGetModeInfo(vbeInfoPtr pVbe, int mode)
505706f2543Smrg{
506706f2543Smrg    VbeModeInfoBlock *block = NULL;
507706f2543Smrg
508706f2543Smrg    memset(pVbe->memory, 0, sizeof(VbeModeInfoBlock));
509706f2543Smrg
510706f2543Smrg    /*
511706f2543Smrg    Input:
512706f2543Smrg	AH    := 4Fh	Super VGA support
513706f2543Smrg	AL    := 01h	Return Super VGA mode information
514706f2543Smrg	CX    := 	Super VGA video mode
515706f2543Smrg			(mode number must be one of those returned by Function 0)
516706f2543Smrg	ES:DI := Pointer to buffer
517706f2543Smrg
518706f2543Smrg    Output:
519706f2543Smrg	AX    := status
520706f2543Smrg	(All other registers are preserved)
521706f2543Smrg     */
522706f2543Smrg    pVbe->pInt10->num = 0x10;
523706f2543Smrg    pVbe->pInt10->ax = 0x4f01;
524706f2543Smrg    pVbe->pInt10->cx = mode;
525706f2543Smrg    pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
526706f2543Smrg    pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
527706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
528706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
529706f2543Smrg	return NULL;
530706f2543Smrg
531706f2543Smrg    block = malloc(sizeof(VbeModeInfoBlock));
532706f2543Smrg    if (block)
533706f2543Smrg	memcpy(block, pVbe->memory, sizeof(*block));
534706f2543Smrg
535706f2543Smrg    return block;
536706f2543Smrg}
537706f2543Smrg
538706f2543Smrgvoid
539706f2543SmrgVBEFreeModeInfo(VbeModeInfoBlock *block)
540706f2543Smrg{
541706f2543Smrg    free(block);
542706f2543Smrg}
543706f2543Smrg
544706f2543SmrgBool
545706f2543SmrgVBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function,
546706f2543Smrg	       pointer *memory, int *size, int *real_mode_pages)
547706f2543Smrg{
548706f2543Smrg    /*
549706f2543Smrg    Input:
550706f2543Smrg	AH    := 4Fh	Super VGA support
551706f2543Smrg	AL    := 04h	Save/restore Super VGA video state
552706f2543Smrg	DL    := 00h	Return save/restore state buffer size
553706f2543Smrg	CX    := Requested states
554706f2543Smrg		D0 = Save/restore video hardware state
555706f2543Smrg		D1 = Save/restore video BIOS data state
556706f2543Smrg		D2 = Save/restore video DAC state
557706f2543Smrg		D3 = Save/restore Super VGA state
558706f2543Smrg
559706f2543Smrg    Output:
560706f2543Smrg	AX = Status
561706f2543Smrg	BX = Number of 64-byte blocks to hold the state buffer
562706f2543Smrg	(All other registers are preserved)
563706f2543Smrg
564706f2543Smrg
565706f2543Smrg    Input:
566706f2543Smrg	AH    := 4Fh	Super VGA support
567706f2543Smrg	AL    := 04h	Save/restore Super VGA video state
568706f2543Smrg	DL    := 01h	Save Super VGA video state
569706f2543Smrg	CX    := Requested states (see above)
570706f2543Smrg	ES:BX := Pointer to buffer
571706f2543Smrg
572706f2543Smrg    Output:
573706f2543Smrg	AX    := Status
574706f2543Smrg	(All other registers are preserved)
575706f2543Smrg
576706f2543Smrg
577706f2543Smrg    Input:
578706f2543Smrg	AH    := 4Fh	Super VGA support
579706f2543Smrg	AL    := 04h	Save/restore Super VGA video state
580706f2543Smrg	DL    := 02h	Restore Super VGA video state
581706f2543Smrg	CX    := Requested states (see above)
582706f2543Smrg	ES:BX := Pointer to buffer
583706f2543Smrg
584706f2543Smrg    Output:
585706f2543Smrg	AX     := Status
586706f2543Smrg	(All other registers are preserved)
587706f2543Smrg     */
588706f2543Smrg
589706f2543Smrg    if ((pVbe->version & 0xff00) > 0x100) {
590706f2543Smrg        int screen = pVbe->pInt10->scrnIndex;
591706f2543Smrg        if (function == MODE_QUERY ||
592706f2543Smrg	    (function == MODE_SAVE && !*memory)) {
593706f2543Smrg	    /* Query amount of memory to save state */
594706f2543Smrg
595706f2543Smrg	    pVbe->pInt10->num = 0x10;
596706f2543Smrg	    pVbe->pInt10->ax = 0x4f04;
597706f2543Smrg	    pVbe->pInt10->dx = 0;
598706f2543Smrg	    pVbe->pInt10->cx = 0x000f;
599706f2543Smrg	    xf86ExecX86int10(pVbe->pInt10);
600706f2543Smrg	    if (R16(pVbe->pInt10->ax) != 0x4f)
601706f2543Smrg	        return FALSE;
602706f2543Smrg
603706f2543Smrg	    if (function == MODE_SAVE) {
604706f2543Smrg	        int npages = (R16(pVbe->pInt10->bx) * 64) / 4096 + 1;
605706f2543Smrg		if ((*memory = xf86Int10AllocPages(pVbe->pInt10, npages,
606706f2543Smrg						   real_mode_pages)) == NULL) {
607706f2543Smrg		    xf86DrvMsg(screen, X_ERROR,
608706f2543Smrg			       "Cannot allocate memory to save SVGA state.\n");
609706f2543Smrg		    return FALSE;
610706f2543Smrg		}
611706f2543Smrg	    }
612706f2543Smrg	    *size = pVbe->pInt10->bx * 64;
613706f2543Smrg	}
614706f2543Smrg
615706f2543Smrg	/* Save/Restore Super VGA state */
616706f2543Smrg	if (function != MODE_QUERY) {
617706f2543Smrg
618706f2543Smrg	    if (!*memory) return FALSE;
619706f2543Smrg	    pVbe->pInt10->num = 0x10;
620706f2543Smrg	    pVbe->pInt10->ax = 0x4f04;
621706f2543Smrg	    switch (function) {
622706f2543Smrg	    case MODE_SAVE:
623706f2543Smrg	      pVbe->pInt10->dx = 1;
624706f2543Smrg	      break;
625706f2543Smrg	    case MODE_RESTORE:
626706f2543Smrg	      pVbe->pInt10->dx = 2;
627706f2543Smrg	      break;
628706f2543Smrg	    case MODE_QUERY:
629706f2543Smrg	      return FALSE;
630706f2543Smrg	    }
631706f2543Smrg	    pVbe->pInt10->cx = 0x000f;
632706f2543Smrg
633706f2543Smrg	    pVbe->pInt10->es = SEG_ADDR(*real_mode_pages);
634706f2543Smrg	    pVbe->pInt10->bx = SEG_OFF(*real_mode_pages);
635706f2543Smrg	    xf86ExecX86int10(pVbe->pInt10);
636706f2543Smrg	    return (R16(pVbe->pInt10->ax) == 0x4f);
637706f2543Smrg
638706f2543Smrg	}
639706f2543Smrg    }
640706f2543Smrg    return TRUE;
641706f2543Smrg}
642706f2543Smrg
643706f2543SmrgBool
644706f2543SmrgVBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window)
645706f2543Smrg{
646706f2543Smrg    /*
647706f2543Smrg    Input:
648706f2543Smrg	AH    := 4Fh	Super VGA support
649706f2543Smrg	AL    := 05h
650706f2543Smrg
651706f2543Smrg    Output:
652706f2543Smrg     */
653706f2543Smrg    pVbe->pInt10->num = 0x10;
654706f2543Smrg    pVbe->pInt10->ax = 0x4f05;
655706f2543Smrg    pVbe->pInt10->bx = window;
656706f2543Smrg    pVbe->pInt10->dx = iBank;
657706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
658706f2543Smrg
659706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
660706f2543Smrg	return FALSE;
661706f2543Smrg
662706f2543Smrg    return TRUE;
663706f2543Smrg}
664706f2543Smrg
665706f2543SmrgBool
666706f2543SmrgVBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command,
667706f2543Smrg				int width, int *pixels, int *bytes, int *max)
668706f2543Smrg{
669706f2543Smrg    if (command < SCANWID_SET || command > SCANWID_GET_MAX)
670706f2543Smrg	return FALSE;
671706f2543Smrg
672706f2543Smrg    /*
673706f2543Smrg    Input:
674706f2543Smrg	AX := 4F06h VBE Set/Get Logical Scan Line Length
675706f2543Smrg	BL := 00h Set Scan Line Length in Pixels
676706f2543Smrg	   := 01h Get Scan Line Length
677706f2543Smrg	   := 02h Set Scan Line Length in Bytes
678706f2543Smrg	   := 03h Get Maximum Scan Line Length
679706f2543Smrg	CX := If BL=00h Desired Width in Pixels
680706f2543Smrg	      If BL=02h Desired Width in Bytes
681706f2543Smrg	      (Ignored for Get Functions)
682706f2543Smrg
683706f2543Smrg    Output:
684706f2543Smrg	AX := VBE Return Status
685706f2543Smrg	BX := Bytes Per Scan Line
686706f2543Smrg	CX := Actual Pixels Per Scan Line
687706f2543Smrg	      (truncated to nearest complete pixel)
688706f2543Smrg	DX := Maximum Number of Scan Lines
689706f2543Smrg     */
690706f2543Smrg
691706f2543Smrg    pVbe->pInt10->num = 0x10;
692706f2543Smrg    pVbe->pInt10->ax = 0x4f06;
693706f2543Smrg    pVbe->pInt10->bx = command;
694706f2543Smrg    if (command == SCANWID_SET || command == SCANWID_SET_BYTES)
695706f2543Smrg	pVbe->pInt10->cx = width;
696706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
697706f2543Smrg
698706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
699706f2543Smrg	return FALSE;
700706f2543Smrg
701706f2543Smrg    if (command == SCANWID_GET || command == SCANWID_GET_MAX) {
702706f2543Smrg	if (pixels)
703706f2543Smrg	    *pixels = R16(pVbe->pInt10->cx);
704706f2543Smrg	if (bytes)
705706f2543Smrg	    *bytes = R16(pVbe->pInt10->bx);
706706f2543Smrg	if (max)
707706f2543Smrg	    *max = R16(pVbe->pInt10->dx);
708706f2543Smrg    }
709706f2543Smrg
710706f2543Smrg    return TRUE;
711706f2543Smrg}
712706f2543Smrg
713706f2543SmrgBool
714706f2543SmrgVBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace)
715706f2543Smrg{
716706f2543Smrg    pVbe->pInt10->num = 0x10;
717706f2543Smrg    pVbe->pInt10->ax = 0x4f07;
718706f2543Smrg    pVbe->pInt10->bx = wait_retrace ? 0x80 : 0x00;
719706f2543Smrg    pVbe->pInt10->cx = x;
720706f2543Smrg    pVbe->pInt10->dx = y;
721706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
722706f2543Smrg
723706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
724706f2543Smrg	return FALSE;
725706f2543Smrg
726706f2543Smrg    return TRUE;
727706f2543Smrg}
728706f2543Smrg
729706f2543SmrgBool
730706f2543SmrgVBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y)
731706f2543Smrg{
732706f2543Smrg    pVbe->pInt10->num = 0x10;
733706f2543Smrg    pVbe->pInt10->ax = 0x4f07;
734706f2543Smrg    pVbe->pInt10->bx = 0x01;
735706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
736706f2543Smrg
737706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
738706f2543Smrg	return FALSE;
739706f2543Smrg
740706f2543Smrg    *x = pVbe->pInt10->cx;
741706f2543Smrg    *y = pVbe->pInt10->dx;
742706f2543Smrg
743706f2543Smrg    return TRUE;
744706f2543Smrg}
745706f2543Smrg
746706f2543Smrgint
747706f2543SmrgVBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits)
748706f2543Smrg{
749706f2543Smrg    /*
750706f2543Smrg    Input:
751706f2543Smrg	AX := 4F08h VBE Set/Get Palette Format
752706f2543Smrg	BL := 00h Set DAC Palette Format
753706f2543Smrg	   := 01h Get DAC Palette Format
754706f2543Smrg	BH := Desired bits of color per primary
755706f2543Smrg	      (Set DAC Palette Format only)
756706f2543Smrg
757706f2543Smrg    Output:
758706f2543Smrg	AX := VBE Return Status
759706f2543Smrg	BH := Current number of bits of color per primary
760706f2543Smrg     */
761706f2543Smrg
762706f2543Smrg    pVbe->pInt10->num = 0x10;
763706f2543Smrg    pVbe->pInt10->ax = 0x4f08;
764706f2543Smrg    if (!bits)
765706f2543Smrg	pVbe->pInt10->bx = 0x01;
766706f2543Smrg    else
767706f2543Smrg	pVbe->pInt10->bx = (bits & 0x00ff) << 8;
768706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
769706f2543Smrg
770706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
771706f2543Smrg	return 0;
772706f2543Smrg
773706f2543Smrg    return (bits != 0 ? bits : (pVbe->pInt10->bx >> 8) & 0x00ff);
774706f2543Smrg}
775706f2543Smrg
776706f2543SmrgCARD32 *
777706f2543SmrgVBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num,
778706f2543Smrg		      CARD32 *data, Bool secondary, Bool wait_retrace)
779706f2543Smrg{
780706f2543Smrg    /*
781706f2543Smrg    Input:
782706f2543Smrg    (16-bit)
783706f2543Smrg	AX    := 4F09h VBE Load/Unload Palette Data
784706f2543Smrg	BL    := 00h Set Palette Data
785706f2543Smrg	      := 01h Get Palette Data
786706f2543Smrg	      := 02h Set Secondary Palette Data
787706f2543Smrg	      := 03h Get Secondary Palette Data
788706f2543Smrg	      := 80h Set Palette Data during Vertical Retrace
789706f2543Smrg	CX    := Number of palette registers to update (to a maximum of 256)
790706f2543Smrg	DX    := First of the palette registers to update (start)
791706f2543Smrg	ES:DI := Table of palette values (see below for format)
792706f2543Smrg
793706f2543Smrg    Output:
794706f2543Smrg	AX    := VBE Return Status
795706f2543Smrg
796706f2543Smrg
797706f2543Smrg    Input:
798706f2543Smrg    (32-bit)
799706f2543Smrg	BL     := 00h Set Palette Data
800706f2543Smrg	       := 80h Set Palette Data during Vertical Retrace
801706f2543Smrg	CX     := Number of palette registers to update (to a maximum of 256)
802706f2543Smrg	DX     := First of the palette registers to update (start)
803706f2543Smrg	ES:EDI := Table of palette values (see below for format)
804706f2543Smrg	DS     := Selector for memory mapped registers
805706f2543Smrg     */
806706f2543Smrg
807706f2543Smrg    pVbe->pInt10->num = 0x10;
808706f2543Smrg    pVbe->pInt10->ax = 0x4f09;
809706f2543Smrg    if (!secondary)
810706f2543Smrg	pVbe->pInt10->bx = set && wait_retrace ? 0x80 : set ? 0 : 1;
811706f2543Smrg    else
812706f2543Smrg	pVbe->pInt10->bx = set ? 2 : 3;
813706f2543Smrg    pVbe->pInt10->cx = num;
814706f2543Smrg    pVbe->pInt10->dx = first;
815706f2543Smrg    pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
816706f2543Smrg    pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
817706f2543Smrg    if (set)
818706f2543Smrg	memcpy(pVbe->memory, data, num * sizeof(CARD32));
819706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
820706f2543Smrg
821706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
822706f2543Smrg	return NULL;
823706f2543Smrg
824706f2543Smrg    if (set)
825706f2543Smrg	return data;
826706f2543Smrg
827706f2543Smrg    data = malloc(num * sizeof(CARD32));
828706f2543Smrg    memcpy(data, pVbe->memory, num * sizeof(CARD32));
829706f2543Smrg
830706f2543Smrg    return data;
831706f2543Smrg}
832706f2543Smrg
833706f2543SmrgVBEpmi *
834706f2543SmrgVBEGetVBEpmi(vbeInfoPtr pVbe)
835706f2543Smrg{
836706f2543Smrg    VBEpmi *pmi;
837706f2543Smrg
838706f2543Smrg    /*
839706f2543Smrg    Input:
840706f2543Smrg	AH    := 4Fh	Super VGA support
841706f2543Smrg	AL    := 0Ah	Protected Mode Interface
842706f2543Smrg	BL    := 00h	Return Protected Mode Table
843706f2543Smrg
844706f2543Smrg    Output:
845706f2543Smrg	AX    := Status
846706f2543Smrg	ES    := Real Mode Segment of Table
847706f2543Smrg	DI    := Offset of Table
848706f2543Smrg	CX    := Lenght of Table including protected mode code in bytes (for copying purposes)
849706f2543Smrg	(All other registers are preserved)
850706f2543Smrg     */
851706f2543Smrg
852706f2543Smrg    pVbe->pInt10->num = 0x10;
853706f2543Smrg    pVbe->pInt10->ax = 0x4f0a;
854706f2543Smrg    pVbe->pInt10->bx = 0;
855706f2543Smrg    pVbe->pInt10->di = 0;
856706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
857706f2543Smrg
858706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
859706f2543Smrg	return NULL;
860706f2543Smrg
861706f2543Smrg    pmi = malloc(sizeof(VBEpmi));
862706f2543Smrg    pmi->seg_tbl = R16(pVbe->pInt10->es);
863706f2543Smrg    pmi->tbl_off = R16(pVbe->pInt10->di);
864706f2543Smrg    pmi->tbl_len = R16(pVbe->pInt10->cx);
865706f2543Smrg
866706f2543Smrg    return pmi;
867706f2543Smrg}
868706f2543Smrg
869706f2543Smrg#if 0
870706f2543SmrgvbeModeInfoPtr
871706f2543SmrgVBEBuildVbeModeList(vbeInfoPtr pVbe, VbeInfoBlock *vbe)
872706f2543Smrg{
873706f2543Smrg    vbeModeInfoPtr ModeList = NULL;
874706f2543Smrg
875706f2543Smrg    int i = 0;
876706f2543Smrg    while (vbe->VideoModePtr[i] != 0xffff) {
877706f2543Smrg	vbeModeInfoPtr m;
878706f2543Smrg	VbeModeInfoBlock *mode;
879706f2543Smrg	int id = vbe->VideoModePtr[i++];
880706f2543Smrg	int bpp;
881706f2543Smrg
882706f2543Smrg	if ((mode = VBEGetModeInfo(pVbe, id)) == NULL)
883706f2543Smrg	    continue;
884706f2543Smrg
885706f2543Smrg 	bpp = mode->BitsPerPixel;
886706f2543Smrg
887706f2543Smrg	m = xnfcalloc(sizeof(vbeModeInfoRec),1);
888706f2543Smrg	m->width = mode->XResolution;
889706f2543Smrg	m->height = mode->YResolution;
890706f2543Smrg	m->bpp = bpp;
891706f2543Smrg	m->n = id;
892706f2543Smrg	m->next = ModeList;
893706f2543Smrg
894706f2543Smrg	xf86DrvMsgVerb(pVbe->pInt10->scrnIndex, X_PROBED, 3,
895706f2543Smrg		       "BIOS reported VESA mode 0x%x: x:%i y:%i bpp:%i\n",
896706f2543Smrg		       m->n, m->width, m->height, m->bpp);
897706f2543Smrg
898706f2543Smrg	ModeList = m;
899706f2543Smrg
900706f2543Smrg	VBEFreeModeInfo(mode);
901706f2543Smrg    }
902706f2543Smrg    return ModeList;
903706f2543Smrg}
904706f2543Smrg
905706f2543Smrgunsigned short
906706f2543SmrgVBECalcVbeModeIndex(vbeModeInfoPtr m, DisplayModePtr mode, int bpp)
907706f2543Smrg{
908706f2543Smrg    while (m) {
909706f2543Smrg	if (bpp == m->bpp
910706f2543Smrg	    && mode->HDisplay == m->width
911706f2543Smrg	    && mode->VDisplay == m->height)
912706f2543Smrg	    return m->n;
913706f2543Smrg	m = m->next;
914706f2543Smrg    }
915706f2543Smrg    return 0;
916706f2543Smrg}
917706f2543Smrg#endif
918706f2543Smrg
919706f2543Smrgvoid
920706f2543SmrgVBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr,
921706f2543Smrg		  vbeSaveRestoreFunction function)
922706f2543Smrg{
923706f2543Smrg    Bool SaveSucc = FALSE;
924706f2543Smrg
925706f2543Smrg    if (VBE_VERSION_MAJOR(pVbe->version) > 1
926706f2543Smrg	&& (function == MODE_SAVE || vbe_sr->pstate)) {
927706f2543Smrg	if (function == MODE_RESTORE)
928706f2543Smrg	    memcpy(vbe_sr->state, vbe_sr->pstate, vbe_sr->stateSize);
929706f2543Smrg	ErrorF("VBESaveRestore\n");
930706f2543Smrg	if ((VBESaveRestore(pVbe,function,
931706f2543Smrg			    (pointer)&vbe_sr->state,
932706f2543Smrg			    &vbe_sr->stateSize,&vbe_sr->statePage))) {
933706f2543Smrg	    if (function == MODE_SAVE) {
934706f2543Smrg		SaveSucc = TRUE;
935706f2543Smrg		vbe_sr->stateMode = -1; /* invalidate */
936706f2543Smrg		/* don't rely on the memory not being touched */
937706f2543Smrg		if (vbe_sr->pstate == NULL)
938706f2543Smrg		    vbe_sr->pstate = malloc(vbe_sr->stateSize);
939706f2543Smrg		memcpy(vbe_sr->pstate, vbe_sr->state, vbe_sr->stateSize);
940706f2543Smrg	    }
941706f2543Smrg	    ErrorF("VBESaveRestore done with success\n");
942706f2543Smrg	    return;
943706f2543Smrg	}
944706f2543Smrg	ErrorF("VBESaveRestore done\n");
945706f2543Smrg    }
946706f2543Smrg
947706f2543Smrg    if (function == MODE_SAVE && !SaveSucc)
948706f2543Smrg	    (void)VBEGetVBEMode(pVbe, &vbe_sr->stateMode);
949706f2543Smrg
950706f2543Smrg    if (function == MODE_RESTORE && vbe_sr->stateMode != -1)
951706f2543Smrg	    VBESetVBEMode(pVbe, vbe_sr->stateMode, NULL);
952706f2543Smrg
953706f2543Smrg}
954706f2543Smrg
955706f2543Smrgint
956706f2543SmrgVBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock)
957706f2543Smrg{
958706f2543Smrg    /*
959706f2543Smrg    Input:
960706f2543Smrg	AX := 4F0Bh VBE Get Pixel Clock
961706f2543Smrg	BL := 00h Get Pixel Clock
962706f2543Smrg	ECX := pixel clock in units of Hz
963706f2543Smrg        DX := mode number
964706f2543Smrg
965706f2543Smrg    Output:
966706f2543Smrg	AX := VBE Return Status
967706f2543Smrg	ECX := Closest pixel clock
968706f2543Smrg     */
969706f2543Smrg
970706f2543Smrg    pVbe->pInt10->num = 0x10;
971706f2543Smrg    pVbe->pInt10->ax = 0x4f0b;
972706f2543Smrg    pVbe->pInt10->bx = 0x00;
973706f2543Smrg    pVbe->pInt10->cx = clock;
974706f2543Smrg    pVbe->pInt10->dx = mode;
975706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
976706f2543Smrg
977706f2543Smrg    if (R16(pVbe->pInt10->ax) != 0x4f)
978706f2543Smrg	return 0;
979706f2543Smrg
980706f2543Smrg    return pVbe->pInt10->cx;
981706f2543Smrg}
982706f2543Smrg
983706f2543SmrgBool
984706f2543SmrgVBEDPMSSet(vbeInfoPtr pVbe, int mode)
985706f2543Smrg{
986706f2543Smrg    /*
987706f2543Smrg    Input:
988706f2543Smrg	AX := 4F10h DPMS
989706f2543Smrg	BL := 01h Set Display Power State
990706f2543Smrg	BH := requested power state
991706f2543Smrg
992706f2543Smrg    Output:
993706f2543Smrg	AX := VBE Return Status
994706f2543Smrg     */
995706f2543Smrg
996706f2543Smrg    pVbe->pInt10->num = 0x10;
997706f2543Smrg    pVbe->pInt10->ax = 0x4f10;
998706f2543Smrg    pVbe->pInt10->bx = 0x01;
999706f2543Smrg    switch (mode) {
1000706f2543Smrg    case DPMSModeOn:
1001706f2543Smrg	break;
1002706f2543Smrg    case DPMSModeStandby:
1003706f2543Smrg	pVbe->pInt10->bx |= 0x100;
1004706f2543Smrg	break;
1005706f2543Smrg    case DPMSModeSuspend:
1006706f2543Smrg	pVbe->pInt10->bx |= 0x200;
1007706f2543Smrg	break;
1008706f2543Smrg    case DPMSModeOff:
1009706f2543Smrg	pVbe->pInt10->bx |= 0x400;
1010706f2543Smrg	break;
1011706f2543Smrg    }
1012706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
1013706f2543Smrg    return (R16(pVbe->pInt10->ax) == 0x4f);
1014706f2543Smrg}
1015706f2543Smrg
1016706f2543Smrgvoid
1017706f2543SmrgVBEInterpretPanelID(int scrnIndex, struct vbePanelID *data)
1018706f2543Smrg{
1019706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1020706f2543Smrg    DisplayModePtr mode;
1021706f2543Smrg    const float PANEL_HZ = 60.0;
1022706f2543Smrg
1023706f2543Smrg    if (!data)
1024706f2543Smrg	return;
1025706f2543Smrg
1026706f2543Smrg    xf86DrvMsg(scrnIndex, X_INFO, "PanelID returned panel resolution %dx%d\n",
1027706f2543Smrg	    data->hsize, data->vsize);
1028706f2543Smrg
1029706f2543Smrg    if (pScrn->monitor->nHsync || pScrn->monitor->nVrefresh)
1030706f2543Smrg	return;
1031706f2543Smrg
1032706f2543Smrg    if (data->hsize < 320 || data->vsize < 240) {
1033706f2543Smrg	xf86DrvMsg(scrnIndex, X_INFO, "...which I refuse to believe\n");
1034706f2543Smrg	return;
1035706f2543Smrg    }
1036706f2543Smrg
1037706f2543Smrg    mode = xf86CVTMode(data->hsize, data->vsize, PANEL_HZ, 1, 0);
1038706f2543Smrg
1039706f2543Smrg    pScrn->monitor->nHsync = 1;
1040706f2543Smrg    pScrn->monitor->hsync[0].lo = 29.37;
1041706f2543Smrg    pScrn->monitor->hsync[0].hi = (float)mode->Clock / (float)mode->HTotal;
1042706f2543Smrg    pScrn->monitor->nVrefresh = 1;
1043706f2543Smrg    pScrn->monitor->vrefresh[0].lo = 56.0;
1044706f2543Smrg    pScrn->monitor->vrefresh[0].hi =
1045706f2543Smrg	(float)mode->Clock*1000.0 / (float)mode->HTotal / (float)mode->VTotal;
1046706f2543Smrg
1047706f2543Smrg    if (pScrn->monitor->vrefresh[0].hi < 59.47)
1048706f2543Smrg	pScrn->monitor->vrefresh[0].hi = 59.47;
1049706f2543Smrg
1050706f2543Smrg    free(mode);
1051706f2543Smrg}
1052706f2543Smrg
1053706f2543Smrgstruct vbePanelID *
1054706f2543SmrgVBEReadPanelID(vbeInfoPtr pVbe)
1055706f2543Smrg{
1056706f2543Smrg    int RealOff = pVbe->real_mode_base;
1057706f2543Smrg    pointer page = pVbe->memory;
1058706f2543Smrg    void *tmp = NULL;
1059706f2543Smrg    int screen = pVbe->pInt10->scrnIndex;
1060706f2543Smrg
1061706f2543Smrg    pVbe->pInt10->ax = 0x4F11;
1062706f2543Smrg    pVbe->pInt10->bx = 0x01;
1063706f2543Smrg    pVbe->pInt10->cx = 0;
1064706f2543Smrg    pVbe->pInt10->dx = 0;
1065706f2543Smrg    pVbe->pInt10->es = SEG_ADDR(RealOff);
1066706f2543Smrg    pVbe->pInt10->di = SEG_OFF(RealOff);
1067706f2543Smrg    pVbe->pInt10->num = 0x10;
1068706f2543Smrg
1069706f2543Smrg    xf86ExecX86int10(pVbe->pInt10);
1070706f2543Smrg
1071706f2543Smrg    if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
1072706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID invalid\n");
1073706f2543Smrg	goto error;
1074706f2543Smrg    }
1075706f2543Smrg
1076706f2543Smrg    switch (pVbe->pInt10->ax & 0xff00) {
1077706f2543Smrg    case 0x0:
1078706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read successfully\n");
1079706f2543Smrg	tmp = xnfalloc(32);
1080706f2543Smrg	memcpy(tmp, page, 32);
1081706f2543Smrg	break;
1082706f2543Smrg    case 0x100:
1083706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID read failed\n");
1084706f2543Smrg	break;
1085706f2543Smrg    default:
1086706f2543Smrg	xf86DrvMsgVerb(screen,X_INFO,3,"VESA VBE PanelID unknown failure %i\n",
1087706f2543Smrg		       pVbe->pInt10->ax & 0xff00);
1088706f2543Smrg	break;
1089706f2543Smrg    }
1090706f2543Smrg
1091706f2543Smrgerror:
1092706f2543Smrg    return tmp;
1093706f2543Smrg}
1094