vmware.c revision 739a6cd7
1/* **********************************************************
2 * Copyright (C) 1998-2001 VMware, Inc.
3 * All Rights Reserved
4 * **********************************************************/
5#ifdef VMX86_DEVEL
6char rcsId_vmware[] =
7    "Id: vmware.c,v 1.11 2001/02/23 02:10:39 yoel Exp $";
8#endif
9
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14/*
15 * TODO: support the vmware linux kernel fb driver (Option "UseFBDev").
16 */
17
18#include "xf86.h"
19#include "xf86_OSproc.h"
20
21#include "compiler.h"	/* inb/outb */
22
23#include "xf86Pci.h"		/* pci */
24
25#include "mipointer.h"		/* sw cursor */
26#include "micmap.h"		/* mi color map */
27#include "vgaHW.h"		/* VGA hardware */
28#include "fb.h"
29#include "shadowfb.h"           /* ShadowFB wrappers */
30
31#include "xf86cmap.h"		/* xf86HandleColormaps */
32
33#include "vmware.h"
34#include "guest_os.h"
35#include "vm_device_version.h"
36#include "svga_modes.h"
37#include "vmware_bootstrap.h"
38#include "vmware_common.h"
39
40#ifndef HAVE_XORG_SERVER_1_5_0
41#include <xf86_ansic.h>
42#include <xf86_libc.h>
43#endif
44
45#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5)
46
47#define xf86LoaderReqSymLists(...) do {} while (0)
48#define LoaderRefSymLists(...) do {} while (0)
49
50#else
51
52const char *vgahwSymbols[] = {
53    "vgaHWGetHWRec",
54    "vgaHWGetIOBase",
55    "vgaHWGetIndex",
56    "vgaHWInit",
57    "vgaHWProtect",
58    "vgaHWRestore",
59    "vgaHWSave",
60    "vgaHWSaveScreen",
61    "vgaHWUnlock",
62    NULL
63};
64
65static const char *fbSymbols[] = {
66    "fbCreateDefColormap",
67    "fbPictureInit",
68    "fbScreenInit",
69    NULL
70};
71
72static const char *ramdacSymbols[] = {
73    "xf86CreateCursorInfoRec",
74    "xf86DestroyCursorInfoRec",
75    "xf86InitCursor",
76    NULL
77};
78
79static const char *shadowfbSymbols[] = {
80    "ShadowFBInit2",
81    NULL
82};
83#endif
84
85/* Table of default modes to always add to the mode list. */
86
87typedef struct {
88   int width;
89   int height;
90} VMWAREDefaultMode;
91
92#define VMW_MIN_INITIAL_WIDTH 800
93#define VMW_MIN_INITIAL_HEIGHT 600
94
95#define SVGA_DEFAULT_MODE(width, height) { width, height, },
96
97static const VMWAREDefaultMode VMWAREDefaultModes[] = {
98   SVGA_DEFAULT_MODES
99};
100
101#undef SVGA_DEFAULT_MODE
102
103static void VMWAREStopFIFO(ScrnInfoPtr pScrn);
104static void VMWARESave(ScrnInfoPtr pScrn);
105
106static Bool
107VMWAREGetRec(ScrnInfoPtr pScrn)
108{
109    if (pScrn->driverPrivate != NULL) {
110        return TRUE;
111    }
112    pScrn->driverPrivate = xnfcalloc(sizeof(VMWARERec), 1);
113    /* FIXME: Initialize driverPrivate... */
114    return TRUE;
115}
116
117static void
118VMWAREFreeRec(ScrnInfoPtr pScrn)
119{
120    if (pScrn->driverPrivate) {
121        free(pScrn->driverPrivate);
122        pScrn->driverPrivate = NULL;
123    }
124}
125
126CARD32
127vmwareReadReg(VMWAREPtr pVMWARE, int index)
128{
129    /*
130     * Block SIGIO for the duration, so we don't get interrupted after the
131     * outl but before the inl by a mouse move (which write to our registers).
132     */
133    int oldsigio, ret;
134    oldsigio = xf86BlockSIGIO();
135    outl(pVMWARE->indexReg, index);
136    ret = inl(pVMWARE->valueReg);
137    xf86UnblockSIGIO(oldsigio);
138    return ret;
139}
140
141void
142vmwareWriteReg(VMWAREPtr pVMWARE, int index, CARD32 value)
143{
144    /*
145     * Block SIGIO for the duration, so we don't get interrupted in between
146     * the outls by a mouse move (which write to our registers).
147     */
148    int oldsigio;
149    oldsigio = xf86BlockSIGIO();
150    outl(pVMWARE->indexReg, index);
151    outl(pVMWARE->valueReg, value);
152    xf86UnblockSIGIO(oldsigio);
153}
154
155void
156vmwareWriteWordToFIFO(VMWAREPtr pVMWARE, CARD32 value)
157{
158    volatile CARD32* vmwareFIFO = pVMWARE->vmwareFIFO;
159
160    /* Need to sync? */
161    if ((vmwareFIFO[SVGA_FIFO_NEXT_CMD] + sizeof(CARD32) == vmwareFIFO[SVGA_FIFO_STOP])
162     || (vmwareFIFO[SVGA_FIFO_NEXT_CMD] == vmwareFIFO[SVGA_FIFO_MAX] - sizeof(CARD32) &&
163	 vmwareFIFO[SVGA_FIFO_STOP] == vmwareFIFO[SVGA_FIFO_MIN])) {
164        VmwareLog(("Syncing because of full fifo\n"));
165        vmwareWaitForFB(pVMWARE);
166    }
167
168    vmwareFIFO[vmwareFIFO[SVGA_FIFO_NEXT_CMD] / sizeof(CARD32)] = value;
169
170    write_mem_barrier();
171
172    if(vmwareFIFO[SVGA_FIFO_NEXT_CMD] == vmwareFIFO[SVGA_FIFO_MAX] -
173       sizeof(CARD32)) {
174        vmwareFIFO[SVGA_FIFO_NEXT_CMD] = vmwareFIFO[SVGA_FIFO_MIN];
175    } else {
176        vmwareFIFO[SVGA_FIFO_NEXT_CMD] += sizeof(CARD32);
177    }
178}
179
180void
181vmwareWaitForFB(VMWAREPtr pVMWARE)
182{
183    vmwareWriteReg(pVMWARE, SVGA_REG_SYNC, 1);
184    while (vmwareReadReg(pVMWARE, SVGA_REG_BUSY));
185}
186
187void
188vmwareSendSVGACmdUpdate(VMWAREPtr pVMWARE, BoxPtr pBB)
189{
190    vmwareWriteWordToFIFO(pVMWARE, SVGA_CMD_UPDATE);
191    vmwareWriteWordToFIFO(pVMWARE, pBB->x1);
192    vmwareWriteWordToFIFO(pVMWARE, pBB->y1);
193    vmwareWriteWordToFIFO(pVMWARE, pBB->x2 - pBB->x1);
194    vmwareWriteWordToFIFO(pVMWARE, pBB->y2 - pBB->y1);
195}
196
197void
198vmwareSendSVGACmdUpdateFullScreen(VMWAREPtr pVMWARE)
199{
200    BoxRec BB;
201
202    BB.x1 = 0;
203    BB.y1 = 0;
204    BB.x2 = pVMWARE->ModeReg.svga_reg_width;
205    BB.y2 = pVMWARE->ModeReg.svga_reg_height;
206    vmwareSendSVGACmdUpdate(pVMWARE, &BB);
207}
208
209static CARD32
210vmwareCalculateWeight(CARD32 mask)
211{
212    CARD32 weight;
213
214    for (weight = 0; mask; mask >>= 1) {
215        if (mask & 1) {
216            weight++;
217        }
218    }
219    return weight;
220}
221
222/*
223 *-----------------------------------------------------------------------------
224 *
225 * VMXGetVMwareSvgaId --
226 *
227 *    Retrieve the SVGA_ID of the VMware SVGA adapter.
228 *    This function should hide any backward compatibility mess.
229 *
230 * Results:
231 *    The SVGA_ID_* of the present VMware adapter.
232 *
233 * Side effects:
234 *    ins/outs
235 *
236 *-----------------------------------------------------------------------------
237 */
238
239static uint32
240VMXGetVMwareSvgaId(VMWAREPtr pVMWARE)
241{
242    uint32 vmware_svga_id;
243
244    /* Any version with any SVGA_ID_* support will initialize SVGA_REG_ID
245     * to SVGA_ID_0 to support versions of this driver with SVGA_ID_0.
246     *
247     * Versions of SVGA_ID_0 ignore writes to the SVGA_REG_ID register.
248     *
249     * Versions of SVGA_ID_1 will allow us to overwrite the content
250     * of the SVGA_REG_ID register only with the values SVGA_ID_0 or SVGA_ID_1.
251     *
252     * Versions of SVGA_ID_2 will allow us to overwrite the content
253     * of the SVGA_REG_ID register only with the values SVGA_ID_0 or SVGA_ID_1
254     * or SVGA_ID_2.
255     */
256
257    vmwareWriteReg(pVMWARE, SVGA_REG_ID, SVGA_ID_2);
258    vmware_svga_id = vmwareReadReg(pVMWARE, SVGA_REG_ID);
259    if (vmware_svga_id == SVGA_ID_2) {
260        return SVGA_ID_2;
261    }
262
263    vmwareWriteReg(pVMWARE, SVGA_REG_ID, SVGA_ID_1);
264    vmware_svga_id = vmwareReadReg(pVMWARE, SVGA_REG_ID);
265    if (vmware_svga_id == SVGA_ID_1) {
266        return SVGA_ID_1;
267    }
268
269    if (vmware_svga_id == SVGA_ID_0) {
270        return SVGA_ID_0;
271    }
272
273    /* No supported VMware SVGA devices found */
274    return SVGA_ID_INVALID;
275}
276
277static Bool
278VMWAREPreInit(ScrnInfoPtr pScrn, int flags)
279{
280    MessageType from;
281    VMWAREPtr pVMWARE;
282    OptionInfoPtr options;
283    int bpp24flags;
284    uint32 id;
285    int i;
286    ClockRange* clockRanges;
287    unsigned long domainIOBase = 0;
288    uint32 width = 0, height = 0;
289    Bool defaultMode;
290
291#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
292#ifndef BUILD_FOR_420
293    domainIOBase = pScrn->domainIOBase;
294#endif
295#endif
296
297    if (flags & PROBE_DETECT) {
298        return FALSE;
299    }
300
301    if (pScrn->numEntities != 1) {
302        return FALSE;
303    }
304
305    if (!VMWAREGetRec(pScrn)) {
306        return FALSE;
307    }
308    pVMWARE = VMWAREPTR(pScrn);
309
310    pVMWARE->pvtSema = &pScrn->vtSema;
311
312    pVMWARE->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
313    pVMWARE->PciInfo = xf86GetPciInfoForEntity(pVMWARE->pEnt->index);
314    if (pVMWARE->PciInfo == NULL) {
315        return FALSE;
316    }
317
318    if (DEVICE_ID(pVMWARE->PciInfo) == PCI_DEVICE_ID_VMWARE_SVGA) {
319        pVMWARE->indexReg = domainIOBase +
320           SVGA_LEGACY_BASE_PORT + SVGA_INDEX_PORT*sizeof(uint32);
321        pVMWARE->valueReg = domainIOBase +
322           SVGA_LEGACY_BASE_PORT + SVGA_VALUE_PORT*sizeof(uint32);
323    } else {
324        /* Note:  This setting of valueReg causes unaligned I/O */
325#if XSERVER_LIBPCIACCESS
326        pVMWARE->portIOBase = pVMWARE->PciInfo->regions[0].base_addr;
327#else
328        pVMWARE->portIOBase = pVMWARE->PciInfo->ioBase[0];
329#endif
330        pVMWARE->indexReg = domainIOBase +
331           pVMWARE->portIOBase + SVGA_INDEX_PORT;
332        pVMWARE->valueReg = domainIOBase +
333           pVMWARE->portIOBase + SVGA_VALUE_PORT;
334    }
335    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
336               "VMware SVGA regs at (0x%04lx, 0x%04lx)\n",
337               pVMWARE->indexReg, pVMWARE->valueReg);
338
339    if (!xf86LoadSubModule(pScrn, "vgahw")) {
340        return FALSE;
341    }
342
343    xf86LoaderReqSymLists(vgahwSymbols, NULL);
344
345    if (!vgaHWGetHWRec(pScrn)) {
346        return FALSE;
347    }
348
349#ifdef HAVE_XORG_SERVER_1_12_0
350    vgaHWSetStdFuncs(VGAHWPTR(pScrn));
351#endif
352
353    /*
354     * Save the current video state.  Do it here before VMXGetVMwareSvgaId
355     * writes to any registers.
356     */
357    VMWARESave(pScrn);
358
359    id = VMXGetVMwareSvgaId(pVMWARE);
360    if (id == SVGA_ID_0 || id == SVGA_ID_INVALID) {
361        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
362                   "No supported VMware SVGA found (read ID 0x%08x).\n", id);
363        return FALSE;
364    }
365    pVMWARE->suspensionSavedRegId = id;
366
367#if !XSERVER_LIBPCIACCESS
368    pVMWARE->PciTag = pciTag(pVMWARE->PciInfo->bus, pVMWARE->PciInfo->device,
369                             pVMWARE->PciInfo->func);
370#endif
371    pVMWARE->Primary = xf86IsPrimaryPci(pVMWARE->PciInfo);
372
373    pScrn->monitor = pScrn->confScreen->monitor;
374
375#ifdef ACCELERATE_OPS
376    pVMWARE->vmwareCapability = vmwareReadReg(pVMWARE, SVGA_REG_CAPABILITIES);
377#else
378    pVMWARE->vmwareCapability = vmwareReadReg(pVMWARE, SVGA_REG_CAPABILITIES) &
379	SVGA_CAP_PITCHLOCK;
380#endif
381
382    pVMWARE->bitsPerPixel = vmwareReadReg(pVMWARE,
383                                          SVGA_REG_HOST_BITS_PER_PIXEL);
384    if (pVMWARE->vmwareCapability & SVGA_CAP_8BIT_EMULATION) {
385       vmwareWriteReg(pVMWARE, SVGA_REG_BITS_PER_PIXEL, pVMWARE->bitsPerPixel);
386    }
387
388    pVMWARE->depth = vmwareReadReg(pVMWARE, SVGA_REG_DEPTH);
389    pVMWARE->videoRam = vmwareReadReg(pVMWARE, SVGA_REG_VRAM_SIZE);
390    pVMWARE->memPhysBase = vmwareReadReg(pVMWARE, SVGA_REG_FB_START);
391    pVMWARE->maxWidth = vmwareReadReg(pVMWARE, SVGA_REG_MAX_WIDTH);
392    pVMWARE->maxHeight = vmwareReadReg(pVMWARE, SVGA_REG_MAX_HEIGHT);
393    pVMWARE->cursorDefined = FALSE;
394    pVMWARE->cursorShouldBeHidden = FALSE;
395
396    if (pVMWARE->vmwareCapability & SVGA_CAP_CURSOR_BYPASS_2) {
397        pVMWARE->cursorRemoveFromFB = SVGA_CURSOR_ON_REMOVE_FROM_FB;
398        pVMWARE->cursorRestoreToFB = SVGA_CURSOR_ON_RESTORE_TO_FB;
399    } else {
400        pVMWARE->cursorRemoveFromFB = SVGA_CURSOR_ON_HIDE;
401        pVMWARE->cursorRestoreToFB = SVGA_CURSOR_ON_SHOW;
402    }
403
404    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "caps:  0x%08X\n", pVMWARE->vmwareCapability);
405    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "depth: %d\n", pVMWARE->depth);
406    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "bpp:   %d\n", pVMWARE->bitsPerPixel);
407
408    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "vram:  %d\n", pVMWARE->videoRam);
409    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "pbase: 0x%08lx\n", pVMWARE->memPhysBase);
410    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "mwidt: %d\n", pVMWARE->maxWidth);
411    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED, 2, "mheig: %d\n", pVMWARE->maxHeight);
412
413    if (pVMWARE->vmwareCapability & SVGA_CAP_8BIT_EMULATION) {
414        bpp24flags = Support24bppFb | Support32bppFb;
415    } else {
416        switch (pVMWARE->depth) {
417        case 16:
418            /*
419             * In certain cases, the Windows host appears to
420             * report 16 bpp and 16 depth but 555 weight.  Just
421             * silently convert it to depth of 15.
422             */
423            if (pVMWARE->bitsPerPixel == 16 &&
424                pVMWARE->weight.green == 5)
425                pVMWARE->depth = 15;
426        case 8:
427        case 15:
428            bpp24flags = NoDepth24Support;
429         break;
430        case 32:
431            /*
432             * There is no 32 bit depth, apparently it can get
433             * reported this way sometimes on the Windows host.
434             */
435            if (pVMWARE->bitsPerPixel == 32)
436                pVMWARE->depth = 24;
437        case 24:
438            if (pVMWARE->bitsPerPixel == 24)
439                bpp24flags = Support24bppFb;
440            else
441                bpp24flags = Support32bppFb;
442            break;
443       default:
444            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
445                       "Adapter is using an unsupported depth (%d).\n",
446                       pVMWARE->depth);
447            return FALSE;
448       }
449    }
450
451    if (!xf86SetDepthBpp(pScrn, pVMWARE->depth, pVMWARE->bitsPerPixel,
452                         pVMWARE->bitsPerPixel, bpp24flags)) {
453        return FALSE;
454    }
455
456    /* Check that the returned depth is one we support */
457    switch (pScrn->depth) {
458    case 8:
459    case 15:
460    case 16:
461    case 24:
462        /* OK */
463        break;
464    default:
465        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
466                   "Given depth (%d) is not supported by this driver\n",
467                   pScrn->depth);
468        return FALSE;
469    }
470
471    if (pScrn->bitsPerPixel != pVMWARE->bitsPerPixel) {
472        if (pVMWARE->vmwareCapability & SVGA_CAP_8BIT_EMULATION) {
473            vmwareWriteReg(pVMWARE, SVGA_REG_BITS_PER_PIXEL,
474                           pScrn->bitsPerPixel);
475            pVMWARE->bitsPerPixel =
476               vmwareReadReg(pVMWARE, SVGA_REG_BITS_PER_PIXEL);
477            pVMWARE->depth = vmwareReadReg(pVMWARE, SVGA_REG_DEPTH);
478        } else {
479            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
480                       "Currently unavailable depth/bpp of %d/%d requested.\n"
481                       "\tThe guest X server must run at the same depth and bpp as the host\n"
482                       "\t(which are currently %d/%d).  This is automatically detected.  Please\n"
483                       "\tdo not specify a depth on the command line or via the config file.\n",
484                       pScrn->depth, pScrn->bitsPerPixel,
485                       pVMWARE->depth, pVMWARE->bitsPerPixel);
486            return FALSE;
487        }
488    }
489
490    /*
491     * Defer reading the colour registers until here in case we changed
492     * bpp above.
493     */
494
495    pVMWARE->weight.red =
496       vmwareCalculateWeight(vmwareReadReg(pVMWARE, SVGA_REG_RED_MASK));
497    pVMWARE->weight.green =
498       vmwareCalculateWeight(vmwareReadReg(pVMWARE, SVGA_REG_GREEN_MASK));
499    pVMWARE->weight.blue =
500       vmwareCalculateWeight(vmwareReadReg(pVMWARE, SVGA_REG_BLUE_MASK));
501    pVMWARE->offset.blue = 0;
502    pVMWARE->offset.green = pVMWARE->weight.blue;
503    pVMWARE->offset.red = pVMWARE->weight.green + pVMWARE->offset.green;
504    pVMWARE->defaultVisual = vmwareReadReg(pVMWARE, SVGA_REG_PSEUDOCOLOR) ?
505       PseudoColor : TrueColor;
506
507    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED,
508                   2, "depth: %d\n", pVMWARE->depth);
509    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED,
510                   2, "bpp:   %d\n", pVMWARE->bitsPerPixel);
511    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED,
512                   2, "w.red: %d\n", (int)pVMWARE->weight.red);
513    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED,
514                   2, "w.grn: %d\n", (int)pVMWARE->weight.green);
515    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED,
516                   2, "w.blu: %d\n", (int)pVMWARE->weight.blue);
517    xf86DrvMsgVerb(pScrn->scrnIndex, X_PROBED,
518                   2, "vis:   %d\n", pVMWARE->defaultVisual);
519
520    if (pScrn->depth != pVMWARE->depth) {
521        if (pVMWARE->vmwareCapability & SVGA_CAP_8BIT_EMULATION) {
522            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
523                       "Currently unavailable depth of %d requested.\n"
524                       "\tIf the guest X server's BPP matches the host's "
525                       "BPP, then\n\tthe guest X server's depth must also "
526                       "match the\n\thost's depth (currently %d).\n",
527                       pScrn->depth, pVMWARE->depth);
528        } else {
529            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
530                       "Currently unavailable depth of %d requested.\n"
531                       "\tThe guest X server must run at the same depth as "
532                       "the host (which\n\tis currently %d).  This is "
533                       "automatically detected.  Please do not\n\tspecify "
534                       "a depth on the command line or via the config file.\n",
535                       pScrn->depth, pVMWARE->depth);
536        }
537           return FALSE;
538    }
539    xf86PrintDepthBpp(pScrn);
540
541#if 0
542    if (pScrn->depth == 24 && pix24bpp == 0) {
543        pix24bpp = xf86GetBppFromDepth(pScrn, 24);
544    }
545#endif
546
547    if (pScrn->depth > 8) {
548        rgb zeros = { 0, 0, 0 };
549
550        if (!xf86SetWeight(pScrn, pVMWARE->weight, zeros)) {
551            return FALSE;
552        }
553        /* FIXME check returned weight */
554    }
555    if (!xf86SetDefaultVisual(pScrn, pVMWARE->defaultVisual)) {
556        return FALSE;
557    }
558    if (pScrn->defaultVisual != pVMWARE->defaultVisual) {
559        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
560                   "Given visual (%d) is not supported by this driver (%d is required)\n",
561                   pScrn->defaultVisual, pVMWARE->defaultVisual);
562        return FALSE;
563    }
564#if 0
565    bytesPerPixel = pScrn->bitsPerPixel / 8;
566#endif
567    pScrn->progClock = TRUE;
568
569#if 0 /* MGA does not do this */
570    if (pScrn->visual != 0) {	/* FIXME */
571        /* print error message */
572        return FALSE;
573    }
574#endif
575
576    xf86CollectOptions(pScrn, NULL);
577    if (!(options = VMWARECopyOptions()))
578        return FALSE;
579    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
580
581    if (pScrn->depth <= 8) {
582        pScrn->rgbBits = 8;
583    }
584
585    if (!pScrn->chipset) {
586        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04x is not recognised\n", DEVICE_ID(pVMWARE->PciInfo));
587        return FALSE;
588    }
589
590    from = X_DEFAULT;
591    pVMWARE->hwCursor = TRUE;
592    if (xf86GetOptValBool(options, OPTION_HW_CURSOR, &pVMWARE->hwCursor)) {
593        from = X_CONFIG;
594    }
595    if (pVMWARE->hwCursor && !(pVMWARE->vmwareCapability & SVGA_CAP_CURSOR)) {
596        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "HW cursor is not supported in this configuration\n");
597        from = X_PROBED;
598        pVMWARE->hwCursor = FALSE;
599    }
600    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
601               pVMWARE->hwCursor ? "HW" : "SW");
602    pScrn->videoRam = pVMWARE->videoRam / 1024;
603    pScrn->memPhysBase = pVMWARE->memPhysBase;
604
605    from = X_DEFAULT;
606    defaultMode = TRUE;
607    if (xf86GetOptValBool(options, OPTION_DEFAULT_MODE, &defaultMode)) {
608        from = X_CONFIG;
609    }
610
611    width = vmwareReadReg(pVMWARE, SVGA_REG_WIDTH);
612    height = vmwareReadReg(pVMWARE, SVGA_REG_HEIGHT);
613    width = MAX(width, VMW_MIN_INITIAL_WIDTH);
614    height = MAX(height, VMW_MIN_INITIAL_HEIGHT);
615
616    if (width > pVMWARE->maxWidth || height > pVMWARE->maxHeight) {
617	/*
618	 * This is an error condition and shouldn't happen.
619	 * revert to MIN_INITIAL_ values
620	 */
621	width = VMW_MIN_INITIAL_WIDTH;
622	height = VMW_MIN_INITIAL_HEIGHT;
623    }
624
625    xf86DrvMsg(pScrn->scrnIndex, from,
626	       "Will %sset up a driver mode with dimensions %dx%d.\n",
627	       defaultMode ? "" : "not ", width, height);
628
629    free(options);
630
631    {
632        Gamma zeros = { 0.0, 0.0, 0.0 };
633        if (!xf86SetGamma(pScrn, zeros)) {
634            return FALSE;
635        }
636    }
637#if 0
638    if ((i = xf86GetPciInfoForScreen(pScrn->scrnIndex, &pciList, NULL)) != 1) {
639        /* print error message */
640        VMWAREFreeRec(pScrn);
641        if (i > 0) {
642            free(pciList);
643        }
644        return FALSE;
645    }
646#endif
647    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
648    clockRanges->next = NULL;
649    clockRanges->minClock = 1;
650    clockRanges->maxClock = 400000000;
651    clockRanges->clockIndex = -1;
652    clockRanges->interlaceAllowed = FALSE;
653    clockRanges->doubleScanAllowed = FALSE;
654    clockRanges->ClockMulFactor = 1;
655    clockRanges->ClockDivFactor = 1;
656
657    if (defaultMode) {
658	vmwareAddDefaultMode(pScrn, width, height);
659    }
660
661    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes,
662                          clockRanges, NULL, 256, pVMWARE->maxWidth,
663                          pVMWARE->bitsPerPixel * 1,
664                          128, pVMWARE->maxHeight,
665                          pScrn->display->virtualX, pScrn->display->virtualY,
666                          pVMWARE->videoRam,
667                          LOOKUP_BEST_REFRESH | LOOKUP_OPTIONAL_TOLERANCES);
668
669    if (i == -1) {
670        VMWAREFreeRec(pScrn);
671        return FALSE;
672    }
673    xf86PruneDriverModes(pScrn);
674    if (i == 0 || pScrn->modes == NULL) {
675        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
676        VMWAREFreeRec(pScrn);
677        return FALSE;
678    }
679
680    pScrn->currentMode = pScrn->modes;
681    pScrn->virtualX = pScrn->modes->HDisplay;
682    pScrn->virtualY = pScrn->modes->VDisplay;
683
684    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
685
686    xf86PrintModes(pScrn);
687    xf86SetDpi(pScrn, 0, 0);
688    if (!xf86LoadSubModule(pScrn, "fb") ||
689        !xf86LoadSubModule(pScrn, "shadowfb")) {
690        VMWAREFreeRec(pScrn);
691        return FALSE;
692    }
693    xf86LoaderReqSymLists(fbSymbols, shadowfbSymbols, NULL);
694
695    /* Need ramdac for hwcursor */
696    if (pVMWARE->hwCursor) {
697        if (!xf86LoadSubModule(pScrn, "ramdac")) {
698            VMWAREFreeRec(pScrn);
699            return FALSE;
700        }
701        xf86LoaderReqSymLists(ramdacSymbols, NULL);
702    }
703
704    return TRUE;
705}
706
707static Bool
708VMWAREMapMem(ScrnInfoPtr pScrn)
709{
710    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
711#if XSERVER_LIBPCIACCESS
712    int err;
713    struct pci_device *const device = pVMWARE->PciInfo;
714    void *fbBase;
715#endif
716
717#if XSERVER_LIBPCIACCESS
718   err = pci_device_map_range(device,
719                              pVMWARE->memPhysBase,
720                              pVMWARE->videoRam,
721                              PCI_DEV_MAP_FLAG_WRITABLE,
722			      &fbBase);
723   if (err) {
724       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
725                  "Unable to map frame buffer BAR. %s (%d)\n",
726                  strerror (err), err);
727       return FALSE;
728   }
729   pVMWARE->FbBase = fbBase;
730#else
731    pVMWARE->FbBase = xf86MapPciMem(pScrn->scrnIndex, 0,
732                                    pVMWARE->PciTag,
733                                    pVMWARE->memPhysBase,
734                                    pVMWARE->videoRam);
735#endif
736    if (!pVMWARE->FbBase)
737        return FALSE;
738
739    VmwareLog(("FB Mapped: %p/%u -> %p/%u\n",
740               pVMWARE->memPhysBase, pVMWARE->videoRam,
741               pVMWARE->FbBase, pVMWARE->videoRam));
742    return TRUE;
743}
744
745static Bool
746VMWAREUnmapMem(ScrnInfoPtr pScrn)
747{
748    VMWAREPtr pVMWARE;
749
750    pVMWARE = VMWAREPTR(pScrn);
751
752    VmwareLog(("Unmapped: %p/%u\n", pVMWARE->FbBase, pVMWARE->videoRam));
753
754#if XSERVER_LIBPCIACCESS
755    pci_device_unmap_range(pVMWARE->PciInfo, pVMWARE->FbBase, pVMWARE->videoRam);
756#else
757    xf86UnMapVidMem(pScrn->scrnIndex, pVMWARE->FbBase, pVMWARE->videoRam);
758#endif
759    pVMWARE->FbBase = NULL;
760    return TRUE;
761}
762
763static void
764VMWARESave(ScrnInfoPtr pScrn)
765{
766    vgaHWPtr hwp = VGAHWPTR(pScrn);
767    vgaRegPtr vgaReg = &hwp->SavedReg;
768    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
769    VMWARERegPtr vmwareReg = &pVMWARE->SavedReg;
770
771    vgaHWSave(pScrn, vgaReg, VGA_SR_ALL);
772
773    vmwareReg->svga_reg_enable = vmwareReadReg(pVMWARE, SVGA_REG_ENABLE);
774    vmwareReg->svga_reg_width = vmwareReadReg(pVMWARE, SVGA_REG_WIDTH);
775    vmwareReg->svga_reg_height = vmwareReadReg(pVMWARE, SVGA_REG_HEIGHT);
776    vmwareReg->svga_reg_bits_per_pixel =
777       vmwareReadReg(pVMWARE, SVGA_REG_BITS_PER_PIXEL);
778    vmwareReg->svga_reg_id = vmwareReadReg(pVMWARE, SVGA_REG_ID);
779
780    /* XXX this should be based on the cap bit, not hwCursor... */
781    if (pVMWARE->hwCursor) {
782       vmwareReg->svga_reg_cursor_on =
783          vmwareReadReg(pVMWARE, SVGA_REG_CURSOR_ON);
784       vmwareReg->svga_reg_cursor_x =
785          vmwareReadReg(pVMWARE, SVGA_REG_CURSOR_X);
786       vmwareReg->svga_reg_cursor_y =
787          vmwareReadReg(pVMWARE, SVGA_REG_CURSOR_Y);
788       vmwareReg->svga_reg_cursor_id =
789          vmwareReadReg(pVMWARE, SVGA_REG_CURSOR_ID);
790    }
791
792    vmwareReg->svga_fifo_enabled = vmwareReadReg(pVMWARE, SVGA_REG_CONFIG_DONE);
793}
794
795static void
796VMWARERestoreRegs(ScrnInfoPtr pScrn, VMWARERegPtr vmwareReg)
797{
798    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
799    VmwareLog(("VMWARERestoreRegs: W: %d, H: %d, BPP: %d, Enable: %d\n",
800	       vmwareReg->svga_reg_width, vmwareReg->svga_reg_height,
801	       vmwareReg->svga_reg_bits_per_pixel, vmwareReg->svga_reg_enable));
802    if (vmwareReg->svga_reg_enable) {
803        vmwareWriteReg(pVMWARE, SVGA_REG_ID, vmwareReg->svga_reg_id);
804        vmwareWriteReg(pVMWARE, SVGA_REG_WIDTH, vmwareReg->svga_reg_width);
805        vmwareWriteReg(pVMWARE, SVGA_REG_HEIGHT, vmwareReg->svga_reg_height);
806        vmwareWriteReg(pVMWARE, SVGA_REG_BITS_PER_PIXEL,
807                       vmwareReg->svga_reg_bits_per_pixel);
808        vmwareWriteReg(pVMWARE, SVGA_REG_ENABLE, vmwareReg->svga_reg_enable);
809        vmwareWriteReg(pVMWARE, SVGA_REG_GUEST_ID, GUEST_OS_LINUX);
810        if (pVMWARE->hwCursor) {
811            vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ID,
812                           vmwareReg->svga_reg_cursor_id);
813            vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_X,
814                           vmwareReg->svga_reg_cursor_x);
815            vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_Y,
816                           vmwareReg->svga_reg_cursor_y);
817            vmwareWriteReg(pVMWARE, SVGA_REG_CURSOR_ON,
818                           vmwareReg->svga_reg_cursor_on);
819        }
820    } else {
821        vmwareWriteReg(pVMWARE, SVGA_REG_ID, vmwareReg->svga_reg_id);
822        vmwareWriteReg(pVMWARE, SVGA_REG_WIDTH, vmwareReg->svga_reg_width);
823        vmwareWriteReg(pVMWARE, SVGA_REG_HEIGHT, vmwareReg->svga_reg_height);
824        vmwareWriteReg(pVMWARE, SVGA_REG_BITS_PER_PIXEL,
825                       vmwareReg->svga_reg_bits_per_pixel);
826	vmwareWriteReg(pVMWARE, SVGA_REG_ENABLE, vmwareReg->svga_reg_enable);
827    }
828}
829
830static void
831VMWARERestore(ScrnInfoPtr pScrn)
832{
833    vgaHWPtr hwp = VGAHWPTR(pScrn);
834    vgaRegPtr vgaReg = &hwp->SavedReg;
835    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
836    VMWARERegPtr vmwareReg = &pVMWARE->SavedReg;
837
838    vmwareWaitForFB(pVMWARE);
839    if (!vmwareReg->svga_fifo_enabled) {
840        VMWAREStopFIFO(pScrn);
841    }
842
843    vgaHWProtect(pScrn, TRUE);
844    VMWARERestoreRegs(pScrn, vmwareReg);
845    vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
846    vgaHWProtect(pScrn, FALSE);
847}
848
849static Bool
850VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool rebuildPixmap)
851{
852    vgaHWPtr hwp = VGAHWPTR(pScrn);
853    vgaRegPtr vgaReg = &hwp->ModeReg;
854    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
855    VMWARERegPtr vmwareReg = &pVMWARE->ModeReg;
856
857    vgaHWUnlock(hwp);
858    if (!vgaHWInit(pScrn, mode))
859        return FALSE;
860    pScrn->vtSema = TRUE;
861
862    if (pVMWARE->vmwareCapability & SVGA_CAP_PITCHLOCK)
863	vmwareWriteReg(pVMWARE, SVGA_REG_PITCHLOCK, 0);
864    vmwareReg->svga_reg_enable = 1;
865    vmwareReg->svga_reg_width = max(mode->HDisplay, pScrn->virtualX);
866    vmwareReg->svga_reg_height = max(mode->VDisplay, pScrn->virtualY);
867    vmwareReg->svga_reg_bits_per_pixel = pVMWARE->bitsPerPixel;
868
869    vgaHWProtect(pScrn, TRUE);
870
871    vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
872    VMWARERestoreRegs(pScrn, vmwareReg);
873
874    if (pVMWARE->hwCursor) {
875        vmwareCursorModeInit(pScrn, mode);
876    }
877
878    VmwareLog(("Required mode: %ux%u\n", mode->HDisplay, mode->VDisplay));
879    VmwareLog(("Virtual:       %ux%u\n", pScrn->virtualX, pScrn->virtualY));
880    VmwareLog(("dispWidth:     %u\n", pScrn->displayWidth));
881    pVMWARE->fbOffset = vmwareReadReg(pVMWARE, SVGA_REG_FB_OFFSET);
882    pVMWARE->fbPitch = vmwareReadReg(pVMWARE, SVGA_REG_BYTES_PER_LINE);
883    pVMWARE->FbSize = vmwareReadReg(pVMWARE, SVGA_REG_FB_SIZE);
884
885    pScrn->displayWidth = (pVMWARE->fbPitch * 8) / ((pScrn->bitsPerPixel + 7) & ~7);
886    VmwareLog(("fbOffset:      %u\n", pVMWARE->fbOffset));
887    VmwareLog(("fbPitch:       %u\n", pVMWARE->fbPitch));
888    VmwareLog(("fbSize:        %u\n", pVMWARE->FbSize));
889    VmwareLog(("New dispWidth: %u\n", pScrn->displayWidth));
890
891    vmwareCheckVideoSanity(pScrn);
892
893    if (rebuildPixmap) {
894        pScrn->pScreen->ModifyPixmapHeader((*pScrn->pScreen->GetScreenPixmap)(pScrn->pScreen),
895                                           pScrn->pScreen->width,
896                                           pScrn->pScreen->height,
897                                           pScrn->pScreen->rootDepth,
898                                           pScrn->bitsPerPixel,
899                                           PixmapBytePad(pScrn->displayWidth,
900                                                         pScrn->pScreen->rootDepth),
901                                           (pointer)(pVMWARE->FbBase + pScrn->fbOffset));
902
903        (*pScrn->EnableDisableFBAccess)(XF86_SCRN_ARG(pScrn), FALSE);
904        (*pScrn->EnableDisableFBAccess)(XF86_SCRN_ARG(pScrn), TRUE);
905    }
906
907    vgaHWProtect(pScrn, FALSE);
908
909    /*
910     * Push the new Xinerama state to X clients and the hardware,
911     * synchronously with the mode change. Note that this must happen
912     * AFTER we write the new width and height to the hardware
913     * registers, since updating the WIDTH and HEIGHT registers will
914     * reset the device's multimon topology.
915     */
916    vmwareNextXineramaState(pVMWARE);
917
918    return TRUE;
919}
920
921void
922vmwareNextXineramaState(VMWAREPtr pVMWARE)
923{
924    VMWARERegPtr vmwareReg = &pVMWARE->ModeReg;
925
926    /*
927     * Switch to the next Xinerama state (from pVMWARE->xineramaNextState).
928     *
929     * This new state will be available to X clients via the Xinerama
930     * extension, and we push the new state to the virtual hardware,
931     * in order to configure a number of virtual monitors within the
932     * device's framebuffer.
933     *
934     * This function can be called at any time, but it should usually be
935     * called just after a mode switch. This is for two reasons:
936     *
937     *   1) We don't want X clients to see a Xinerama topology and a video
938     *      mode that are inconsistent with each other, so we'd like to switch
939     *      both at the same time.
940     *
941     *   2) We must set the host's display topology registers after setting
942     *      the new video mode, since writes to WIDTH/HEIGHT will reset the
943     *      hardware display topology.
944     */
945
946    /*
947     * Update Xinerama info appropriately.
948     */
949    if (pVMWARE->xinerama && !pVMWARE->xineramaStatic) {
950       if (pVMWARE->xineramaNextState) {
951          free(pVMWARE->xineramaState);
952          pVMWARE->xineramaState = pVMWARE->xineramaNextState;
953          pVMWARE->xineramaNumOutputs = pVMWARE->xineramaNextNumOutputs;
954
955          pVMWARE->xineramaNextState = NULL;
956          pVMWARE->xineramaNextNumOutputs = 0;
957
958       } else {
959          /*
960           * There is no next state pending. Switch back to
961           * single-monitor mode. This is necessary for resetting the
962           * Xinerama state if we get a mode change which doesn't
963           * follow a VMwareCtrlDoSetTopology call.
964           */
965          VMWAREXineramaPtr basicState =
966             (VMWAREXineramaPtr)calloc(1, sizeof (VMWAREXineramaRec));
967          if (basicState) {
968             basicState->x_org = 0;
969             basicState->y_org = 0;
970             basicState->width = vmwareReg->svga_reg_width;
971             basicState->height = vmwareReg->svga_reg_height;
972
973             free(pVMWARE->xineramaState);
974             pVMWARE->xineramaState = basicState;
975             pVMWARE->xineramaNumOutputs = 1;
976          }
977       }
978    }
979
980    /*
981     * Update host's view of guest topology. This tells the device
982     * how we're carving up its framebuffer into virtual screens.
983     */
984    if (pVMWARE->vmwareCapability & SVGA_CAP_DISPLAY_TOPOLOGY) {
985        if (pVMWARE->xinerama) {
986            int i = 0;
987            VMWAREXineramaPtr xineramaState = pVMWARE->xineramaState;
988            vmwareWriteReg(pVMWARE, SVGA_REG_NUM_GUEST_DISPLAYS,
989                           pVMWARE->xineramaNumOutputs);
990
991            for (i = 0; i < pVMWARE->xineramaNumOutputs; i++) {
992                vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_ID, i);
993                vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_IS_PRIMARY, i == 0);
994                vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_POSITION_X,
995                               xineramaState[i].x_org);
996                vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_POSITION_Y,
997                               xineramaState[i].y_org);
998                vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_WIDTH,
999                               xineramaState[i].width);
1000                vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_HEIGHT,
1001                               xineramaState[i].height);
1002            }
1003        } else {
1004            vmwareWriteReg(pVMWARE, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
1005
1006            vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_ID, 0);
1007            vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_IS_PRIMARY, TRUE);
1008            vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_POSITION_X, 0);
1009            vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_POSITION_Y, 0);
1010            vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_WIDTH, vmwareReg->svga_reg_width);
1011            vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_HEIGHT, vmwareReg->svga_reg_height);
1012        }
1013
1014        /* Done. */
1015        vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_ID, SVGA_INVALID_DISPLAY_ID);
1016    }
1017}
1018
1019static void
1020VMWAREAdjustFrame(ADJUST_FRAME_ARGS_DECL)
1021{
1022    /* FIXME */
1023}
1024
1025static void
1026VMWAREInitFIFO(ScrnInfoPtr pScrn)
1027{
1028    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1029#if XSERVER_LIBPCIACCESS
1030    struct pci_device *const device = pVMWARE->PciInfo;
1031    int err;
1032    void *mmioVirtBase;
1033#endif
1034    volatile CARD32* vmwareFIFO;
1035    Bool extendedFifo;
1036    int min;
1037
1038    TRACEPOINT
1039
1040    pVMWARE->mmioPhysBase = vmwareReadReg(pVMWARE, SVGA_REG_MEM_START);
1041    pVMWARE->mmioSize = vmwareReadReg(pVMWARE, SVGA_REG_MEM_SIZE) & ~3;
1042#if XSERVER_LIBPCIACCESS
1043    err = pci_device_map_range(device, pVMWARE->mmioPhysBase,
1044                               pVMWARE->mmioSize,
1045                               PCI_DEV_MAP_FLAG_WRITABLE,
1046                               &mmioVirtBase);
1047    if (err) {
1048        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1049                   "Unable to map mmio BAR. %s (%d)\n",
1050                   strerror (err), err);
1051        return;
1052    }
1053    pVMWARE->mmioVirtBase = mmioVirtBase;
1054#else
1055    pVMWARE->mmioVirtBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1056                                          pVMWARE->PciTag,
1057                                          pVMWARE->mmioPhysBase,
1058                                          pVMWARE->mmioSize);
1059#endif
1060    vmwareFIFO = pVMWARE->vmwareFIFO = (CARD32*)pVMWARE->mmioVirtBase;
1061
1062    extendedFifo = pVMWARE->vmwareCapability & SVGA_CAP_EXTENDED_FIFO;
1063    min = extendedFifo ? vmwareReadReg(pVMWARE, SVGA_REG_MEM_REGS) : 4;
1064
1065    vmwareWaitForFB(pVMWARE);
1066    vmwareWriteReg(pVMWARE, SVGA_REG_CONFIG_DONE, 0);
1067
1068    vmwareFIFO[SVGA_FIFO_MIN] = min * sizeof(CARD32);
1069    vmwareFIFO[SVGA_FIFO_MAX] = pVMWARE->mmioSize;
1070    vmwareFIFO[SVGA_FIFO_NEXT_CMD] = min * sizeof(CARD32);
1071    vmwareFIFO[SVGA_FIFO_STOP] = min * sizeof(CARD32);
1072    vmwareWriteReg(pVMWARE, SVGA_REG_CONFIG_DONE, 1);
1073}
1074
1075static void
1076VMWAREStopFIFO(ScrnInfoPtr pScrn)
1077{
1078    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1079
1080    TRACEPOINT
1081
1082    vmwareWriteReg(pVMWARE, SVGA_REG_CONFIG_DONE, 0);
1083#if XSERVER_LIBPCIACCESS
1084    pci_device_unmap_range(pVMWARE->PciInfo, pVMWARE->mmioVirtBase, pVMWARE->mmioSize);
1085#else
1086    xf86UnMapVidMem(pScrn->scrnIndex, pVMWARE->mmioVirtBase, pVMWARE->mmioSize);
1087#endif
1088}
1089
1090static Bool
1091VMWARECloseScreen(CLOSE_SCREEN_ARGS_DECL)
1092{
1093    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1094    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1095    ScreenPtr save = &pVMWARE->ScrnFuncs;
1096
1097    VmwareLog(("cursorSema: %d\n", pVMWARE->cursorSema));
1098
1099    if (*pVMWARE->pvtSema) {
1100        if (pVMWARE->videoStreams) {
1101            vmwareVideoEnd(pScreen);
1102        }
1103
1104        if (pVMWARE->CursorInfoRec) {
1105            vmwareCursorCloseScreen(pScreen);
1106        }
1107
1108        VMWARERestore(pScrn);
1109        VMWAREUnmapMem(pScrn);
1110
1111        pScrn->vtSema = FALSE;
1112    }
1113
1114    pScreen->CloseScreen = save->CloseScreen;
1115    pScreen->SaveScreen = save->SaveScreen;
1116
1117#if VMWARE_DRIVER_FUNC
1118    pScrn->DriverFunc = NULL;
1119#endif
1120
1121    return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
1122}
1123
1124static Bool
1125VMWARESaveScreen(ScreenPtr pScreen, int mode)
1126{
1127    VmwareLog(("VMWareSaveScreen() mode = %d\n", mode));
1128
1129    /*
1130     * This thoroughly fails to do anything useful to svga mode.  I doubt
1131     * we care; who wants to idle-blank their VM's screen anyway?
1132     */
1133    return vgaHWSaveScreen(pScreen, mode);
1134}
1135
1136/* disabled by default to reduce spew in DEBUG_LOGGING mode. */
1137/*#define DEBUG_LOG_UPDATES*/
1138
1139static void
1140VMWAREPreDirtyBBUpdate(ScrnInfoPtr pScrn, int nboxes, BoxPtr boxPtr)
1141{
1142    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1143
1144#ifdef DEBUG_LOG_UPDATES
1145    {
1146        int i;
1147        for (i = 0; i < nboxes; i++) {
1148            VmwareLog(("PreUpdate #%d (%d, %d, w = %d, h = %d)\n", nboxes - i,
1149                       boxPtr[i].x1, boxPtr[i].y1,
1150                       boxPtr[i].x2 - boxPtr[i].x1,
1151                       boxPtr[i].y2 - boxPtr[i].y1));
1152        }
1153    }
1154#endif
1155
1156    /*
1157     * We only register this callback if we have a HW cursor.
1158     */
1159    while (nboxes--) {
1160        if (BOX_INTERSECT(*boxPtr, pVMWARE->hwcur.box)) {
1161            if (!pVMWARE->cursorExcludedForUpdate) {
1162                PRE_OP_HIDE_CURSOR();
1163                pVMWARE->cursorExcludedForUpdate = TRUE;
1164            }
1165	    break;
1166        }
1167        boxPtr++;
1168    }
1169}
1170
1171static void
1172VMWAREPostDirtyBBUpdate(ScrnInfoPtr pScrn, int nboxes, BoxPtr boxPtr)
1173{
1174    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1175    while (nboxes--) {
1176#ifdef DEBUG_LOG_UPDATES
1177        VmwareLog(("PostUpdate #%d (%d, %d, w = %d, h = %d)\n", nboxes,
1178                   boxPtr->x1, boxPtr->y1,
1179                   boxPtr->x2 - boxPtr->x1, boxPtr->y2 - boxPtr->y1));
1180#endif
1181
1182        /* Clip off (y only) for offscreen memory */
1183        if (boxPtr->y2 >= pVMWARE->ModeReg.svga_reg_height)
1184            boxPtr->y2 = pVMWARE->ModeReg.svga_reg_height;
1185        if (boxPtr->y1 >= pVMWARE->ModeReg.svga_reg_height)
1186            boxPtr->y1 = pVMWARE->ModeReg.svga_reg_height;
1187        if (boxPtr->y1 == boxPtr->y2) {
1188            boxPtr++;
1189            continue;
1190        }
1191
1192        vmwareSendSVGACmdUpdate(pVMWARE, boxPtr++);
1193    }
1194
1195    if (pVMWARE->hwCursor && pVMWARE->cursorExcludedForUpdate) {
1196        POST_OP_SHOW_CURSOR();
1197        pVMWARE->cursorExcludedForUpdate = FALSE;
1198    }
1199}
1200
1201static void
1202VMWARELoadPalette(ScrnInfoPtr pScrn, int numColors, int* indices,
1203                  LOCO* colors, VisualPtr pVisual)
1204{
1205    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1206    int i;
1207
1208    for (i = 0; i < numColors; i++) {
1209        vmwareWriteReg(pVMWARE, SVGA_PALETTE_BASE + *indices * 3 + 0, colors[*indices].red);
1210        vmwareWriteReg(pVMWARE, SVGA_PALETTE_BASE + *indices * 3 + 1, colors[*indices].green);
1211        vmwareWriteReg(pVMWARE, SVGA_PALETTE_BASE + *indices * 3 + 2, colors[*indices].blue);
1212        indices++;
1213    }
1214    VmwareLog(("Palette loading done\n"));
1215}
1216
1217
1218DisplayModeRec *
1219VMWAREAddDisplayMode(ScrnInfoPtr pScrn,
1220                     const char *name,
1221                     int width,
1222                     int height)
1223{
1224   DisplayModeRec *mode;
1225
1226   mode = malloc(sizeof(DisplayModeRec));
1227   memset(mode, 0, sizeof *mode);
1228
1229   mode->name = malloc(strlen(name) + 1);
1230   strcpy(mode->name, name);
1231   mode->status = MODE_OK;
1232   mode->type = M_T_DEFAULT;
1233   mode->HDisplay = width;
1234   mode->VDisplay = height;
1235
1236   mode->next = pScrn->modes;
1237   mode->prev = pScrn->modes->prev;
1238   pScrn->modes->prev->next = mode;
1239   pScrn->modes->prev = mode;
1240
1241   return mode;
1242}
1243
1244
1245/*
1246 *-----------------------------------------------------------------------------
1247 *
1248 * vmwareIsRegionEqual --
1249 *
1250 *    This function implements REGION_EQUAL because older versions of
1251 *    regionstr.h don't define it.
1252 *    It is a slightly modified version of miRegionEqual from $Xorg: miregion.c
1253 *
1254 * Results:
1255 *    TRUE if regions are equal; FALSE otherwise
1256 *
1257 * Side effects:
1258 *    None.
1259 *
1260 *-----------------------------------------------------------------------------
1261 */
1262
1263Bool
1264vmwareIsRegionEqual(const RegionPtr reg1,
1265                    const RegionPtr reg2)
1266{
1267    int i, num;
1268    BoxPtr rects1, rects2;
1269
1270    if ((reg1->extents.x1 != reg2->extents.x1) ||
1271        (reg1->extents.x2 != reg2->extents.x2) ||
1272        (reg1->extents.y1 != reg2->extents.y1) ||
1273        (reg1->extents.y2 != reg2->extents.y2)) {
1274        return FALSE;
1275    }
1276
1277    num = REGION_NUM_RECTS(reg1);
1278    if (num != REGION_NUM_RECTS(reg2)) {
1279        return FALSE;
1280    }
1281
1282    rects1 = REGION_RECTS(reg1);
1283    rects2 = REGION_RECTS(reg2);
1284
1285    for (i = 0; i < num; i++) {
1286        if ((rects1[i].x1 != rects2[i].x1) ||
1287            (rects1[i].x2 != rects2[i].x2) ||
1288            (rects1[i].y1 != rects2[i].y1) ||
1289            (rects1[i].y2 != rects2[i].y2)) {
1290            return FALSE;
1291        }
1292    }
1293
1294    return TRUE;
1295}
1296
1297static Bool
1298VMWAREScreenInit(SCREEN_INIT_ARGS_DECL)
1299{
1300    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1301    vgaHWPtr hwp;
1302    VMWAREPtr pVMWARE;
1303    OptionInfoPtr options;
1304    Bool useXinerama = TRUE;
1305
1306    pVMWARE = VMWAREPTR(pScrn);
1307
1308
1309    xf86CollectOptions(pScrn, NULL);
1310    if (!(options = VMWARECopyOptions()))
1311        return FALSE;
1312    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
1313
1314    /*
1315     * Init xinerama preferences.
1316     */
1317    useXinerama = xf86ReturnOptValBool(options, OPTION_XINERAMA,
1318                                       pVMWARE->vmwareCapability & SVGA_CAP_MULTIMON);
1319    if (useXinerama && !(pVMWARE->vmwareCapability & SVGA_CAP_MULTIMON)) {
1320       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1321                  "Xinerama is not safely supported by the current virtual hardware. "
1322                  "Do not request resolutions that require > 16MB of framebuffer.\n");
1323    }
1324
1325
1326    if (useXinerama && xf86IsOptionSet(options, OPTION_GUI_LAYOUT)) {
1327       const char *topology = xf86GetOptValString(options, OPTION_GUI_LAYOUT);
1328       if (topology) {
1329          pVMWARE->xineramaState =
1330             VMWAREParseTopologyString(pScrn, topology,
1331				       &pVMWARE->xineramaNumOutputs, "gui");
1332
1333         pVMWARE->xineramaStatic = pVMWARE->xineramaState != NULL;
1334
1335         free(topology);
1336       }
1337    } else if (useXinerama &&
1338	       xf86IsOptionSet(options, OPTION_STATIC_XINERAMA)) {
1339       const char *topology = xf86GetOptValString(options, OPTION_STATIC_XINERAMA);
1340       if (topology) {
1341          pVMWARE->xineramaState =
1342             VMWAREParseTopologyString(pScrn, topology,
1343				       &pVMWARE->xineramaNumOutputs,
1344				       "static Xinerama");
1345
1346         pVMWARE->xineramaStatic = pVMWARE->xineramaState != NULL;
1347
1348         free(topology);
1349       }
1350    }
1351
1352    free(options);
1353
1354    /* Initialise VMWARE_CTRL extension. */
1355    VMwareCtrl_ExtInit(pScrn);
1356
1357    /* Initialise Xinerama extension. */
1358    if (useXinerama) {
1359       VMwareXinerama_ExtInit(pScrn);
1360    }
1361
1362    if (pVMWARE->xinerama && pVMWARE->xineramaStatic) {
1363       xf86DrvMsg(pScrn->scrnIndex, X_INFO, pVMWARE->xineramaState ?
1364                                            "Using static Xinerama.\n" :
1365                                            "Failed to configure static Xinerama.\n");
1366    }
1367
1368    /*
1369     * If using the vgahw module, its data structures and related
1370     * things are typically initialised/mapped here.
1371     */
1372    hwp = VGAHWPTR(pScrn);
1373    vgaHWGetIOBase(hwp);
1374
1375    VMWAREInitFIFO(pScrn);
1376
1377    /* Initialise the first mode */
1378    VMWAREModeInit(pScrn, pScrn->currentMode, FALSE);
1379
1380    /* Set the viewport if supported */
1381    VMWAREAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
1382
1383    /*
1384     * Setup the screen's visuals, and initialise the framebuffer
1385     * code.
1386     */
1387    VMWAREMapMem(pScrn);
1388
1389    /*
1390     * Clear the framebuffer (and any black-border mode areas).
1391     */
1392    memset(pVMWARE->FbBase, 0, pVMWARE->FbSize);
1393    vmwareSendSVGACmdUpdateFullScreen(pVMWARE);
1394
1395    /* Reset the visual list */
1396    miClearVisualTypes();
1397
1398    /*
1399     * Setup the visuals supported.  This driver only supports
1400     * TrueColor for bpp > 8, so the default set of visuals isn't
1401     * acceptable.  To deal with this, call miSetVisualTypes with
1402     * the appropriate visual mask.
1403     */
1404    if (pScrn->bitsPerPixel > 8) {
1405        if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
1406                              pScrn->rgbBits, pScrn->defaultVisual)) {
1407            return FALSE;
1408        }
1409    } else {
1410        if (!miSetVisualTypes(pScrn->depth,
1411                              miGetDefaultVisualMask(pScrn->depth),
1412                              pScrn->rgbBits, pScrn->defaultVisual)) {
1413            return FALSE;
1414        }
1415    }
1416
1417    miSetPixmapDepths();
1418
1419    /*
1420     * Initialise the framebuffer.
1421     */
1422    if (!fbScreenInit(pScreen, pVMWARE->FbBase + pVMWARE->fbOffset,
1423                      pScrn->virtualX, pScrn->virtualY,
1424                      pScrn->xDpi, pScrn->yDpi,
1425                      pScrn->displayWidth,
1426                      pScrn->bitsPerPixel)) {
1427        return FALSE;
1428    }
1429
1430    /* Override the default mask/offset settings */
1431    if (pScrn->bitsPerPixel > 8) {
1432        int i;
1433        VisualPtr visual;
1434
1435        for (i = 0, visual = pScreen->visuals;
1436             i < pScreen->numVisuals; i++, visual++) {
1437            if ((visual->class | DynamicClass) == DirectColor) {
1438                visual->offsetRed = pScrn->offset.red;
1439                visual->offsetGreen = pScrn->offset.green;
1440                visual->offsetBlue = pScrn->offset.blue;
1441                visual->redMask = pScrn->mask.red;
1442                visual->greenMask = pScrn->mask.green;
1443                visual->blueMask = pScrn->mask.blue;
1444            }
1445        }
1446    }
1447
1448    /* must be after RGB ordering fixed */
1449    fbPictureInit (pScreen, 0, 0);
1450
1451    /*
1452     * Save the old screen vector.
1453     */
1454    pVMWARE->ScrnFuncs = *pScreen;
1455
1456    /*
1457     * Set initial black & white colourmap indices.
1458     */
1459    xf86SetBlackWhitePixels(pScreen);
1460
1461    /*
1462     * Initialize shadowfb to notify us of dirty rectangles.  We only
1463     * need preFB access callbacks if we're using the hw cursor.
1464     */
1465    if (!ShadowFBInit2(pScreen,
1466                       pVMWARE->hwCursor ? VMWAREPreDirtyBBUpdate : NULL,
1467                       VMWAREPostDirtyBBUpdate)) {
1468        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1469                   "ShadowFB initialization failed\n");
1470        return FALSE;
1471    }
1472
1473    /*
1474     * If we have a hw cursor, we need to hook functions that might
1475     * read from the framebuffer.
1476     */
1477    if (pVMWARE->hwCursor) {
1478        vmwareCursorHookWrappers(pScreen);
1479    }
1480
1481    /*
1482     * If backing store is to be supported (as is usually the case),
1483     * initialise it.
1484     */
1485    xf86SetBackingStore(pScreen);
1486    xf86SetSilkenMouse(pScreen);
1487
1488    /*
1489     * Initialize software cursor.
1490     */
1491    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1492
1493    /*
1494     * Initialize hardware cursor.
1495     */
1496    if (pVMWARE->hwCursor) {
1497        if (!vmwareCursorInit(pScreen)) {
1498            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1499                       "Hardware cursor initialization failed\n");
1500            pVMWARE->hwCursor = FALSE;
1501        }
1502    }
1503
1504    /*
1505     * Install colourmap functions.  If using the vgahw module,
1506     * vgaHandleColormaps would usually be called here.
1507     */
1508    if (!fbCreateDefColormap(pScreen))
1509        return FALSE;
1510
1511    if (!xf86HandleColormaps(pScreen, 256, 8,
1512                             VMWARELoadPalette, NULL,
1513                             CMAP_PALETTED_TRUECOLOR |
1514                             CMAP_RELOAD_ON_MODE_SWITCH)) {
1515        return FALSE;
1516    }
1517
1518    /*
1519     * We explictly add a set of default modes because the X server will
1520     * not include modes larger than the initial one.
1521     */
1522   {
1523      unsigned int i;
1524      unsigned int numModes = sizeof (VMWAREDefaultModes) / sizeof *(VMWAREDefaultModes);
1525      char name[10];
1526      for (i = 0; i < numModes; i++) {
1527         const VMWAREDefaultMode *mode = &VMWAREDefaultModes[i];
1528
1529         /* Only modes that fit the hardware maximums should be added. */
1530         if (mode->width <= pVMWARE->maxWidth && mode->height <= pVMWARE->maxHeight) {
1531            snprintf(name, 10, "%dx%d", mode->width, mode->height);
1532            VMWAREAddDisplayMode(pScrn, name, mode->width, mode->height);
1533         }
1534      }
1535
1536      /* Add the hardware maximums as a mode. */
1537      snprintf(name, 10, "%dx%d", pVMWARE->maxWidth, pVMWARE->maxHeight);
1538      VMWAREAddDisplayMode(pScrn, name, pVMWARE->maxWidth, pVMWARE->maxHeight);
1539   }
1540
1541    /*
1542     * We will lazily add the dynamic modes as the are needed when new
1543     * modes are requested through the control extension.
1544     */
1545    memset(&pVMWARE->dynModes, 0, sizeof pVMWARE->dynModes);
1546
1547#if VMWARE_DRIVER_FUNC
1548    pScrn->DriverFunc = VMWareDriverFunc;
1549#endif
1550
1551    /* Report any unused options (only for the first generation) */
1552    if (serverGeneration == 1) {
1553        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1554    }
1555
1556    /* Initialize Xv extension */
1557    pVMWARE->videoStreams = NULL;
1558    if (vmwareVideoEnabled(pVMWARE)) {
1559        if (!vmwareVideoInit(pScreen)) {
1560            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Xv initialization failed\n");
1561        }
1562    }
1563
1564    /**
1565     * Wrap CloseScreen and SaveScreen. Do this late since we
1566     * want to be first in the callchain, to avoid using resources
1567     * already taken down in CloseScreen.
1568     */
1569
1570    pVMWARE->ScrnFuncs.CloseScreen = pScreen->CloseScreen;
1571    pVMWARE->ScrnFuncs.SaveScreen = pScreen->SaveScreen;
1572
1573    pScreen->CloseScreen = VMWARECloseScreen;
1574    pScreen->SaveScreen = VMWARESaveScreen;
1575
1576    /* Done */
1577    return TRUE;
1578}
1579
1580static Bool
1581VMWARESwitchMode(SWITCH_MODE_ARGS_DECL)
1582{
1583    SCRN_INFO_PTR(arg);
1584    ScreenPtr pScreen = pScrn->pScreen;
1585
1586    pScreen->mmWidth = (pScreen->width * VMWARE_INCHTOMM +
1587			pScrn->xDpi / 2) / pScrn->xDpi;
1588    pScreen->mmHeight = (pScreen->height * VMWARE_INCHTOMM +
1589			 pScrn->yDpi / 2) / pScrn->yDpi;
1590
1591    return VMWAREModeInit(pScrn, mode, TRUE);
1592}
1593
1594static Bool
1595VMWAREEnterVT(VT_FUNC_ARGS_DECL)
1596{
1597    SCRN_INFO_PTR(arg);
1598    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1599
1600    /*
1601     * After system resumes from hiberation, EnterVT will be called and this
1602     * is a good place to restore the SVGA ID register.
1603     */
1604    vmwareWriteReg(pVMWARE, SVGA_REG_ID, pVMWARE->suspensionSavedRegId);
1605
1606    if (!pVMWARE->SavedReg.svga_fifo_enabled) {
1607        VMWAREInitFIFO(pScrn);
1608    }
1609
1610    return VMWAREModeInit(pScrn, pScrn->currentMode, TRUE);
1611}
1612
1613static void
1614VMWARELeaveVT(VT_FUNC_ARGS_DECL)
1615{
1616    SCRN_INFO_PTR(arg);
1617    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1618
1619    /*
1620     * Before shutting down system for hibneration, LeaveVT will be called,
1621     * we save the ID register value here and later restore it in EnterVT.
1622     */
1623    pVMWARE->suspensionSavedRegId = vmwareReadReg(pVMWARE, SVGA_REG_ID);
1624
1625    VMWARERestore(pScrn);
1626}
1627
1628static void
1629VMWAREFreeScreen(FREE_SCREEN_ARGS_DECL)
1630{
1631    SCRN_INFO_PTR(arg);
1632    /*
1633     * If the vgahw module is used vgaHWFreeHWRec() would be called
1634     * here.
1635     */
1636   VMWAREFreeRec(pScrn);
1637}
1638
1639static ModeStatus
1640VMWAREValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
1641{
1642    return MODE_OK;
1643}
1644
1645void
1646vmwlegacy_hookup(ScrnInfoPtr pScrn)
1647{
1648    pScrn->PreInit = VMWAREPreInit;
1649    pScrn->ScreenInit = VMWAREScreenInit;
1650    pScrn->SwitchMode = VMWARESwitchMode;
1651    pScrn->EnterVT = VMWAREEnterVT;
1652    pScrn->LeaveVT = VMWARELeaveVT;
1653    pScrn->FreeScreen = VMWAREFreeScreen;
1654    pScrn->ValidMode = VMWAREValidMode;
1655}
1656
1657#ifdef XFree86LOADER
1658void
1659VMWARERefSymLists(void)
1660{
1661    LoaderRefSymLists(vgahwSymbols, fbSymbols, ramdacSymbols,
1662		      shadowfbSymbols, NULL);
1663}
1664#endif	/* XFree86LOADER */
1665