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