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#include <stdint.h>
38
39#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
40#include "xf86Resources.h"
41#endif
42
43#ifndef XSERVER_LIBPCIACCESS
44#include "vm_basic_types.h"
45#include "svga_reg.h"
46#endif
47
48#ifndef HAVE_XORG_SERVER_1_5_0
49#include <xf86_ansic.h>
50#include <xf86_libc.h>
51#endif
52
53#ifdef XSERVER_PLATFORM_BUS
54#include "xf86platformBus.h"
55#endif
56
57#ifdef HaveDriverFuncs
58#define VMWARE_DRIVER_FUNC HaveDriverFuncs
59#else
60#define VMWARE_DRIVER_FUNC 0
61#endif
62
63/*
64 * So that the file compiles unmodified when dropped in to a < 6.9 source tree.
65 */
66#ifndef _X_EXPORT
67#define _X_EXPORT
68#endif
69/*
70 * So that the file compiles unmodified when dropped into an xfree source tree.
71 */
72#ifndef XORG_VERSION_CURRENT
73#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT
74#endif
75
76/*
77 * This is the only way I know to turn a #define of an integer constant into
78 * a constant string.
79 */
80#define VMW_INNERSTRINGIFY(s) #s
81#define VMW_STRING(str) VMW_INNERSTRINGIFY(str)
82
83#define VMWARE_DRIVER_NAME "vmware"
84#define VMWARE_NAME "vmware"
85
86static char vmware_driver_name[] = VMWARE_DRIVER_NAME;
87
88#define VMWARE_DRIVER_VERSION \
89   (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL)
90#define VMWARE_DRIVER_VERSION_STRING \
91    VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \
92    "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL)
93
94#if !XSERVER_LIBPCIACCESS
95static const char VMWAREBuildStr[] = "VMware Guest X Server "
96    VMWARE_DRIVER_VERSION_STRING " - build=$Name:  $\n";
97#else
98static char vmware_name[] = VMWARE_NAME;
99#endif
100
101/*
102 * Standard four digit version string expected by VMware Tools installer.
103 * As the driver's version is only  {major, minor, patchlevel},
104 * The fourth digit may describe the commit number relative to the
105 * last version tag as output from `git describe`
106 */
107
108#ifdef __GNUC__
109#ifdef VMW_SUBPATCH
110const char vmware_drv_modinfo[]
111__attribute__((section(".modinfo"),unused)) =
112  "version=" VMWARE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH);
113#else
114const char vmware_drv_modinfo[]
115__attribute__((section(".modinfo"),unused)) =
116  "version=" VMWARE_DRIVER_VERSION_STRING ".0";
117#endif /*VMW_SUBPATCH*/
118#endif
119
120#ifndef XSERVER_LIBPCIACCESS
121static resRange vmwareLegacyRes[] = {
122    { ResExcIoBlock, SVGA_LEGACY_BASE_PORT,
123      SVGA_LEGACY_BASE_PORT + SVGA_NUM_PORTS*sizeof(uint32)},
124    _VGA_EXCLUSIVE, _END
125};
126#else
127#define vmwareLegacyRes NULL
128#endif
129
130#if XSERVER_LIBPCIACCESS
131#define VENDOR_ID(p)      (p)->vendor_id
132#define DEVICE_ID(p)      (p)->device_id
133#define SUBVENDOR_ID(p)   (p)->subvendor_id
134#define SUBSYS_ID(p)      (p)->subdevice_id
135#define CHIP_REVISION(p)  (p)->revision
136#else
137#define VENDOR_ID(p)      (p)->vendor
138#define DEVICE_ID(p)      (p)->chipType
139#define SUBVENDOR_ID(p)   (p)->subsysVendor
140#define SUBSYS_ID(p)      (p)->subsysCard
141#define CHIP_REVISION(p)  (p)->chipRev
142#endif
143
144#if XSERVER_LIBPCIACCESS
145
146#define VMWARE_DEVICE_MATCH(d, i) \
147    {PCI_VENDOR_ID_VMWARE, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) }
148
149static const struct pci_id_match VMwareDeviceMatch[] = {
150    VMWARE_DEVICE_MATCH (PCI_DEVICE_ID_VMWARE_SVGA2, 0 ),
151    VMWARE_DEVICE_MATCH (PCI_DEVICE_ID_VMWARE_SVGA, 0 ),
152    { 0, 0, 0 },
153};
154#endif
155
156/*
157 * Currently, even the PCI obedient 0405 chip still only obeys IOSE and
158 * MEMSE for the SVGA resources.  Thus, RES_EXCLUSIVE_VGA is required.
159 *
160 * The 0710 chip also uses hardcoded IO ports that aren't disablable.
161 */
162
163static PciChipsets VMWAREPciChipsets[] = {
164    { PCI_DEVICE_ID_VMWARE_SVGA2, PCI_DEVICE_ID_VMWARE_SVGA2, RES_EXCLUSIVE_VGA },
165    { PCI_DEVICE_ID_VMWARE_SVGA, PCI_DEVICE_ID_VMWARE_SVGA, vmwareLegacyRes },
166    { -1,		       -1,		    RES_UNDEFINED }
167};
168
169static SymTabRec VMWAREChipsets[] = {
170    { PCI_DEVICE_ID_VMWARE_SVGA2, "vmware0405" },
171    { PCI_DEVICE_ID_VMWARE_SVGA, "vmware0710" },
172    { -1,                  NULL }
173};
174
175#ifdef XFree86LOADER
176static XF86ModuleVersionInfo vmwareVersRec = {
177    VMWARE_DRIVER_NAME,
178    MODULEVENDORSTRING,
179    MODINFOSTRING1,
180    MODINFOSTRING2,
181    XORG_VERSION_CURRENT,
182    PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
183    ABI_CLASS_VIDEODRV,
184    ABI_VIDEODRV_VERSION,
185    MOD_CLASS_VIDEODRV,
186    { 0, 0, 0, 0}
187};
188#endif	/* XFree86LOADER */
189
190static const OptionInfoRec VMWAREOptions[] = {
191    { OPTION_HW_CURSOR, "HWcursor",     OPTV_BOOLEAN,   {0},    FALSE },
192    { OPTION_XINERAMA,  "Xinerama",     OPTV_BOOLEAN,   {0},    FALSE },
193    { OPTION_STATIC_XINERAMA, "StaticXinerama", OPTV_STRING, {0}, FALSE },
194    { OPTION_GUI_LAYOUT, "GuiLayout", OPTV_STRING, {0}, FALSE },
195    { OPTION_DEFAULT_MODE, "AddDefaultMode", OPTV_BOOLEAN,   {0},    FALSE },
196    { OPTION_RENDER_ACCEL, "RenderAccel", OPTV_BOOLEAN, {0}, FALSE},
197    { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE},
198    { OPTION_DIRECT_PRESENTS, "DirectPresents", OPTV_BOOLEAN, {0}, FALSE},
199    { OPTION_HW_PRESENTS, "HWPresents", OPTV_BOOLEAN, {0}, FALSE},
200    { OPTION_RENDERCHECK, "RenderCheck", OPTV_BOOLEAN, {0}, FALSE},
201    { -1,               NULL,           OPTV_NONE,      {0},    FALSE }
202};
203
204OptionInfoPtr VMWARECopyOptions(void)
205{
206    OptionInfoPtr options;
207    if (!(options = malloc(sizeof(VMWAREOptions))))
208        return NULL;
209
210    memcpy(options, VMWAREOptions, sizeof(VMWAREOptions));
211    return options;
212}
213
214/*
215 * Also in vmwgfx_hosted.h, which we don't include.
216 */
217void *
218vmwgfx_hosted_detect(void);
219
220static Bool
221VMwarePreinitStub(ScrnInfoPtr pScrn, int flags)
222{
223#if XSERVER_LIBPCIACCESS
224    struct pci_device *pciInfo;
225#else
226    pciVideoPtr pciInfo;
227#endif /* XSERVER_LIBPCIACCESS */
228    EntityInfoPtr pEnt;
229
230    pScrn->PreInit = pScrn->driverPrivate;
231
232#ifdef BUILD_VMWGFX
233    pScrn->driverPrivate = NULL;
234
235    /*
236     * Try vmwgfx path.
237     */
238    if ((*pScrn->PreInit)(pScrn, flags))
239	return TRUE;
240
241    /*
242     * Can't run legacy hosted
243     */
244    if (vmwgfx_hosted_detect())
245	return FALSE;
246#else
247    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
248	       "Driver was compiled without KMS- and 3D support.\n");
249#endif /* defined(BUILD_VMWGFX) */
250    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
251	       "Disabling 3D support.\n");
252    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
253	       "Disabling Render Acceleration.\n");
254    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
255	       "Disabling RandR12+ support.\n");
256
257    pScrn->driverPrivate = NULL;
258    vmwlegacy_hookup(pScrn);
259
260    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
261    pciInfo = xf86GetPciInfoForEntity(pEnt->index);
262    if (pciInfo == NULL)
263        return FALSE;
264
265    pScrn->chipset = xstrdup(xf86TokenToString(VMWAREChipsets,
266					       DEVICE_ID(pciInfo)));
267    if (pScrn->chipset == NULL)
268	return FALSE;
269
270    return (*pScrn->PreInit)(pScrn, flags);
271};
272
273#if XSERVER_LIBPCIACCESS
274static Bool
275VMwarePciProbe (DriverPtr           drv,
276                int                 entity_num,
277                struct pci_device   *device,
278                intptr_t            match_data)
279{
280    ScrnInfoPtr     scrn = NULL;
281
282    scrn = xf86ConfigPciEntity(scrn, 0, entity_num, VMWAREPciChipsets,
283                               NULL, NULL, NULL, NULL, NULL);
284    if (scrn != NULL) {
285        scrn->driverVersion = VMWARE_DRIVER_VERSION;
286        scrn->driverName = vmware_driver_name;
287        scrn->name = vmware_name;
288        scrn->Probe = NULL;
289    }
290
291    switch (DEVICE_ID(device)) {
292    case PCI_DEVICE_ID_VMWARE_SVGA2:
293    case PCI_DEVICE_ID_VMWARE_SVGA:
294        xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Valid device\n");
295
296#ifdef BUILD_VMWGFX
297	vmwgfx_hookup(scrn);
298#else
299	vmwlegacy_hookup(scrn);
300#endif /* defined(BUILD_VMWGFX) */
301
302	scrn->driverPrivate = scrn->PreInit;
303	scrn->PreInit = VMwarePreinitStub;
304        break;
305    default:
306        xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Unknown device\n");
307    }
308    return scrn != NULL;
309}
310#else
311
312/*
313 *----------------------------------------------------------------------
314 *
315 *  RewriteTagString --
316 *
317 *      Rewrites the given string, removing the $Name:  $, and
318 *      replacing it with the contents.  The output string must
319 *      have enough room, or else.
320 *
321 * Results:
322 *
323 *      Output string updated.
324 *
325 * Side effects:
326 *      None.
327 *
328 *----------------------------------------------------------------------
329 */
330
331static void
332RewriteTagString(const char *istr, char *ostr, int osize)
333{
334    int chr;
335    Bool inTag = FALSE;
336    char *op = ostr;
337
338    do {
339	chr = *istr++;
340	if (chr == '$') {
341	    if (inTag) {
342		inTag = FALSE;
343		for (; op > ostr && op[-1] == ' '; op--) {
344		}
345		continue;
346	    }
347	    if (strncmp(istr, "Name:", 5) == 0) {
348		istr += 5;
349		istr += strspn(istr, " ");
350		inTag = TRUE;
351		continue;
352	    }
353	}
354	*op++ = chr;
355    } while (chr);
356}
357
358static Bool
359VMWAREProbe(DriverPtr drv, int flags)
360{
361    int numDevSections, numUsed;
362    GDevPtr *devSections;
363    int *usedChips;
364    int i;
365    Bool foundScreen = FALSE;
366    char buildString[sizeof(VMWAREBuildStr)];
367
368    RewriteTagString(VMWAREBuildStr, buildString, sizeof(VMWAREBuildStr));
369    xf86MsgVerb(X_PROBED, 4, "%s", buildString);
370
371    numDevSections = xf86MatchDevice(VMWARE_DRIVER_NAME, &devSections);
372    if (numDevSections <= 0) {
373#ifdef DEBUG
374        xf86MsgVerb(X_ERROR, 0, "No vmware driver section\n");
375#endif
376        return FALSE;
377    }
378    if (xf86GetPciVideoInfo()) {
379        VmwareLog(("Some PCI Video Info Exists\n"));
380        numUsed = xf86MatchPciInstances(VMWARE_NAME, PCI_VENDOR_ID_VMWARE,
381                                        VMWAREChipsets, VMWAREPciChipsets, devSections,
382                                        numDevSections, drv, &usedChips);
383        free(devSections);
384        if (numUsed <= 0)
385            return FALSE;
386        if (flags & PROBE_DETECT)
387            foundScreen = TRUE;
388        else
389            for (i = 0; i < numUsed; i++) {
390                ScrnInfoPtr pScrn = NULL;
391
392                VmwareLog(("Even some VMware SVGA PCI instances exists\n"));
393                pScrn = xf86ConfigPciEntity(pScrn, flags, usedChips[i],
394                                            VMWAREPciChipsets, NULL, NULL, NULL,
395                                            NULL, NULL);
396                if (pScrn) {
397                    VmwareLog(("And even configuration succeeded\n"));
398                    pScrn->driverVersion = VMWARE_DRIVER_VERSION;
399                    pScrn->driverName = VMWARE_DRIVER_NAME;
400                    pScrn->name = VMWARE_NAME;
401                    pScrn->Probe = VMWAREProbe;
402
403#ifdef BUILD_VMWGFX
404		    vmwgfx_hookup(pScrn);
405#else
406		    vmwlegacy_hookup(pScrn);
407#endif /* defined(BUILD_VMWGFX) */
408
409		    pScrn->driverPrivate = pScrn->PreInit;
410		    pScrn->PreInit = VMwarePreinitStub;
411                    foundScreen = TRUE;
412                }
413            }
414        free(usedChips);
415    }
416    return foundScreen;
417}
418#endif
419
420#ifdef XSERVER_PLATFORM_BUS
421static Bool
422VMwarePlatformProbe(DriverPtr drv, int entity, int flags,
423                    struct xf86_platform_device *dev, intptr_t match_data)
424{
425    ScrnInfoPtr pScrn;
426    int scrnFlag = 0;
427
428    if (!dev->pdev)
429        return FALSE;
430
431    if (flags & PLATFORM_PROBE_GPU_SCREEN)
432        scrnFlag = XF86_ALLOCATE_GPU_SCREEN;
433
434    pScrn = xf86AllocateScreen(drv, scrnFlag);
435    if (!pScrn)
436        return FALSE;
437
438    if (xf86IsEntitySharable(entity))
439        xf86SetEntityShared(entity);
440
441    xf86AddEntityToScreen(pScrn, entity);
442
443    pScrn->driverVersion = VMWARE_DRIVER_VERSION;
444    pScrn->driverName = VMWARE_DRIVER_NAME;
445    pScrn->name = VMWARE_NAME;
446    pScrn->Probe = NULL;
447#ifdef BUILD_VMWGFX
448    vmwgfx_hookup(pScrn);
449#else
450    vmwlegacy_hookup(pScrn);
451#endif
452    pScrn->driverPrivate = pScrn->PreInit;
453    pScrn->PreInit = VMwarePreinitStub;
454
455    return TRUE;
456}
457#endif
458
459static void
460VMWAREIdentify(int flags)
461{
462    xf86PrintChipsets(VMWARE_NAME, "driver for VMware SVGA", VMWAREChipsets);
463}
464
465static const OptionInfoRec *
466VMWAREAvailableOptions(int chipid, int busid)
467{
468    return VMWAREOptions;
469}
470
471#if VMWARE_DRIVER_FUNC
472static Bool
473VMWareDriverFunc(ScrnInfoPtr pScrn,
474                 xorgDriverFuncOp op,
475                 pointer data)
476{
477   uint32_t *flag;
478   xorgRRModeMM *modemm;
479
480   switch (op) {
481   case GET_REQUIRED_HW_INTERFACES:
482      flag = (uint32_t *)data;
483
484      if (flag) {
485#ifdef BUILD_VMWGFX
486	  vmwgfx_modify_flags(flag);
487#else
488         *flag = HW_IO | HW_MMIO;
489#endif
490      }
491      return TRUE;
492   case RR_GET_MODE_MM:
493      modemm = (xorgRRModeMM *)data;
494
495      /*
496       * Because changing the resolution of the guest is usually changing the size
497       * of a window on the host desktop, the real physical DPI will not change. To
498       * keep the guest in sync, we scale the 'physical' screen dimensions to
499       * keep the DPI constant.
500       */
501      if (modemm && modemm->mode) {
502	  modemm->mmWidth = (modemm->mode->HDisplay * VMWARE_INCHTOMM +
503			     pScrn->xDpi / 2)  / pScrn->xDpi;
504	  modemm->mmHeight = (modemm->mode->VDisplay * VMWARE_INCHTOMM +
505			      pScrn->yDpi / 2) / pScrn->yDpi;
506      }
507      return TRUE;
508#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 18
509   case SUPPORTS_SERVER_FDS:
510      return TRUE;
511#endif
512   default:
513      return FALSE;
514   }
515}
516#endif
517
518
519_X_EXPORT DriverRec vmware = {
520    VMWARE_DRIVER_VERSION,
521    vmware_driver_name,
522    VMWAREIdentify,
523#if XSERVER_LIBPCIACCESS
524    NULL,
525#else
526    VMWAREProbe,
527#endif
528    VMWAREAvailableOptions,
529    NULL,
530    0,
531#if VMWARE_DRIVER_FUNC
532    VMWareDriverFunc,
533#endif
534#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 4
535#if XSERVER_LIBPCIACCESS
536    VMwareDeviceMatch,
537    VMwarePciProbe,
538#else
539    NULL,
540    NULL,
541#endif
542#endif
543#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 13
544#ifdef XSERVER_PLATFORM_BUS
545    VMwarePlatformProbe,
546#else
547    NULL,
548#endif
549#endif
550};
551
552
553#ifdef XFree86LOADER
554static MODULESETUPPROTO(vmwareSetup);
555
556_X_EXPORT XF86ModuleData vmwareModuleData = {
557    &vmwareVersRec,
558    vmwareSetup,
559    NULL
560};
561
562static pointer
563vmwareSetup(pointer module, pointer opts, int *errmaj, int *errmin)
564{
565    static Bool setupDone = FALSE;
566
567    if (!setupDone) {
568        setupDone = TRUE;
569
570        xf86AddDriver(&vmware, module, VMWARE_DRIVER_FUNC);
571
572        VMWARERefSymLists();
573
574        return (pointer)1;
575    }
576    if (errmaj) {
577        *errmaj = LDR_ONCEONLY;
578    }
579    return NULL;
580}
581#endif	/* XFree86LOADER */
582