xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/vbe/vbe.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun 
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *                   XFree86 vbe module
4*4882a593Smuzhiyun  *               Copyright 2000 Egbert Eich
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * The mode query/save/set/restore functions from the vesa driver
7*4882a593Smuzhiyun  * have been moved here.
8*4882a593Smuzhiyun  * Copyright (c) 2000 by Conectiva S.A. (http://www.conectiva.com)
9*4882a593Smuzhiyun  * Authors: Paulo César Pereira de Andrade <pcpa@conectiva.com.br>
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #ifdef HAVE_XORG_CONFIG_H
13*4882a593Smuzhiyun #include <xorg-config.h>
14*4882a593Smuzhiyun #endif
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <string.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "xf86.h"
19*4882a593Smuzhiyun #include "xf86Modes.h"
20*4882a593Smuzhiyun #include "vbe.h"
21*4882a593Smuzhiyun #include <X11/extensions/dpmsconst.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define VERSION(x) VBE_VERSION_MAJOR(x),VBE_VERSION_MINOR(x)
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #if X_BYTE_ORDER == X_LITTLE_ENDIAN
26*4882a593Smuzhiyun #define B_O16(x)  (x)
27*4882a593Smuzhiyun #define B_O32(x)  (x)
28*4882a593Smuzhiyun #else
29*4882a593Smuzhiyun #define B_O16(x)  ((((x) & 0xff) << 8) | (((x) & 0xff) >> 8))
30*4882a593Smuzhiyun #define B_O32(x)  ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \
31*4882a593Smuzhiyun                   | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun #define L_ADD(x)  (B_O32(x) & 0xffff) + ((B_O32(x) >> 12) & 0xffff00)
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define FARP(p)		(((unsigned)(p & 0xffff0000) >> 12) | (p & 0xffff))
36*4882a593Smuzhiyun #define R16(v)		((v) & 0xffff)
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun static unsigned char *vbeReadEDID(vbeInfoPtr pVbe);
39*4882a593Smuzhiyun static Bool vbeProbeDDC(vbeInfoPtr pVbe);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun static const char vbeVersionString[] = "VBE2";
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun vbeInfoPtr
VBEInit(xf86Int10InfoPtr pInt,int entityIndex)44*4882a593Smuzhiyun VBEInit(xf86Int10InfoPtr pInt, int entityIndex)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun     return VBEExtendedInit(pInt, entityIndex, 0);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun vbeInfoPtr
VBEExtendedInit(xf86Int10InfoPtr pInt,int entityIndex,int Flags)50*4882a593Smuzhiyun VBEExtendedInit(xf86Int10InfoPtr pInt, int entityIndex, int Flags)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun     int RealOff;
53*4882a593Smuzhiyun     void *page = NULL;
54*4882a593Smuzhiyun     ScrnInfoPtr pScrn = xf86FindScreenForEntity(entityIndex);
55*4882a593Smuzhiyun     vbeControllerInfoPtr vbe = NULL;
56*4882a593Smuzhiyun     Bool init_int10 = FALSE;
57*4882a593Smuzhiyun     vbeInfoPtr vip = NULL;
58*4882a593Smuzhiyun     int screen;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun     if (!pScrn)
61*4882a593Smuzhiyun         return NULL;
62*4882a593Smuzhiyun     screen = pScrn->scrnIndex;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun     if (!pInt) {
65*4882a593Smuzhiyun         if (!xf86LoadSubModule(pScrn, "int10"))
66*4882a593Smuzhiyun             goto error;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "initializing int10\n");
69*4882a593Smuzhiyun         pInt = xf86ExtendedInitInt10(entityIndex, Flags);
70*4882a593Smuzhiyun         if (!pInt)
71*4882a593Smuzhiyun             goto error;
72*4882a593Smuzhiyun         init_int10 = TRUE;
73*4882a593Smuzhiyun     }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun     page = xf86Int10AllocPages(pInt, 1, &RealOff);
76*4882a593Smuzhiyun     if (!page)
77*4882a593Smuzhiyun         goto error;
78*4882a593Smuzhiyun     vbe = (vbeControllerInfoPtr) page;
79*4882a593Smuzhiyun     memcpy(vbe->VbeSignature, vbeVersionString, 4);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun     pInt->ax = 0x4F00;
82*4882a593Smuzhiyun     pInt->es = SEG_ADDR(RealOff);
83*4882a593Smuzhiyun     pInt->di = SEG_OFF(RealOff);
84*4882a593Smuzhiyun     pInt->num = 0x10;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun     xf86ExecX86int10(pInt);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun     if ((pInt->ax & 0xff) != 0x4f) {
89*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA BIOS not detected\n");
90*4882a593Smuzhiyun         goto error;
91*4882a593Smuzhiyun     }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun     switch (pInt->ax & 0xff00) {
94*4882a593Smuzhiyun     case 0:
95*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "VESA BIOS detected\n");
96*4882a593Smuzhiyun         break;
97*4882a593Smuzhiyun     case 0x100:
98*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "VESA BIOS function failed\n");
99*4882a593Smuzhiyun         goto error;
100*4882a593Smuzhiyun     case 0x200:
101*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "VESA BIOS not supported\n");
102*4882a593Smuzhiyun         goto error;
103*4882a593Smuzhiyun     case 0x300:
104*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "VESA BIOS not supported in current mode\n");
105*4882a593Smuzhiyun         goto error;
106*4882a593Smuzhiyun     default:
107*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "Invalid\n");
108*4882a593Smuzhiyun         goto error;
109*4882a593Smuzhiyun     }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun     xf86DrvMsgVerb(screen, X_INFO, 4,
112*4882a593Smuzhiyun                    "VbeVersion is %d, OemStringPtr is 0x%08lx,\n"
113*4882a593Smuzhiyun                    "\tOemVendorNamePtr is 0x%08lx, OemProductNamePtr is 0x%08lx,\n"
114*4882a593Smuzhiyun                    "\tOemProductRevPtr is 0x%08lx\n",
115*4882a593Smuzhiyun                    vbe->VbeVersion, (unsigned long) vbe->OemStringPtr,
116*4882a593Smuzhiyun                    (unsigned long) vbe->OemVendorNamePtr,
117*4882a593Smuzhiyun                    (unsigned long) vbe->OemProductNamePtr,
118*4882a593Smuzhiyun                    (unsigned long) vbe->OemProductRevPtr);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun     xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE Version %i.%i\n",
121*4882a593Smuzhiyun                    VERSION(vbe->VbeVersion));
122*4882a593Smuzhiyun     xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE Total Mem: %i kB\n",
123*4882a593Smuzhiyun                    vbe->TotalMem * 64);
124*4882a593Smuzhiyun     xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE OEM: %s\n",
125*4882a593Smuzhiyun                    (CARD8 *) xf86int10Addr(pInt, L_ADD(vbe->OemStringPtr)));
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun     if (B_O16(vbe->VbeVersion) >= 0x200) {
128*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE OEM Software Rev: %i.%i\n",
129*4882a593Smuzhiyun                        VERSION(vbe->OemSoftwareRev));
130*4882a593Smuzhiyun         if (vbe->OemVendorNamePtr)
131*4882a593Smuzhiyun             xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE OEM Vendor: %s\n",
132*4882a593Smuzhiyun                            (CARD8 *) xf86int10Addr(pInt,
133*4882a593Smuzhiyun                                                    L_ADD(vbe->
134*4882a593Smuzhiyun                                                          OemVendorNamePtr)));
135*4882a593Smuzhiyun         if (vbe->OemProductNamePtr)
136*4882a593Smuzhiyun             xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE OEM Product: %s\n",
137*4882a593Smuzhiyun                            (CARD8 *) xf86int10Addr(pInt,
138*4882a593Smuzhiyun                                                    L_ADD(vbe->
139*4882a593Smuzhiyun                                                          OemProductNamePtr)));
140*4882a593Smuzhiyun         if (vbe->OemProductRevPtr)
141*4882a593Smuzhiyun             xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE OEM Product Rev: %s\n",
142*4882a593Smuzhiyun                            (CARD8 *) xf86int10Addr(pInt,
143*4882a593Smuzhiyun                                                    L_ADD(vbe->
144*4882a593Smuzhiyun                                                          OemProductRevPtr)));
145*4882a593Smuzhiyun     }
146*4882a593Smuzhiyun     vip = (vbeInfoPtr) xnfalloc(sizeof(vbeInfoRec));
147*4882a593Smuzhiyun     vip->version = B_O16(vbe->VbeVersion);
148*4882a593Smuzhiyun     vip->pInt10 = pInt;
149*4882a593Smuzhiyun     vip->ddc = DDC_UNCHECKED;
150*4882a593Smuzhiyun     vip->memory = page;
151*4882a593Smuzhiyun     vip->real_mode_base = RealOff;
152*4882a593Smuzhiyun     vip->num_pages = 1;
153*4882a593Smuzhiyun     vip->init_int10 = init_int10;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun     return vip;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun  error:
158*4882a593Smuzhiyun     if (page)
159*4882a593Smuzhiyun         xf86Int10FreePages(pInt, page, 1);
160*4882a593Smuzhiyun     if (init_int10)
161*4882a593Smuzhiyun         xf86FreeInt10(pInt);
162*4882a593Smuzhiyun     return NULL;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun void
vbeFree(vbeInfoPtr pVbe)166*4882a593Smuzhiyun vbeFree(vbeInfoPtr pVbe)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun     if (!pVbe)
169*4882a593Smuzhiyun         return;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun     xf86Int10FreePages(pVbe->pInt10, pVbe->memory, pVbe->num_pages);
172*4882a593Smuzhiyun     /* If we have initalized int10 we ought to free it, too */
173*4882a593Smuzhiyun     if (pVbe->init_int10)
174*4882a593Smuzhiyun         xf86FreeInt10(pVbe->pInt10);
175*4882a593Smuzhiyun     free(pVbe);
176*4882a593Smuzhiyun     return;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun static Bool
vbeProbeDDC(vbeInfoPtr pVbe)180*4882a593Smuzhiyun vbeProbeDDC(vbeInfoPtr pVbe)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun     const char *ddc_level;
183*4882a593Smuzhiyun     int screen = pVbe->pInt10->pScrn->scrnIndex;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun     if (pVbe->ddc == DDC_NONE)
186*4882a593Smuzhiyun         return FALSE;
187*4882a593Smuzhiyun     if (pVbe->ddc != DDC_UNCHECKED)
188*4882a593Smuzhiyun         return TRUE;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4F15;
191*4882a593Smuzhiyun     pVbe->pInt10->bx = 0;
192*4882a593Smuzhiyun     pVbe->pInt10->cx = 0;
193*4882a593Smuzhiyun     pVbe->pInt10->es = 0;
194*4882a593Smuzhiyun     pVbe->pInt10->di = 0;
195*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun     if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
200*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC not supported\n");
201*4882a593Smuzhiyun         pVbe->ddc = DDC_NONE;
202*4882a593Smuzhiyun         return FALSE;
203*4882a593Smuzhiyun     }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun     switch ((pVbe->pInt10->ax >> 8) & 0xff) {
206*4882a593Smuzhiyun     case 0:
207*4882a593Smuzhiyun         xf86DrvMsg(screen, X_INFO, "VESA VBE DDC supported\n");
208*4882a593Smuzhiyun         switch (pVbe->pInt10->bx & 0x3) {
209*4882a593Smuzhiyun         case 0:
210*4882a593Smuzhiyun             ddc_level = " none";
211*4882a593Smuzhiyun             pVbe->ddc = DDC_NONE;
212*4882a593Smuzhiyun             break;
213*4882a593Smuzhiyun         case 1:
214*4882a593Smuzhiyun             ddc_level = " 1";
215*4882a593Smuzhiyun             pVbe->ddc = DDC_1;
216*4882a593Smuzhiyun             break;
217*4882a593Smuzhiyun         case 2:
218*4882a593Smuzhiyun             ddc_level = " 2";
219*4882a593Smuzhiyun             pVbe->ddc = DDC_2;
220*4882a593Smuzhiyun             break;
221*4882a593Smuzhiyun         case 3:
222*4882a593Smuzhiyun             ddc_level = " 1 + 2";
223*4882a593Smuzhiyun             pVbe->ddc = DDC_1_2;
224*4882a593Smuzhiyun             break;
225*4882a593Smuzhiyun         default:
226*4882a593Smuzhiyun             ddc_level = "";
227*4882a593Smuzhiyun             pVbe->ddc = DDC_NONE;
228*4882a593Smuzhiyun             break;
229*4882a593Smuzhiyun         }
230*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC Level%s\n", ddc_level);
231*4882a593Smuzhiyun         if (pVbe->pInt10->bx & 0x4) {
232*4882a593Smuzhiyun             xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC Screen blanked"
233*4882a593Smuzhiyun                            "for data transfer\n");
234*4882a593Smuzhiyun             pVbe->ddc_blank = TRUE;
235*4882a593Smuzhiyun         }
236*4882a593Smuzhiyun         else
237*4882a593Smuzhiyun             pVbe->ddc_blank = FALSE;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3,
240*4882a593Smuzhiyun                        "VESA VBE DDC transfer in appr. %x sec.\n",
241*4882a593Smuzhiyun                        (pVbe->pInt10->bx >> 8) & 0xff);
242*4882a593Smuzhiyun     }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun     return TRUE;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun typedef enum {
248*4882a593Smuzhiyun     VBEOPT_NOVBE,
249*4882a593Smuzhiyun     VBEOPT_NODDC
250*4882a593Smuzhiyun } VBEOpts;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun static const OptionInfoRec VBEOptions[] = {
253*4882a593Smuzhiyun     {VBEOPT_NOVBE, "NoVBE", OPTV_BOOLEAN, {0}, FALSE},
254*4882a593Smuzhiyun     {VBEOPT_NODDC, "NoDDC", OPTV_BOOLEAN, {0}, FALSE},
255*4882a593Smuzhiyun     {-1, NULL, OPTV_NONE, {0}, FALSE},
256*4882a593Smuzhiyun };
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static unsigned char *
vbeReadEDID(vbeInfoPtr pVbe)259*4882a593Smuzhiyun vbeReadEDID(vbeInfoPtr pVbe)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun     int RealOff = pVbe->real_mode_base;
262*4882a593Smuzhiyun     void *page = pVbe->memory;
263*4882a593Smuzhiyun     unsigned char *tmp = NULL;
264*4882a593Smuzhiyun     Bool novbe = FALSE;
265*4882a593Smuzhiyun     Bool noddc = FALSE;
266*4882a593Smuzhiyun     ScrnInfoPtr pScrn = pVbe->pInt10->pScrn;
267*4882a593Smuzhiyun     int screen = pScrn->scrnIndex;
268*4882a593Smuzhiyun     OptionInfoPtr options;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun     if (!page)
271*4882a593Smuzhiyun         return NULL;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun     options = xnfalloc(sizeof(VBEOptions));
274*4882a593Smuzhiyun     (void) memcpy(options, VBEOptions, sizeof(VBEOptions));
275*4882a593Smuzhiyun     xf86ProcessOptions(screen, pScrn->options, options);
276*4882a593Smuzhiyun     xf86GetOptValBool(options, VBEOPT_NOVBE, &novbe);
277*4882a593Smuzhiyun     xf86GetOptValBool(options, VBEOPT_NODDC, &noddc);
278*4882a593Smuzhiyun     free(options);
279*4882a593Smuzhiyun     if (novbe || noddc)
280*4882a593Smuzhiyun         return NULL;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun     if (!vbeProbeDDC(pVbe))
283*4882a593Smuzhiyun         goto error;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun     memset(page, 0, sizeof(vbeInfoPtr));
286*4882a593Smuzhiyun     strcpy(page, vbeVersionString);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4F15;
289*4882a593Smuzhiyun     pVbe->pInt10->bx = 0x01;
290*4882a593Smuzhiyun     pVbe->pInt10->cx = 0;
291*4882a593Smuzhiyun     pVbe->pInt10->dx = 0;
292*4882a593Smuzhiyun     pVbe->pInt10->es = SEG_ADDR(RealOff);
293*4882a593Smuzhiyun     pVbe->pInt10->di = SEG_OFF(RealOff);
294*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun     if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
299*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC invalid\n");
300*4882a593Smuzhiyun         goto error;
301*4882a593Smuzhiyun     }
302*4882a593Smuzhiyun     switch (pVbe->pInt10->ax & 0xff00) {
303*4882a593Smuzhiyun     case 0x0:
304*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC read successfully\n");
305*4882a593Smuzhiyun         tmp = (unsigned char *) xnfalloc(128);
306*4882a593Smuzhiyun         memcpy(tmp, page, 128);
307*4882a593Smuzhiyun         break;
308*4882a593Smuzhiyun     case 0x100:
309*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC read failed\n");
310*4882a593Smuzhiyun         break;
311*4882a593Smuzhiyun     default:
312*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE DDC unkown failure %i\n",
313*4882a593Smuzhiyun                        pVbe->pInt10->ax & 0xff00);
314*4882a593Smuzhiyun         break;
315*4882a593Smuzhiyun     }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun  error:
318*4882a593Smuzhiyun     return tmp;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun xf86MonPtr
vbeDoEDID(vbeInfoPtr pVbe,void * unused)322*4882a593Smuzhiyun vbeDoEDID(vbeInfoPtr pVbe, void *unused)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun     unsigned char *DDC_data = NULL;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun     if (!pVbe)
327*4882a593Smuzhiyun         return NULL;
328*4882a593Smuzhiyun     if (pVbe->version < 0x102)
329*4882a593Smuzhiyun         return NULL;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun     DDC_data = vbeReadEDID(pVbe);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun     if (!DDC_data)
334*4882a593Smuzhiyun         return NULL;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun     return xf86InterpretEDID(pVbe->pInt10->pScrn->scrnIndex, DDC_data);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun #define GET_UNALIGNED2(x) \
340*4882a593Smuzhiyun             ((*(CARD16*)(x)) | (*(((CARD16*)(x) + 1))) << 16)
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun VbeInfoBlock *
VBEGetVBEInfo(vbeInfoPtr pVbe)343*4882a593Smuzhiyun VBEGetVBEInfo(vbeInfoPtr pVbe)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun     VbeInfoBlock *block = NULL;
346*4882a593Smuzhiyun     int i, pStr, pModes;
347*4882a593Smuzhiyun     char *str;
348*4882a593Smuzhiyun     CARD16 major, *modes;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun     memset(pVbe->memory, 0, sizeof(VbeInfoBlock));
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun     /*
353*4882a593Smuzhiyun        Input:
354*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
355*4882a593Smuzhiyun        AL    := 00h     Return Super VGA information
356*4882a593Smuzhiyun        ES:DI := Pointer to buffer
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun        Output:
359*4882a593Smuzhiyun        AX    := status
360*4882a593Smuzhiyun        (All other registers are preserved)
361*4882a593Smuzhiyun      */
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun     ((char *) pVbe->memory)[0] = 'V';
364*4882a593Smuzhiyun     ((char *) pVbe->memory)[1] = 'B';
365*4882a593Smuzhiyun     ((char *) pVbe->memory)[2] = 'E';
366*4882a593Smuzhiyun     ((char *) pVbe->memory)[3] = '2';
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
369*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f00;
370*4882a593Smuzhiyun     pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
371*4882a593Smuzhiyun     pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
372*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
375*4882a593Smuzhiyun         return NULL;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun     block = calloc(sizeof(VbeInfoBlock), 1);
378*4882a593Smuzhiyun     block->VESASignature[0] = ((char *) pVbe->memory)[0];
379*4882a593Smuzhiyun     block->VESASignature[1] = ((char *) pVbe->memory)[1];
380*4882a593Smuzhiyun     block->VESASignature[2] = ((char *) pVbe->memory)[2];
381*4882a593Smuzhiyun     block->VESASignature[3] = ((char *) pVbe->memory)[3];
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun     block->VESAVersion = *(CARD16 *) (((char *) pVbe->memory) + 4);
384*4882a593Smuzhiyun     major = (unsigned) block->VESAVersion >> 8;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun     pStr = GET_UNALIGNED2((((char *) pVbe->memory) + 6));
387*4882a593Smuzhiyun     str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
388*4882a593Smuzhiyun     block->OEMStringPtr = strdup(str);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun     block->Capabilities[0] = ((char *) pVbe->memory)[10];
391*4882a593Smuzhiyun     block->Capabilities[1] = ((char *) pVbe->memory)[11];
392*4882a593Smuzhiyun     block->Capabilities[2] = ((char *) pVbe->memory)[12];
393*4882a593Smuzhiyun     block->Capabilities[3] = ((char *) pVbe->memory)[13];
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun     pModes = GET_UNALIGNED2((((char *) pVbe->memory) + 14));
396*4882a593Smuzhiyun     modes = xf86int10Addr(pVbe->pInt10, FARP(pModes));
397*4882a593Smuzhiyun     i = 0;
398*4882a593Smuzhiyun     while (modes[i] != 0xffff)
399*4882a593Smuzhiyun         i++;
400*4882a593Smuzhiyun     block->VideoModePtr = xallocarray(i + 1, sizeof(CARD16));
401*4882a593Smuzhiyun     memcpy(block->VideoModePtr, modes, sizeof(CARD16) * i);
402*4882a593Smuzhiyun     block->VideoModePtr[i] = 0xffff;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun     block->TotalMemory = *(CARD16 *) (((char *) pVbe->memory) + 18);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun     if (major < 2)
407*4882a593Smuzhiyun         memcpy(&block->OemSoftwareRev, ((char *) pVbe->memory) + 20, 236);
408*4882a593Smuzhiyun     else {
409*4882a593Smuzhiyun         block->OemSoftwareRev = *(CARD16 *) (((char *) pVbe->memory) + 20);
410*4882a593Smuzhiyun         pStr = GET_UNALIGNED2((((char *) pVbe->memory) + 22));
411*4882a593Smuzhiyun         str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
412*4882a593Smuzhiyun         block->OemVendorNamePtr = strdup(str);
413*4882a593Smuzhiyun         pStr = GET_UNALIGNED2((((char *) pVbe->memory) + 26));
414*4882a593Smuzhiyun         str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
415*4882a593Smuzhiyun         block->OemProductNamePtr = strdup(str);
416*4882a593Smuzhiyun         pStr = GET_UNALIGNED2((((char *) pVbe->memory) + 30));
417*4882a593Smuzhiyun         str = xf86int10Addr(pVbe->pInt10, FARP(pStr));
418*4882a593Smuzhiyun         block->OemProductRevPtr = strdup(str);
419*4882a593Smuzhiyun         memcpy(&block->Reserved, ((char *) pVbe->memory) + 34, 222);
420*4882a593Smuzhiyun         memcpy(&block->OemData, ((char *) pVbe->memory) + 256, 256);
421*4882a593Smuzhiyun     }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun     return block;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun void
VBEFreeVBEInfo(VbeInfoBlock * block)427*4882a593Smuzhiyun VBEFreeVBEInfo(VbeInfoBlock * block)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun     free(block->OEMStringPtr);
430*4882a593Smuzhiyun     free(block->VideoModePtr);
431*4882a593Smuzhiyun     if (((unsigned) block->VESAVersion >> 8) >= 2) {
432*4882a593Smuzhiyun         free(block->OemVendorNamePtr);
433*4882a593Smuzhiyun         free(block->OemProductNamePtr);
434*4882a593Smuzhiyun         free(block->OemProductRevPtr);
435*4882a593Smuzhiyun     }
436*4882a593Smuzhiyun     free(block);
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun Bool
VBESetVBEMode(vbeInfoPtr pVbe,int mode,VbeCRTCInfoBlock * block)440*4882a593Smuzhiyun VBESetVBEMode(vbeInfoPtr pVbe, int mode, VbeCRTCInfoBlock * block)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun     /*
443*4882a593Smuzhiyun        Input:
444*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
445*4882a593Smuzhiyun        AL    := 02h     Set Super VGA video mode
446*4882a593Smuzhiyun        BX    := Video mode
447*4882a593Smuzhiyun        D0-D8  := Mode number
448*4882a593Smuzhiyun        D9-D10 := Reserved (must be 0)
449*4882a593Smuzhiyun        D11    := 0 Use current default refresh rate
450*4882a593Smuzhiyun        := 1 Use user specified CRTC values for refresh rate
451*4882a593Smuzhiyun        D12-13   Reserved for VBE/AF (must be 0)
452*4882a593Smuzhiyun        D14    := 0 Use windowed frame buffer model
453*4882a593Smuzhiyun        := 1 Use linear/flat frame buffer model
454*4882a593Smuzhiyun        D15    := 0 Clear video memory
455*4882a593Smuzhiyun        := 1 Don't clear video memory
456*4882a593Smuzhiyun        ES:DI := Pointer to VbeCRTCInfoBlock structure
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun        Output: AX = Status
459*4882a593Smuzhiyun        (All other registers are preserved)
460*4882a593Smuzhiyun      */
461*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
462*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f02;
463*4882a593Smuzhiyun     pVbe->pInt10->bx = mode;
464*4882a593Smuzhiyun     if (block) {
465*4882a593Smuzhiyun         pVbe->pInt10->bx |= 1 << 11;
466*4882a593Smuzhiyun         memcpy(pVbe->memory, block, sizeof(VbeCRTCInfoBlock));
467*4882a593Smuzhiyun         pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
468*4882a593Smuzhiyun         pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
469*4882a593Smuzhiyun     }
470*4882a593Smuzhiyun     else
471*4882a593Smuzhiyun         pVbe->pInt10->bx &= ~(1 << 11);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun     return (R16(pVbe->pInt10->ax) == 0x4f);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun Bool
VBEGetVBEMode(vbeInfoPtr pVbe,int * mode)479*4882a593Smuzhiyun VBEGetVBEMode(vbeInfoPtr pVbe, int *mode)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun     /*
482*4882a593Smuzhiyun        Input:
483*4882a593Smuzhiyun        AH := 4Fh        Super VGA support
484*4882a593Smuzhiyun        AL := 03h        Return current video mode
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun        Output:
487*4882a593Smuzhiyun        AX := Status
488*4882a593Smuzhiyun        BX := Current video mode
489*4882a593Smuzhiyun        (All other registers are preserved)
490*4882a593Smuzhiyun      */
491*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
492*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f03;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) == 0x4f) {
497*4882a593Smuzhiyun         *mode = R16(pVbe->pInt10->bx);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun         return TRUE;
500*4882a593Smuzhiyun     }
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun     return FALSE;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun VbeModeInfoBlock *
VBEGetModeInfo(vbeInfoPtr pVbe,int mode)506*4882a593Smuzhiyun VBEGetModeInfo(vbeInfoPtr pVbe, int mode)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun     VbeModeInfoBlock *block = NULL;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun     memset(pVbe->memory, 0, sizeof(VbeModeInfoBlock));
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun     /*
513*4882a593Smuzhiyun        Input:
514*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
515*4882a593Smuzhiyun        AL    := 01h     Return Super VGA mode information
516*4882a593Smuzhiyun        CX    :=         Super VGA video mode
517*4882a593Smuzhiyun        (mode number must be one of those returned by Function 0)
518*4882a593Smuzhiyun        ES:DI := Pointer to buffer
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun        Output:
521*4882a593Smuzhiyun        AX    := status
522*4882a593Smuzhiyun        (All other registers are preserved)
523*4882a593Smuzhiyun      */
524*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
525*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f01;
526*4882a593Smuzhiyun     pVbe->pInt10->cx = mode;
527*4882a593Smuzhiyun     pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
528*4882a593Smuzhiyun     pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
529*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
530*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
531*4882a593Smuzhiyun         return NULL;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun     block = malloc(sizeof(VbeModeInfoBlock));
534*4882a593Smuzhiyun     if (block)
535*4882a593Smuzhiyun         memcpy(block, pVbe->memory, sizeof(*block));
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun     return block;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun void
VBEFreeModeInfo(VbeModeInfoBlock * block)541*4882a593Smuzhiyun VBEFreeModeInfo(VbeModeInfoBlock * block)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun     free(block);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun Bool
VBESaveRestore(vbeInfoPtr pVbe,vbeSaveRestoreFunction function,void ** memory,int * size,int * real_mode_pages)547*4882a593Smuzhiyun VBESaveRestore(vbeInfoPtr pVbe, vbeSaveRestoreFunction function,
548*4882a593Smuzhiyun                void **memory, int *size, int *real_mode_pages)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun     /*
551*4882a593Smuzhiyun        Input:
552*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
553*4882a593Smuzhiyun        AL    := 04h     Save/restore Super VGA video state
554*4882a593Smuzhiyun        DL    := 00h     Return save/restore state buffer size
555*4882a593Smuzhiyun        CX    := Requested states
556*4882a593Smuzhiyun        D0 = Save/restore video hardware state
557*4882a593Smuzhiyun        D1 = Save/restore video BIOS data state
558*4882a593Smuzhiyun        D2 = Save/restore video DAC state
559*4882a593Smuzhiyun        D3 = Save/restore Super VGA state
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun        Output:
562*4882a593Smuzhiyun        AX = Status
563*4882a593Smuzhiyun        BX = Number of 64-byte blocks to hold the state buffer
564*4882a593Smuzhiyun        (All other registers are preserved)
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun        Input:
567*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
568*4882a593Smuzhiyun        AL    := 04h     Save/restore Super VGA video state
569*4882a593Smuzhiyun        DL    := 01h     Save Super VGA video state
570*4882a593Smuzhiyun        CX    := Requested states (see above)
571*4882a593Smuzhiyun        ES:BX := Pointer to buffer
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun        Output:
574*4882a593Smuzhiyun        AX    := Status
575*4882a593Smuzhiyun        (All other registers are preserved)
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun        Input:
578*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
579*4882a593Smuzhiyun        AL    := 04h     Save/restore Super VGA video state
580*4882a593Smuzhiyun        DL    := 02h     Restore Super VGA video state
581*4882a593Smuzhiyun        CX    := Requested states (see above)
582*4882a593Smuzhiyun        ES:BX := Pointer to buffer
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun        Output:
585*4882a593Smuzhiyun        AX     := Status
586*4882a593Smuzhiyun        (All other registers are preserved)
587*4882a593Smuzhiyun      */
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun     if ((pVbe->version & 0xff00) > 0x100) {
590*4882a593Smuzhiyun         int screen = pVbe->pInt10->pScrn->scrnIndex;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun         if (function == MODE_QUERY || (function == MODE_SAVE && !*memory)) {
593*4882a593Smuzhiyun             /* Query amount of memory to save state */
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun             pVbe->pInt10->num = 0x10;
596*4882a593Smuzhiyun             pVbe->pInt10->ax = 0x4f04;
597*4882a593Smuzhiyun             pVbe->pInt10->dx = 0;
598*4882a593Smuzhiyun             pVbe->pInt10->cx = 0x000f;
599*4882a593Smuzhiyun             xf86ExecX86int10(pVbe->pInt10);
600*4882a593Smuzhiyun             if (R16(pVbe->pInt10->ax) != 0x4f)
601*4882a593Smuzhiyun                 return FALSE;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun             if (function == MODE_SAVE) {
604*4882a593Smuzhiyun                 int npages = (R16(pVbe->pInt10->bx) * 64) / 4096 + 1;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun                 if ((*memory = xf86Int10AllocPages(pVbe->pInt10, npages,
607*4882a593Smuzhiyun                                                    real_mode_pages)) == NULL) {
608*4882a593Smuzhiyun                     xf86DrvMsg(screen, X_ERROR,
609*4882a593Smuzhiyun                                "Cannot allocate memory to save SVGA state.\n");
610*4882a593Smuzhiyun                     return FALSE;
611*4882a593Smuzhiyun                 }
612*4882a593Smuzhiyun             }
613*4882a593Smuzhiyun             *size = pVbe->pInt10->bx * 64;
614*4882a593Smuzhiyun         }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun         /* Save/Restore Super VGA state */
617*4882a593Smuzhiyun         if (function != MODE_QUERY) {
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun             if (!*memory)
620*4882a593Smuzhiyun                 return FALSE;
621*4882a593Smuzhiyun             pVbe->pInt10->num = 0x10;
622*4882a593Smuzhiyun             pVbe->pInt10->ax = 0x4f04;
623*4882a593Smuzhiyun             switch (function) {
624*4882a593Smuzhiyun             case MODE_SAVE:
625*4882a593Smuzhiyun                 pVbe->pInt10->dx = 1;
626*4882a593Smuzhiyun                 break;
627*4882a593Smuzhiyun             case MODE_RESTORE:
628*4882a593Smuzhiyun                 pVbe->pInt10->dx = 2;
629*4882a593Smuzhiyun                 break;
630*4882a593Smuzhiyun             case MODE_QUERY:
631*4882a593Smuzhiyun                 return FALSE;
632*4882a593Smuzhiyun             }
633*4882a593Smuzhiyun             pVbe->pInt10->cx = 0x000f;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun             pVbe->pInt10->es = SEG_ADDR(*real_mode_pages);
636*4882a593Smuzhiyun             pVbe->pInt10->bx = SEG_OFF(*real_mode_pages);
637*4882a593Smuzhiyun             xf86ExecX86int10(pVbe->pInt10);
638*4882a593Smuzhiyun             return (R16(pVbe->pInt10->ax) == 0x4f);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun         }
641*4882a593Smuzhiyun     }
642*4882a593Smuzhiyun     return TRUE;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun Bool
VBEBankSwitch(vbeInfoPtr pVbe,unsigned int iBank,int window)646*4882a593Smuzhiyun VBEBankSwitch(vbeInfoPtr pVbe, unsigned int iBank, int window)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun     /*
649*4882a593Smuzhiyun        Input:
650*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
651*4882a593Smuzhiyun        AL    := 05h
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun        Output:
654*4882a593Smuzhiyun      */
655*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
656*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f05;
657*4882a593Smuzhiyun     pVbe->pInt10->bx = window;
658*4882a593Smuzhiyun     pVbe->pInt10->dx = iBank;
659*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
662*4882a593Smuzhiyun         return FALSE;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun     return TRUE;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun Bool
VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe,vbeScanwidthCommand command,int width,int * pixels,int * bytes,int * max)668*4882a593Smuzhiyun VBESetGetLogicalScanlineLength(vbeInfoPtr pVbe, vbeScanwidthCommand command,
669*4882a593Smuzhiyun                                int width, int *pixels, int *bytes, int *max)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun     if (command < SCANWID_SET || command > SCANWID_GET_MAX)
672*4882a593Smuzhiyun         return FALSE;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun     /*
675*4882a593Smuzhiyun        Input:
676*4882a593Smuzhiyun        AX := 4F06h VBE Set/Get Logical Scan Line Length
677*4882a593Smuzhiyun        BL := 00h Set Scan Line Length in Pixels
678*4882a593Smuzhiyun        := 01h Get Scan Line Length
679*4882a593Smuzhiyun        := 02h Set Scan Line Length in Bytes
680*4882a593Smuzhiyun        := 03h Get Maximum Scan Line Length
681*4882a593Smuzhiyun        CX := If BL=00h Desired Width in Pixels
682*4882a593Smuzhiyun        If BL=02h Desired Width in Bytes
683*4882a593Smuzhiyun        (Ignored for Get Functions)
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun        Output:
686*4882a593Smuzhiyun        AX := VBE Return Status
687*4882a593Smuzhiyun        BX := Bytes Per Scan Line
688*4882a593Smuzhiyun        CX := Actual Pixels Per Scan Line
689*4882a593Smuzhiyun        (truncated to nearest complete pixel)
690*4882a593Smuzhiyun        DX := Maximum Number of Scan Lines
691*4882a593Smuzhiyun      */
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
694*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f06;
695*4882a593Smuzhiyun     pVbe->pInt10->bx = command;
696*4882a593Smuzhiyun     if (command == SCANWID_SET || command == SCANWID_SET_BYTES)
697*4882a593Smuzhiyun         pVbe->pInt10->cx = width;
698*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
701*4882a593Smuzhiyun         return FALSE;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun     if (command == SCANWID_GET || command == SCANWID_GET_MAX) {
704*4882a593Smuzhiyun         if (pixels)
705*4882a593Smuzhiyun             *pixels = R16(pVbe->pInt10->cx);
706*4882a593Smuzhiyun         if (bytes)
707*4882a593Smuzhiyun             *bytes = R16(pVbe->pInt10->bx);
708*4882a593Smuzhiyun         if (max)
709*4882a593Smuzhiyun             *max = R16(pVbe->pInt10->dx);
710*4882a593Smuzhiyun     }
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun     return TRUE;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun Bool
VBESetDisplayStart(vbeInfoPtr pVbe,int x,int y,Bool wait_retrace)716*4882a593Smuzhiyun VBESetDisplayStart(vbeInfoPtr pVbe, int x, int y, Bool wait_retrace)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
719*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f07;
720*4882a593Smuzhiyun     pVbe->pInt10->bx = wait_retrace ? 0x80 : 0x00;
721*4882a593Smuzhiyun     pVbe->pInt10->cx = x;
722*4882a593Smuzhiyun     pVbe->pInt10->dx = y;
723*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
726*4882a593Smuzhiyun         return FALSE;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun     return TRUE;
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun Bool
VBEGetDisplayStart(vbeInfoPtr pVbe,int * x,int * y)732*4882a593Smuzhiyun VBEGetDisplayStart(vbeInfoPtr pVbe, int *x, int *y)
733*4882a593Smuzhiyun {
734*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
735*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f07;
736*4882a593Smuzhiyun     pVbe->pInt10->bx = 0x01;
737*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
740*4882a593Smuzhiyun         return FALSE;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun     *x = pVbe->pInt10->cx;
743*4882a593Smuzhiyun     *y = pVbe->pInt10->dx;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun     return TRUE;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun int
VBESetGetDACPaletteFormat(vbeInfoPtr pVbe,int bits)749*4882a593Smuzhiyun VBESetGetDACPaletteFormat(vbeInfoPtr pVbe, int bits)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun     /*
752*4882a593Smuzhiyun        Input:
753*4882a593Smuzhiyun        AX := 4F08h VBE Set/Get Palette Format
754*4882a593Smuzhiyun        BL := 00h Set DAC Palette Format
755*4882a593Smuzhiyun        := 01h Get DAC Palette Format
756*4882a593Smuzhiyun        BH := Desired bits of color per primary
757*4882a593Smuzhiyun        (Set DAC Palette Format only)
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun        Output:
760*4882a593Smuzhiyun        AX := VBE Return Status
761*4882a593Smuzhiyun        BH := Current number of bits of color per primary
762*4882a593Smuzhiyun      */
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
765*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f08;
766*4882a593Smuzhiyun     if (!bits)
767*4882a593Smuzhiyun         pVbe->pInt10->bx = 0x01;
768*4882a593Smuzhiyun     else
769*4882a593Smuzhiyun         pVbe->pInt10->bx = (bits & 0x00ff) << 8;
770*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
773*4882a593Smuzhiyun         return 0;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun     return (bits != 0 ? bits : (pVbe->pInt10->bx >> 8) & 0x00ff);
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun CARD32 *
VBESetGetPaletteData(vbeInfoPtr pVbe,Bool set,int first,int num,CARD32 * data,Bool secondary,Bool wait_retrace)779*4882a593Smuzhiyun VBESetGetPaletteData(vbeInfoPtr pVbe, Bool set, int first, int num,
780*4882a593Smuzhiyun                      CARD32 *data, Bool secondary, Bool wait_retrace)
781*4882a593Smuzhiyun {
782*4882a593Smuzhiyun     /*
783*4882a593Smuzhiyun        Input:
784*4882a593Smuzhiyun        (16-bit)
785*4882a593Smuzhiyun        AX    := 4F09h VBE Load/Unload Palette Data
786*4882a593Smuzhiyun        BL    := 00h Set Palette Data
787*4882a593Smuzhiyun        := 01h Get Palette Data
788*4882a593Smuzhiyun        := 02h Set Secondary Palette Data
789*4882a593Smuzhiyun        := 03h Get Secondary Palette Data
790*4882a593Smuzhiyun        := 80h Set Palette Data during Vertical Retrace
791*4882a593Smuzhiyun        CX    := Number of palette registers to update (to a maximum of 256)
792*4882a593Smuzhiyun        DX    := First of the palette registers to update (start)
793*4882a593Smuzhiyun        ES:DI := Table of palette values (see below for format)
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun        Output:
796*4882a593Smuzhiyun        AX    := VBE Return Status
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun        Input:
799*4882a593Smuzhiyun        (32-bit)
800*4882a593Smuzhiyun        BL     := 00h Set Palette Data
801*4882a593Smuzhiyun        := 80h Set Palette Data during Vertical Retrace
802*4882a593Smuzhiyun        CX     := Number of palette registers to update (to a maximum of 256)
803*4882a593Smuzhiyun        DX     := First of the palette registers to update (start)
804*4882a593Smuzhiyun        ES:EDI := Table of palette values (see below for format)
805*4882a593Smuzhiyun        DS     := Selector for memory mapped registers
806*4882a593Smuzhiyun      */
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
809*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f09;
810*4882a593Smuzhiyun     if (!secondary)
811*4882a593Smuzhiyun         pVbe->pInt10->bx = set && wait_retrace ? 0x80 : set ? 0 : 1;
812*4882a593Smuzhiyun     else
813*4882a593Smuzhiyun         pVbe->pInt10->bx = set ? 2 : 3;
814*4882a593Smuzhiyun     pVbe->pInt10->cx = num;
815*4882a593Smuzhiyun     pVbe->pInt10->dx = first;
816*4882a593Smuzhiyun     pVbe->pInt10->es = SEG_ADDR(pVbe->real_mode_base);
817*4882a593Smuzhiyun     pVbe->pInt10->di = SEG_OFF(pVbe->real_mode_base);
818*4882a593Smuzhiyun     if (set)
819*4882a593Smuzhiyun         memcpy(pVbe->memory, data, num * sizeof(CARD32));
820*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
823*4882a593Smuzhiyun         return NULL;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun     if (set)
826*4882a593Smuzhiyun         return data;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun     data = xallocarray(num, sizeof(CARD32));
829*4882a593Smuzhiyun     memcpy(data, pVbe->memory, num * sizeof(CARD32));
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun     return data;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun VBEpmi *
VBEGetVBEpmi(vbeInfoPtr pVbe)835*4882a593Smuzhiyun VBEGetVBEpmi(vbeInfoPtr pVbe)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun     VBEpmi *pmi;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun     /*
840*4882a593Smuzhiyun        Input:
841*4882a593Smuzhiyun        AH    := 4Fh     Super VGA support
842*4882a593Smuzhiyun        AL    := 0Ah     Protected Mode Interface
843*4882a593Smuzhiyun        BL    := 00h     Return Protected Mode Table
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun        Output:
846*4882a593Smuzhiyun        AX    := Status
847*4882a593Smuzhiyun        ES    := Real Mode Segment of Table
848*4882a593Smuzhiyun        DI    := Offset of Table
849*4882a593Smuzhiyun        CX    := Lenght of Table including protected mode code in bytes (for copying purposes)
850*4882a593Smuzhiyun        (All other registers are preserved)
851*4882a593Smuzhiyun      */
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
854*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f0a;
855*4882a593Smuzhiyun     pVbe->pInt10->bx = 0;
856*4882a593Smuzhiyun     pVbe->pInt10->di = 0;
857*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
860*4882a593Smuzhiyun         return NULL;
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun     pmi = malloc(sizeof(VBEpmi));
863*4882a593Smuzhiyun     pmi->seg_tbl = R16(pVbe->pInt10->es);
864*4882a593Smuzhiyun     pmi->tbl_off = R16(pVbe->pInt10->di);
865*4882a593Smuzhiyun     pmi->tbl_len = R16(pVbe->pInt10->cx);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun     return pmi;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun #if 0
871*4882a593Smuzhiyun vbeModeInfoPtr
872*4882a593Smuzhiyun VBEBuildVbeModeList(vbeInfoPtr pVbe, VbeInfoBlock * vbe)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun     vbeModeInfoPtr ModeList = NULL;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun     int i = 0;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun     while (vbe->VideoModePtr[i] != 0xffff) {
879*4882a593Smuzhiyun         vbeModeInfoPtr m;
880*4882a593Smuzhiyun         VbeModeInfoBlock *mode;
881*4882a593Smuzhiyun         int id = vbe->VideoModePtr[i++];
882*4882a593Smuzhiyun         int bpp;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun         if ((mode = VBEGetModeInfo(pVbe, id)) == NULL)
885*4882a593Smuzhiyun             continue;
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun         bpp = mode->BitsPerPixel;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun         m = xnfcalloc(sizeof(vbeModeInfoRec), 1);
890*4882a593Smuzhiyun         m->width = mode->XResolution;
891*4882a593Smuzhiyun         m->height = mode->YResolution;
892*4882a593Smuzhiyun         m->bpp = bpp;
893*4882a593Smuzhiyun         m->n = id;
894*4882a593Smuzhiyun         m->next = ModeList;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun         xf86DrvMsgVerb(pVbe->pInt10->pScrn->scrnIndex, X_PROBED, 3,
897*4882a593Smuzhiyun                        "BIOS reported VESA mode 0x%x: x:%i y:%i bpp:%i\n",
898*4882a593Smuzhiyun                        m->n, m->width, m->height, m->bpp);
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun         ModeList = m;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun         VBEFreeModeInfo(mode);
903*4882a593Smuzhiyun     }
904*4882a593Smuzhiyun     return ModeList;
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun unsigned short
908*4882a593Smuzhiyun VBECalcVbeModeIndex(vbeModeInfoPtr m, DisplayModePtr mode, int bpp)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun     while (m) {
911*4882a593Smuzhiyun         if (bpp == m->bpp
912*4882a593Smuzhiyun             && mode->HDisplay == m->width && mode->VDisplay == m->height)
913*4882a593Smuzhiyun             return m->n;
914*4882a593Smuzhiyun         m = m->next;
915*4882a593Smuzhiyun     }
916*4882a593Smuzhiyun     return 0;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun #endif
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun void
VBEVesaSaveRestore(vbeInfoPtr pVbe,vbeSaveRestorePtr vbe_sr,vbeSaveRestoreFunction function)921*4882a593Smuzhiyun VBEVesaSaveRestore(vbeInfoPtr pVbe, vbeSaveRestorePtr vbe_sr,
922*4882a593Smuzhiyun                    vbeSaveRestoreFunction function)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun     Bool SaveSucc = FALSE;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun     if (VBE_VERSION_MAJOR(pVbe->version) > 1
927*4882a593Smuzhiyun         && (function == MODE_SAVE || vbe_sr->pstate)) {
928*4882a593Smuzhiyun         if (function == MODE_RESTORE)
929*4882a593Smuzhiyun             memcpy(vbe_sr->state, vbe_sr->pstate, vbe_sr->stateSize);
930*4882a593Smuzhiyun         ErrorF("VBESaveRestore\n");
931*4882a593Smuzhiyun         if ((VBESaveRestore(pVbe, function,
932*4882a593Smuzhiyun                             (void *) &vbe_sr->state,
933*4882a593Smuzhiyun                             &vbe_sr->stateSize, &vbe_sr->statePage))) {
934*4882a593Smuzhiyun             if (function == MODE_SAVE) {
935*4882a593Smuzhiyun                 SaveSucc = TRUE;
936*4882a593Smuzhiyun                 vbe_sr->stateMode = -1; /* invalidate */
937*4882a593Smuzhiyun                 /* don't rely on the memory not being touched */
938*4882a593Smuzhiyun                 if (vbe_sr->pstate == NULL)
939*4882a593Smuzhiyun                     vbe_sr->pstate = malloc(vbe_sr->stateSize);
940*4882a593Smuzhiyun                 memcpy(vbe_sr->pstate, vbe_sr->state, vbe_sr->stateSize);
941*4882a593Smuzhiyun             }
942*4882a593Smuzhiyun             ErrorF("VBESaveRestore done with success\n");
943*4882a593Smuzhiyun             return;
944*4882a593Smuzhiyun         }
945*4882a593Smuzhiyun         ErrorF("VBESaveRestore done\n");
946*4882a593Smuzhiyun     }
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun     if (function == MODE_SAVE && !SaveSucc)
949*4882a593Smuzhiyun         (void) VBEGetVBEMode(pVbe, &vbe_sr->stateMode);
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun     if (function == MODE_RESTORE && vbe_sr->stateMode != -1)
952*4882a593Smuzhiyun         VBESetVBEMode(pVbe, vbe_sr->stateMode, NULL);
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun int
VBEGetPixelClock(vbeInfoPtr pVbe,int mode,int clock)957*4882a593Smuzhiyun VBEGetPixelClock(vbeInfoPtr pVbe, int mode, int clock)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun     /*
960*4882a593Smuzhiyun        Input:
961*4882a593Smuzhiyun        AX := 4F0Bh VBE Get Pixel Clock
962*4882a593Smuzhiyun        BL := 00h Get Pixel Clock
963*4882a593Smuzhiyun        ECX := pixel clock in units of Hz
964*4882a593Smuzhiyun        DX := mode number
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun        Output:
967*4882a593Smuzhiyun        AX := VBE Return Status
968*4882a593Smuzhiyun        ECX := Closest pixel clock
969*4882a593Smuzhiyun      */
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
972*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f0b;
973*4882a593Smuzhiyun     pVbe->pInt10->bx = 0x00;
974*4882a593Smuzhiyun     pVbe->pInt10->cx = clock;
975*4882a593Smuzhiyun     pVbe->pInt10->dx = mode;
976*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun     if (R16(pVbe->pInt10->ax) != 0x4f)
979*4882a593Smuzhiyun         return 0;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun     return pVbe->pInt10->cx;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun Bool
VBEDPMSSet(vbeInfoPtr pVbe,int mode)985*4882a593Smuzhiyun VBEDPMSSet(vbeInfoPtr pVbe, int mode)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun     /*
988*4882a593Smuzhiyun        Input:
989*4882a593Smuzhiyun        AX := 4F10h DPMS
990*4882a593Smuzhiyun        BL := 01h Set Display Power State
991*4882a593Smuzhiyun        BH := requested power state
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun        Output:
994*4882a593Smuzhiyun        AX := VBE Return Status
995*4882a593Smuzhiyun      */
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
998*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4f10;
999*4882a593Smuzhiyun     pVbe->pInt10->bx = 0x01;
1000*4882a593Smuzhiyun     switch (mode) {
1001*4882a593Smuzhiyun     case DPMSModeOn:
1002*4882a593Smuzhiyun         break;
1003*4882a593Smuzhiyun     case DPMSModeStandby:
1004*4882a593Smuzhiyun         pVbe->pInt10->bx |= 0x100;
1005*4882a593Smuzhiyun         break;
1006*4882a593Smuzhiyun     case DPMSModeSuspend:
1007*4882a593Smuzhiyun         pVbe->pInt10->bx |= 0x200;
1008*4882a593Smuzhiyun         break;
1009*4882a593Smuzhiyun     case DPMSModeOff:
1010*4882a593Smuzhiyun         pVbe->pInt10->bx |= 0x400;
1011*4882a593Smuzhiyun         break;
1012*4882a593Smuzhiyun     }
1013*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
1014*4882a593Smuzhiyun     return (R16(pVbe->pInt10->ax) == 0x4f);
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun void
VBEInterpretPanelID(ScrnInfoPtr pScrn,struct vbePanelID * data)1018*4882a593Smuzhiyun VBEInterpretPanelID(ScrnInfoPtr pScrn, struct vbePanelID *data)
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun     DisplayModePtr mode;
1021*4882a593Smuzhiyun     const float PANEL_HZ = 60.0;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun     if (!data)
1024*4882a593Smuzhiyun         return;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PanelID returned panel resolution %dx%d\n",
1027*4882a593Smuzhiyun                data->hsize, data->vsize);
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun     if (pScrn->monitor->nHsync || pScrn->monitor->nVrefresh)
1030*4882a593Smuzhiyun         return;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun     if (data->hsize < 320 || data->vsize < 240) {
1033*4882a593Smuzhiyun         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "...which I refuse to believe\n");
1034*4882a593Smuzhiyun         return;
1035*4882a593Smuzhiyun     }
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun     mode = xf86CVTMode(data->hsize, data->vsize, PANEL_HZ, 1, 0);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun     pScrn->monitor->nHsync = 1;
1040*4882a593Smuzhiyun     pScrn->monitor->hsync[0].lo = 29.37;
1041*4882a593Smuzhiyun     pScrn->monitor->hsync[0].hi = (float) mode->Clock / (float) mode->HTotal;
1042*4882a593Smuzhiyun     pScrn->monitor->nVrefresh = 1;
1043*4882a593Smuzhiyun     pScrn->monitor->vrefresh[0].lo = 56.0;
1044*4882a593Smuzhiyun     pScrn->monitor->vrefresh[0].hi =
1045*4882a593Smuzhiyun         (float) mode->Clock * 1000.0 / (float) mode->HTotal /
1046*4882a593Smuzhiyun         (float) mode->VTotal;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun     if (pScrn->monitor->vrefresh[0].hi < 59.47)
1049*4882a593Smuzhiyun         pScrn->monitor->vrefresh[0].hi = 59.47;
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun     free(mode);
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun struct vbePanelID *
VBEReadPanelID(vbeInfoPtr pVbe)1055*4882a593Smuzhiyun VBEReadPanelID(vbeInfoPtr pVbe)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun     int RealOff = pVbe->real_mode_base;
1058*4882a593Smuzhiyun     void *page = pVbe->memory;
1059*4882a593Smuzhiyun     void *tmp = NULL;
1060*4882a593Smuzhiyun     int screen = pVbe->pInt10->pScrn->scrnIndex;
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun     pVbe->pInt10->ax = 0x4F11;
1063*4882a593Smuzhiyun     pVbe->pInt10->bx = 0x01;
1064*4882a593Smuzhiyun     pVbe->pInt10->cx = 0;
1065*4882a593Smuzhiyun     pVbe->pInt10->dx = 0;
1066*4882a593Smuzhiyun     pVbe->pInt10->es = SEG_ADDR(RealOff);
1067*4882a593Smuzhiyun     pVbe->pInt10->di = SEG_OFF(RealOff);
1068*4882a593Smuzhiyun     pVbe->pInt10->num = 0x10;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun     xf86ExecX86int10(pVbe->pInt10);
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun     if ((pVbe->pInt10->ax & 0xff) != 0x4f) {
1073*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE PanelID invalid\n");
1074*4882a593Smuzhiyun         goto error;
1075*4882a593Smuzhiyun     }
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun     switch (pVbe->pInt10->ax & 0xff00) {
1078*4882a593Smuzhiyun     case 0x0:
1079*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3,
1080*4882a593Smuzhiyun                        "VESA VBE PanelID read successfully\n");
1081*4882a593Smuzhiyun         tmp = xnfalloc(32);
1082*4882a593Smuzhiyun         memcpy(tmp, page, 32);
1083*4882a593Smuzhiyun         break;
1084*4882a593Smuzhiyun     case 0x100:
1085*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3, "VESA VBE PanelID read failed\n");
1086*4882a593Smuzhiyun         break;
1087*4882a593Smuzhiyun     default:
1088*4882a593Smuzhiyun         xf86DrvMsgVerb(screen, X_INFO, 3,
1089*4882a593Smuzhiyun                        "VESA VBE PanelID unknown failure %i\n",
1090*4882a593Smuzhiyun                        pVbe->pInt10->ax & 0xff00);
1091*4882a593Smuzhiyun         break;
1092*4882a593Smuzhiyun     }
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun  error:
1095*4882a593Smuzhiyun     return tmp;
1096*4882a593Smuzhiyun }
1097