/* * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * Copyright © 2007 OpenedHand Ltd * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of OpenedHand Ltd not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. OpenedHand Ltd makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * This file is heavily copied from hw/xfree86/dri/xf86dri.c * * Authors: * Dodji Seketeli */ #ifdef HAVE_CONFIG_H #include #endif #ifdef XEPHYR_DRI #include #define NEED_REPLIES #define NEED_EVENTS #include #include #define _XF86DRI_SERVER_ #include #include #include "misc.h" #include "dixstruct.h" #include "extnsionst.h" #include "colormapst.h" #include "cursorstr.h" #include "scrnintstr.h" #include "servermd.h" #include "swaprep.h" #include "ephyrdri.h" #define _HAVE_XALLOC_DECLS #include "ephyrlog.h" static int DRIErrorBase; static DISPATCH_PROC(ProcXF86DRIQueryVersion); static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); static DISPATCH_PROC(ProcXF86DRIOpenConnection); static DISPATCH_PROC(ProcXF86DRICloseConnection); static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); static DISPATCH_PROC(ProcXF86DRICreateContext); static DISPATCH_PROC(ProcXF86DRIDestroyContext); static DISPATCH_PROC(ProcXF86DRICreateDrawable); static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); static DISPATCH_PROC(ProcXF86DRIDispatch); static DISPATCH_PROC(ProcXF86DRIAuthConnection); static DISPATCH_PROC(SProcXF86DRIQueryVersion); static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); static DISPATCH_PROC(SProcXF86DRIDispatch); static void XF86DRIResetProc(ExtensionEntry* extEntry); static unsigned char DRIReqCode = 0; extern void ephyrDRIExtensionInit(void); void ephyrDRIExtensionInit(void) { ExtensionEntry* extEntry; EPHYR_LOG ("enter\n") ; #ifdef XF86DRI_EVENTS EventType = CreateNewResourceType(XF86DRIFreeEvents); #endif if ((extEntry = AddExtension(XF86DRINAME, XF86DRINumberEvents, XF86DRINumberErrors, ProcXF86DRIDispatch, SProcXF86DRIDispatch, XF86DRIResetProc, StandardMinorOpcode))) { DRIReqCode = (unsigned char)extEntry->base; DRIErrorBase = extEntry->errorBase; } EPHYR_LOG ("leave\n") ; } /*ARGSUSED*/ static void XF86DRIResetProc ( ExtensionEntry* extEntry ) { } static int ProcXF86DRIQueryVersion (register ClientPtr client) { xXF86DRIQueryVersionReply rep; register int n; EPHYR_LOG ("enter\n") ; REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.majorVersion = XF86DRI_MAJOR_VERSION; rep.minorVersion = XF86DRI_MINOR_VERSION; rep.patchVersion = XF86DRI_PATCH_VERSION; if (client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swaps(&rep.majorVersion, n); swaps(&rep.minorVersion, n); swapl(&rep.patchVersion, n); } WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) { xXF86DRIQueryDirectRenderingCapableReply rep; Bool isCapable; register int n; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIQueryDirectRenderingCapableReq); REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) { return BadValue; } rep.isCapable = isCapable; if (!LocalClient(client) || client->swapped) rep.isCapable = 0; if (client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); } WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIOpenConnection (register ClientPtr client) { xXF86DRIOpenConnectionReply rep; drm_handle_t hSAREA; char* busIdString; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIOpenConnectionReq); REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } if (!ephyrDRIOpenConnection(stuff->screen, &hSAREA, &busIdString)) { return BadValue; } rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.busIdStringLength = 0; if (busIdString) rep.busIdStringLength = strlen(busIdString); rep.length = (SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + ((rep.busIdStringLength + 3) & ~3)) >> 2; rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); #if defined(LONG64) && !defined(__linux__) rep.hSAREAHigh = (CARD32)(hSAREA >> 32); #else rep.hSAREAHigh = 0; #endif WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); if (rep.busIdStringLength) WriteToClient(client, rep.busIdStringLength, busIdString); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIAuthConnection (register ClientPtr client) { xXF86DRIAuthConnectionReply rep; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIAuthConnectionReq); REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.authenticated = 1; if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) { ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); rep.authenticated = 0; } WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRICloseConnection (register ClientPtr client) { EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRICloseConnectionReq); REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } /* DRICloseConnection( screenInfo.screens[stuff->screen]); */ EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIGetClientDriverName (register ClientPtr client) { xXF86DRIGetClientDriverNameReply rep; char* clientDriverName; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIGetClientDriverNameReq); REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } ephyrDRIGetClientDriverName (stuff->screen, (int *)&rep.ddxDriverMajorVersion, (int *)&rep.ddxDriverMinorVersion, (int *)&rep.ddxDriverPatchVersion, &clientDriverName); rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.clientDriverNameLength = 0; if (clientDriverName) rep.clientDriverNameLength = strlen(clientDriverName); rep.length = (SIZEOF(xXF86DRIGetClientDriverNameReply) - SIZEOF(xGenericReply) + ((rep.clientDriverNameLength + 3) & ~3)) >> 2; WriteToClient(client, sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); if (rep.clientDriverNameLength) WriteToClient(client, rep.clientDriverNameLength, clientDriverName); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRICreateContext (register ClientPtr client) { xXF86DRICreateContextReply rep; ScreenPtr pScreen; VisualPtr visual; int i; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRICreateContextReq); REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; pScreen = screenInfo.screens[stuff->screen]; visual = pScreen->visuals; /* Find the requested X visual */ for (i = 0; i < pScreen->numVisuals; i++, visual++) if (visual->vid == stuff->visual) break; if (i == pScreen->numVisuals) { /* No visual found */ return BadValue; } /* if (!DRICreateContext( pScreen, visual, stuff->context, (drm_context_t *)&rep.hHWContext)) { return BadValue; } */ WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIDestroyContext (register ClientPtr client) { EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIDestroyContextReq); REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } /* if (!DRIDestroyContext( screenInfo.screens[stuff->screen], stuff->context)) { return BadValue; } */ EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRICreateDrawable (ClientPtr client) { xXF86DRICreateDrawableReply rep; DrawablePtr pDrawable; int rc; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRICreateDrawableReq); REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rc = dixLookupDrawable (&pDrawable, stuff->drawable, client, 0, DixReadAccess); if (rc != Success) return rc; /*TODO: this cannot work. We must properly * do the mapping between the xephyr drawable and * the host drawable */ if (!ephyrDRICreateDrawable (stuff->screen, 0/*should be host drawableID*/, (drm_drawable_t *)&rep.hHWDrawable)) { return BadValue; } WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIDestroyDrawable (register ClientPtr client) { REQUEST(xXF86DRIDestroyDrawableReq); DrawablePtr pDrawable; REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); int rc; EPHYR_LOG ("enter\n") ; if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, DixReadAccess); if (rc != Success) return rc; if (!ephyrDRIDestroyDrawable(stuff->screen, 0/*should be drawable in host x*/)) { return BadValue; } EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIGetDrawableInfo (register ClientPtr client) { xXF86DRIGetDrawableInfoReply rep; DrawablePtr drawable; int X, Y, W, H, backX, backY, rc; drm_clip_rect_t * pClipRects, *pClippedRects; drm_clip_rect_t * pBackClipRects; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIGetDrawableInfoReq); REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; /*TODO: this cannot work. * We must properly do the mapping * between xephyr drawable and the host drawable */ rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixReadAccess); if (rc != Success) return rc; if (!ephyrDRIGetDrawableInfo (stuff->screen, drawable/*should be the drawable in hostx*/, (unsigned int*)&rep.drawableTableIndex, (unsigned int*)&rep.drawableTableStamp, (int*)&X, (int*)&Y, (int*)&W, (int*)&H, (int*)&rep.numClipRects, &pClipRects, &backX, &backY, (int*)&rep.numBackClipRects, &pBackClipRects)) { return BadValue; } rep.drawableX = X; rep.drawableY = Y; rep.drawableWidth = W; rep.drawableHeight = H; rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - SIZEOF(xGenericReply)); rep.backX = backX; rep.backY = backY; if (rep.numBackClipRects) rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; pClippedRects = pClipRects; if (rep.numClipRects) { /* Clip cliprects to screen dimensions (redirected windows) */ pClippedRects = xalloc(rep.numClipRects * sizeof(drm_clip_rect_t)); if (pClippedRects) { ScreenPtr pScreen = screenInfo.screens[stuff->screen]; int i, j; for (i = 0, j = 0; i < rep.numClipRects; i++) { pClippedRects[j].x1 = max(pClipRects[i].x1, 0); pClippedRects[j].y1 = max(pClipRects[i].y1, 0); pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width); pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height); if (pClippedRects[j].x1 < pClippedRects[j].x2 && pClippedRects[j].y1 < pClippedRects[j].y2) { j++; } } rep.numClipRects = j; } else { rep.numClipRects = 0; } rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; } rep.length = ((rep.length + 3) & ~3) >> 2; WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); if (rep.numClipRects) { WriteToClient(client, sizeof(drm_clip_rect_t) * rep.numClipRects, (char *)pClippedRects); xfree(pClippedRects); } if (rep.numBackClipRects) { WriteToClient(client, sizeof(drm_clip_rect_t) * rep.numBackClipRects, (char *)pBackClipRects); } EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIGetDeviceInfo (register ClientPtr client) { xXF86DRIGetDeviceInfoReply rep; drm_handle_t hFrameBuffer; void *pDevPrivate; EPHYR_LOG ("enter\n") ; REQUEST(xXF86DRIGetDeviceInfoReq); REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; if (!ephyrDRIGetDeviceInfo (stuff->screen, &hFrameBuffer, (int*)&rep.framebufferOrigin, (int*)&rep.framebufferSize, (int*)&rep.framebufferStride, (int*)&rep.devPrivateSize, &pDevPrivate)) { return BadValue; } rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); #if defined(LONG64) && !defined(__linux__) rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); #else rep.hFrameBufferHigh = 0; #endif rep.length = 0; if (rep.devPrivateSize) { rep.length = (SIZEOF(xXF86DRIGetDeviceInfoReply) - SIZEOF(xGenericReply) + ((rep.devPrivateSize + 3) & ~3)) >> 2; } WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); if (rep.length) { WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); } EPHYR_LOG ("leave\n") ; return (client->noClientException); } static int ProcXF86DRIDispatch (register ClientPtr client) { REQUEST(xReq); EPHYR_LOG ("enter\n") ; switch (stuff->data) { case X_XF86DRIQueryVersion: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIQueryVersion(client); } case X_XF86DRIQueryDirectRenderingCapable: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIQueryDirectRenderingCapable(client); } } if (!LocalClient(client)) return DRIErrorBase + XF86DRIClientNotLocal; switch (stuff->data) { case X_XF86DRIOpenConnection: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIOpenConnection(client); } case X_XF86DRICloseConnection: { EPHYR_LOG ("leave\n") ; return ProcXF86DRICloseConnection(client); } case X_XF86DRIGetClientDriverName: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIGetClientDriverName(client); } case X_XF86DRICreateContext: { EPHYR_LOG ("leave\n") ; return ProcXF86DRICreateContext(client); } case X_XF86DRIDestroyContext: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIDestroyContext(client); } case X_XF86DRICreateDrawable: { EPHYR_LOG ("leave\n") ; return ProcXF86DRICreateDrawable(client); } case X_XF86DRIDestroyDrawable: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIDestroyDrawable(client); } case X_XF86DRIGetDrawableInfo: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIGetDrawableInfo(client); } case X_XF86DRIGetDeviceInfo: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIGetDeviceInfo(client); } case X_XF86DRIAuthConnection: { EPHYR_LOG ("leave\n") ; return ProcXF86DRIAuthConnection(client); } /* {Open,Close}FullScreen are deprecated now */ default: { EPHYR_LOG ("leave\n") ; return BadRequest; } } } static int SProcXF86DRIQueryVersion (register ClientPtr client) { register int n; REQUEST(xXF86DRIQueryVersionReq); swaps(&stuff->length, n); return ProcXF86DRIQueryVersion(client); } static int SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) { register int n; REQUEST(xXF86DRIQueryDirectRenderingCapableReq); swaps(&stuff->length, n); swapl(&stuff->screen, n); return ProcXF86DRIQueryDirectRenderingCapable(client); } static int SProcXF86DRIDispatch (register ClientPtr client) { REQUEST(xReq); EPHYR_LOG ("enter\n") ; /* * Only local clients are allowed DRI access, but remote clients still need * these requests to find out cleanly. */ switch (stuff->data) { case X_XF86DRIQueryVersion: { EPHYR_LOG ("leave\n") ; return SProcXF86DRIQueryVersion(client); } case X_XF86DRIQueryDirectRenderingCapable: { EPHYR_LOG ("leave\n") ; return SProcXF86DRIQueryDirectRenderingCapable(client); } default: { EPHYR_LOG ("leave\n") ; return DRIErrorBase + XF86DRIClientNotLocal; } } } #endif /*XEPHYR_DRI*/