vmwarectrl.c revision 6df26cac
1/* 2 * Copyright 2006 by VMware, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the copyright holder(s) 23 * and author(s) shall not be used in advertising or otherwise to promote 24 * the sale, use or other dealings in this Software without prior written 25 * authorization from the copyright holder(s) and author(s). 26 */ 27 28/* 29 * vmwarectrl.c -- 30 * 31 * The implementation of the VMWARE_CTRL protocol extension that 32 * allows X clients to communicate with the driver. 33 */ 34 35 36#ifdef HAVE_CONFIG_H 37#include "config.h" 38#endif 39 40#define NEED_REPLIES 41#define NEED_EVENTS 42#include "dixstruct.h" 43#include "extnsionst.h" 44#include <X11/X.h> 45#include <X11/extensions/panoramiXproto.h> 46 47#include "vmware.h" 48#include "vmwarectrlproto.h" 49 50 51/* 52 *---------------------------------------------------------------------------- 53 * 54 * VMwareCtrlQueryVersion -- 55 * 56 * Implementation of QueryVersion command handler. Initialises and 57 * sends a reply. 58 * 59 * Results: 60 * Standard response codes. 61 * 62 * Side effects: 63 * Writes reply to client 64 * 65 *---------------------------------------------------------------------------- 66 */ 67 68static int 69VMwareCtrlQueryVersion(ClientPtr client) 70{ 71 xVMwareCtrlQueryVersionReply rep = { 0, }; 72 register int n; 73 74 REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq); 75 76 rep.type = X_Reply; 77 rep.length = 0; 78 rep.sequenceNumber = client->sequence; 79 rep.majorVersion = VMWARE_CTRL_MAJOR_VERSION; 80 rep.minorVersion = VMWARE_CTRL_MINOR_VERSION; 81 if (client->swapped) { 82 swaps(&rep.sequenceNumber, n); 83 swapl(&rep.length, n); 84 swapl(&rep.majorVersion, n); 85 swapl(&rep.minorVersion, n); 86 } 87 WriteToClient(client, sizeof(xVMwareCtrlQueryVersionReply), (char *)&rep); 88 89 return client->noClientException; 90} 91 92 93/* 94 *---------------------------------------------------------------------------- 95 * 96 * VMwareCtrlDoSetRes -- 97 * 98 * Set the custom resolution into the mode list. 99 * 100 * This is done by alternately updating one of two dynamic modes. It is 101 * done this way because the server gets upset if you try to switch 102 * to a new resolution that has the same index as the current one. 103 * 104 * Results: 105 * TRUE on success, FALSE otherwise. 106 * 107 * Side effects: 108 * One dynamic mode will be updated if successful. 109 * 110 *---------------------------------------------------------------------------- 111 */ 112 113static Bool 114VMwareCtrlDoSetRes(ScrnInfoPtr pScrn, 115 CARD32 x, 116 CARD32 y, 117 Bool resetXinerama) 118{ 119 DisplayModePtr mode; 120 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 121 122 if (pScrn && pScrn->modes) { 123 VmwareLog(("DoSetRes: %d %d\n", x, y)); 124 125 if (resetXinerama) { 126 xfree(pVMWARE->xineramaNextState); 127 pVMWARE->xineramaNextState = NULL; 128 pVMWARE->xineramaNextNumOutputs = 0; 129 } 130 131 /* 132 * Don't resize larger than possible but don't 133 * return an X Error either. 134 */ 135 if (x > pVMWARE->maxWidth || 136 y > pVMWARE->maxHeight) { 137 return TRUE; 138 } 139 140 /* 141 * Switch the dynamic modes so that we alternate 142 * which one gets updated on each call. 143 */ 144 mode = pVMWARE->dynMode1; 145 pVMWARE->dynMode1 = pVMWARE->dynMode2; 146 pVMWARE->dynMode2 = mode; 147 148 /* 149 * Initialise the dynamic mode if it hasn't been used before. 150 */ 151 if (!pVMWARE->dynMode1) { 152 pVMWARE->dynMode1 = VMWAREAddDisplayMode(pScrn, "DynMode", 1, 1); 153 } 154 mode = pVMWARE->dynMode1; 155 156 mode->HDisplay = x; 157 mode->VDisplay = y; 158 159 return TRUE; 160 } else { 161 return FALSE; 162 } 163} 164 165 166/* 167 *---------------------------------------------------------------------------- 168 * 169 * VMwareCtrlSetRes -- 170 * 171 * Implementation of SetRes command handler. Initialises and sends a 172 * reply. 173 * 174 * Results: 175 * Standard response codes. 176 * 177 * Side effects: 178 * Writes reply to client 179 * 180 *---------------------------------------------------------------------------- 181 */ 182 183static int 184VMwareCtrlSetRes(ClientPtr client) 185{ 186 REQUEST(xVMwareCtrlSetResReq); 187 xVMwareCtrlSetResReply rep = { 0, }; 188 ScrnInfoPtr pScrn; 189 ExtensionEntry *ext; 190 register int n; 191 192 REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq); 193 194 if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { 195 return BadMatch; 196 } 197 198 pScrn = ext->extPrivate; 199 if (pScrn->scrnIndex != stuff->screen) { 200 return BadMatch; 201 } 202 203 if (!VMwareCtrlDoSetRes(pScrn, stuff->x, stuff->y, TRUE)) { 204 return BadValue; 205 } 206 207 rep.type = X_Reply; 208 rep.length = (sizeof(xVMwareCtrlSetResReply) - sizeof(xGenericReply)) >> 2; 209 rep.sequenceNumber = client->sequence; 210 rep.screen = stuff->screen; 211 rep.x = stuff->x; 212 rep.y = stuff->y; 213 if (client->swapped) { 214 swaps(&rep.sequenceNumber, n); 215 swapl(&rep.length, n); 216 swapl(&rep.screen, n); 217 swapl(&rep.x, n); 218 swapl(&rep.y, n); 219 } 220 WriteToClient(client, sizeof(xVMwareCtrlSetResReply), (char *)&rep); 221 222 return client->noClientException; 223} 224 225 226/* 227 *---------------------------------------------------------------------------- 228 * 229 * VMwareCtrlDoSetTopology -- 230 * 231 * Set the custom topology and set a dynamic mode to the bounding box 232 * of the passed topology. If a topology is already pending, then do 233 * nothing but do not return failure. 234 * 235 * Results: 236 * TRUE on success, FALSE otherwise. 237 * 238 * Side effects: 239 * One dynamic mode and the pending xinerama state will be updated if 240 * successful. 241 * 242 *---------------------------------------------------------------------------- 243 */ 244 245static Bool 246VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn, 247 xXineramaScreenInfo *extents, 248 unsigned long number) 249{ 250 VMWAREPtr pVMWARE = VMWAREPTR(pScrn); 251 252 if (pVMWARE && pVMWARE->xinerama) { 253 VMWAREXineramaPtr xineramaState; 254 short maxX = 0; 255 short maxY = 0; 256 size_t i; 257 258 if (pVMWARE->xineramaNextState) { 259 VmwareLog(("DoSetTopology: Aborting due to existing pending state\n")); 260 return TRUE; 261 } 262 263 for (i = 0; i < number; i++) { 264 maxX = MAX(maxX, extents[i].x_org + extents[i].width); 265 maxY = MAX(maxY, extents[i].y_org + extents[i].height); 266 } 267 268 VmwareLog(("DoSetTopology: %d %d\n", maxX, maxY)); 269 270 xineramaState = (VMWAREXineramaPtr)xcalloc(number, sizeof(VMWAREXineramaRec)); 271 if (xineramaState) { 272 memcpy(xineramaState, extents, number * sizeof (VMWAREXineramaRec)); 273 274 xfree(pVMWARE->xineramaNextState); 275 pVMWARE->xineramaNextState = xineramaState; 276 pVMWARE->xineramaNextNumOutputs = number; 277 278 return VMwareCtrlDoSetRes(pScrn, maxX, maxY, FALSE); 279 } else { 280 return FALSE; 281 } 282 } else { 283 return FALSE; 284 } 285} 286 287 288/* 289 *---------------------------------------------------------------------------- 290 * 291 * VMwareCtrlSetTopology -- 292 * 293 * Implementation of SetTopology command handler. Initialises and sends a 294 * reply. 295 * 296 * Results: 297 * Standard response codes. 298 * 299 * Side effects: 300 * Writes reply to client 301 * 302 *---------------------------------------------------------------------------- 303 */ 304 305static int 306VMwareCtrlSetTopology(ClientPtr client) 307{ 308 REQUEST(xVMwareCtrlSetTopologyReq); 309 xVMwareCtrlSetTopologyReply rep = { 0, }; 310 ScrnInfoPtr pScrn; 311 ExtensionEntry *ext; 312 register int n; 313 xXineramaScreenInfo *extents; 314 315 REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq); 316 317 if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { 318 return BadMatch; 319 } 320 321 pScrn = ext->extPrivate; 322 if (pScrn->scrnIndex != stuff->screen) { 323 return BadMatch; 324 } 325 326 extents = (xXineramaScreenInfo *)(stuff + 1); 327 if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) { 328 return BadValue; 329 } 330 331 rep.type = X_Reply; 332 rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2; 333 rep.sequenceNumber = client->sequence; 334 rep.screen = stuff->screen; 335 if (client->swapped) { 336 swaps(&rep.sequenceNumber, n); 337 swapl(&rep.length, n); 338 swapl(&rep.screen, n); 339 } 340 WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep); 341 342 return client->noClientException; 343} 344 345 346/* 347 *---------------------------------------------------------------------------- 348 * 349 * VMwareCtrlDispatch -- 350 * 351 * Dispatcher for VMWARE_CTRL commands. Calls the correct handler for 352 * each command type. 353 * 354 * Results: 355 * Standard response codes. 356 * 357 * Side effects: 358 * Side effects of individual command handlers. 359 * 360 *---------------------------------------------------------------------------- 361 */ 362 363static int 364VMwareCtrlDispatch(ClientPtr client) 365{ 366 REQUEST(xReq); 367 368 switch(stuff->data) { 369 case X_VMwareCtrlQueryVersion: 370 return VMwareCtrlQueryVersion(client); 371 case X_VMwareCtrlSetRes: 372 return VMwareCtrlSetRes(client); 373 case X_VMwareCtrlSetTopology: 374 return VMwareCtrlSetTopology(client); 375 } 376 return BadRequest; 377} 378 379 380/* 381 *---------------------------------------------------------------------------- 382 * 383 * SVMwareCtrlQueryVersion -- 384 * 385 * Wrapper for QueryVersion handler that handles input from other-endian 386 * clients. 387 * 388 * Results: 389 * Standard response codes. 390 * 391 * Side effects: 392 * Side effects of unswapped implementation. 393 * 394 *---------------------------------------------------------------------------- 395 */ 396 397static int 398SVMwareCtrlQueryVersion(ClientPtr client) 399{ 400 register int n; 401 402 REQUEST(xVMwareCtrlQueryVersionReq); 403 REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq); 404 405 swaps(&stuff->length, n); 406 407 return VMwareCtrlQueryVersion(client); 408} 409 410 411/* 412 *---------------------------------------------------------------------------- 413 * 414 * SVMwareCtrlSetRes -- 415 * 416 * Wrapper for SetRes handler that handles input from other-endian 417 * clients. 418 * 419 * Results: 420 * Standard response codes. 421 * 422 * Side effects: 423 * Side effects of unswapped implementation. 424 * 425 *---------------------------------------------------------------------------- 426 */ 427 428static int 429SVMwareCtrlSetRes(ClientPtr client) 430{ 431 register int n; 432 433 REQUEST(xVMwareCtrlSetResReq); 434 REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq); 435 436 swaps(&stuff->length, n); 437 swapl(&stuff->screen, n); 438 swapl(&stuff->x, n); 439 swapl(&stuff->y, n); 440 441 return VMwareCtrlSetRes(client); 442} 443 444 445/* 446 *---------------------------------------------------------------------------- 447 * 448 * SVMwareCtrlSetTopology -- 449 * 450 * Wrapper for SetTopology handler that handles input from other-endian 451 * clients. 452 * 453 * Results: 454 * Standard response codes. 455 * 456 * Side effects: 457 * Side effects of unswapped implementation. 458 * 459 *---------------------------------------------------------------------------- 460 */ 461 462static int 463SVMwareCtrlSetTopology(ClientPtr client) 464{ 465 register int n; 466 467 REQUEST(xVMwareCtrlSetTopologyReq); 468 REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq); 469 470 swaps(&stuff->length, n); 471 swapl(&stuff->screen, n); 472 swapl(&stuff->number, n); 473 /* Each extent is a struct of shorts. */ 474 SwapRestS(stuff); 475 476 return VMwareCtrlSetTopology(client); 477} 478 479 480/* 481 *---------------------------------------------------------------------------- 482 * 483 * SVMwareCtrlDispatch -- 484 * 485 * Wrapper for dispatcher that handles input from other-endian clients. 486 * 487 * Results: 488 * Standard response codes. 489 * 490 * Side effects: 491 * Side effects of individual command handlers. 492 * 493 *---------------------------------------------------------------------------- 494 */ 495 496static int 497SVMwareCtrlDispatch(ClientPtr client) 498{ 499 REQUEST(xReq); 500 501 switch(stuff->data) { 502 case X_VMwareCtrlQueryVersion: 503 return SVMwareCtrlQueryVersion(client); 504 case X_VMwareCtrlSetRes: 505 return SVMwareCtrlSetRes(client); 506 case X_VMwareCtrlSetTopology: 507 return SVMwareCtrlSetTopology(client); 508 } 509 return BadRequest; 510} 511 512 513/* 514 *---------------------------------------------------------------------------- 515 * 516 * VMwareCtrlResetProc -- 517 * 518 * Cleanup handler called when the extension is removed. 519 * 520 * Results: 521 * None 522 * 523 * Side effects: 524 * None 525 * 526 *---------------------------------------------------------------------------- 527 */ 528 529static void 530VMwareCtrlResetProc(ExtensionEntry* extEntry) 531{ 532 /* Currently, no cleanup is necessary. */ 533} 534 535 536/* 537 *---------------------------------------------------------------------------- 538 * 539 * VMwareCtrl_ExitInit -- 540 * 541 * Initialiser for the VMWARE_CTRL protocol extension. 542 * 543 * Results: 544 * None. 545 * 546 * Side effects: 547 * Protocol extension will be registered if successful. 548 * 549 *---------------------------------------------------------------------------- 550 */ 551 552void 553VMwareCtrl_ExtInit(ScrnInfoPtr pScrn) 554{ 555 ExtensionEntry *myext; 556 557 if (!(myext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { 558 if (!(myext = AddExtension(VMWARE_CTRL_PROTOCOL_NAME, 0, 0, 559 VMwareCtrlDispatch, 560 SVMwareCtrlDispatch, 561 VMwareCtrlResetProc, 562 StandardMinorOpcode))) { 563 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 564 "Failed to add VMWARE_CTRL extension\n"); 565 return; 566 } 567 568 /* 569 * For now, only support one screen as that's all the virtual 570 * hardware supports. 571 */ 572 myext->extPrivate = pScrn; 573 574 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 575 "Initialized VMWARE_CTRL extension version %d.%d\n", 576 VMWARE_CTRL_MAJOR_VERSION, VMWARE_CTRL_MINOR_VERSION); 577 } 578} 579