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