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