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