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