/* * Copyright 2011 VMWare, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Author: Unknown at vmware * Author: Thomas Hellstrom */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xf86.h" #include "compiler.h" #include "xf86Pci.h" /* pci */ #include "vm_device_version.h" #include "vmware_bootstrap.h" #include #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 #include "xf86Resources.h" #endif #ifndef XSERVER_LIBPCIACCESS #include "vm_basic_types.h" #include "svga_reg.h" #endif #ifndef HAVE_XORG_SERVER_1_5_0 #include #include #endif #ifdef XSERVER_PLATFORM_BUS #include "xf86platformBus.h" #endif #ifdef HaveDriverFuncs #define VMWARE_DRIVER_FUNC HaveDriverFuncs #else #define VMWARE_DRIVER_FUNC 0 #endif /* * So that the file compiles unmodified when dropped in to a < 6.9 source tree. */ #ifndef _X_EXPORT #define _X_EXPORT #endif /* * So that the file compiles unmodified when dropped into an xfree source tree. */ #ifndef XORG_VERSION_CURRENT #define XORG_VERSION_CURRENT XF86_VERSION_CURRENT #endif /* * This is the only way I know to turn a #define of an integer constant into * a constant string. */ #define VMW_INNERSTRINGIFY(s) #s #define VMW_STRING(str) VMW_INNERSTRINGIFY(str) #define VMWARE_DRIVER_NAME "vmware" #define VMWARE_NAME "vmware" static char vmware_driver_name[] = VMWARE_DRIVER_NAME; #define VMWARE_DRIVER_VERSION \ (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL) #define VMWARE_DRIVER_VERSION_STRING \ VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \ "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL) #if !XSERVER_LIBPCIACCESS static const char VMWAREBuildStr[] = "VMware Guest X Server " VMWARE_DRIVER_VERSION_STRING " - build=$Name$\n"; #else static char vmware_name[] = VMWARE_NAME; #endif /* * Standard four digit version string expected by VMware Tools installer. * As the driver's version is only {major, minor, patchlevel}, * The fourth digit may describe the commit number relative to the * last version tag as output from `git describe` */ #ifdef __GNUC__ #ifdef VMW_SUBPATCH const char vmware_drv_modinfo[] __attribute__((section(".modinfo"),unused)) = "version=" VMWARE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH); #else const char vmware_drv_modinfo[] __attribute__((section(".modinfo"),unused)) = "version=" VMWARE_DRIVER_VERSION_STRING ".0"; #endif /*VMW_SUBPATCH*/ #endif #ifndef XSERVER_LIBPCIACCESS static resRange vmwareLegacyRes[] = { { ResExcIoBlock, SVGA_LEGACY_BASE_PORT, SVGA_LEGACY_BASE_PORT + SVGA_NUM_PORTS*sizeof(uint32)}, _VGA_EXCLUSIVE, _END }; #else #define vmwareLegacyRes NULL #endif #if XSERVER_LIBPCIACCESS #define VENDOR_ID(p) (p)->vendor_id #define DEVICE_ID(p) (p)->device_id #define SUBVENDOR_ID(p) (p)->subvendor_id #define SUBSYS_ID(p) (p)->subdevice_id #define CHIP_REVISION(p) (p)->revision #else #define VENDOR_ID(p) (p)->vendor #define DEVICE_ID(p) (p)->chipType #define SUBVENDOR_ID(p) (p)->subsysVendor #define SUBSYS_ID(p) (p)->subsysCard #define CHIP_REVISION(p) (p)->chipRev #endif #if XSERVER_LIBPCIACCESS #define VMWARE_DEVICE_MATCH(d, i) \ {PCI_VENDOR_ID_VMWARE, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) } static const struct pci_id_match VMwareDeviceMatch[] = { VMWARE_DEVICE_MATCH (PCI_DEVICE_ID_VMWARE_SVGA2, 0 ), VMWARE_DEVICE_MATCH (PCI_DEVICE_ID_VMWARE_SVGA, 0 ), { 0, 0, 0 }, }; #endif /* * Currently, even the PCI obedient 0405 chip still only obeys IOSE and * MEMSE for the SVGA resources. Thus, RES_EXCLUSIVE_VGA is required. * * The 0710 chip also uses hardcoded IO ports that aren't disablable. */ static PciChipsets VMWAREPciChipsets[] = { { PCI_DEVICE_ID_VMWARE_SVGA2, PCI_DEVICE_ID_VMWARE_SVGA2, RES_EXCLUSIVE_VGA }, { PCI_DEVICE_ID_VMWARE_SVGA, PCI_DEVICE_ID_VMWARE_SVGA, vmwareLegacyRes }, { -1, -1, RES_UNDEFINED } }; static SymTabRec VMWAREChipsets[] = { { PCI_DEVICE_ID_VMWARE_SVGA2, "vmware0405" }, { PCI_DEVICE_ID_VMWARE_SVGA, "vmware0710" }, { -1, NULL } }; #ifdef XFree86LOADER static XF86ModuleVersionInfo vmwareVersRec = { VMWARE_DRIVER_NAME, MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, { 0, 0, 0, 0} }; #endif /* XFree86LOADER */ static const OptionInfoRec VMWAREOptions[] = { { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_XINERAMA, "Xinerama", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_STATIC_XINERAMA, "StaticXinerama", OPTV_STRING, {0}, FALSE }, { OPTION_GUI_LAYOUT, "GuiLayout", OPTV_STRING, {0}, FALSE }, { OPTION_DEFAULT_MODE, "AddDefaultMode", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_RENDER_ACCEL, "RenderAccel", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_DIRECT_PRESENTS, "DirectPresents", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_HW_PRESENTS, "HWPresents", OPTV_BOOLEAN, {0}, FALSE}, { OPTION_RENDERCHECK, "RenderCheck", OPTV_BOOLEAN, {0}, FALSE}, { -1, NULL, OPTV_NONE, {0}, FALSE } }; OptionInfoPtr VMWARECopyOptions(void) { OptionInfoPtr options; if (!(options = malloc(sizeof(VMWAREOptions)))) return NULL; memcpy(options, VMWAREOptions, sizeof(VMWAREOptions)); return options; } /* * Also in vmwgfx_hosted.h, which we don't include. */ void * vmwgfx_hosted_detect(void); static Bool VMwarePreinitStub(ScrnInfoPtr pScrn, int flags) { #if XSERVER_LIBPCIACCESS struct pci_device *pciInfo; #else pciVideoPtr pciInfo; #endif /* XSERVER_LIBPCIACCESS */ EntityInfoPtr pEnt; pScrn->PreInit = pScrn->driverPrivate; #ifdef BUILD_VMWGFX pScrn->driverPrivate = NULL; /* * Try vmwgfx path. */ if ((*pScrn->PreInit)(pScrn, flags)) return TRUE; /* * Can't run legacy hosted */ if (vmwgfx_hosted_detect()) return FALSE; #else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Driver was compiled without KMS- and 3D support.\n"); #endif /* defined(BUILD_VMWGFX) */ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling 3D support.\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling Render Acceleration.\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Disabling RandR12+ support.\n"); pScrn->driverPrivate = NULL; vmwlegacy_hookup(pScrn); pEnt = xf86GetEntityInfo(pScrn->entityList[0]); pciInfo = xf86GetPciInfoForEntity(pEnt->index); if (pciInfo == NULL) return FALSE; pScrn->chipset = xstrdup(xf86TokenToString(VMWAREChipsets, DEVICE_ID(pciInfo))); if (pScrn->chipset == NULL) return FALSE; return (*pScrn->PreInit)(pScrn, flags); }; #if XSERVER_LIBPCIACCESS static Bool VMwarePciProbe (DriverPtr drv, int entity_num, struct pci_device *device, intptr_t match_data) { ScrnInfoPtr scrn = NULL; scrn = xf86ConfigPciEntity(scrn, 0, entity_num, VMWAREPciChipsets, NULL, NULL, NULL, NULL, NULL); if (scrn != NULL) { scrn->driverVersion = VMWARE_DRIVER_VERSION; scrn->driverName = vmware_driver_name; scrn->name = vmware_name; scrn->Probe = NULL; } switch (DEVICE_ID(device)) { case PCI_DEVICE_ID_VMWARE_SVGA2: case PCI_DEVICE_ID_VMWARE_SVGA: xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Valid device\n"); #ifdef BUILD_VMWGFX vmwgfx_hookup(scrn); #else vmwlegacy_hookup(scrn); #endif /* defined(BUILD_VMWGFX) */ scrn->driverPrivate = scrn->PreInit; scrn->PreInit = VMwarePreinitStub; break; default: xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Unknown device\n"); } return scrn != NULL; } #else /* *---------------------------------------------------------------------- * * RewriteTagString -- * * Rewrites the given string, removing the $Name$, and * replacing it with the contents. The output string must * have enough room, or else. * * Results: * * Output string updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void RewriteTagString(const char *istr, char *ostr, int osize) { int chr; Bool inTag = FALSE; char *op = ostr; do { chr = *istr++; if (chr == '$') { if (inTag) { inTag = FALSE; for (; op > ostr && op[-1] == ' '; op--) { } continue; } if (strncmp(istr, "Name:", 5) == 0) { istr += 5; istr += strspn(istr, " "); inTag = TRUE; continue; } } *op++ = chr; } while (chr); } static Bool VMWAREProbe(DriverPtr drv, int flags) { int numDevSections, numUsed; GDevPtr *devSections; int *usedChips; int i; Bool foundScreen = FALSE; char buildString[sizeof(VMWAREBuildStr)]; RewriteTagString(VMWAREBuildStr, buildString, sizeof(VMWAREBuildStr)); xf86MsgVerb(X_PROBED, 4, "%s", buildString); numDevSections = xf86MatchDevice(VMWARE_DRIVER_NAME, &devSections); if (numDevSections <= 0) { #ifdef DEBUG xf86MsgVerb(X_ERROR, 0, "No vmware driver section\n"); #endif return FALSE; } if (xf86GetPciVideoInfo()) { VmwareLog(("Some PCI Video Info Exists\n")); numUsed = xf86MatchPciInstances(VMWARE_NAME, PCI_VENDOR_ID_VMWARE, VMWAREChipsets, VMWAREPciChipsets, devSections, numDevSections, drv, &usedChips); free(devSections); if (numUsed <= 0) return FALSE; if (flags & PROBE_DETECT) foundScreen = TRUE; else for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn = NULL; VmwareLog(("Even some VMware SVGA PCI instances exists\n")); pScrn = xf86ConfigPciEntity(pScrn, flags, usedChips[i], VMWAREPciChipsets, NULL, NULL, NULL, NULL, NULL); if (pScrn) { VmwareLog(("And even configuration suceeded\n")); pScrn->driverVersion = VMWARE_DRIVER_VERSION; pScrn->driverName = VMWARE_DRIVER_NAME; pScrn->name = VMWARE_NAME; pScrn->Probe = VMWAREProbe; #ifdef BUILD_VMWGFX vmwgfx_hookup(pScrn); #else vmwlegacy_hookup(pScrn); #endif /* defined(BUILD_VMWGFX) */ pScrn->driverPrivate = pScrn->PreInit; pScrn->PreInit = VMwarePreinitStub; foundScreen = TRUE; } } free(usedChips); } return foundScreen; } #endif #ifdef XSERVER_PLATFORM_BUS static Bool VMwarePlatformProbe(DriverPtr drv, int entity, int flags, struct xf86_platform_device *dev, intptr_t match_data) { ScrnInfoPtr pScrn; int scrnFlag = 0; if (!dev->pdev) return FALSE; if (flags & PLATFORM_PROBE_GPU_SCREEN) scrnFlag = XF86_ALLOCATE_GPU_SCREEN; pScrn = xf86AllocateScreen(drv, scrnFlag); if (!pScrn) return FALSE; if (xf86IsEntitySharable(entity)) xf86SetEntityShared(entity); xf86AddEntityToScreen(pScrn, entity); pScrn->driverVersion = VMWARE_DRIVER_VERSION; pScrn->driverName = VMWARE_DRIVER_NAME; pScrn->name = VMWARE_NAME; pScrn->Probe = NULL; #ifdef BUILD_VMWGFX vmwgfx_hookup(pScrn); #else vmwlegacy_hookup(pScrn); #endif pScrn->driverPrivate = pScrn->PreInit; pScrn->PreInit = VMwarePreinitStub; return TRUE; } #endif static void VMWAREIdentify(int flags) { xf86PrintChipsets(VMWARE_NAME, "driver for VMware SVGA", VMWAREChipsets); } static const OptionInfoRec * VMWAREAvailableOptions(int chipid, int busid) { return VMWAREOptions; } #if VMWARE_DRIVER_FUNC static Bool VMWareDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer data) { uint32_t *flag; xorgRRModeMM *modemm; switch (op) { case GET_REQUIRED_HW_INTERFACES: flag = (uint32_t *)data; if (flag) { #ifdef BUILD_VMWGFX vmwgfx_modify_flags(flag); #else *flag = HW_IO | HW_MMIO; #endif } return TRUE; case RR_GET_MODE_MM: modemm = (xorgRRModeMM *)data; /* * Because changing the resolution of the guest is usually changing the size * of a window on the host desktop, the real physical DPI will not change. To * keep the guest in sync, we scale the 'physical' screen dimensions to * keep the DPI constant. */ if (modemm && modemm->mode) { modemm->mmWidth = (modemm->mode->HDisplay * VMWARE_INCHTOMM + pScrn->xDpi / 2) / pScrn->xDpi; modemm->mmHeight = (modemm->mode->VDisplay * VMWARE_INCHTOMM + pScrn->yDpi / 2) / pScrn->yDpi; } return TRUE; #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 18 case SUPPORTS_SERVER_FDS: return TRUE; #endif default: return FALSE; } } #endif _X_EXPORT DriverRec vmware = { VMWARE_DRIVER_VERSION, vmware_driver_name, VMWAREIdentify, #if XSERVER_LIBPCIACCESS NULL, #else VMWAREProbe, #endif VMWAREAvailableOptions, NULL, 0, #if VMWARE_DRIVER_FUNC VMWareDriverFunc, #endif #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 4 #if XSERVER_LIBPCIACCESS VMwareDeviceMatch, VMwarePciProbe, #else NULL, NULL, #endif #endif #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 13 #ifdef XSERVER_PLATFORM_BUS VMwarePlatformProbe, #else NULL, #endif #endif }; #ifdef XFree86LOADER static MODULESETUPPROTO(vmwareSetup); _X_EXPORT XF86ModuleData vmwareModuleData = { &vmwareVersRec, vmwareSetup, NULL }; static pointer vmwareSetup(pointer module, pointer opts, int *errmaj, int *errmin) { static Bool setupDone = FALSE; if (!setupDone) { setupDone = TRUE; xf86AddDriver(&vmware, module, VMWARE_DRIVER_FUNC); VMWARERefSymLists(); return (pointer)1; } if (errmaj) { *errmaj = LDR_ONCEONLY; } return NULL; } #endif /* XFree86LOADER */