1/* 2 * Copyright 2006-2011 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#ifdef HAVE_CONFIG_H 35#include "config.h" 36#endif 37 38#include <xorg-server.h> 39#include "dixstruct.h" 40#include "extnsionst.h" 41#include <X11/X.h> 42#include <X11/extensions/panoramiXproto.h> 43 44#include "vmwarectrlproto.h" 45#include "vmwgfx_driver.h" 46#include "vmwgfx_drmi.h" 47 48/* 49 *---------------------------------------------------------------------------- 50 * 51 * VMwareCtrlQueryVersion -- 52 * 53 * Implementation of QueryVersion command handler. Initialises and 54 * sends a reply. 55 * 56 * Results: 57 * Standard response codes. 58 * 59 * Side effects: 60 * Writes reply to client 61 * 62 *---------------------------------------------------------------------------- 63 */ 64 65static int 66VMwareCtrlQueryVersion(ClientPtr client) 67{ 68 xVMwareCtrlQueryVersionReply rep = { 0, }; 69 register int n; 70 71 REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq); 72 73 rep.type = X_Reply; 74 rep.length = 0; 75 rep.sequenceNumber = client->sequence; 76 rep.majorVersion = VMWARE_CTRL_MAJOR_VERSION; 77 rep.minorVersion = VMWARE_CTRL_MINOR_VERSION; 78 if (client->swapped) { 79 _swaps(&rep.sequenceNumber, n); 80 _swapl(&rep.length, n); 81 _swapl(&rep.majorVersion, n); 82 _swapl(&rep.minorVersion, n); 83 } 84 WriteToClient(client, sizeof(xVMwareCtrlQueryVersionReply), (char *)&rep); 85 86 return client->noClientException; 87} 88 89 90/* 91 *---------------------------------------------------------------------------- 92 * 93 * VMwareCtrlDoSetRes -- 94 * 95 * Set the custom resolution into the mode list. 96 * 97 * This is done by alternately updating one of two dynamic modes. It is 98 * done this way because the server gets upset if you try to switch 99 * to a new resolution that has the same index as the current one. 100 * 101 * Results: 102 * TRUE on success, FALSE otherwise. 103 * 104 * Side effects: 105 * One dynamic mode will be updated if successful. 106 * 107 *---------------------------------------------------------------------------- 108 */ 109 110static Bool 111VMwareCtrlDoSetRes(ScrnInfoPtr pScrn, 112 CARD32 x, 113 CARD32 y) 114{ 115 modesettingPtr ms = modesettingPTR(pScrn); 116 struct drm_vmw_rect rect; 117 int ret; 118 119 rect.x = 0; 120 rect.y = 0; 121 rect.w = x; 122 rect.h = y; 123 124 ms->autoLayout = FALSE; 125 ret = vmwgfx_update_gui_layout(ms->fd, 1, &rect); 126 return (ret == 0); 127} 128 129 130/* 131 *---------------------------------------------------------------------------- 132 * 133 * VMwareCtrlSetRes -- 134 * 135 * Implementation of SetRes command handler. Initialises and sends a 136 * reply. 137 * 138 * Results: 139 * Standard response codes. 140 * 141 * Side effects: 142 * Writes reply to client 143 * 144 *---------------------------------------------------------------------------- 145 */ 146 147static int 148VMwareCtrlSetRes(ClientPtr client) 149{ 150 REQUEST(xVMwareCtrlSetResReq); 151 xVMwareCtrlSetResReply rep = { 0, }; 152 ScrnInfoPtr pScrn; 153 ExtensionEntry *ext; 154 register int n; 155 156 REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq); 157 158 if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { 159 return BadMatch; 160 } 161 162 pScrn = ext->extPrivate; 163 if (pScrn->scrnIndex != stuff->screen) { 164 return BadMatch; 165 } 166 167 if (!VMwareCtrlDoSetRes(pScrn, stuff->x, stuff->y)) { 168 return BadValue; 169 } 170 171 rep.type = X_Reply; 172 rep.length = (sizeof(xVMwareCtrlSetResReply) - sizeof(xGenericReply)) >> 2; 173 rep.sequenceNumber = client->sequence; 174 rep.screen = stuff->screen; 175 rep.x = stuff->x; 176 rep.y = stuff->y; 177 if (client->swapped) { 178 _swaps(&rep.sequenceNumber, n); 179 _swapl(&rep.length, n); 180 _swapl(&rep.screen, n); 181 _swapl(&rep.x, n); 182 _swapl(&rep.y, n); 183 } 184 WriteToClient(client, sizeof(xVMwareCtrlSetResReply), (char *)&rep); 185 186 return client->noClientException; 187} 188 189 190/* 191 *---------------------------------------------------------------------------- 192 * 193 * VMwareCtrlDoSetTopology -- 194 * 195 * Set the custom topology and set a dynamic mode to the bounding box 196 * of the passed topology. If a topology is already pending, then do 197 * nothing but do not return failure. 198 * 199 * Results: 200 * TRUE on success, FALSE otherwise. 201 * 202 * Side effects: 203 * One dynamic mode and the pending xinerama state will be updated if 204 * successful. 205 * 206 *---------------------------------------------------------------------------- 207 */ 208 209static Bool 210VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn, 211 xXineramaScreenInfo *extents, 212 unsigned long number) 213{ 214 modesettingPtr ms = modesettingPTR(pScrn); 215 struct drm_vmw_rect *rects; 216 int i; 217 int ret; 218 219 rects = calloc(number, sizeof(*rects)); 220 if (!rects) 221 return FALSE; 222 223 for (i = 0; i < number; i++) { 224 rects[i].x = extents[i].x_org; 225 rects[i].y = extents[i].y_org; 226 rects[i].w = extents[i].width; 227 rects[i].h = extents[i].height; 228 } 229 230 ms->autoLayout = FALSE; 231 ret = vmwgfx_update_gui_layout(ms->fd, number, rects); 232 233 free(rects); 234 return (ret == 0); 235} 236 237 238/* 239 *---------------------------------------------------------------------------- 240 * 241 * VMwareCtrlSetTopology -- 242 * 243 * Implementation of SetTopology command handler. Initialises and sends a 244 * reply. 245 * 246 * Results: 247 * Standard response codes. 248 * 249 * Side effects: 250 * Writes reply to client 251 * 252 *---------------------------------------------------------------------------- 253 */ 254 255static int 256VMwareCtrlSetTopology(ClientPtr client) 257{ 258 REQUEST(xVMwareCtrlSetTopologyReq); 259 xVMwareCtrlSetTopologyReply rep = { 0, }; 260 ScrnInfoPtr pScrn; 261 ExtensionEntry *ext; 262 register int n; 263 xXineramaScreenInfo *extents; 264 265 REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq); 266 267 if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { 268 return BadMatch; 269 } 270 271 pScrn = ext->extPrivate; 272 if (pScrn->scrnIndex != stuff->screen) { 273 return BadMatch; 274 } 275 276 extents = (xXineramaScreenInfo *)(stuff + 1); 277 if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) { 278 return BadValue; 279 } 280 281 rep.type = X_Reply; 282 rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2; 283 rep.sequenceNumber = client->sequence; 284 rep.screen = stuff->screen; 285 if (client->swapped) { 286 _swaps(&rep.sequenceNumber, n); 287 _swapl(&rep.length, n); 288 _swapl(&rep.screen, n); 289 } 290 WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep); 291 292 return client->noClientException; 293} 294 295 296/* 297 *---------------------------------------------------------------------------- 298 * 299 * VMwareCtrlDispatch -- 300 * 301 * Dispatcher for VMWARE_CTRL commands. Calls the correct handler for 302 * each command type. 303 * 304 * Results: 305 * Standard response codes. 306 * 307 * Side effects: 308 * Side effects of individual command handlers. 309 * 310 *---------------------------------------------------------------------------- 311 */ 312 313static int 314VMwareCtrlDispatch(ClientPtr client) 315{ 316 REQUEST(xReq); 317 318 switch(stuff->data) { 319 case X_VMwareCtrlQueryVersion: 320 return VMwareCtrlQueryVersion(client); 321 case X_VMwareCtrlSetRes: 322 return VMwareCtrlSetRes(client); 323 case X_VMwareCtrlSetTopology: 324 return VMwareCtrlSetTopology(client); 325 } 326 return BadRequest; 327} 328 329 330/* 331 *---------------------------------------------------------------------------- 332 * 333 * SVMwareCtrlQueryVersion -- 334 * 335 * Wrapper for QueryVersion handler that handles input from other-endian 336 * clients. 337 * 338 * Results: 339 * Standard response codes. 340 * 341 * Side effects: 342 * Side effects of unswapped implementation. 343 * 344 *---------------------------------------------------------------------------- 345 */ 346 347static int 348SVMwareCtrlQueryVersion(ClientPtr client) 349{ 350 register int n; 351 352 REQUEST(xVMwareCtrlQueryVersionReq); 353 REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq); 354 355 _swaps(&stuff->length, n); 356 357 return VMwareCtrlQueryVersion(client); 358} 359 360 361/* 362 *---------------------------------------------------------------------------- 363 * 364 * SVMwareCtrlSetRes -- 365 * 366 * Wrapper for SetRes handler that handles input from other-endian 367 * clients. 368 * 369 * Results: 370 * Standard response codes. 371 * 372 * Side effects: 373 * Side effects of unswapped implementation. 374 * 375 *---------------------------------------------------------------------------- 376 */ 377 378static int 379SVMwareCtrlSetRes(ClientPtr client) 380{ 381 register int n; 382 383 REQUEST(xVMwareCtrlSetResReq); 384 REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq); 385 386 _swaps(&stuff->length, n); 387 _swapl(&stuff->screen, n); 388 _swapl(&stuff->x, n); 389 _swapl(&stuff->y, n); 390 391 return VMwareCtrlSetRes(client); 392} 393 394 395/* 396 *---------------------------------------------------------------------------- 397 * 398 * SVMwareCtrlSetTopology -- 399 * 400 * Wrapper for SetTopology handler that handles input from other-endian 401 * clients. 402 * 403 * Results: 404 * Standard response codes. 405 * 406 * Side effects: 407 * Side effects of unswapped implementation. 408 * 409 *---------------------------------------------------------------------------- 410 */ 411 412static int 413SVMwareCtrlSetTopology(ClientPtr client) 414{ 415 register int n; 416 417 REQUEST(xVMwareCtrlSetTopologyReq); 418 REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq); 419 420 _swaps(&stuff->length, n); 421 _swapl(&stuff->screen, n); 422 _swapl(&stuff->number, n); 423 /* Each extent is a struct of shorts. */ 424 SwapRestS(stuff); 425 426 return VMwareCtrlSetTopology(client); 427} 428 429 430/* 431 *---------------------------------------------------------------------------- 432 * 433 * SVMwareCtrlDispatch -- 434 * 435 * Wrapper for dispatcher that handles input from other-endian clients. 436 * 437 * Results: 438 * Standard response codes. 439 * 440 * Side effects: 441 * Side effects of individual command handlers. 442 * 443 *---------------------------------------------------------------------------- 444 */ 445 446static int 447SVMwareCtrlDispatch(ClientPtr client) 448{ 449 REQUEST(xReq); 450 451 switch(stuff->data) { 452 case X_VMwareCtrlQueryVersion: 453 return SVMwareCtrlQueryVersion(client); 454 case X_VMwareCtrlSetRes: 455 return SVMwareCtrlSetRes(client); 456 case X_VMwareCtrlSetTopology: 457 return SVMwareCtrlSetTopology(client); 458 } 459 return BadRequest; 460} 461 462 463/* 464 *---------------------------------------------------------------------------- 465 * 466 * VMwareCtrlResetProc -- 467 * 468 * Cleanup handler called when the extension is removed. 469 * 470 * Results: 471 * None 472 * 473 * Side effects: 474 * None 475 * 476 *---------------------------------------------------------------------------- 477 */ 478 479static void 480VMwareCtrlResetProc(ExtensionEntry* extEntry) 481{ 482 /* Currently, no cleanup is necessary. */ 483} 484 485 486/* 487 *---------------------------------------------------------------------------- 488 * 489 * VMwareCtrl_ExitInit -- 490 * 491 * Initialiser for the VMWARE_CTRL protocol extension. 492 * 493 * Results: 494 * None. 495 * 496 * Side effects: 497 * Protocol extension will be registered if successful. 498 * 499 *---------------------------------------------------------------------------- 500 */ 501 502void 503vmw_ctrl_ext_init(ScrnInfoPtr pScrn) 504{ 505 ExtensionEntry *myext; 506 507 if (!(myext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) { 508 if (!(myext = AddExtension(VMWARE_CTRL_PROTOCOL_NAME, 0, 0, 509 VMwareCtrlDispatch, 510 SVMwareCtrlDispatch, 511 VMwareCtrlResetProc, 512 StandardMinorOpcode))) { 513 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 514 "Failed to add VMWARE_CTRL extension\n"); 515 return; 516 } 517 518 /* 519 * For now, only support one screen as that's all the virtual 520 * hardware supports. 521 */ 522 myext->extPrivate = pScrn; 523 524 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 525 "Initialized VMWARE_CTRL extension version %d.%d\n", 526 VMWARE_CTRL_MAJOR_VERSION, VMWARE_CTRL_MINOR_VERSION); 527 } 528} 529