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