vmware_bootstrap.c revision 3bfa90b6
1/*
2 * Copyright 2011 VMWare, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Author: Unknown at vmware
26 * Author: Thomas Hellstrom <thellstrom@vmware.com>
27 */
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "xf86.h"
33#include "compiler.h"
34#include "xf86Pci.h"		/* pci */
35#include "vm_device_version.h"
36#include "vmware_bootstrap.h"
37
38#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
39#include "xf86Resources.h"
40#endif
41
42#ifndef XSERVER_LIBPCIACCESS
43#include "vm_basic_types.h"
44#include "svga_reg.h"
45#endif
46
47#ifndef HAVE_XORG_SERVER_1_5_0
48#include <xf86_ansic.h>
49#include <xf86_libc.h>
50#endif
51
52#ifdef HaveDriverFuncs
53#define VMWARE_DRIVER_FUNC HaveDriverFuncs
54#else
55#define VMWARE_DRIVER_FUNC 0
56#endif
57
58/*
59 * So that the file compiles unmodified when dropped in to a < 6.9 source tree.
60 */
61#ifndef _X_EXPORT
62#define _X_EXPORT
63#endif
64/*
65 * So that the file compiles unmodified when dropped into an xfree source tree.
66 */
67#ifndef XORG_VERSION_CURRENT
68#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT
69#endif
70
71/*
72 * This is the only way I know to turn a #define of an integer constant into
73 * a constant string.
74 */
75#define VMW_INNERSTRINGIFY(s) #s
76#define VMW_STRING(str) VMW_INNERSTRINGIFY(str)
77
78#define VMWARE_NAME "vmware"
79#define VMWARE_DRIVER_NAME "vmware"
80#define VMWARE_DRIVER_VERSION \
81   (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL)
82#define VMWARE_DRIVER_VERSION_STRING \
83    VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \
84    "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL)
85
86static const char VMWAREBuildStr[] = "VMware Guest X Server "
87    VMWARE_DRIVER_VERSION_STRING " - build=$Name:  $\n";
88
89/*
90 * Standard four digit version string expected by VMware Tools installer.
91 * As the driver's version is only  {major, minor, patchlevel},
92 * The fourth digit may describe the commit number relative to the
93 * last version tag as output from `git describe`
94 */
95
96#ifdef __GNUC__
97#ifdef VMW_SUBPATCH
98const char vmware_drv_modinfo[]
99__attribute__((section(".modinfo"),unused)) =
100  "version=" VMWARE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH);
101#else
102const char vmware_drv_modinfo[]
103__attribute__((section(".modinfo"),unused)) =
104  "version=" VMWARE_DRIVER_VERSION_STRING ".0";
105#endif /*VMW_SUBPATCH*/
106#endif
107
108#ifndef XSERVER_LIBPCIACCESS
109static resRange vmwareLegacyRes[] = {
110    { ResExcIoBlock, SVGA_LEGACY_BASE_PORT,
111      SVGA_LEGACY_BASE_PORT + SVGA_NUM_PORTS*sizeof(uint32)},
112    _VGA_EXCLUSIVE, _END
113};
114#else
115#define vmwareLegacyRes NULL
116#endif
117
118#if XSERVER_LIBPCIACCESS
119#define VENDOR_ID(p)      (p)->vendor_id
120#define DEVICE_ID(p)      (p)->device_id
121#define SUBVENDOR_ID(p)   (p)->subvendor_id
122#define SUBSYS_ID(p)      (p)->subdevice_id
123#define CHIP_REVISION(p)  (p)->revision
124#else
125#define VENDOR_ID(p)      (p)->vendor
126#define DEVICE_ID(p)      (p)->chipType
127#define SUBVENDOR_ID(p)   (p)->subsysVendor
128#define SUBSYS_ID(p)      (p)->subsysCard
129#define CHIP_REVISION(p)  (p)->chipRev
130#endif
131
132#if XSERVER_LIBPCIACCESS
133
134#define VMWARE_DEVICE_MATCH(d, i) \
135    {PCI_VENDOR_ID_VMWARE, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) }
136
137static const struct pci_id_match VMwareDeviceMatch[] = {
138    VMWARE_DEVICE_MATCH (PCI_DEVICE_ID_VMWARE_SVGA2, 0 ),
139    VMWARE_DEVICE_MATCH (PCI_DEVICE_ID_VMWARE_SVGA, 0 ),
140    { 0, 0, 0 },
141};
142#endif
143
144/*
145 * Currently, even the PCI obedient 0405 chip still only obeys IOSE and
146 * MEMSE for the SVGA resources.  Thus, RES_EXCLUSIVE_VGA is required.
147 *
148 * The 0710 chip also uses hardcoded IO ports that aren't disablable.
149 */
150
151static PciChipsets VMWAREPciChipsets[] = {
152    { PCI_DEVICE_ID_VMWARE_SVGA2, PCI_DEVICE_ID_VMWARE_SVGA2, RES_EXCLUSIVE_VGA },
153    { PCI_DEVICE_ID_VMWARE_SVGA, PCI_DEVICE_ID_VMWARE_SVGA, vmwareLegacyRes },
154    { -1,		       -1,		    RES_UNDEFINED }
155};
156
157static SymTabRec VMWAREChipsets[] = {
158    { PCI_DEVICE_ID_VMWARE_SVGA2, "vmware0405" },
159    { PCI_DEVICE_ID_VMWARE_SVGA, "vmware0710" },
160    { -1,                  NULL }
161};
162
163#ifdef XFree86LOADER
164static XF86ModuleVersionInfo vmwareVersRec = {
165    VMWARE_DRIVER_NAME,
166    MODULEVENDORSTRING,
167    MODINFOSTRING1,
168    MODINFOSTRING2,
169    XORG_VERSION_CURRENT,
170    PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
171    ABI_CLASS_VIDEODRV,
172    ABI_VIDEODRV_VERSION,
173    MOD_CLASS_VIDEODRV,
174    { 0, 0, 0, 0}
175};
176#endif	/* XFree86LOADER */
177
178static const OptionInfoRec VMWAREOptions[] = {
179    { OPTION_HW_CURSOR, "HWcursor",     OPTV_BOOLEAN,   {0},    FALSE },
180    { OPTION_XINERAMA,  "Xinerama",     OPTV_BOOLEAN,   {0},    FALSE },
181    { OPTION_STATIC_XINERAMA, "StaticXinerama", OPTV_STRING, {0}, FALSE },
182    { OPTION_GUI_LAYOUT, "GuiLayout", OPTV_STRING, {0}, FALSE },
183    { OPTION_DEFAULT_MODE, "AddDefaultMode", OPTV_BOOLEAN,   {0},    FALSE },
184    { OPTION_RENDER_ACCEL, "RenderAccel", OPTV_BOOLEAN, {0}, FALSE},
185    { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE},
186    { OPTION_DIRECT_PRESENTS, "DirectPresents", OPTV_BOOLEAN, {0}, FALSE},
187    { OPTION_HW_PRESENTS, "HWPresents", OPTV_BOOLEAN, {0}, FALSE},
188    { OPTION_RENDERCHECK, "RenderCheck", OPTV_BOOLEAN, {0}, FALSE},
189    { -1,               NULL,           OPTV_NONE,      {0},    FALSE }
190};
191
192OptionInfoPtr VMWARECopyOptions(void)
193{
194    OptionInfoPtr options;
195    if (!(options = malloc(sizeof(VMWAREOptions))))
196        return NULL;
197
198    memcpy(options, VMWAREOptions, sizeof(VMWAREOptions));
199    return options;
200}
201
202static Bool
203VMwarePreinitStub(ScrnInfoPtr pScrn, int flags)
204{
205#if XSERVER_LIBPCIACCESS
206    struct pci_device *pciInfo;
207#else
208    pciVideoPtr pciInfo;
209#endif /* XSERVER_LIBPCIACCESS */
210    EntityInfoPtr pEnt;
211
212    pScrn->PreInit = pScrn->driverPrivate;
213
214#ifdef BUILD_VMWGFX
215    pScrn->driverPrivate = NULL;
216
217    /*
218     * Try vmwgfx path.
219     */
220    if ((*pScrn->PreInit)(pScrn, flags))
221	return TRUE;
222
223#else
224    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
225	       "Driver was compiled without KMS- and 3D support.\n");
226#endif /* defined(BUILD_VMWGFX) */
227    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
228	       "Disabling 3D support.\n");
229    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
230	       "Disabling Render Acceleration.\n");
231    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
232	       "Disabling RandR12+ support.\n");
233
234    pScrn->driverPrivate = NULL;
235    vmwlegacy_hookup(pScrn);
236
237    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
238    if (pEnt->location.type != BUS_PCI)
239        return FALSE;
240
241    pciInfo = xf86GetPciInfoForEntity(pEnt->index);
242    if (pciInfo == NULL)
243        return FALSE;
244
245    pScrn->chipset = (char*)xf86TokenToString(VMWAREChipsets,
246					      DEVICE_ID(pciInfo));
247
248    return (*pScrn->PreInit)(pScrn, flags);
249};
250
251#if XSERVER_LIBPCIACCESS
252static Bool
253VMwarePciProbe (DriverPtr           drv,
254                int                 entity_num,
255                struct pci_device   *device,
256                intptr_t            match_data)
257{
258    ScrnInfoPtr     scrn = NULL;
259    EntityInfoPtr   entity;
260
261    scrn = xf86ConfigPciEntity(scrn, 0, entity_num, VMWAREPciChipsets,
262                               NULL, NULL, NULL, NULL, NULL);
263    if (scrn != NULL) {
264        scrn->driverVersion = VMWARE_DRIVER_VERSION;
265        scrn->driverName = VMWARE_DRIVER_NAME;
266        scrn->name = VMWARE_NAME;
267        scrn->Probe = NULL;
268    }
269
270    entity = xf86GetEntityInfo(entity_num);
271    switch (DEVICE_ID(device)) {
272    case PCI_DEVICE_ID_VMWARE_SVGA2:
273    case PCI_DEVICE_ID_VMWARE_SVGA:
274        xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Valid device\n");
275
276#ifdef BUILD_VMWGFX
277	vmwgfx_hookup(scrn);
278#else
279	vmwlegacy_hookup(scrn);
280#endif /* defined(BUILD_VMWGFX) */
281
282	scrn->driverPrivate = scrn->PreInit;
283	scrn->PreInit = VMwarePreinitStub;
284        break;
285    default:
286        xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Unknown device\n");
287    }
288    return scrn != NULL;
289}
290#else
291
292/*
293 *----------------------------------------------------------------------
294 *
295 *  RewriteTagString --
296 *
297 *      Rewrites the given string, removing the $Name:  $, and
298 *      replacing it with the contents.  The output string must
299 *      have enough room, or else.
300 *
301 * Results:
302 *
303 *      Output string updated.
304 *
305 * Side effects:
306 *      None.
307 *
308 *----------------------------------------------------------------------
309 */
310
311static void
312RewriteTagString(const char *istr, char *ostr, int osize)
313{
314    int chr;
315    Bool inTag = FALSE;
316    char *op = ostr;
317
318    do {
319	chr = *istr++;
320	if (chr == '$') {
321	    if (inTag) {
322		inTag = FALSE;
323		for (; op > ostr && op[-1] == ' '; op--) {
324		}
325		continue;
326	    }
327	    if (strncmp(istr, "Name:", 5) == 0) {
328		istr += 5;
329		istr += strspn(istr, " ");
330		inTag = TRUE;
331		continue;
332	    }
333	}
334	*op++ = chr;
335    } while (chr);
336}
337
338static Bool
339VMWAREProbe(DriverPtr drv, int flags)
340{
341    int numDevSections, numUsed;
342    GDevPtr *devSections;
343    int *usedChips;
344    int i;
345    Bool foundScreen = FALSE;
346    char buildString[sizeof(VMWAREBuildStr)];
347
348    RewriteTagString(VMWAREBuildStr, buildString, sizeof(VMWAREBuildStr));
349    xf86MsgVerb(X_PROBED, 4, "%s", buildString);
350
351    numDevSections = xf86MatchDevice(VMWARE_DRIVER_NAME, &devSections);
352    if (numDevSections <= 0) {
353#ifdef DEBUG
354        xf86MsgVerb(X_ERROR, 0, "No vmware driver section\n");
355#endif
356        return FALSE;
357    }
358    if (xf86GetPciVideoInfo()) {
359        VmwareLog(("Some PCI Video Info Exists\n"));
360        numUsed = xf86MatchPciInstances(VMWARE_NAME, PCI_VENDOR_ID_VMWARE,
361                                        VMWAREChipsets, VMWAREPciChipsets, devSections,
362                                        numDevSections, drv, &usedChips);
363        free(devSections);
364        if (numUsed <= 0)
365            return FALSE;
366        if (flags & PROBE_DETECT)
367            foundScreen = TRUE;
368        else
369            for (i = 0; i < numUsed; i++) {
370                ScrnInfoPtr pScrn = NULL;
371
372                VmwareLog(("Even some VMware SVGA PCI instances exists\n"));
373                pScrn = xf86ConfigPciEntity(pScrn, flags, usedChips[i],
374                                            VMWAREPciChipsets, NULL, NULL, NULL,
375                                            NULL, NULL);
376                if (pScrn) {
377                    VmwareLog(("And even configuration suceeded\n"));
378                    pScrn->driverVersion = VMWARE_DRIVER_VERSION;
379                    pScrn->driverName = VMWARE_DRIVER_NAME;
380                    pScrn->name = VMWARE_NAME;
381                    pScrn->Probe = VMWAREProbe;
382
383#ifdef BUILD_VMWGFX
384		    vmwgfx_hookup(pScrn);
385#else
386		    vmwlegacy_hookup(pScrn);
387#endif /* defined(BUILD_VMWGFX) */
388
389		    pScrn->driverPrivate = pScrn->PreInit;
390		    pScrn->PreInit = VMwarePreinitStub;
391                    foundScreen = TRUE;
392                }
393            }
394        free(usedChips);
395    }
396    return foundScreen;
397}
398#endif
399
400static void
401VMWAREIdentify(int flags)
402{
403    xf86PrintChipsets(VMWARE_NAME, "driver for VMware SVGA", VMWAREChipsets);
404}
405
406static const OptionInfoRec *
407VMWAREAvailableOptions(int chipid, int busid)
408{
409    return VMWAREOptions;
410}
411
412#if VMWARE_DRIVER_FUNC
413static Bool
414VMWareDriverFunc(ScrnInfoPtr pScrn,
415                 xorgDriverFuncOp op,
416                 pointer data)
417{
418   CARD32 *flag;
419   xorgRRModeMM *modemm;
420
421   switch (op) {
422   case GET_REQUIRED_HW_INTERFACES:
423      flag = (CARD32 *)data;
424
425      if (flag) {
426         *flag = HW_IO | HW_MMIO;
427      }
428      return TRUE;
429   case RR_GET_MODE_MM:
430      modemm = (xorgRRModeMM *)data;
431
432      /*
433       * Because changing the resolution of the guest is usually changing the size
434       * of a window on the host desktop, the real physical DPI will not change. To
435       * keep the guest in sync, we scale the 'physical' screen dimensions to
436       * keep the DPI constant.
437       */
438      if (modemm && modemm->mode) {
439	  modemm->mmWidth = (modemm->mode->HDisplay * VMWARE_INCHTOMM +
440			     pScrn->xDpi / 2)  / pScrn->xDpi;
441	  modemm->mmHeight = (modemm->mode->VDisplay * VMWARE_INCHTOMM +
442			      pScrn->yDpi / 2) / pScrn->yDpi;
443      }
444      return TRUE;
445   default:
446      return FALSE;
447   }
448}
449#endif
450
451
452_X_EXPORT DriverRec vmware = {
453    VMWARE_DRIVER_VERSION,
454    VMWARE_DRIVER_NAME,
455    VMWAREIdentify,
456#if XSERVER_LIBPCIACCESS
457    NULL,
458#else
459    VMWAREProbe,
460#endif
461    VMWAREAvailableOptions,
462    NULL,
463    0,
464#if VMWARE_DRIVER_FUNC
465    VMWareDriverFunc,
466#endif
467#if XSERVER_LIBPCIACCESS
468    VMwareDeviceMatch,
469    VMwarePciProbe,
470#endif
471};
472
473
474#ifdef XFree86LOADER
475static MODULESETUPPROTO(vmwareSetup);
476
477_X_EXPORT XF86ModuleData vmwareModuleData = {
478    &vmwareVersRec,
479    vmwareSetup,
480    NULL
481};
482
483static pointer
484vmwareSetup(pointer module, pointer opts, int *errmaj, int *errmin)
485{
486    static Bool setupDone = FALSE;
487
488    if (!setupDone) {
489        setupDone = TRUE;
490
491        xf86AddDriver(&vmware, module, VMWARE_DRIVER_FUNC);
492
493        VMWARERefSymLists();
494
495        return (pointer)1;
496    }
497    if (errmaj) {
498        *errmaj = LDR_ONCEONLY;
499    }
500    return NULL;
501}
502#endif	/* XFree86LOADER */
503