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