summaryrefslogtreecommitdiffstats
path: root/src/glx
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx')
-rw-r--r--src/glx/mini/Makefile.X1179
-rw-r--r--src/glx/mini/NOTES115
-rw-r--r--src/glx/mini/dispatch.c64
-rw-r--r--src/glx/mini/dri.h124
-rw-r--r--src/glx/mini/dri_util.c715
-rw-r--r--src/glx/mini/dri_util.h523
-rw-r--r--src/glx/mini/driver.h177
-rw-r--r--src/glx/mini/drm.h657
-rw-r--r--src/glx/mini/drmtest.c140
-rw-r--r--src/glx/mini/example.miniglx.conf26
-rw-r--r--src/glx/mini/miniglx.c1975
-rw-r--r--src/glx/mini/miniglxP.h194
-rw-r--r--src/glx/mini/miniglx_events.c962
-rw-r--r--src/glx/mini/sarea.h96
-rw-r--r--src/glx/mini/xf86drm.c1587
-rw-r--r--src/glx/mini/xf86drm.h609
16 files changed, 8043 insertions, 0 deletions
diff --git a/src/glx/mini/Makefile.X11 b/src/glx/mini/Makefile.X11
new file mode 100644
index 00000000000..2e818f0b017
--- /dev/null
+++ b/src/glx/mini/Makefile.X11
@@ -0,0 +1,79 @@
+# Build a subset DRI-based libGL.so library.
+# Indirect rendering not supported, etc.
+
+TOP = ../../..
+
+default: linux-solo
+
+C_SOURCES = dispatch.c \
+ dri_util.c \
+ ../../mesa/glapi/glapi.c \
+ ../../mesa/glapi/glthread.c \
+ miniglx.c \
+ miniglx_events.c \
+ xf86drm.c
+
+OBJECTS = $(C_SOURCES:.c=.o)
+
+INCLUDES = -I. $(INCLUDE_DIRS)
+LIBS = -ldl
+
+### Include directories
+
+INCLUDE_DIRS = \
+ -I$(TOP)/include \
+ -I$(TOP)/src/mesa \
+ -I$(TOP)/src/mesa/main \
+ -I$(TOP)/src/mesa/glapi \
+ -I$(TOP)/src/mesa/math \
+ -I$(TOP)/src/mesa/transform \
+ -I$(TOP)/src/mesa/swrast \
+ -I$(TOP)/src/mesa/swrast_setup
+
+
+##### RULES #####
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+.S.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
+
+
+##### TARGETS #####
+
+targets: depend libGL.so.1.2
+
+libGL.so.1.2: $(OBJECTS) Makefile.X11
+ rm -f $@ && gcc -shared -Wl,-soname,libGL.so -Wl,-Bsymbolic $(OBJECTS) $(LIBS) -o $@
+ rm -f $(TOP)/lib/libGL.so*
+ rm -f $(TOP)/lib/miniglx.conf
+ install -D libGL.so.1.2 $(TOP)/lib/libGL.so.1.2
+ ln -s libGL.so.1.2 $(TOP)/lib/libGL.so.1
+ ln -s libGL.so.1 $(TOP)/lib/libGL.so
+ install example.miniglx.conf $(TOP)/lib/miniglx.conf
+
+drmtest: xf86drm.o drmtest.o
+ rm -f drmtest && $(CC) -o drmtest xf86drm.o drmtest.o
+
+# Run 'make -f Makefile.X11 dep' to update the dependencies if you change
+# what's included by any source file.
+depend: $(C_SOURCES) $(ASM_SOURCES)
+ makedepend -fdepend -Y $(INCLUDES) \
+ $(C_SOURCES) $(ASM_SOURCES)
+
+
+# Emacs tags
+tags:
+ etags `find . -name \*.[ch]` `find ../include`
+
+
+# Remove .o and backup files
+clean:
+ -rm -f drmtest $(TOP)/lib/libGL.so*
+ -rm -f */*.o */*~ */*.o */*~
+
+
+include $(TOP)/Make-config
+
+include depend
diff --git a/src/glx/mini/NOTES b/src/glx/mini/NOTES
new file mode 100644
index 00000000000..1774107d634
--- /dev/null
+++ b/src/glx/mini/NOTES
@@ -0,0 +1,115 @@
+
+
+Getting MiniGLX up and running
+------------------------------
+
+It's necessary to do a bit of work to set up an environment to run miniglx.
+
+For the radeon driver, it's necessary to get the right set of kernel
+modules installed before attempting to run any programs:
+
+ rmmod radeon agpgart;
+ insmod agpgart;
+ insmod $(MESA)/src/kernel/radeonfb/radeonfb.o;
+ insmod $(MESA)/src/kernel/radeon/radeon.o;
+
+For all drivers, its necessary to reach the compiled libraries, and
+tell MiniGLX where to find it's configuration file:
+
+ export LD_LIBRARY_PATH=$(MESA)/lib;
+ export MINIGLX_CONF=$(MESA)/lib/miniglx.conf
+
+------------------------------------------------------------
+
+MiniGLX Example Programs
+------------------------
+
+The following programs will work with miniglx:
+
+ $(MESA)/tests/miniglx
+ $(MESA)/xdemos/glxgears
+
+Thanks to the miniglut stub library, most of the mesa glut demos will
+work. In particular, the following have been tested. (Note there is
+no keyboard or mouse interaction with these demos).
+
+ $(MESA)/demos/gears
+ $(MESA)/demos/geartrain
+ $(MESA)/demos/morph3d
+ $(MESA)/demos/isosurf
+ $(MESA)/demos/texobj
+ $(MESA)/demos/texcyl
+ $(MESA)/demos/gloss
+ $(MESA)/demos/fire
+ $(MESA)/demos/tunnel
+ $(MESA)/demos/teapot
+ $(MESA)/samples/prim
+ $(MESA)/samples/olympic
+ $(MESA)/samples/star
+ $(MESA)/samples/wave
+ ...etc
+
+In fact most of the glut demos seem to work within the constraints of
+having no keyboard/mouse interactivity. Furthermore, the use of the
+glut wrapper means that these programs don't require recompilation to
+run under MiniGLX -- the same binary works with both regular GLX and
+MiniGLX.
+
+
+------------------------------------------------------------
+
+Porting GLX apps to MiniGLX
+---------------------------
+
+A quick list of issues encountered in porting existing GLX apps to
+MiniGLX. Listed in no particular order.
+
+1) No input events
+
+MiniGLX doesn't provide an input layer, so any X11 input event
+handling in the existing app will have to be redone for whatever
+input devices exist on the target.
+
+2) No configuration, expose events
+
+Many GLX and Xlib programs wait on an event to ensure the window has
+become visible after being mapped. MiniGLX provides no equivalent
+facility.
+
+3) Different headers
+
+X11/Xlib.h, GL/GLX.h, etc must not be used if the program is being
+compiled against MiniGLX.
+
+The equivalent header is GL/MiniGLX.h.
+
+4) Different library
+
+It may be necessary to link directly against the minGLX libGL.so.
+
+5) Reduced number of Xlib and GLX entrypoints.
+
+By definition (MiniGLX is a subset of GLX), many Xlib and GLX
+entrypoints, structures and macros are not present in MiniGLX. It
+will be necessary to find and eliminate all references to
+non-supported entrypoints.
+
+
+---------------------------------------------------------------
+
+Bugs in radeonfb.o -- the radeon framebuffer driver.
+----------------------------------------------------
+
+Several bugs have been found in the radeonfb.o framebuffer driver.
+Most of these are resolved in the version included in the MiniGLX
+sources, but some remain:
+
+1) Occasionally, after entering graphics mode, colors appear 'shifted'
+or 'translated', particularly in higher resolution modes. This is
+definitely a bug in radeonfb.o as this can be provoked even when using
+the software dri driver (fb_dri.so). Importance: High. Workaround:
+Use 800x600 as it seems to be less frequent at this resolution,
+otherwise, restart the application.
+
+
+
diff --git a/src/glx/mini/dispatch.c b/src/glx/mini/dispatch.c
new file mode 100644
index 00000000000..264cd4cba82
--- /dev/null
+++ b/src/glx/mini/dispatch.c
@@ -0,0 +1,64 @@
+/**
+ * \file miniglx/dispatch.c
+ *
+ * \brief C-based dispatch of the OpenGL entry points (glAccum(), glBegin(),
+ * etc).
+ *
+ * \author Brian Paul <[email protected]>
+ *
+ * \note This code IS NOT USED if we're compiling on an x86 system and using
+ * the glapi_x86.S assembly code.
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <GL/gl.h>
+#include "glapi.h"
+#include "glapitable.h"
+
+
+#if !(defined(USE_X86_ASM) || defined(USE_SPARC_ASM))
+
+#define KEYWORD1
+
+#define KEYWORD2
+
+#define NAME(func) gl##func
+
+#define DISPATCH(func, args, msg) \
+ const struct _glapi_table *dispatch; \
+ dispatch = _glapi_Dispatch ? _glapi_Dispatch : _glapi_get_dispatch();\
+ (dispatch->func) args
+
+#define RETURN_DISPATCH(func, args, msg) \
+ const struct _glapi_table *dispatch; \
+ dispatch = _glapi_Dispatch ? _glapi_Dispatch : _glapi_get_dispatch();\
+ return (dispatch->func) args
+
+
+#include "glapitemp.h"
+
+#endif /* USE_X86_ASM */
diff --git a/src/glx/mini/dri.h b/src/glx/mini/dri.h
new file mode 100644
index 00000000000..71f9a1acbf9
--- /dev/null
+++ b/src/glx/mini/dri.h
@@ -0,0 +1,124 @@
+/**
+ * \file miniglxP.h
+ * \brief Define replacements for some X data types and define the DRI-related
+ * data structures.
+ *
+ * \note Cut down version of glxclient.h.
+ *
+ */
+
+#ifndef _dri_h_
+#define _dri_h_
+
+#include "driver.h"
+
+typedef struct __DRIscreenRec __DRIscreen; /**< \copydoc __DRIscreenRec */
+typedef struct __DRIcontextRec __DRIcontext; /**< \copydoc __DRIcontextRec */
+typedef struct __DRIdrawableRec __DRIdrawable; /**< \copydoc __DRIdrawableRec */
+
+/**
+ * \brief Screen dependent methods.
+ *
+ * This structure is initialized during the MiniGLXDisplayRec::createScreen
+ * call.
+ */
+struct __DRIscreenRec {
+ /**
+ * \brief Method to destroy the private DRI screen data.
+ */
+ void (*destroyScreen)(__DRIscreen *screen);
+
+ /**
+ * \brief Method to create the private DRI context data and initialize the
+ * context dependent methods.
+ */
+ void *(*createContext)(__DRIscreen *screen, const __GLcontextModes *glVisual,
+ void *sharedPrivate);
+ /**
+ * \brief Method to create the private DRI drawable data and initialize the
+ * drawable dependent methods.
+ */
+ void *(*createDrawable)(__DRIscreen *screen,
+ int width, int height, int index,
+ const __GLcontextModes *glVisual);
+
+ /*
+ * XXX in the future, implement this:
+ void *(*createPBuffer)(Display *dpy, int scrn, GLXPbuffer pbuffer,
+ GLXFBConfig config, __DRIdrawable *pdraw);
+ */
+
+ /**
+ * \brief Opaque pointer to private per screen direct rendering data.
+ *
+ * \c NULL if direct rendering is not supported on this screen. Never
+ * dereferenced in libGL.
+ */
+};
+
+/**
+ * \brief Context dependent methods.
+ *
+ * This structure is initialized during the __DRIscreenRec::createContext call.
+ */
+struct __DRIcontextRec {
+ /**
+ * \brief Method to destroy the private DRI context data.
+ */
+ void (*destroyContext)(__DRIcontext *context);
+
+ /**
+ * \brief Method to bind a DRI drawable to a DRI graphics context.
+ *
+ * \todo XXX in the future, also pass a 'read' GLXDrawable for
+ * glXMakeCurrentReadSGI() and GLX 1.3's glXMakeContextCurrent().
+ */
+ GLboolean (*bindContext)(__DRIscreen *screen, __DRIdrawable *drawable, __DRIcontext *context);
+
+ /**
+ * \brief Method to unbind a DRI drawable to a DRI graphics context.
+ */
+ GLboolean (*unbindContext)(__DRIdrawable *drawable, __DRIcontext *context);
+ /**
+ * \brief Opaque pointer to private per context direct rendering data.
+ *
+ * NULL if direct rendering is not supported on the display or
+ * screen used to create this context. Never dereferenced in libGL.
+ */
+};
+
+/**
+ * \brief Drawable dependent methods.
+ *
+ * This structure is initialized during the __DRIscreenRec::createDrawable call.
+ *
+ * __DRIscreenRec::createDrawable is not called by libGL at this time. It's
+ * currently used via the dri_util.c utility code instead.
+ */
+struct __DRIdrawableRec {
+ /**
+ * \brief Method to destroy the private DRI drawable data.
+ */
+ void (*destroyDrawable)(__DRIdrawable *drawable);
+
+
+ /**
+ * \brief Method to swap the front and back buffers.
+ */
+ void (*swapBuffers)(__DRIdrawable *drawable);
+
+ /**
+ * \brief Opaque pointer to private per drawable direct rendering data.
+ *
+ * \c NULL if direct rendering is not supported on the display or
+ * screen used to create this drawable. Never dereferenced in libGL.
+ */
+};
+
+typedef void *(driCreateScreenFunc)(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext);
+
+/** This must be implemented in each driver */
+extern driCreateScreenFunc __driCreateScreen;
+
+#endif /* _dri_h_ */
diff --git a/src/glx/mini/dri_util.c b/src/glx/mini/dri_util.c
new file mode 100644
index 00000000000..6d79d2037c0
--- /dev/null
+++ b/src/glx/mini/dri_util.c
@@ -0,0 +1,715 @@
+/**
+ * \file dri_util.c
+ * \brief DRI utility functions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/fb.h>
+#include <linux/vt.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+
+#include "sarea.h"
+#include "dri_util.h"
+
+/**
+ * \brief Print message to \c stderr if the \c LIBGL_DEBUG environment variable
+ * is set.
+ *
+ * Is called from the drivers.
+ *
+ * \param f \e printf like format.
+ *
+ * \internal
+ * This function is a wrapper around vfprintf().
+ */
+void
+__driUtilMessage(const char *f, ...)
+{
+ va_list args;
+
+ if (getenv("LIBGL_DEBUG")) {
+ fprintf(stderr, "libGL error: \n");
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+
+/*****************************************************************/
+/** \name Visual utility functions */
+/*****************************************************************/
+/*@{*/
+
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context (un)binding functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Unbind context.
+ *
+ * \param drawable __DRIdrawable
+ * \param context __DRIcontext
+ * \param will_rebind not used.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::UnbindContext, and then decrements
+ * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
+ * return.
+ *
+ * While casting the opaque private pointers associated with the parameters into their
+ * respective real types it also assures they are not null.
+ */
+static GLboolean driUnbindContext(__DRIdrawable *drawable,
+ __DRIcontext *context)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+ __DRIscreenPrivate *psp;
+
+ if (pdp == NULL || pcp == NULL)
+ return GL_FALSE;
+
+ if (!(psp = (__DRIscreenPrivate *)pdp->driScreenPriv))
+ return GL_FALSE;
+
+ /* Let driver unbind drawable from context */
+ (*psp->DriverAPI.UnbindContext)(pcp);
+
+ if (pdp->refcount == 0)
+ return GL_FALSE;
+
+ --pdp->refcount;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Unbind context.
+ *
+ * \param pDRIScreen __DRIscreen
+ * \param drawable __DRIdrawable
+ * \param context __DRIcontext
+ *
+ * \internal
+ * This function and increments __DRIdrawablePrivateRec::refcount and calls
+ * __DriverAPIRec::MakeCurrent to binds the drawable.
+ *
+ * While casting the opaque private pointers into their
+ * respective real types it also assures they are not null.
+ */
+static GLboolean driBindContext(__DRIscreen *screen, __DRIdrawable *drawable,
+ __DRIcontext *context)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+
+ if (psp == NULL)
+ return GL_FALSE;
+
+ if (pdp == NULL || pcp == NULL) {
+ (*psp->DriverAPI.MakeCurrent)(0, 0, 0);
+ return GL_TRUE;
+ }
+
+ /* Bind the drawable to the context */
+ pcp->driDrawablePriv = pdp;
+ pdp->driContextPriv = pcp;
+ pdp->refcount++;
+
+ /* Call device-specific MakeCurrent */
+ (*psp->DriverAPI.MakeCurrent)(pcp, pdp, pdp);
+
+ return GL_TRUE;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Drawable handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Update private drawable information.
+ *
+ * \param pdp pointer to the private drawable information to update.
+ *
+ * \internal
+ * This function is a no-op. Should never be called but is referenced as an
+ * external symbol from client drivers.
+ */
+void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
+{
+ __DRIscreenPrivate *psp = pdp->driScreenPriv;
+
+ pdp->numClipRects = psp->pSAREA->drawableTable[pdp->index].flags ? 1 : 0;
+ pdp->lastStamp = *(pdp->pStamp);
+}
+
+
+/**
+ * \brief Swap buffers.
+ *
+ * \param pDRIscreen __DRIscreen
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DRIdrawablePrivate::swapBuffers.
+ *
+ * Is called directly from glXSwapBuffers().
+ */
+static void driSwapBuffers(__DRIdrawable *drawable)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ if (pdp)
+ pdp->swapBuffers(pdp);
+}
+
+
+/**
+ * \brief Destroy per-drawable private information.
+ *
+ * \param pDRIscreen __DRIscreen
+ * \param drawablePrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyBuffer on \p drawablePrivate,
+ * frees the clip rects if any, and finally frees \p drawablePrivate itself.
+ */
+static void driDestroyDrawable(__DRIdrawable *drawable)
+{
+ __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
+ __DRIscreenPrivate *psp;
+
+ if (pdp) {
+ psp = pdp->driScreenPriv;
+ (*psp->DriverAPI.DestroyBuffer)(pdp);
+ if (pdp->pClipRects)
+ free(pdp->pClipRects);
+ free(pdp);
+ }
+}
+
+
+/**
+ * \brief Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param draw the GLX drawable info.
+ * \param vid visual ID.
+ * \param pdraw will receive the drawable dependent methods.
+ *
+ *
+ * \returns a opaque pointer to the per-drawable private info on success, or NULL
+ * on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIdrawablePrivateRec structure,
+ * initializing the invariant window dimensions and clip rects. It obtains the
+ * visual config, converts it into a __GLcontextModesRec and passes it to
+ * __DriverAPIRec::CreateBuffer to create a buffer.
+ */
+static void *driCreateDrawable(__DRIscreen *screen,
+ int width, int height, int index,
+ const __GLcontextModes *glVisual)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIdrawablePrivate *pdp;
+
+ if (!psp)
+ return NULL;
+
+ if (!(pdp = (__DRIdrawablePrivate *)malloc(sizeof(__DRIdrawablePrivate))))
+ return NULL;
+
+ pdp->index = index;
+ pdp->refcount = 0;
+ pdp->lastStamp = -1;
+ pdp->numBackClipRects = 0;
+ pdp->pBackClipRects = NULL;
+
+ /* Initialize with the invariant window dimensions and clip rects here.
+ */
+ pdp->x = 0;
+ pdp->y = 0;
+ pdp->w = width;
+ pdp->h = height;
+ pdp->numClipRects = 0;
+ pdp->pClipRects = (XF86DRIClipRectPtr) malloc(sizeof(XF86DRIClipRectRec));
+ (pdp->pClipRects)[0].x1 = 0;
+ (pdp->pClipRects)[0].y1 = 0;
+ (pdp->pClipRects)[0].x2 = width;
+ (pdp->pClipRects)[0].y2 = height;
+
+ pdp->driScreenPriv = psp;
+ pdp->driContextPriv = 0;
+
+ pdp->frontBuffer = psp->pFB;
+ pdp->currentBuffer = pdp->frontBuffer;
+ pdp->currentPitch = psp->fbStride;
+ pdp->backBuffer = psp->pFB + psp->fbStride * psp->fbHeight;
+
+ if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, glVisual, GL_FALSE)) {
+ free(pdp);
+ return NULL;
+ }
+
+ pdp->entry.destroyDrawable = driDestroyDrawable;
+ pdp->entry.swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
+ pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
+
+ pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
+ return (void *) pdp;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Context handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Destroy the per-context private information.
+ *
+ * \param contextPrivate opaque pointer to the per-drawable private info.
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
+ * drmDestroyContext(), and finally frees \p contextPrivate.
+ */
+static void driDestroyContext(__DRIcontext *context)
+{
+ __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
+ __DRIscreenPrivate *psp = NULL;
+
+ if (pcp) {
+ (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
+ psp = pcp->driDrawablePriv->driScreenPriv;
+ if (psp->fd) {
+ printf(">>> drmDestroyContext(0x%x)\n", (int) pcp->hHWContext);
+ drmDestroyContext(psp->fd, pcp->hHWContext);
+ }
+ free(pcp);
+ }
+}
+
+/**
+ * \brief Create the per-drawable private driver information.
+ *
+ * \param dpy the display handle.
+ * \param vis the visual information.
+ * \param sharedPrivate the shared context dependent methods or NULL if non-existent.
+ * \param pctx will receive the context dependent methods.
+ *
+ * \returns a opaque pointer to the per-context private information on success, or NULL
+ * on failure.
+ *
+ * \internal
+ * This function allocates and fills a __DRIcontextPrivateRec structure. It
+ * gets the visual, converts it into a __GLcontextModesRec and passes it
+ * to __DriverAPIRec::CreateContext to create the context.
+ */
+static void *driCreateContext(__DRIscreen *screen,
+ const __GLcontextModes *glVisual,
+ void *sharedPrivate)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ __DRIcontextPrivate *pcp;
+ __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
+ void *shareCtx;
+
+ if (!psp)
+ return NULL;
+
+ if (!(pcp = (__DRIcontextPrivate *)malloc(sizeof(__DRIcontextPrivate))))
+ return NULL;
+
+ pcp->driScreenPriv = psp;
+ pcp->driDrawablePriv = NULL;
+
+ if (psp->fd) {
+ if (drmCreateContext(psp->fd, &pcp->hHWContext)) {
+ fprintf(stderr, ">>> drmCreateContext failed\n");
+ free(pcp);
+ return NULL;
+ }
+ }
+
+ shareCtx = pshare ? pshare->driverPrivate : NULL;
+
+ if (!(*psp->DriverAPI.CreateContext)(glVisual, pcp, shareCtx)) {
+ if (psp->fd)
+ (void) drmDestroyContext(psp->fd, pcp->hHWContext);
+ free(pcp);
+ return NULL;
+ }
+
+ pcp->entry.destroyContext = driDestroyContext;
+ pcp->entry.bindContext = driBindContext;
+ pcp->entry.unbindContext = driUnbindContext;
+
+ return pcp;
+}
+
+/*@}*/
+
+
+/*****************************************************************/
+/** \name Screen handling functions */
+/*****************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Destroy the per-screen private information.
+ *
+ * \param pDRIscreen __DRIscreen
+ *
+ * \internal
+ * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
+ * drmClose(), and finally frees \p screenPrivate.
+ */
+static void driDestroyScreen(__DRIscreen *screen)
+{
+ __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
+ if (psp) {
+ if (psp->DriverAPI.DestroyScreen)
+ (*psp->DriverAPI.DestroyScreen)(psp);
+
+ if (psp->fd)
+ (void)drmClose(psp->fd);
+
+ free(psp->pDevPriv);
+ free(psp);
+ }
+}
+
+
+/**
+ * \brief Create the per-screen private information.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param psc will receive the screen dependent methods.
+ * \param numConfigs number of visuals.
+ * \param config visuals.
+ * \param driverAPI driver callbacks structure.
+ *
+ * \return a pointer to the per-screen private information.
+ *
+ * \internal
+ * This function allocates and fills a __DRIscreenPrivateRec structure. It
+ * opens the DRM device verifying that the exported version matches the
+ * expected. It copies the driver callback functions and calls
+ * __DriverAPIRec::InitDriver.
+ *
+ * If a client maps the framebuffer and SAREA regions.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+ if(!(psp = (__DRIscreenPrivate *)malloc(sizeof(__DRIscreenPrivate))))
+ return NULL;
+
+ psp->fd = drmOpen(NULL, driverContext->pciBusID);
+ if (psp->fd < 0) {
+ fprintf(stderr, "libGL error: failed to open DRM: %s\n",
+ strerror(-psp->fd));
+ free(psp);
+ return NULL;
+ }
+
+ {
+ drmVersionPtr version = drmGetVersion(psp->fd);
+ if (version) {
+ psp->drmMajor = version->version_major;
+ psp->drmMinor = version->version_minor;
+ psp->drmPatch = version->version_patchlevel;
+ drmFreeVersion(version);
+ }
+ else {
+ fprintf(stderr, "libGL error: failed to get drm version: %s\n",
+ strerror(-psp->fd));
+ free(psp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Fake various version numbers.
+ */
+ psp->ddxMajor = 4;
+ psp->ddxMinor = 0;
+ psp->ddxPatch = 1;
+ psp->driMajor = 4;
+ psp->driMinor = 1;
+ psp->driPatch = 0;
+
+ /* install driver's callback functions */
+ psp->DriverAPI = *driverAPI;
+
+ /*
+ * Get device-specific info. pDevPriv will point to a struct
+ * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
+ * that has information about the screen size, depth, pitch,
+ * ancilliary buffers, DRM mmap handles, etc.
+ */
+ psp->fbOrigin = driverContext->shared.fbOrigin;
+ psp->fbSize = driverContext->shared.fbSize;
+ psp->fbStride = driverContext->shared.fbStride;
+ psp->devPrivSize = driverContext->driverClientMsgSize;
+ psp->pDevPriv = driverContext->driverClientMsg;
+ psp->fbWidth = driverContext->shared.virtualWidth;
+ psp->fbHeight = driverContext->shared.virtualHeight;
+ psp->fbBPP = driverContext->bpp;
+
+ if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
+ /* Already mapped in server */
+ psp->pFB = driverContext->FBAddress;
+ psp->pSAREA = driverContext->pSAREA;
+ } else {
+ /*
+ * Map the framebuffer region.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
+ (drmAddressPtr)&psp->pFB)) {
+ fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+ /*
+ * Map the SAREA region. Further mmap regions may be setup in
+ * each DRI driver's "createScreen" function.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hSAREA,
+ driverContext->shared.SAREASize,
+ (drmAddressPtr)&psp->pSAREA)) {
+ fprintf(stderr, "libGL error: drmMap of sarea failed\n");
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+#ifdef _EMBEDDED
+ mprotect(psp->pSAREA, driverContext->shared.SAREASize, PROT_READ);
+#endif
+ }
+
+
+ /* Initialize the screen specific GLX driver */
+ if (psp->DriverAPI.InitDriver) {
+ if (!(*psp->DriverAPI.InitDriver)(psp)) {
+ fprintf(stderr, "libGL error: InitDriver failed\n");
+ free(psp->pDevPriv);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+ }
+
+ psp->entry.destroyScreen = driDestroyScreen;
+ psp->entry.createContext = driCreateContext;
+ psp->entry.createDrawable = driCreateDrawable;
+
+ return psp;
+}
+
+
+
+/**
+ * \brief Create the per-screen private information.
+ *
+ * Version for drivers without a DRM module.
+ *
+ * \param dpy the display handle.
+ * \param scrn the screen number.
+ * \param numConfigs number of visuals.
+ * \param config visuals.
+ * \param driverAPI driver callbacks structure.
+ *
+ * \internal
+ * Same as __driUtilCreateScreen() but without opening the DRM device.
+ */
+__DRIscreenPrivate *
+__driUtilCreateScreenNoDRM(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI)
+{
+ __DRIscreenPrivate *psp;
+
+ psp = (__DRIscreenPrivate *)calloc(1, sizeof(__DRIscreenPrivate));
+ if (!psp)
+ return NULL;
+
+ psp->ddxMajor = 4;
+ psp->ddxMinor = 0;
+ psp->ddxPatch = 1;
+ psp->driMajor = 4;
+ psp->driMinor = 1;
+ psp->driPatch = 0;
+ psp->fd = 0;
+
+ psp->fbOrigin = driverContext->shared.fbOrigin;
+ psp->fbSize = driverContext->shared.fbSize;
+ psp->fbStride = driverContext->shared.fbStride;
+ psp->devPrivSize = driverContext->driverClientMsgSize;
+ psp->pDevPriv = driverContext->driverClientMsg;
+ psp->fbWidth = driverContext->shared.virtualWidth;
+ psp->fbHeight = driverContext->shared.virtualHeight;
+ psp->fbBPP = driverContext->bpp;
+
+ psp->pFB = driverContext->FBAddress;
+
+ /* install driver's callback functions */
+ psp->DriverAPI = *driverAPI;
+
+ if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
+ /* Already mapped in server */
+ psp->pFB = driverContext->FBAddress;
+ psp->pSAREA = driverContext->pSAREA;
+ } else {
+ psp->fd = open("/dev/mem", O_RDWR, 0);
+ /*
+ * Map the framebuffer region.
+ */
+ if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
+ (drmAddressPtr)&psp->pFB)) {
+ fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+ driverContext->FBAddress = psp->pFB;
+
+ /*
+ * Map the SAREA region. Non-DRM drivers use a shmem SAREA
+ */
+ int id;
+ id = shmget(driverContext->shared.hSAREA, driverContext->shared.SAREASize, 0);
+ driverContext->pSAREA = shmat(id, NULL, 0);
+ if (!driverContext->pSAREA) {
+ fprintf(stderr, "libGL error: shmget of sarea failed\n");
+ (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
+ (void)drmClose(psp->fd);
+ free(psp);
+ return NULL;
+ }
+
+ close(psp->fd);
+ psp->fd = 0;
+ }
+
+ /* Initialize the screen specific GLX driver */
+ if (psp->DriverAPI.InitDriver) {
+ if (!(*psp->DriverAPI.InitDriver)(psp)) {
+ fprintf(stderr, "libGL error: InitDriver failed\n");
+ free(psp->pDevPriv);
+ free(psp);
+ return NULL;
+ }
+ }
+
+ psp->entry.destroyScreen = driDestroyScreen;
+ psp->entry.createContext = driCreateContext;
+ psp->entry.createDrawable = driCreateDrawable;
+
+ return psp;
+}
+
+/**
+ * Calculate amount of swap interval used between GLX buffer swaps.
+ *
+ * The usage value, on the range [0,max], is the fraction of total swap
+ * interval time used between GLX buffer swaps is calculated.
+ *
+ * \f$p = t_d / (i * t_r)\f$
+ *
+ * Where \f$t_d\$f is the time since the last GLX buffer swap, \f$i\f$ is the
+ * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
+ * required for a single vertical refresh period (as returned by \c
+ * glXGetMscRateOML).
+ *
+ * See the documentation for the GLX_MESA_swap_frame_usage extension for more
+ * details.
+ *
+ * \param dPriv Pointer to the private drawable structure.
+ * \return If less than a single swap interval time period was required
+ * between GLX buffer swaps, a number greater than 0 and less than
+ * 1.0 is returned. If exactly one swap interval time period is
+ * required, 1.0 is returned, and if more than one is required then
+ * a number greater than 1.0 will be returned.
+ *
+ * \sa glXSwapIntervalSGI(), glXGetMscRateOML().
+ */
+float
+driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
+ int64_t current_ust )
+{
+ return 0.0f;
+}
+
+/**
+ * Compare the current GLX API version with a driver supplied required version.
+ *
+ * The minimum required version is compared with the API version exported by
+ * the \c __glXGetInternalVersion function (in libGL.so).
+ *
+ * \param required_version Minimum required internal GLX API version.
+ * \return A tri-value return, as from strcmp is returned. A value less
+ * than, equal to, or greater than zero will be returned if the
+ * internal GLX API version is less than, equal to, or greater
+ * than \c required_version.
+ *
+ * \sa __glXGetInternalVersion().
+ */
+int driCompareGLXAPIVersion( GLuint required_version )
+{
+ return 0;
+}
+
+/*@}*/
diff --git a/src/glx/mini/dri_util.h b/src/glx/mini/dri_util.h
new file mode 100644
index 00000000000..b653b3c4316
--- /dev/null
+++ b/src/glx/mini/dri_util.h
@@ -0,0 +1,523 @@
+/**
+ * \file dri_util.h
+ * \brief DRI utility functions definitions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * Look for more comments in the dri_util.c file.
+ *
+ * \author Kevin E. Martin <[email protected]>
+ * \author Brian Paul <[email protected]>
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _DRI_UTIL_H_
+#define _DRI_UTIL_H_
+
+#include <inttypes.h>
+#include "dri.h" /* public entry points */
+#include "sarea.h" /* for XF86DRISAREAPtr */
+
+#define _SOLO
+
+typedef unsigned long CARD32;
+typedef int (* PFNGLXGETUSTPROC) ( uint64_t * ust );
+
+typedef struct __DRIdisplayPrivateRec __DRIdisplayPrivate; /**< \brief Alias for __DRIdisplayPrivateRec */
+typedef struct __DRIscreenPrivateRec __DRIscreenPrivate; /**< \brief Alias for __DRIscreenPrivateRec */
+typedef struct __DRIcontextPrivateRec __DRIcontextPrivate; /**< \brief Alias for __DRIcontextPrivateRec */
+typedef struct __DRIdrawablePrivateRec __DRIdrawablePrivate; /**< \brief Alias for __DRIdrawablePrivateRec */
+typedef struct __DRIswapInfoRec __DRIswapInfo; /**< \brief Alias for __DRIswapInfoPrivateRec */
+
+
+/**
+ * Used by DRI_VALIDATE_DRAWABLE_INFO
+ */
+#define DRI_VALIDATE_DRAWABLE_INFO_ONCE(pDrawPriv) \
+ do { \
+ if (*(pDrawPriv->pStamp) != pDrawPriv->lastStamp) { \
+ __driUtilUpdateDrawableInfo(pDrawPriv); \
+ } \
+ } while (0)
+
+
+/**
+ * \brief Utility macro to validate the drawable information.
+ *
+ * See __DRIdrawablePrivateRec::pStamp and __DRIdrawablePrivateRec::lastStamp.
+ */
+#define DRI_VALIDATE_DRAWABLE_INFO(psp, pdp) \
+do { \
+ DRI_VALIDATE_DRAWABLE_INFO_ONCE(pdp); \
+} while (0)
+
+
+/**
+ * Driver callback functions.
+ *
+ * Each DRI driver must have one of these structures with all the pointers set
+ * to appropriate functions within the driver.
+ *
+ * When glXCreateContext() is called, for example, it'll call a helper function
+ * dri_util.c which in turn will jump through the \a CreateContext pointer in
+ * this structure.
+ */
+struct __DriverAPIRec {
+ /**
+ * Driver initialization callback
+ */
+ GLboolean (*InitDriver)(__DRIscreenPrivate *driScrnPriv);
+
+ /**
+ * Screen destruction callback
+ */
+ void (*DestroyScreen)(__DRIscreenPrivate *driScrnPriv);
+
+ /**
+ * Context creation callback
+ */
+ GLboolean (*CreateContext)(const __GLcontextModes *glVis,
+ __DRIcontextPrivate *driContextPriv,
+ void *sharedContextPrivate);
+
+ /**
+ * Context destruction callback
+ */
+ void (*DestroyContext)(__DRIcontextPrivate *driContextPriv);
+
+ /**
+ * Buffer (drawable) creation callback
+ */
+ GLboolean (*CreateBuffer)(__DRIscreenPrivate *driScrnPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ const __GLcontextModes *glVis,
+ GLboolean pixmapBuffer);
+
+ /**
+ * Buffer (drawable) destruction callback
+ */
+ void (*DestroyBuffer)(__DRIdrawablePrivate *driDrawPriv);
+
+ /**
+ * Buffer swapping callback
+ */
+ void (*SwapBuffers)(__DRIdrawablePrivate *driDrawPriv);
+
+ /**
+ * Context activation callback
+ */
+ GLboolean (*MakeCurrent)(__DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv);
+
+ /**
+ * Context unbinding callback
+ */
+ GLboolean (*UnbindContext)(__DRIcontextPrivate *driContextPriv);
+
+ /**
+ * Full screen mode opening callback.
+ *
+ * \deprecated Full screen functionality is no longer used by DRI.
+ * Drivers should simply install a function returning
+ * \c GL_TRUE for backwards compatability.
+ */
+ GLboolean (*OpenFullScreen)(__DRIcontextPrivate *driContextPriv);
+
+ /**
+ * Full screen mode closing callback.
+ *
+ * \deprecated Full screen functionality is no longer used by DRI.
+ * Drivers should simply install a function returning
+ * \c GL_TRUE for backwards compatability.
+ */
+ GLboolean (*CloseFullScreen)(__DRIcontextPrivate *driContextPriv);
+
+ /* Retrieves statistics about buffer swap operations. Required if
+ * GLX_OML_sync_control or GLX_MESA_swap_frame_usage is supported.
+ */
+ int (*GetSwapInfo)( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo );
+
+
+ /* Required if GLX_SGI_video_sync or GLX_OML_sync_control is
+ * supported.
+ */
+ int (*GetMSC)( __DRIscreenPrivate * priv, int64_t * count );
+
+ /**
+ * These are required if GLX_OML_sync_control is supported.
+ */
+ /*@{*/
+ int (*WaitForMSC)( __DRIdrawablePrivate *priv, int64_t target_msc,
+ int64_t divisor, int64_t remainder,
+ int64_t * msc );
+ int (*WaitForSBC)( __DRIdrawablePrivate *priv, int64_t target_sbc,
+ int64_t * msc, int64_t * sbc );
+
+ int64_t (*SwapBuffersMSC)( __DRIdrawablePrivate *priv, int64_t target_msc,
+ int64_t divisor, int64_t remainder );
+ /*@}*/
+};
+
+
+struct __DRIswapInfoRec {
+ /**
+ * Number of swapBuffers operations that have been *completed*.
+ */
+ uint64_t swap_count;
+
+ /*
+ * Unadjusted system time of the last buffer swap. This is the time
+ * when the swap completed, not the time when swapBuffers was called.
+ */
+ int64_t swap_ust;
+
+ /*
+ * Number of swap operations that occurred after the swap deadline. That
+ * is if a swap happens more than swap_interval frames after the previous
+ * swap, it has missed its deadline. If swap_interval is 0, then the
+ * swap deadline is 1 frame after the previous swap.
+ */
+ uint64_t swap_missed_count;
+
+ /*
+ * Amount of time used by the last swap that missed its deadline. This
+ * is calculated as (__glXGetUST() - swap_ust) / (swap_interval *
+ * time_for_single_vrefresh)). If the actual value of swap_interval is
+ * 0, then 1 is used instead. If swap_missed_count is non-zero, this
+ * should be greater-than 1.0.
+ */
+ float swap_missed_usage;
+};
+
+
+/**
+ * \brief Per-drawable private DRI driver information.
+ *
+ */
+struct __DRIdrawablePrivateRec {
+
+ /**
+ * \brief Public entry points
+ */
+ __DRIdrawable entry;
+
+ /**
+ * \brief Kernel drawable handle
+ *
+ * \note Not currently used.
+ */
+ drmDrawable hHWDrawable;
+
+ /**
+ * \brief Driver's private drawable information.
+ *
+ * This structure is opaque.
+ */
+ void *driverPrivate;
+
+ /**
+ * \brief Reference count for number of context's currently bound to this
+ * drawable.
+ *
+ * Once it reaches zero, the drawable can be destroyed.
+ *
+ * \note This behavior will change with GLX 1.3.
+ */
+ int refcount;
+
+ /**
+ * \brief Index of this drawable information in the SAREA.
+ */
+ unsigned int index;
+
+ /**
+ * \brief Pointer to the "drawable has changed ID" stamp in the SAREA.
+ */
+ unsigned int *pStamp;
+
+ /**
+ * \brief Last value of the stamp.
+ *
+ * If this differs from the value stored at
+ * __DRIdrawablePrivateRec::pStamp, then the drawable information has been
+ * modified by the X server, and the drawable information (below) should be
+ * retrieved from the X server.
+ */
+ unsigned int lastStamp;
+
+ /**
+ * \name Drawable
+ * Drawable information used in software fallbacks.
+ */
+ /*@{*/
+ int x;
+ int y;
+ int w;
+ int h;
+ int numClipRects;
+ XF86DRIClipRectPtr pClipRects;
+ /*@}*/
+
+ /**
+ * \name Back and depthbuffer
+ * Information about the back and depthbuffer where different from above.
+ */
+ /*@{*/
+ int backX;
+ int backY;
+ int backClipRectType;
+ int numBackClipRects;
+ XF86DRIClipRectPtr pBackClipRects;
+ /*@}*/
+
+ /**
+ * \brief Pointer to context to which this drawable is currently bound.
+ */
+ __DRIcontextPrivate *driContextPriv;
+
+ /**
+ * \brief Pointer to screen on which this drawable was created.
+ */
+ __DRIscreenPrivate *driScreenPriv;
+
+ int cpp;
+ void *frontBuffer;
+ void *backBuffer;
+ void *currentBuffer;
+ int currentPitch;
+
+ int depthCpp;
+ void *depthBuffer;
+ int depthPitch;
+
+ /**
+ * \brief Called via glXSwapBuffers().
+ */
+ void (*swapBuffers)( __DRIdrawablePrivate *dPriv );
+};
+
+/**
+ * \brief Per-context private driver information.
+ */
+struct __DRIcontextPrivateRec {
+ /**
+ * \brief Public entry points
+ */
+ __DRIcontext entry;
+
+ /**
+ * \brief Kernel context handle used to access the device lock.
+ */
+ drmContext hHWContext;
+
+ /**
+ * \brief Device driver's private context data. This structure is opaque.
+ */
+ void *driverPrivate;
+
+ /**
+ * \brief Pointer to drawable currently bound to this context.
+ */
+ __DRIdrawablePrivate *driDrawablePriv;
+
+ /**
+ * \brief Pointer to screen on which this context was created.
+ */
+ __DRIscreenPrivate *driScreenPriv;
+};
+
+/**
+ * \brief Per-screen private driver information.
+ */
+struct __DRIscreenPrivateRec {
+
+ /**
+ * \brief Public entry points
+ */
+ __DRIscreen entry;
+
+ /**
+ * \brief Callback functions into the hardware-specific DRI driver code.
+ */
+ struct __DriverAPIRec DriverAPI;
+
+ /**
+ * \name DDX version
+ * DDX / 2D driver version information.
+ */
+ /*@{*/
+ int ddxMajor;
+ int ddxMinor;
+ int ddxPatch;
+ /*@}*/
+
+ /**
+ * \name DRI version
+ * DRI X extension version information.
+ */
+ /*@{*/
+ int driMajor;
+ int driMinor;
+ int driPatch;
+ /*@}*/
+
+ /**
+ * \name DRM version
+ * DRM (kernel module) version information.
+ */
+ /*@{*/
+ int drmMajor;
+ int drmMinor;
+ int drmPatch;
+ /*@}*/
+
+ /**
+ * \brief ID used when the client sets the drawable lock.
+ *
+ * The X server uses this value to detect if the client has died while
+ * holding the drawable lock.
+ */
+ int drawLockID;
+
+ /**
+ * \brief File descriptor returned when the kernel device driver is opened.
+ *
+ * Used to:
+ * - authenticate client to kernel
+ * - map the frame buffer, SAREA, etc.
+ * - close the kernel device driver
+ */
+ int fd;
+
+ /**
+ * \brief SAREA pointer
+ *
+ * Used to access:
+ * - the device lock
+ * - the device-independent per-drawable and per-context(?) information
+ */
+ XF86DRISAREAPtr pSAREA;
+
+ /**
+ * \name Direct frame buffer access information
+ * Used for software fallbacks.
+ */
+ /*@{*/
+ unsigned char *pFB;
+ int fbSize;
+ int fbOrigin;
+ int fbStride;
+ int fbWidth;
+ int fbHeight;
+ int fbBPP;
+ /*@}*/
+
+ /**
+ * \name Device-dependent private information (stored in the SAREA).
+ *
+ * This data is accessed by the client driver only.
+ */
+ /*@{*/
+ void *pDevPriv;
+ int devPrivSize;
+ /*@}*/
+
+ /**
+ * \brief Dummy context to which drawables are bound when not bound to any
+ * other context.
+ *
+ * A dummy hHWContext is created for this context, and is used by the GL
+ * core when a hardware lock is required but the drawable is not currently
+ * bound (e.g., potentially during a SwapBuffers request). The dummy
+ * context is created when the first "real" context is created on this
+ * screen.
+ */
+ __DRIcontextPrivate dummyContextPriv;
+
+ /**
+ * \brief Hash table to hold the drawable information for this screen.
+ */
+ void *drawHash;
+
+ /**
+ * \brief Device-dependent private information (not stored in the SAREA).
+ *
+ * This pointer is never touched by the DRI layer.
+ */
+ void *private;
+
+ /**
+ * \brief Full screen mode.
+ *
+ * If we're in full screen mode (via DRIOpenFullScreen()), this points to
+ * the drawable that was bound. Otherwise, this is NULL.
+ */
+ __DRIdrawablePrivate *fullscreen;
+};
+
+extern void
+__driUtilMessage(const char *f, ...);
+
+
+extern void
+__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp);
+
+
+extern __DRIscreenPrivate *
+__driUtilCreateScreen(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI);
+
+__DRIscreenPrivate *
+__driUtilCreateScreenNoDRM(struct DRIDriverRec *driver,
+ struct DRIDriverContextRec *driverContext,
+ const struct __DriverAPIRec *driverAPI);
+
+extern float
+driCalculateSwapUsage( __DRIdrawablePrivate *dPriv,
+ int64_t last_swap_ust, int64_t current_ust );
+
+/* Test the version of the internal GLX API. Returns a value like strcmp. */
+extern int
+driCompareGLXAPIVersion( GLuint required_version );
+
+/** This is optionally implemented in each driver */
+extern void
+__driRegisterExtensions( void );
+
+#endif /* _DRI_UTIL_H_ */
diff --git a/src/glx/mini/driver.h b/src/glx/mini/driver.h
new file mode 100644
index 00000000000..a3ec96083b8
--- /dev/null
+++ b/src/glx/mini/driver.h
@@ -0,0 +1,177 @@
+/**
+ * \file driver.h
+ * \brief DRI utility functions definitions.
+ *
+ * This module acts as glue between GLX and the actual hardware driver. A DRI
+ * driver doesn't really \e have to use any of this - it's optional. But, some
+ * useful stuff is done here that otherwise would have to be duplicated in most
+ * drivers.
+ *
+ * Basically, these utility functions take care of some of the dirty details of
+ * screen initialization, context creation, context binding, DRM setup, etc.
+ *
+ * These functions are compiled into each DRI driver so libGL.so knows nothing
+ * about them.
+ *
+ * Look for more comments in the dri_util.c file.
+ *
+ * \author Kevin E. Martin <[email protected]>
+ * \author Brian Paul <[email protected]>
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _driver_H_
+#define _driver_H_
+
+#define CAPI /* XXX this should be globally defined somewhere */
+
+#include "GL/gl.h"
+#include "GL/internal/glcore.h"
+
+/**
+ * \brief Clip rectangle definition.
+ */
+typedef struct _XF86DRIClipRect {
+ unsigned short x1; /**< \brief Upper: inclusive */
+ unsigned short y1; /**< \brief Left: inclusive */
+ unsigned short x2; /**< \brief Lower: exclusive */
+ unsigned short y2; /**< \brief Right: exclusive */
+} XF86DRIClipRectRec, *XF86DRIClipRectPtr;
+
+/**
+ * \brief DRIDriverContext type.
+ */
+typedef struct DRIDriverContextRec {
+ const char *pciBusID;
+ int pciBus;
+ int pciDevice;
+ int pciFunc;
+ int chipset;
+ int bpp;
+ int cpp;
+
+ unsigned long FBStart; /**< \brief physical address of the framebuffer */
+ unsigned long MMIOStart; /**< \brief physical address of the MMIO region */
+
+ int FBSize; /**< \brief size of the mmap'd framebuffer in bytes */
+ int MMIOSize; /**< \brief size of the mmap'd MMIO region in bytes */
+
+ void *FBAddress; /**< \brief start of the mmap'd framebuffer */
+ void *MMIOAddress; /**< \brief start of the mmap'd MMIO region */
+
+ /**
+ * \brief Client configuration details
+ *
+ * These are computed on the server and sent to clients as part of
+ * the initial handshaking.
+ */
+ struct {
+ unsigned long hSAREA;
+ int SAREASize;
+ unsigned long hFrameBuffer;
+ int fbOrigin;
+ int fbSize;
+ int fbStride;
+ int virtualWidth;
+ int virtualHeight;
+ } shared;
+
+ /**
+ * \name From DRIInfoRec
+ */
+ /*@{*/
+ int drmFD; /**< \brief DRM device file descriptor */
+ struct _XF86DRISAREA *pSAREA;
+ unsigned int serverContext; /**< \brief DRM context only active on server */
+ /*@}*/
+
+
+ /**
+ * \name Driver private
+ *
+ * Populated by __driInitFBDev()
+ */
+ /*@{*/
+ void *driverPrivate;
+ void *driverClientMsg;
+ int driverClientMsgSize;
+ /*@}*/
+} DRIDriverContext;
+
+/**
+ * \brief Interface to the DRI driver.
+ *
+ * This structure is retrieved from the loadable driver by the \e
+ * __driDriver symbol to access the Mini GLX specific hardware
+ * initialization and take down routines.
+ */
+typedef struct DRIDriverRec {
+ /**
+ * \brief Get the list of supported gl context modes.
+ */
+ int (*initContextModes)( const DRIDriverContext *context,
+ int *numModes, const __GLcontextModes **modes );
+ /**
+ * \brief Validate the framebuffer device mode
+ */
+ int (*validateMode)( const DRIDriverContext *context );
+
+ /**
+ * \brief Examine mode returned by fbdev (may differ from the one
+ * requested), restore any hw regs clobbered by fbdev.
+ */
+ int (*postValidateMode)( const DRIDriverContext *context );
+
+ /**
+ * \brief Initialize the framebuffer device.
+ */
+ int (*initFBDev)( DRIDriverContext *context );
+
+ /**
+ * \brief Halt the framebuffer device.
+ */
+ void (*haltFBDev)( DRIDriverContext *context );
+
+
+ /**
+ * \brief Idle and shutdown hardware in preparation for a VT switch.
+ */
+ int (*shutdownHardware)( const DRIDriverContext *context );
+
+ /**
+ * \brief Restore hardware state after regaining the VT.
+ */
+ int (*restoreHardware)( const DRIDriverContext *context );
+
+ /**
+ * \brief Notify hardware driver of gain/loose focus. May be zero
+ * as this is of limited utility for most drivers.
+ */
+ void (*notifyFocus)( int have_focus );
+} DRIDriver;
+
+#endif /* _driver_H_ */
diff --git a/src/glx/mini/drm.h b/src/glx/mini/drm.h
new file mode 100644
index 00000000000..4180d1eb1a3
--- /dev/null
+++ b/src/glx/mini/drm.h
@@ -0,0 +1,657 @@
+/**
+ * \file drm.h
+ * \brief Header for the Direct Rendering Manager
+ *
+ * This file defines the DRM device ioctls and the strucutre of respective user
+ * arguments.
+ *
+ * \sa xf86drm.h and xf86drm.c for an user-friendlier interface.
+ *
+ * \author Rickard E. (Rik) Faith <[email protected]>
+ *
+ * \par Acknowledgements:
+ * Dec 1999, Richard Henderson <[email protected]>, move to generic \c cmpxchg.
+ */
+
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#if defined(__linux__)
+#include <linux/config.h>
+#include <asm/ioctl.h> /* For _IO* macros */
+#define DRM_IOCTL_NR(n) _IOC_NR(n)
+#define DRM_IOC_VOID _IOC_NONE
+#define DRM_IOC_READ _IOC_READ
+#define DRM_IOC_WRITE _IOC_WRITE
+#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) && defined(XFree86Server)
+/* Prevent name collision when including sys/ioccom.h */
+#undef ioctl
+#include <sys/ioccom.h>
+#define ioctl(a,b,c) xf86ioctl(a,b,c)
+#else
+#include <sys/ioccom.h>
+#endif /* __FreeBSD__ && xf86ioctl */
+#define DRM_IOCTL_NR(n) ((n) & 0xff)
+#define DRM_IOC_VOID IOC_VOID
+#define DRM_IOC_READ IOC_OUT
+#define DRM_IOC_WRITE IOC_IN
+#define DRM_IOC_READWRITE IOC_INOUT
+#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
+#endif
+
+#define XFREE86_VERSION(major,minor,patch,snap) \
+ ((major << 16) | (minor << 8) | patch)
+
+#ifndef CONFIG_XFREE86_VERSION
+#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0)
+#endif
+
+#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
+#define DRM_PROC_DEVICES "/proc/devices"
+#define DRM_PROC_MISC "/proc/misc"
+#define DRM_PROC_DRM "/proc/drm"
+#define DRM_DEV_DRM "/dev/drm"
+#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID 0
+#define DRM_DEV_GID 0
+#endif
+
+#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
+#define DRM_MAJOR 226
+#define DRM_MAX_MINOR 15
+#endif
+#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */
+#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */
+#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */
+#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */
+
+#define _DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */
+#define _DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */
+#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+
+typedef unsigned long drm_handle_t;
+typedef unsigned int drm_context_t;
+typedef unsigned int drm_drawable_t;
+typedef unsigned int drm_magic_t;
+
+
+/**
+ * Cliprect.
+ *
+ * \warning: If you change this structure, make sure you change
+ * XF86DRIClipRectRec in the server as well
+ *
+ * \note KW: Actually it's illegal to change either for
+ * backwards-compatibility reasons.
+ */
+typedef struct drm_clip_rect {
+ unsigned short x1;
+ unsigned short y1;
+ unsigned short x2;
+ unsigned short y2;
+} drm_clip_rect_t;
+
+
+/**
+ * Texture region,
+ */
+typedef struct drm_tex_region {
+ unsigned char next;
+ unsigned char prev;
+ unsigned char in_use;
+ unsigned char padding;
+ unsigned int age;
+} drm_tex_region_t;
+
+
+/**
+ * \brief DRM_IOCTL_VERSION ioctl argument type.
+ *
+ * \sa drmGetVersion().
+ */
+typedef struct drm_version {
+ int version_major; /**< Major version */
+ int version_minor; /**< Minor version */
+ int version_patchlevel;/**< Patch level */
+ size_t name_len; /**< Length of name buffer */
+ char *name; /**< Name of driver */
+ size_t date_len; /**< Length of date buffer */
+ char *date; /**< User-space buffer to hold date */
+ size_t desc_len; /**< Length of desc buffer */
+ char *desc; /**< User-space buffer to hold desc */
+} drm_version_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_UNIQUE ioctl argument type.
+ *
+ * \sa drmGetBusid() and drmSetBusId().
+ */
+typedef struct drm_unique {
+ size_t unique_len; /**< Length of unique */
+ char *unique; /**< Unique name for driver instantiation */
+} drm_unique_t;
+
+
+typedef struct drm_list {
+ int count; /**< Length of user-space structures */
+ drm_version_t *version;
+} drm_list_t;
+
+
+typedef struct drm_block {
+ int unused;
+} drm_block_t;
+
+
+/**
+ * \brief DRM_IOCTL_CONTROL ioctl argument type.
+ *
+ * \sa drmCtlInstHandler() and drmCtlUninstHandler().
+ */
+typedef struct drm_control {
+ enum {
+ DRM_ADD_COMMAND,
+ DRM_RM_COMMAND,
+ DRM_INST_HANDLER,
+ DRM_UNINST_HANDLER
+ } func;
+ int irq;
+} drm_control_t;
+
+
+/**
+ * \brief Type of memory to map.
+ */
+typedef enum drm_map_type {
+ _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */
+ _DRM_REGISTERS = 1, /**< no caching, no core dump */
+ _DRM_SHM = 2, /**< shared, cached */
+ _DRM_AGP = 3, /**< AGP/GART */
+ _DRM_SCATTER_GATHER = 4 /**< Scatter/gather memory for PCI DMA */
+} drm_map_type_t;
+
+
+/**
+ * \brief Memory mapping flags.
+ */
+typedef enum drm_map_flags {
+ _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */
+ _DRM_READ_ONLY = 0x02,
+ _DRM_LOCKED = 0x04, /**< shared, cached, locked */
+ _DRM_KERNEL = 0x08, /**< kernel requires access */
+ _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
+ _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */
+ _DRM_REMOVABLE = 0x40 /**< Removable mapping */
+} drm_map_flags_t;
+
+
+typedef struct drm_ctx_priv_map {
+ unsigned int ctx_id; /**< Context requesting private mapping */
+ void *handle; /**< Handle of map */
+} drm_ctx_priv_map_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
+ * argument type.
+ *
+ * \sa drmAddMap().
+ */
+typedef struct drm_map {
+ unsigned long offset; /**< Requested physical address (0 for SAREA)*/
+ unsigned long size; /**< Requested physical size (bytes) */
+ drm_map_type_t type; /**< Type of memory to map */
+ drm_map_flags_t flags; /**< Flags */
+ void *handle; /**< User-space: "Handle" to pass to mmap() */
+ /**< Kernel-space: kernel-virtual address */
+ int mtrr; /**< MTRR slot used */
+ /* Private data */
+} drm_map_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_CLIENT ioctl argument type.
+ */
+typedef struct drm_client {
+ int idx; /**< Which client desired? */
+ int auth; /**< Is client authenticated? */
+ unsigned long pid; /**< Process ID */
+ unsigned long uid; /**< User ID */
+ unsigned long magic; /**< Magic */
+ unsigned long iocs; /**< Ioctl count */
+} drm_client_t;
+
+
+typedef enum {
+ _DRM_STAT_LOCK,
+ _DRM_STAT_OPENS,
+ _DRM_STAT_CLOSES,
+ _DRM_STAT_IOCTLS,
+ _DRM_STAT_LOCKS,
+ _DRM_STAT_UNLOCKS,
+ _DRM_STAT_VALUE, /**< Generic value */
+ _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */
+ _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */
+
+ _DRM_STAT_IRQ, /**< IRQ */
+ _DRM_STAT_PRIMARY, /**< Primary DMA bytes */
+ _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */
+ _DRM_STAT_DMA, /**< DMA */
+ _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */
+ _DRM_STAT_MISSED /**< Missed DMA opportunity */
+
+ /* Add to the *END* of the list */
+} drm_stat_type_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_STATS ioctl argument type.
+ */
+typedef struct drm_stats {
+ unsigned long count;
+ struct {
+ unsigned long value;
+ drm_stat_type_t type;
+ } data[15];
+} drm_stats_t;
+
+
+/**
+ * \brief Hardware locking flags.
+ */
+typedef enum drm_lock_flags {
+ _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */
+ _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */
+ _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */
+ _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */
+ /* These *HALT* flags aren't supported yet
+ -- they will be used to support the
+ full-screen DGA-like mode. */
+ _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */
+ _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */
+} drm_lock_flags_t;
+
+
+/**
+ * \brief DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
+ *
+ * \sa drmGetLock() and drmUnlock().
+ */
+typedef struct drm_lock {
+ int context;
+ drm_lock_flags_t flags;
+} drm_lock_t;
+
+
+/**
+ * \brief DMA flags
+ *
+ * \warning
+ * These values \e must match xf86drm.h.
+ *
+ * \sa drm_dma.
+ */
+typedef enum drm_dma_flags {
+ /* Flags for DMA buffer dispatch */
+ _DRM_DMA_BLOCK = 0x01, /**<
+ * Block until buffer dispatched.
+ *
+ * \note The buffer may not yet have
+ * been processed by the hardware --
+ * getting a hardware lock with the
+ * hardware quiescent will ensure
+ * that the buffer has been
+ * processed.
+ */
+ _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */
+ _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */
+
+ /* Flags for DMA buffer request */
+ _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */
+ _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */
+ _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */
+} drm_dma_flags_t;
+
+
+/**
+ * \brief DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
+ *
+ * \sa drmAddBufs().
+ */
+typedef struct drm_buf_desc {
+ int count; /**< Number of buffers of this size */
+ int size; /**< Size in bytes */
+ int low_mark; /**< Low water mark */
+ int high_mark; /**< High water mark */
+ enum {
+ _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
+ _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
+ _DRM_SG_BUFFER = 0x04 /**< Scatter/gather memory buffer */
+ } flags;
+ unsigned long agp_start; /**<
+ * Start address of where the AGP buffers are
+ * in the AGP aperture
+ */
+} drm_buf_desc_t;
+
+
+/**
+ * \brief DRM_IOCTL_INFO_BUFS ioctl argument type.
+ */
+typedef struct drm_buf_info {
+ int count; /**< Entries in list */
+ drm_buf_desc_t *list;
+} drm_buf_info_t;
+
+
+/**
+ * \brief DRM_IOCTL_FREE_BUFS ioctl argument type.
+ */
+typedef struct drm_buf_free {
+ int count;
+ int *list;
+} drm_buf_free_t;
+
+
+/**
+ * \brief Buffer information
+ *
+ * \sa drm_buf_map.
+ */
+typedef struct drm_buf_pub {
+ int idx; /**< Index into the master buffer list */
+ int total; /**< Buffer size */
+ int used; /**< Amount of buffer in use (for DMA) */
+ void *address; /**< Address of buffer */
+} drm_buf_pub_t;
+
+
+/**
+ * \brief DRM_IOCTL_MAP_BUFS ioctl argument type.
+ */
+typedef struct drm_buf_map {
+ int count; /**< Length of the buffer list */
+ void *virtual; /**< Mmap'd area in user-virtual */
+ drm_buf_pub_t *list; /**< Buffer information */
+} drm_buf_map_t;
+
+
+/**
+ * \brief DRM_IOCTL_DMA ioctl argument type.
+ *
+ * Indices here refer to the offset into the buffer list in drm_buf_get.
+ *
+ * \sa drmDMA().
+ */
+typedef struct drm_dma {
+ int context; /**< Context handle */
+ int send_count; /**< Number of buffers to send */
+ int *send_indices; /**< List of handles to buffers */
+ int *send_sizes; /**< Lengths of data to send */
+ drm_dma_flags_t flags; /**< Flags */
+ int request_count; /**< Number of buffers requested */
+ int request_size; /**< Desired size for buffers */
+ int *request_indices; /**< Buffer information */
+ int *request_sizes;
+ int granted_count; /**< Number of buffers granted */
+} drm_dma_t;
+
+
+typedef enum {
+ _DRM_CONTEXT_PRESERVED = 0x01,
+ _DRM_CONTEXT_2DONLY = 0x02
+} drm_ctx_flags_t;
+
+
+/**
+ * \brief DRM_IOCTL_ADD_CTX ioctl argument type.
+ *
+ * \sa drmCreateContext() and drmDestroyContext().
+ */
+typedef struct drm_ctx {
+ drm_context_t handle;
+ drm_ctx_flags_t flags;
+} drm_ctx_t;
+
+
+/**
+ * \brief DRM_IOCTL_RES_CTX ioctl argument type.
+ */
+typedef struct drm_ctx_res {
+ int count;
+ drm_ctx_t *contexts;
+} drm_ctx_res_t;
+
+
+/**
+ * \brief DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
+ */
+typedef struct drm_draw {
+ drm_drawable_t handle;
+} drm_draw_t;
+
+
+/**
+ * \brief DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
+ */
+typedef struct drm_auth {
+ drm_magic_t magic;
+} drm_auth_t;
+
+
+/**
+ * \brief DRM_IOCTL_IRQ_BUSID ioctl argument type.
+ *
+ * \sa drmGetInterruptFromBusID().
+ */
+typedef struct drm_irq_busid {
+ int irq; /**< IRQ number */
+ int busnum; /**< bus number */
+ int devnum; /**< device number */
+ int funcnum; /**< function number */
+} drm_irq_busid_t;
+
+
+typedef enum {
+ _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
+ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
+ _DRM_VBLANK_SIGNAL = 0x8000 /**< Send signal instead of blocking */
+} drm_vblank_seq_type_t;
+
+
+#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
+
+
+struct drm_wait_vblank_request {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ unsigned long signal;
+};
+
+
+struct drm_wait_vblank_reply {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+};
+
+
+/**
+ * \brief DRM_IOCTL_WAIT_VBLANK ioctl argument type.
+ *
+ * \sa drmWaitVBlank().
+ */
+typedef union drm_wait_vblank {
+ struct drm_wait_vblank_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_wait_vblank_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_ENABLE ioctl argument type.
+ *
+ * \sa drmAgpEnable().
+ */
+typedef struct drm_agp_mode {
+ unsigned long mode; /**< AGP mode */
+} drm_agp_mode_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
+ *
+ * \sa drmAgpAlloc() and drmAgpFree().
+ */
+typedef struct drm_agp_buffer {
+ unsigned long size; /**< In bytes -- will round to page boundary */
+ unsigned long handle; /**< Used for binding / unbinding */
+ unsigned long type; /**< Type of memory to allocate */
+ unsigned long physical; /**< Physical used by i810 */
+} drm_agp_buffer_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
+ *
+ * \sa drmAgpBind() and drmAgpUnbind().
+ */
+typedef struct drm_agp_binding {
+ unsigned long handle; /**< From drm_agp_buffer */
+ unsigned long offset; /**< In bytes -- will round to page boundary */
+} drm_agp_binding_t;
+
+
+/**
+ * \brief DRM_IOCTL_AGP_INFO ioctl argument type.
+ *
+ * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(),
+ * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(),
+ * drmAgpVendorId() and drmAgpDeviceId().
+ */
+typedef struct drm_agp_info {
+ int agp_version_major;
+ int agp_version_minor;
+ unsigned long mode;
+ unsigned long aperture_base; /* physical address */
+ unsigned long aperture_size; /* bytes */
+ unsigned long memory_allowed; /* bytes */
+ unsigned long memory_used;
+
+ /* PCI information */
+ unsigned short id_vendor;
+ unsigned short id_device;
+} drm_agp_info_t;
+
+
+/**
+ * \brief DRM_IOCTL_SG_ALLOC ioctl argument type.
+ */
+typedef struct drm_scatter_gather {
+ unsigned long size; /**< In bytes -- will round to page boundary */
+ unsigned long handle; /**< Used for mapping / unmapping */
+} drm_scatter_gather_t;
+
+
+#define DRM_IOCTL_BASE 'd'
+#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type)
+#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
+
+#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t)
+#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
+#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t)
+#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t)
+#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t)
+#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t)
+#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t)
+
+#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
+#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
+#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t)
+#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t)
+#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t)
+#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t)
+#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t)
+#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t)
+#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t)
+#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t)
+#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t)
+
+#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, drm_map_t)
+
+#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, drm_ctx_priv_map_t)
+#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, drm_ctx_priv_map_t)
+
+#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t)
+#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t)
+#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t)
+#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t)
+#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
+#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t)
+#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t)
+#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t)
+#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t)
+#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t)
+#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t)
+#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t)
+#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t)
+
+#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
+#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
+#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t)
+#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t)
+#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t)
+#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t)
+
+#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
+#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t)
+
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+
+/**
+ * Device specific ioctls should only be in their respective headers
+ * The device specific ioctl range is from 0x40 to 0x79.
+ *
+ * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
+ * drmCommandReadWrite().
+ */
+#define DRM_COMMAND_BASE 0x40
+
+#endif
diff --git a/src/glx/mini/drmtest.c b/src/glx/mini/drmtest.c
new file mode 100644
index 00000000000..f9cad3994e0
--- /dev/null
+++ b/src/glx/mini/drmtest.c
@@ -0,0 +1,140 @@
+#include <assert.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include "xf86drm.h"
+
+char *pciBusID = "PCI:1:0:0";
+#define DRM_PAGE_SIZE 4096
+void *pSAREA;
+
+
+static int client( void )
+{
+ int fd, ret, err;
+ drmContext clientContext;
+
+ fprintf(stderr, "Opening client drm\n");
+
+ fd = drmOpen(NULL,pciBusID);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open DRM: %s\n", strerror(-fd));
+ return 1;
+ }
+
+
+ fprintf(stderr, "Create server context\n");
+ if ((err = drmCreateContext(fd, &clientContext)) != 0) {
+ fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+
+ fprintf(stderr, "DRM_LOCK( %d %p %d )\n", fd, pSAREA, clientContext);
+ DRM_LOCK(fd, pSAREA, clientContext, 0);
+ fprintf(stderr, "locked\n");
+ DRM_UNLOCK(fd, pSAREA, clientContext);
+ fprintf(stderr, "DRM_UNLOCK finished\n");
+
+
+ fprintf(stderr, "Closing client drm: %d\n", fd);
+ ret = drmClose(fd);
+ fprintf(stderr, "done %d\n", ret);
+
+ return ret;
+}
+
+int main( int argc, char *argv[] )
+{
+ char *drmModuleName = "radeon";
+ int drmFD;
+ int err;
+ int SAREASize;
+ drmHandle hSAREA;
+ drmContext serverContext;
+
+ /* Note that drmOpen will try to load the kernel module, if needed. */
+ drmFD = drmOpen(drmModuleName, NULL );
+ if (drmFD < 0) {
+ /* failed to open DRM */
+ fprintf(stderr, "[drm] drmOpen failed\n");
+ return 0;
+ }
+
+
+ if ((err = drmSetBusid(drmFD, pciBusID)) < 0) {
+ drmClose(drmFD);
+ fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
+ drmFD, pciBusID, strerror(-err));
+ return 0;
+ }
+
+
+ SAREASize = DRM_PAGE_SIZE;
+
+ if (drmAddMap( drmFD,
+ 0,
+ SAREASize,
+ DRM_SHM,
+ DRM_CONTAINS_LOCK,
+ &hSAREA) < 0)
+ {
+ drmClose(drmFD);
+ fprintf(stderr, "[drm] drmAddMap failed\n");
+ return 0;
+ }
+
+ fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n",
+ SAREASize, hSAREA);
+
+ if (drmMap( drmFD,
+ hSAREA,
+ SAREASize,
+ (drmAddressPtr)(&pSAREA)) < 0)
+ {
+ drmClose(drmFD);
+ fprintf(stderr, "[drm] drmMap failed\n");
+ return 0;
+ }
+
+ memset(pSAREA, 0, SAREASize);
+ fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
+ hSAREA, pSAREA, SAREASize);
+
+ fprintf(stderr, "Create server context\n");
+ if ((err = drmCreateContext(drmFD, &serverContext)) != 0) {
+ fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+
+ fprintf(stderr, "DRM_LOCK( %d %p %d )\n", drmFD, pSAREA, serverContext);
+ DRM_LOCK(drmFD, pSAREA, serverContext, 0);
+ fprintf(stderr, "locked\n");
+ DRM_UNLOCK(drmFD, pSAREA, serverContext);
+ fprintf(stderr, "DRM_UNLOCK finished\n");
+
+
+ client();
+
+
+ fprintf(stderr, "DRM_LOCK( %d %p %d )\n", drmFD, pSAREA, serverContext);
+ DRM_LOCK(drmFD, pSAREA, serverContext, 0);
+ fprintf(stderr, "locked\n");
+ DRM_UNLOCK(drmFD, pSAREA, serverContext);
+ fprintf(stderr, "DRM_UNLOCK finished\n");
+
+
+ drmUnmap(pSAREA, SAREASize);
+ fprintf(stderr, "[drm] unmapped SAREA 0x%08lx from %p, size %d\n",
+ hSAREA, pSAREA, SAREASize);
+ pSAREA = 0;
+
+ fprintf(stderr, "%s: Closing DRM fd\n", __FUNCTION__);
+ (void)drmClose(drmFD);
+
+ return 0;
+}
+
+
+
diff --git a/src/glx/mini/example.miniglx.conf b/src/glx/mini/example.miniglx.conf
new file mode 100644
index 00000000000..06adbffcf35
--- /dev/null
+++ b/src/glx/mini/example.miniglx.conf
@@ -0,0 +1,26 @@
+# Example miniglx configuration file (/etc/miniglx.conf)
+#
+
+# Framebuffer device to open: Might need to change this on dual-head
+# systems.
+fbdevDevice=/dev/fb0
+
+# Which driver?
+# radeon_dri.so -- HW accelerated radeon driver
+# fb_dri.so -- Software rasterizer
+clientDriverName=radeon_dri.so
+
+# The pci bus id of the video card. Find this with scanpci, lspci or
+# look in /proc/pci.
+pciBusID=PCI:1:0:0
+
+# Virtual screen dimensions. Can reduce this to save videocard memory
+# at the expense of maximum window size available.
+virtualWidth=1280
+virtualHeight=1024
+
+# Screen depth. Only 16 & 32bpp supported.
+bpp=32
+
+# Rotated monitor? -- NOTE: only works with subsetted radeon driver!
+rotateMode=0
diff --git a/src/glx/mini/miniglx.c b/src/glx/mini/miniglx.c
new file mode 100644
index 00000000000..25c7b963624
--- /dev/null
+++ b/src/glx/mini/miniglx.c
@@ -0,0 +1,1975 @@
+/**
+ * \file miniglx.c
+ * \brief Mini GLX interface functions.
+ * \author Brian Paul
+ *
+ * The Mini GLX interface is a subset of the GLX interface, plus a
+ * minimal set of Xlib functions.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.0
+ *
+ * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* $Id: miniglx.c,v 1.1 2003/08/22 20:11:43 brianp Exp $ */
+
+/**
+ * \mainpage Mini GLX
+ *
+ * \section miniglxIntro Introduction
+ *
+ * The Mini GLX interface facilitates OpenGL rendering on embedded devices. The
+ * interface is a subset of the GLX interface, plus a minimal set of Xlib-like
+ * functions.
+ *
+ * Programs written to the Mini GLX specification should run unchanged
+ * on systems with the X Window System and the GLX extension (after
+ * recompilation). The intention is to allow flexibility for
+ * prototyping and testing.
+ *
+ * The files in the src/miniglx/ directory are compiled to build the
+ * libGL.so library. This is the library which applications link with.
+ * libGL.so in turn, loads the hardware-specific device driver.
+ *
+ *
+ * \section miniglxDoxygen About Doxygen
+ *
+ * For a list of all files, select <b>File List</b>. Choose a file from
+ * the list for a list of all functions in the file.
+ *
+ * For a list of all functions, types, constants, etc.
+ * select <b>File Members</b>.
+ *
+ *
+ * \section miniglxReferences References
+ *
+ * - <A HREF="file:../../docs/MiniGLX.html">Mini GLX Specification</A>,
+ * Tungsten Graphics, Inc.
+ * - OpenGL Graphics with the X Window System, Silicon Graphics, Inc.,
+ * ftp://ftp.sgi.com/opengl/doc/opengl1.2/glx1.3.ps
+ * - Xlib - C Language X Interface, X Consortium Standard, X Version 11,
+ * Release 6.4, ftp://ftp.x.org/pub/R6.4/xc/doc/hardcopy/X11/xlib.PS.gz
+ * - XFree86 Man pages, The XFree86 Project, Inc.,
+ * http://www.xfree86.org/current/manindex3.html
+ *
+ */
+
+/**
+ * \page datatypes Notes on the XVisualInfo, Visual, and __GLXvisualConfig data types
+ *
+ * -# X (unfortunately) has two (or three) data types which
+ * describe visuals. Ideally, there would just be one.
+ * -# We need the #__GLXvisualConfig type to augment #XVisualInfo and #Visual
+ * because we need to describe the GLX-specific attributes of visuals.
+ * -# In this interface there is a one-to-one-to-one correspondence between
+ * the three types and they're all interconnected.
+ * -# The #XVisualInfo type has a pointer to a #Visual. The #Visual structure
+ * (aka MiniGLXVisualRec) has a pointer to the #__GLXvisualConfig. The
+ * #Visual structure also has a pointer pointing back to the #XVisualInfo.
+ * -# The #XVisualInfo structure is the only one who's contents are public.
+ * -# The glXChooseVisual() and XGetVisualInfo() are the only functions that
+ * return #XVisualInfo structures. They can be freed with XFree(), though
+ * there is a small memory leak.
+ */
+
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+
+#include "miniglxP.h"
+#include "dri.h"
+
+#include "glapi.h"
+#include "xf86drm.h"
+
+
+/**
+ * \brief Current GLX context.
+ *
+ * \sa glXGetCurrentContext().
+ */
+static GLXContext CurrentContext = NULL;
+
+
+
+static Display *SignalDisplay = 0;
+
+static void SwitchVT(int sig)
+{
+ fprintf(stderr, "SwitchVT %d dpy %p\n", sig, SignalDisplay);
+
+ if (SignalDisplay) {
+ SignalDisplay->vtSignalFlag = 1;
+ switch( sig )
+ {
+ case SIGUSR1: /* vt has been released */
+ SignalDisplay->haveVT = 0;
+ break;
+ case SIGUSR2: /* vt has been acquired */
+ SignalDisplay->haveVT = 1;
+ break;
+ }
+ }
+}
+
+/**********************************************************************/
+/** \name Framebuffer device functions */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * \brief Do the first part of setting up the framebuffer device.
+ *
+ * \param dpy the display handle.
+ * \param use_vt use a VT for display or not
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa This is called during XOpenDisplay().
+ *
+ * \internal
+ * Gets the VT number, opens the respective console TTY device. Saves its state
+ * to restore when exiting and goes into graphics mode.
+ *
+ * Opens the framebuffer device and make a copy of the original variable screen
+ * information and gets the fixed screen information. Maps the framebuffer and
+ * MMIO region into the process address space.
+ */
+static GLboolean
+OpenFBDev( Display *dpy, int use_vt )
+{
+ char ttystr[1000];
+ int fd, vtnumber, ttyfd;
+
+ assert(dpy);
+
+ if (geteuid()) {
+ fprintf(stderr, "error: you need to be root\n");
+ return GL_FALSE;
+ }
+
+ if (use_vt) {
+
+ /* open /dev/tty0 and get the VT number */
+ if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) {
+ fprintf(stderr, "error opening /dev/tty0\n");
+ return GL_FALSE;
+ }
+ if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
+ fprintf(stderr, "error: couldn't get a free vt\n");
+ return GL_FALSE;
+ }
+
+ fprintf(stderr, "*** got vt nr: %d\n", vtnumber);
+ close(fd);
+
+ /* open the console tty */
+ sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */
+ dpy->ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
+ if (dpy->ConsoleFD < 0) {
+ fprintf(stderr, "error couldn't open console fd\n");
+ return GL_FALSE;
+ }
+
+ /* save current vt number */
+ {
+ struct vt_stat vts;
+ if (ioctl(dpy->ConsoleFD, VT_GETSTATE, &vts) == 0)
+ dpy->OriginalVT = vts.v_active;
+ }
+
+ /* disconnect from controlling tty */
+ ttyfd = open("/dev/tty", O_RDWR);
+ if (ttyfd >= 0) {
+ ioctl(ttyfd, TIOCNOTTY, 0);
+ close(ttyfd);
+ }
+
+ /* some magic to restore the vt when we exit */
+ {
+ struct vt_mode vt;
+ struct sigaction sig_tty;
+
+ /* Set-up tty signal handler to catch the signal we request below */
+ SignalDisplay = dpy;
+ memset( &sig_tty, 0, sizeof( sig_tty ) );
+ sig_tty.sa_handler = SwitchVT;
+ sigemptyset( &sig_tty.sa_mask );
+ if( sigaction( SIGUSR1, &sig_tty, &dpy->OrigSigUsr1 ) ||
+ sigaction( SIGUSR2, &sig_tty, &dpy->OrigSigUsr2 ) )
+ {
+ fprintf(stderr, "error: can't set up signal handler (%s)",
+ strerror(errno) );
+ return GL_FALSE;
+ }
+
+
+
+ vt.mode = VT_PROCESS;
+ vt.waitv = 0;
+ vt.relsig = SIGUSR1;
+ vt.acqsig = SIGUSR2;
+ if (ioctl(dpy->ConsoleFD, VT_SETMODE, &vt) < 0) {
+ fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+ if (ioctl(dpy->ConsoleFD, VT_ACTIVATE, vtnumber) != 0)
+ printf("ioctl VT_ACTIVATE: %s\n", strerror(errno));
+ if (ioctl(dpy->ConsoleFD, VT_WAITACTIVE, vtnumber) != 0)
+ printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno));
+
+ if (ioctl(dpy->ConsoleFD, VT_GETMODE, &vt) < 0) {
+ fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
+ return GL_FALSE;
+ }
+
+
+
+ }
+
+ /* go into graphics mode */
+ if (ioctl(dpy->ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
+ fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+ }
+
+ /* open the framebuffer device */
+ dpy->FrameBufferFD = open(dpy->fbdevDevice, O_RDWR);
+ if (dpy->FrameBufferFD < 0) {
+ fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* get the original variable screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->OrigVarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* make copy */
+ dpy->VarInfo = dpy->OrigVarInfo; /* structure copy */
+
+ /* Turn off hw accels (otherwise mmap of mmio region will be
+ * refused)
+ */
+ dpy->VarInfo.accel_flags = 0;
+ if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+
+ /* Get the fixed screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+
+ /* mmap the framebuffer into our address space */
+ dpy->driverContext.FBStart = dpy->FixedInfo.smem_start;
+ dpy->driverContext.FBSize = dpy->FixedInfo.smem_len;
+ dpy->driverContext.shared.fbSize = dpy->FixedInfo.smem_len;
+ dpy->driverContext.FBAddress = (caddr_t) mmap(0, /* start */
+ dpy->driverContext.shared.fbSize, /* bytes */
+ PROT_READ | PROT_WRITE, /* prot */
+ MAP_SHARED, /* flags */
+ dpy->FrameBufferFD, /* fd */
+ 0 /* offset */);
+ if (dpy->driverContext.FBAddress == (caddr_t) - 1) {
+ fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* mmap the MMIO region into our address space */
+ dpy->driverContext.MMIOStart = dpy->FixedInfo.mmio_start;
+ dpy->driverContext.MMIOSize = dpy->FixedInfo.mmio_len;
+ dpy->driverContext.MMIOAddress = (caddr_t) mmap(0, /* start */
+ dpy->driverContext.MMIOSize, /* bytes */
+ PROT_READ | PROT_WRITE, /* prot */
+ MAP_SHARED, /* flags */
+ dpy->FrameBufferFD, /* fd */
+ dpy->FixedInfo.smem_len /* offset */);
+ if (dpy->driverContext.MMIOAddress == (caddr_t) - 1) {
+ fprintf(stderr, "error: unable to mmap mmio region: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ fprintf(stderr, "got MMIOAddress %p offset %d\n",
+ dpy->driverContext.MMIOAddress,
+ dpy->FixedInfo.smem_len);
+
+ return GL_TRUE;
+}
+
+
+
+
+/**
+ * \brief Setup up the desired framebuffer device mode.
+ *
+ * \param dpy the display handle.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa This is called during __miniglx_StartServer().
+ *
+ * \internal
+ *
+ * Bumps the size of the window the the next supported mode. Sets the
+ * variable screen information according to the desired mode and asks
+ * the driver to validate the mode. Certifies that a DirectColor or
+ * TrueColor visual is used from the updated fixed screen information.
+ * In the case of DirectColor visuals, sets up an 'identity' colormap to
+ * mimic a TrueColor visual.
+ *
+ * Calls the driver hooks 'ValidateMode' and 'PostValidateMode' to
+ * allow the driver to make modifications to the chosen mode according
+ * to hardware constraints, or to save and restore videocard registers
+ * that may be clobbered by the fbdev driver.
+ *
+ * \todo Timings are hard-coded in the source for a set of supported modes.
+ */
+static GLboolean
+SetupFBDev( Display *dpy )
+{
+ int width, height;
+
+ assert(dpy);
+
+ width = dpy->driverContext.shared.virtualWidth;
+ height = dpy->driverContext.shared.virtualHeight;
+
+ /* Bump size up to next supported mode.
+ */
+ if (width <= 800 && height <= 600) {
+ width = 800; height = 600;
+ }
+ else if (width <= 1024 && height <= 768) {
+ width = 1024; height = 768;
+ }
+ else if (width <= 768 && height <= 1024) {
+ width = 768; height = 1024;
+ }
+ else if (width <= 1280 && height <= 1024) {
+ width = 1280; height = 1024;
+ }
+
+
+ dpy->driverContext.shared.virtualHeight = height;
+ dpy->driverContext.shared.virtualWidth = width;
+ dpy->driverContext.shared.fbStride = width * (dpy->driverContext.bpp / 8);
+
+ /* set the depth, resolution, etc */
+ dpy->VarInfo = dpy->OrigVarInfo;
+ dpy->VarInfo.bits_per_pixel = dpy->driverContext.bpp;
+ dpy->VarInfo.xres_virtual = dpy->driverContext.shared.virtualWidth;
+ dpy->VarInfo.yres_virtual = dpy->driverContext.shared.virtualHeight;
+ dpy->VarInfo.xres = width;
+ dpy->VarInfo.yres = height;
+ dpy->VarInfo.xoffset = 0;
+ dpy->VarInfo.yoffset = 0;
+ dpy->VarInfo.nonstd = 0;
+ dpy->VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
+
+ if (dpy->VarInfo.bits_per_pixel == 32) {
+ dpy->VarInfo.red.offset = 16;
+ dpy->VarInfo.green.offset = 8;
+ dpy->VarInfo.blue.offset = 0;
+ dpy->VarInfo.transp.offset = 24;
+ dpy->VarInfo.red.length = 8;
+ dpy->VarInfo.green.length = 8;
+ dpy->VarInfo.blue.length = 8;
+ dpy->VarInfo.transp.length = 8;
+ }
+ else if (dpy->VarInfo.bits_per_pixel == 16) {
+ dpy->VarInfo.red.offset = 11;
+ dpy->VarInfo.green.offset = 5;
+ dpy->VarInfo.blue.offset = 0;
+ dpy->VarInfo.red.length = 5;
+ dpy->VarInfo.green.length = 6;
+ dpy->VarInfo.blue.length = 5;
+ dpy->VarInfo.transp.offset = 0;
+ dpy->VarInfo.transp.length = 0;
+ }
+ else {
+ fprintf(stderr, "Only 32bpp and 16bpp modes supported at the moment\n");
+ return 0;
+ }
+
+ if (!dpy->driver->validateMode( &dpy->driverContext )) {
+ fprintf(stderr, "Driver validateMode() failed\n");
+ return 0;
+ }
+
+ if (dpy->VarInfo.xres == 1280 &&
+ dpy->VarInfo.yres == 1024) {
+ /* timing values taken from /etc/fb.modes (1280x1024 @ 75Hz) */
+ dpy->VarInfo.pixclock = 7408;
+ dpy->VarInfo.left_margin = 248;
+ dpy->VarInfo.right_margin = 16;
+ dpy->VarInfo.upper_margin = 38;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 144;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else if (dpy->VarInfo.xres == 1024 &&
+ dpy->VarInfo.yres == 768) {
+ /* timing values taken from /etc/fb.modes (1024x768 @ 75Hz) */
+ dpy->VarInfo.pixclock = 12699;
+ dpy->VarInfo.left_margin = 176;
+ dpy->VarInfo.right_margin = 16;
+ dpy->VarInfo.upper_margin = 28;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 96;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else if (dpy->VarInfo.xres == 800 &&
+ dpy->VarInfo.yres == 600) {
+ /* timing values taken from /etc/fb.modes (800x600 @ 75Hz) */
+ dpy->VarInfo.pixclock = 20203;
+ dpy->VarInfo.left_margin = 160;
+ dpy->VarInfo.right_margin = 16;
+ dpy->VarInfo.upper_margin = 21;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 80;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else if (dpy->VarInfo.xres == 768 &&
+ dpy->VarInfo.yres == 1024) {
+ /* timing values for 768x1024 @ 75Hz */
+ dpy->VarInfo.pixclock = 11993;
+ dpy->VarInfo.left_margin = 136;
+ dpy->VarInfo.right_margin = 32;
+ dpy->VarInfo.upper_margin = 41;
+ dpy->VarInfo.lower_margin = 1;
+ dpy->VarInfo.hsync_len = 80;
+ dpy->VarInfo.vsync_len = 3;
+ }
+ else {
+ /* XXX need timings for other screen sizes */
+ fprintf(stderr, "XXXX screen size %d x %d not supported at this time!\n",
+ dpy->VarInfo.xres, dpy->VarInfo.yres);
+ return GL_FALSE;
+ }
+
+ fprintf(stderr, "[miniglx] Setting mode: visible %dx%d virtual %dx%dx%d\n",
+ dpy->VarInfo.xres, dpy->VarInfo.yres,
+ dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
+ dpy->VarInfo.bits_per_pixel);
+
+ /* set variable screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ /* get the variable screen info, in case it has been modified */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->VarInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+
+ fprintf(stderr, "[miniglx] Readback mode: visible %dx%d virtual %dx%dx%d\n",
+ dpy->VarInfo.xres, dpy->VarInfo.yres,
+ dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
+ dpy->VarInfo.bits_per_pixel);
+
+ /* Get the fixed screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
+ fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+
+ if (dpy->FixedInfo.visual != FB_VISUAL_TRUECOLOR &&
+ dpy->FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
+ fprintf(stderr, "non-TRUECOLOR visuals not supported.\n");
+ return GL_FALSE;
+ }
+
+ if (dpy->FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
+ struct fb_cmap cmap;
+ unsigned short red[256], green[256], blue[256];
+ int rcols = 1 << dpy->VarInfo.red.length;
+ int gcols = 1 << dpy->VarInfo.green.length;
+ int bcols = 1 << dpy->VarInfo.blue.length;
+ int i;
+
+ cmap.start = 0;
+ cmap.len = gcols;
+ cmap.red = red;
+ cmap.green = green;
+ cmap.blue = blue;
+ cmap.transp = NULL;
+
+ for (i = 0; i < rcols ; i++)
+ red[i] = (65536/(rcols-1)) * i;
+
+ for (i = 0; i < gcols ; i++)
+ green[i] = (65536/(gcols-1)) * i;
+
+ for (i = 0; i < bcols ; i++)
+ blue[i] = (65536/(bcols-1)) * i;
+
+ if (ioctl(dpy->FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
+ fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
+ exit(1);
+ }
+ }
+
+ /* May need to restore regs fbdev has clobbered:
+ */
+ if (!dpy->driver->postValidateMode( &dpy->driverContext )) {
+ fprintf(stderr, "Driver postValidateMode() failed\n");
+ return 0;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Restore the framebuffer device to state it was in before we started
+ *
+ * Undoes the work done by SetupFBDev().
+ *
+ * \param dpy the display handle.
+ *
+ * \return GL_TRUE on success, or GL_FALSE on failure.
+ *
+ * \sa Called from XDestroyWindow().
+ *
+ * \internal
+ * Restores the original variable screen info.
+ */
+static GLboolean
+RestoreFBDev( Display *dpy )
+{
+ /* restore original variable screen info */
+ if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->OrigVarInfo)) {
+ fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
+ strerror(errno));
+ return GL_FALSE;
+ }
+ dpy->VarInfo = dpy->OrigVarInfo;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * \brief Close the framebuffer device.
+ *
+ * \param dpy the display handle.
+ *
+ * \sa Called from XCloseDisplay().
+ *
+ * \internal
+ * Unmaps the framebuffer and MMIO region. Restores the text mode and the
+ * original virtual terminal. Closes the console and framebuffer devices.
+ */
+static void
+CloseFBDev( Display *dpy )
+{
+ struct vt_mode VT;
+
+ munmap(dpy->driverContext.FBAddress, dpy->driverContext.FBSize);
+ munmap(dpy->driverContext.MMIOAddress, dpy->driverContext.MMIOSize);
+
+ if (dpy->ConsoleFD) {
+ /* restore text mode */
+ ioctl(dpy->ConsoleFD, KDSETMODE, KD_TEXT);
+
+ /* set vt */
+ if (ioctl(dpy->ConsoleFD, VT_GETMODE, &VT) != -1) {
+ VT.mode = VT_AUTO;
+ ioctl(dpy->ConsoleFD, VT_SETMODE, &VT);
+ }
+
+ /* restore original vt */
+ if (dpy->OriginalVT >= 0) {
+ ioctl(dpy->ConsoleFD, VT_ACTIVATE, dpy->OriginalVT);
+ dpy->OriginalVT = -1;
+ }
+
+ close(dpy->ConsoleFD);
+ }
+ close(dpy->FrameBufferFD);
+}
+
+/*@}*/
+
+
+/**********************************************************************/
+/** \name Misc functions needed for DRI drivers */
+/**********************************************************************/
+/*@{*/
+
+/**
+ * \brief Find the DRI screen dependent methods associated with the display.
+ *
+ * \param dpy a display handle, as returned by XOpenDisplay().
+ * \param scrn the screen number. Not referenced.
+ *
+ * \returns a pointer to a __DRIscreenRec structure.
+ *
+ * \internal
+ * Returns the MiniGLXDisplayRec::driScreen attribute.
+ */
+__DRIscreen *
+__glXFindDRIScreen(Display *dpy, int scrn)
+{
+ (void) scrn;
+ return dpy->driScreen;
+}
+
+/**
+ * \brief Validate a drawable.
+ *
+ * \param dpy a display handle, as returned by XOpenDisplay().
+ * \param draw drawable to validate.
+ *
+ * \internal
+ * Since Mini GLX only supports one window, compares the specified drawable with
+ * the MiniGLXDisplayRec::TheWindow attribute.
+ */
+Bool
+__glXWindowExists(Display *dpy, GLXDrawable draw)
+{
+ if (dpy->TheWindow == draw)
+ return True;
+ else
+ return False;
+}
+
+/**
+ * \brief Get current thread ID.
+ *
+ * \return thread ID.
+ *
+ * \internal
+ * Always returns 0.
+ */
+/*unsigned long
+_glthread_GetID(void)
+{
+ return 0;
+}*/
+
+/*@}*/
+
+
+/**
+ * \brief Scan Linux /prog/bus/pci/devices file to determine hardware
+ * chipset based on supplied bus ID.
+ *
+ * \return probed chipset (non-zero) on success, zero otherwise.
+ *
+ * \internal
+ */
+static int get_chipset_from_busid( Display *dpy )
+{
+ char buf[0x200];
+ FILE *file;
+ const char *fname = "/proc/bus/pci/devices";
+ int retval = 0;
+
+ if (!(file = fopen(fname,"r"))) {
+ fprintf(stderr, "couldn't open %s: %s\n", fname, strerror(errno));
+ return 0;
+ }
+
+ while (fgets(buf, sizeof(buf)-1, file)) {
+ unsigned int nr, bus, dev, fn, vendor, device, encode;
+ nr = sscanf(buf, "%04x\t%04x%04x", &encode,
+ &vendor, &device);
+
+ bus = encode >> 16;
+ dev = (encode & 0xFF) >> 3;
+ fn = encode & 0x7;
+
+ if (nr != 3)
+ break;
+
+ if (bus == dpy->driverContext.pciBus &&
+ dev == dpy->driverContext.pciDevice &&
+ fn == dpy->driverContext.pciFunc) {
+ retval = device;
+ break;
+ }
+ }
+
+ fclose(file);
+
+ if (retval)
+ fprintf(stderr, "[miniglx] probed chipset 0x%x\n", retval);
+ else
+ fprintf(stderr, "[miniglx] failed to probe chipset\n");
+
+ return retval;
+}
+
+
+/**
+ * \brief Read settings from a configuration file.
+ *
+ * The configuration file is usually "/etc/miniglx.conf", but can be overridden
+ * with the MINIGLX_CONF environment variable.
+ *
+ * The format consists in \code option = value \endcode lines. The option names
+ * corresponds to the fields in MiniGLXDisplayRec.
+ *
+ * \param dpy the display handle as.
+ *
+ * \return non-zero on success, zero otherwise.
+ *
+ * \internal
+ * Sets some defaults. Opens and parses the the Mini GLX configuration file and
+ * fills in the MiniGLXDisplayRec field that corresponds for each option.
+ */
+static int __read_config_file( Display *dpy )
+{
+ FILE *file;
+ const char *fname;
+
+ /* Fallback/defaults
+ */
+ dpy->fbdevDevice = "/dev/fb0";
+ dpy->clientDriverName = "fb_dri.so";
+ dpy->driverContext.pciBus = 0;
+ dpy->driverContext.pciDevice = 0;
+ dpy->driverContext.pciFunc = 0;
+ dpy->driverContext.chipset = 0;
+ dpy->driverContext.pciBusID = 0;
+ dpy->driverContext.shared.virtualWidth = 1280;
+ dpy->driverContext.shared.virtualHeight = 1024;
+ dpy->driverContext.bpp = 32;
+ dpy->driverContext.cpp = 4;
+ dpy->rotateMode = 0;
+
+ fname = getenv("MINIGLX_CONF");
+ if (!fname) fname = "/etc/miniglx.conf";
+
+ file = fopen(fname, "r");
+ if (!file) {
+ fprintf(stderr, "couldn't open config file %s: %s\n", fname, strerror(errno));
+ return 0;
+ }
+
+
+ while (!feof(file)) {
+ char buf[81], *opt = buf, *val, *tmp1, *tmp2;
+ fgets(buf, sizeof(buf), file);
+
+ /* Parse 'opt = val' -- must be easier ways to do this.
+ */
+ while (isspace(*opt)) opt++;
+ val = opt;
+ if (*val == '#') continue; /* comment */
+ while (!isspace(*val) && *val != '=' && *val) val++;
+ tmp1 = val;
+ while (isspace(*val)) val++;
+ if (*val != '=') continue;
+ *tmp1 = 0;
+ val++;
+ while (isspace(*val)) val++;
+ tmp2 = val;
+ while (!isspace(*tmp2) && *tmp2 != '\n' && *tmp2) tmp2++;
+ *tmp2 = 0;
+
+
+ if (strcmp(opt, "fbdevDevice") == 0)
+ dpy->fbdevDevice = strdup(val);
+ else if (strcmp(opt, "clientDriverName") == 0)
+ dpy->clientDriverName = strdup(val);
+ else if (strcmp(opt, "rotateMode") == 0)
+ dpy->rotateMode = atoi(val) ? 1 : 0;
+ else if (strcmp(opt, "pciBusID") == 0) {
+ if (sscanf(val, "PCI:%d:%d:%d",
+ &dpy->driverContext.pciBus,
+ &dpy->driverContext.pciDevice,
+ &dpy->driverContext.pciFunc) != 3) {
+ fprintf(stderr, "malformed bus id: %s\n", val);
+ continue;
+ }
+ dpy->driverContext.pciBusID = strdup(val);
+ }
+ else if (strcmp(opt, "chipset") == 0) {
+ if (sscanf(val, "0x%x", &dpy->driverContext.chipset) != 1)
+ fprintf(stderr, "malformed chipset: %s\n", opt);
+ }
+ else if (strcmp(opt, "virtualWidth") == 0) {
+ if (sscanf(val, "%d", &dpy->driverContext.shared.virtualWidth) != 1)
+ fprintf(stderr, "malformed virtualWidth: %s\n", opt);
+ }
+ else if (strcmp(opt, "virtualHeight") == 0) {
+ if (sscanf(val, "%d", &dpy->driverContext.shared.virtualHeight) != 1)
+ fprintf(stderr, "malformed virutalHeight: %s\n", opt);
+ }
+ else if (strcmp(opt, "bpp") == 0) {
+ if (sscanf(val, "%d", &dpy->driverContext.bpp) != 1)
+ fprintf(stderr, "malformed bpp: %s\n", opt);
+ dpy->driverContext.cpp = dpy->driverContext.bpp / 8;
+ }
+ }
+
+ fclose(file);
+
+ if (dpy->driverContext.chipset == 0 && dpy->driverContext.pciBusID != 0)
+ dpy->driverContext.chipset = get_chipset_from_busid( dpy );
+
+ return 1;
+}
+
+static int InitDriver( Display *dpy )
+{
+ /*
+ * Begin DRI setup.
+ * We're kind of combining the per-display and per-screen information
+ * which was kept separate in XFree86/DRI's libGL.
+ */
+ dpy->dlHandle = dlopen(dpy->clientDriverName, RTLD_NOW | RTLD_GLOBAL);
+ if (!dpy->dlHandle) {
+ fprintf(stderr, "Unable to open %s: %s\n", dpy->clientDriverName,
+ dlerror());
+ return GL_FALSE;
+ }
+
+ /* Pull in Mini GLX specific hooks:
+ */
+ dpy->driver = (struct DRIDriverRec *) dlsym(dpy->dlHandle,
+ "__driDriver");
+ if (!dpy->driver) {
+ fprintf(stderr, "Couldn't find __driDriver in %s\n",
+ dpy->clientDriverName);
+ dlclose(dpy->dlHandle);
+ return GL_FALSE;
+ }
+
+ /* Pull in standard DRI client-side driver hooks:
+ */
+ dpy->createScreen = (driCreateScreenFunc*) dlsym(dpy->dlHandle,
+ "__driCreateScreen");
+ if (!dpy->createScreen) {
+ fprintf(stderr, "Couldn't find __driCreateScreen in %s\n",
+ dpy->clientDriverName);
+ dlclose(dpy->dlHandle);
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**********************************************************************/
+/** \name Public API functions (Xlib and GLX) */
+/**********************************************************************/
+/*@{*/
+
+
+/**
+ * \brief Initialize the graphics system.
+ *
+ * \param display_name currently ignored. It is recommended to pass it as NULL.
+ * \return a pointer to a #Display if the function is able to initialize
+ * the graphics system, NULL otherwise.
+ *
+ * Allocates a MiniGLXDisplayRec structure and fills in with information from a
+ * configuration file.
+ *
+ * Calls OpenFBDev() to open the framebuffer device and calls
+ * DRIDriverRec::initFBDev to do the client-side initialization on it.
+ *
+ * Loads the DRI driver and pulls in Mini GLX specific hooks into a
+ * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
+ * Asks the driver for a list of supported visuals. Performs the per-screen
+ * client-side initialization. Also setups the callbacks in the screen private
+ * information.
+ *
+ * Does the framebuffer device setup. Calls __miniglx_open_connections() to
+ * serve clients.
+ */
+Display *
+__miniglx_StartServer( const char *display_name )
+{
+ Display *dpy;
+ int use_vt = 0;
+
+ dpy = (Display *)calloc(1, sizeof(Display));
+ if (!dpy)
+ return NULL;
+
+ dpy->IsClient = False;
+
+ if (!__read_config_file( dpy )) {
+ fprintf(stderr, "Couldn't get configuration details\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Open the fbdev device
+ */
+ if (!OpenFBDev(dpy, use_vt)) {
+ fprintf(stderr, "OpenFBDev failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ if (!InitDriver(dpy)) {
+ fprintf(stderr, "InitDriver failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Ask the driver for a list of supported configs:
+ */
+ dpy->driver->initContextModes( &dpy->driverContext, &dpy->numModes, &dpy->modes );
+
+ /* Perform the initialization normally done in the X server
+ */
+ if (!dpy->driver->initFBDev( &dpy->driverContext )) {
+ fprintf(stderr, "%s: __driInitFBDev failed\n", __FUNCTION__);
+ dlclose(dpy->dlHandle);
+ return GL_FALSE;
+ }
+
+ /* do fbdev setup
+ */
+ if (!SetupFBDev(dpy)) {
+ fprintf(stderr, "SetupFBDev failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* unlock here if not using VT -- JDS */
+ if (!use_vt) {
+ if (dpy->driver->restoreHardware)
+ dpy->driver->restoreHardware( &dpy->driverContext );
+ DRM_UNLOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ dpy->hwActive = 1;
+ }
+
+ /* Ready for clients:
+ */
+ if (!__miniglx_open_connections(dpy)) {
+ free(dpy);
+ return NULL;
+ }
+
+ return dpy;
+}
+
+
+/**
+ * \brief Initialize the graphics system.
+ *
+ * \param display_name currently ignored. It is recommended to pass it as NULL.
+ * \return a pointer to a #Display if the function is able to initialize
+ * the graphics system, NULL otherwise.
+ *
+ * Allocates a MiniGLXDisplayRec structure and fills in with information from a
+ * configuration file.
+ *
+ * Calls __miniglx_open_connections() to connect to the server.
+ *
+ * Loads the DRI driver and pulls in Mini GLX specific hooks into a
+ * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
+ * Asks the driver for a list of supported visuals. Performs the per-screen
+ * client-side initialization. Also setups the callbacks in the screen private
+ * information.
+ *
+ * \todo
+ * - read config file
+ * - what about virtualWidth, etc?
+ * - determine dpy->driverClientMsgSize,
+ * - allocate dpy->driverClientMsg
+ */
+Display *
+XOpenDisplay( const char *display_name )
+{
+ Display *dpy;
+
+ dpy = (Display *)calloc(1, sizeof(Display));
+ if (!dpy)
+ return NULL;
+
+ dpy->IsClient = True;
+
+ /* read config file
+ */
+ if (!__read_config_file( dpy )) {
+ fprintf(stderr, "Couldn't get configuration details\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Connect to the server and receive driverClientMsg
+ */
+ if (!__miniglx_open_connections(dpy)) {
+ free(dpy);
+ return NULL;
+ }
+
+ /* dlopen the driver .so file
+ */
+ if (!InitDriver(dpy)) {
+ fprintf(stderr, "InitDriver failed\n");
+ free(dpy);
+ return NULL;
+ }
+
+ /* Ask the driver for a list of supported configs:
+ */
+ dpy->driver->initContextModes( &dpy->driverContext, &dpy->numModes, &dpy->modes );
+
+ /* Perform the client-side initialization.
+ *
+ * Clearly there is a limit of one on the number of windows in
+ * existence at any time.
+ *
+ * Need to shut down DRM and free DRI data in XDestroyWindow(), too.
+ */
+ dpy->driScreen = (*dpy->createScreen)(dpy->driver,
+ &dpy->driverContext);
+ if (!dpy->driScreen) {
+ fprintf(stderr, "%s: __driCreateScreen failed\n", __FUNCTION__);
+ dlclose(dpy->dlHandle);
+ free(dpy);
+ return NULL;
+ }
+
+ /* Anything more to do?
+ */
+ return dpy;
+}
+
+
+/**
+ * \brief Release display resources.
+ *
+ * When the application is about to exit, the resources associated with the
+ * graphics system can be released by calling this function.
+ *
+ * \param dpy display handle. It becomes invalid at this point.
+ *
+ * Destroys the window if any, and destroys the per-screen
+ * driver private information.
+ * Calls __miniglx_close_connections().
+ *
+ * If a server, puts the the framebuffer back into the initial state.
+ *
+ * Finally frees the display structure.
+ */
+void
+XCloseDisplay( Display *dpy )
+{
+ glXMakeCurrent( dpy, NULL, NULL);
+
+ if (dpy->NumWindows)
+ XDestroyWindow( dpy, dpy->TheWindow );
+
+ /* As this is done in XOpenDisplay, need to undo it here:
+ */
+ (*dpy->driScreen->destroyScreen)(dpy->driScreen);
+
+ __miniglx_close_connections( dpy );
+
+ if (!dpy->IsClient) {
+ /* put framebuffer back to initial state
+ */
+ (*dpy->driver->haltFBDev)( &dpy->driverContext );
+ RestoreFBDev(dpy);
+ CloseFBDev(dpy);
+ }
+
+ dlclose(dpy->dlHandle);
+ free(dpy);
+}
+
+
+/**
+ * \brief Window creation.
+ *
+ * \param display a display handle, as returned by XOpenDisplay().
+ * \param parent the parent window for the new window. For Mini GLX this should
+ * be
+ * \code RootWindow(display, 0) \endcode
+ * \param x the window abscissa. For Mini GLX, it should be zero.
+ * \param y the window ordinate. For Mini GLX, it should be zero.
+ * \param width the window width. For Mini GLX, this specifies the desired
+ * screen width such as 1024 or 1280.
+ * \param height the window height. For Mini GLX, this specifies the desired
+ * screen height such as 768 or 1024.
+ * \param border_width the border width. For Mini GLX, it should be zero.
+ * \param depth the window pixel depth. For Mini GLX, this should be the depth
+ * found in the #XVisualInfo object returned by glXChooseVisual()
+ * \param class the window class. For Mini GLX this value should be
+ * #InputOutput.
+ * \param visual the visual type. It should be the visual field of the
+ * #XVisualInfo object returned by glXChooseVisual().
+ * \param valuemask which fields of the XSetWindowAttributes() are to be used.
+ * For Mini GLX this is typically the bitmask
+ * \code CWBackPixel | CWBorderPixel | CWColormap \endcode
+ * \param attributes initial window attributes. The
+ * XSetWindowAttributes::background_pixel, XSetWindowAttributes::border_pixel
+ * and XSetWindowAttributes::colormap fields should be set.
+ *
+ * \return a window handle if it succeeds or zero if it fails.
+ *
+ * \note For Mini GLX, windows are full-screen; they cover the entire frame
+ * buffer. Also, Mini GLX imposes a limit of one window. A second window
+ * cannot be created until the first one is destroyed.
+ *
+ * This function creates and initializes a ::MiniGLXWindowRec structure after
+ * ensuring that there is no other window created. Performs the per-drawable
+ * client-side initialization calling the __DRIscreenRec::createDrawable
+ * method.
+ *
+ */
+Window
+XCreateWindow( Display *dpy, Window parent, int x, int y,
+ unsigned int width, unsigned int height,
+ unsigned int border_width, int depth, unsigned int class,
+ Visual *visual, unsigned long valuemask,
+ XSetWindowAttributes *attributes )
+{
+ Window win;
+
+ /* ignored */
+ (void) x;
+ (void) y;
+ (void) border_width;
+ (void) depth;
+ (void) class;
+ (void) valuemask;
+ (void) attributes;
+
+ if (!dpy->IsClient) {
+ fprintf(stderr, "Server process may not create windows (currently)\n");
+ return NULL;
+ }
+
+ if (dpy->NumWindows > 0)
+ return NULL; /* only allow one window */
+
+ assert(dpy->TheWindow == NULL);
+
+ win = malloc(sizeof(struct MiniGLXWindowRec));
+ if (!win)
+ return NULL;
+
+ /* In rotated mode, translate incoming x,y,width,height into
+ * 'normal' coordinates.
+ */
+ if (dpy->rotateMode) {
+ int tmp;
+ tmp = width; width = height; height = tmp;
+ tmp = x; x = y; y = tmp;
+ }
+
+ /* init other per-window fields */
+ win->x = 0;
+ win->y = 0;
+ win->w = width;
+ win->h = height;
+ win->visual = visual; /* ptr assignment */
+
+ win->bytesPerPixel = dpy->driverContext.cpp;
+ win->rowStride = dpy->driverContext.shared.virtualWidth * win->bytesPerPixel;
+ win->size = win->rowStride * height;
+ win->frontStart = dpy->driverContext.FBAddress;
+ win->frontBottom = (GLubyte *) win->frontStart + (height-1) * win->rowStride;
+
+ /* This is incorrect: the hardware driver could put the backbuffer
+ * just about anywhere. These fields, including the above are
+ * hardware dependent & don't really belong here.
+ */
+ if (visual->mode->doubleBufferMode) {
+ win->backStart = (GLubyte *) win->frontStart +
+ win->rowStride * dpy->driverContext.shared.virtualHeight;
+ win->backBottom = (GLubyte *) win->backStart
+ + (height - 1) * win->rowStride;
+ win->curBottom = win->backBottom;
+ }
+ else {
+ /* single buffered */
+ win->backStart = NULL;
+ win->backBottom = NULL;
+ win->curBottom = win->frontBottom;
+ }
+
+ win->driDrawable = dpy->driScreen->createDrawable(dpy->driScreen,
+ width, height,
+ dpy->clientID, visual->mode);
+
+ if (!win->driDrawable) {
+ fprintf(stderr, "%s: dri.createDrawable failed\n", __FUNCTION__);
+ free(win);
+ return NULL;
+ }
+
+ dpy->NumWindows++;
+ dpy->TheWindow = win;
+
+ return win;
+}
+
+
+/**
+ * \brief Destroy window.
+ *
+ * \param display display handle.
+ * \param w window handle.
+ *
+ * This function calls XUnmapWindow() and frees window \p w.
+ *
+ * In case of destroying the current buffer first unbinds the GLX context
+ * by calling glXMakeCurrent() with no drawable.
+ */
+void
+XDestroyWindow( Display *display, Window win )
+{
+ if (display && display->IsClient && win) {
+ /* check if destroying the current buffer */
+ Window curDraw = glXGetCurrentDrawable();
+ if (win == curDraw) {
+ glXMakeCurrent( display, NULL, NULL);
+ }
+
+ XUnmapWindow( display, win );
+
+ /* Destroy the drawable. */
+ (*win->driDrawable->destroyDrawable)(win->driDrawable);
+ free(win);
+
+ /* unlink window from display */
+ display->NumWindows--;
+ assert(display->NumWindows == 0);
+ display->TheWindow = NULL;
+ }
+}
+
+
+
+
+/**
+ * \brief Create color map structure.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param w the window on whose screen you want to create a color map. This
+ * parameter is ignored by Mini GLX but should be the value returned by the
+ * \code RootWindow(display, 0) \endcode macro.
+ * \param visual a visual type supported on the screen. This parameter is
+ * ignored by Mini GLX but should be the XVisualInfo::visual returned by
+ * glXChooseVisual().
+ * \param alloc the color map entries to be allocated. This parameter is ignored
+ * by Mini GLX but should be set to #AllocNone.
+ *
+ * \return the color map.
+ *
+ * This function is only provided to ease porting. Practically a no-op -
+ * returns a pointer to a dynamically allocated chunk of memory (one byte).
+ */
+Colormap
+XCreateColormap( Display *dpy, Window w, Visual *visual, int alloc )
+{
+ (void) dpy;
+ (void) w;
+ (void) visual;
+ (void) alloc;
+ return (Colormap) malloc(1);
+}
+
+
+/**
+ * \brief Destroy color map structure.
+ *
+ * \param display The display handle as returned by XOpenDisplay().
+ * \param colormap the color map to destroy.
+ *
+ * This function is only provided to ease porting. Practically a no-op.
+ *
+ * Frees the memory pointed by \p colormap.
+ */
+void
+XFreeColormap( Display *display, Colormap colormap )
+{
+ (void) display;
+ (void) colormap;
+ free(colormap);
+}
+
+
+/**
+ * \brief Free client data.
+ *
+ * \param data the data that is to be freed.
+ *
+ * Frees the memory pointed by \p data.
+ */
+void
+XFree( void *data )
+{
+ free(data);
+}
+
+
+/**
+ * \brief Query available visuals.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param vinfo_mask a bitmask indicating which fields of the \p vinfo_template
+ * are to be matched. The value must be \c VisualScreenMask.
+ * \param vinfo_template a template whose fields indicate which visual
+ * attributes must be matched by the results. The XVisualInfo::screen field of
+ * this structure must be zero.
+ * \param nitens_return will hold the number of visuals returned.
+ *
+ * \return the address of an array of all available visuals.
+ *
+ * An example of using XGetVisualInfo() to get all available visuals follows:
+ *
+ * \code
+ * XVisualInfo vinfo_template, *results;
+ * int nitens_return;
+ * Display *dpy = XOpenDisplay(NULL);
+ * vinfo_template.screen = 0;
+ * results = XGetVisualInfo(dpy, VisualScreenMask, &vinfo_template, &nitens_return);
+ * \endcode
+ *
+ * Returns the list of all ::XVisualInfo available, one per
+ * ::__GLcontextMode stored in MiniGLXDisplayRec::modes.
+ */
+XVisualInfo *
+XGetVisualInfo( Display *dpy, long vinfo_mask, XVisualInfo *vinfo_template, int *nitens_return )
+{
+ XVisualInfo *results;
+ Visual *visResults;
+ int i, n;
+
+ ASSERT(vinfo_mask == VisualScreenMask);
+ ASSERT(vinfo_template.screen == 0);
+
+ n = dpy->numModes;
+ results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
+ if (!results) {
+ *nitens_return = 0;
+ return NULL;
+ }
+
+ visResults = (Visual *)calloc(1, n * sizeof(Visual));
+ if (!results) {
+ free(results);
+ *nitens_return = 0;
+ return NULL;
+ }
+
+ for (i = 0; i < n; i++) {
+ visResults[i].mode = dpy->modes + i;
+ visResults[i].visInfo = results + i;
+ visResults[i].dpy = dpy;
+
+ if (dpy->driverContext.bpp == 32)
+ visResults[i].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
+ else
+ visResults[i].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
+
+ results[i].visual = visResults + i;
+ results[i].visualid = i;
+ results[i].class = TrueColor;
+ results[i].depth = dpy->modes[i].redBits +
+ dpy->modes[i].redBits +
+ dpy->modes[i].redBits +
+ dpy->modes[i].redBits;
+ results[i].bits_per_rgb = dpy->driverContext.bpp;
+ }
+ *nitens_return = n;
+ return results;
+}
+
+
+/**
+ * \brief Return a visual that matches specified attributes.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param screen the screen number. It is currently ignored by Mini GLX and
+ * should be zero.
+ * \param attribList a list of GLX attributes which describe the desired pixel
+ * format. It is terminated by the token \c None.
+ *
+ * The attributes are as follows:
+ * \arg GLX_USE_GL:
+ * This attribute should always be present in order to maintain compatibility
+ * with GLX.
+ * \arg GLX_RGBA:
+ * If present, only RGBA pixel formats will be considered. Otherwise, only
+ * color index formats are considered.
+ * \arg GLX_DOUBLEBUFFER:
+ * if present, only double-buffered pixel formats will be chosen.
+ * \arg GLX_RED_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per red pixel component that is acceptable.
+ * \arg GLX_GREEN_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per green pixel component that is acceptable.
+ * \arg GLX_BLUE_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per blue pixel component that is acceptable.
+ * \arg GLX_ALPHA_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per alpha pixel component that is acceptable.
+ * \arg GLX_STENCIL_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per stencil value that is acceptable.
+ * \arg GLX_DEPTH_SIZE \e n:
+ * Must be followed by a non-negative integer indicating the minimum number of
+ * bits per depth component that is acceptable.
+ * \arg None:
+ * This token is used to terminate the attribute list.
+ *
+ * \return a pointer to an #XVisualInfo object which most closely matches the
+ * requirements of the attribute list. If there is no visual which matches the
+ * request, \c NULL will be returned.
+ *
+ * \note Visuals with accumulation buffers are not available.
+ *
+ * This function searches the list of available visual configurations in
+ * MiniGLXDisplayRec::configs for a configuration which best matches the GLX
+ * attribute list parameter. A new ::XVisualInfo object is created which
+ * describes the visual configuration. The match criteria is described in the
+ * specification.
+ */
+XVisualInfo*
+glXChooseVisual( Display *dpy, int screen, int *attribList )
+{
+ Visual *vis;
+ XVisualInfo *visInfo;
+ const int *attrib;
+ GLboolean rgbFlag = GL_FALSE, dbFlag = GL_FALSE, stereoFlag = GL_FALSE;
+ GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits = 0;
+ GLint indexBits = 0, depthBits = 0, stencilBits = 0;
+ GLint numSamples = 0;
+ int i;
+
+ /*
+ * XXX in the future, <screen> might be interpreted as a VT
+ */
+ ASSERT(dpy);
+ ASSERT(screen == 0);
+
+ vis = (Visual *)calloc(1, sizeof(Visual));
+ if (!vis)
+ return NULL;
+
+ visInfo = (XVisualInfo *)malloc(sizeof(XVisualInfo));
+ if (!visInfo) {
+ free(vis);
+ return NULL;
+ }
+
+ visInfo->visual = vis;
+ vis->visInfo = visInfo;
+ vis->dpy = dpy;
+
+ /* parse the attribute list */
+ for (attrib = attribList; attrib && *attrib != None; attrib++) {
+ switch (attrib[0]) {
+ case GLX_DOUBLEBUFFER:
+ dbFlag = GL_TRUE;
+ break;
+ case GLX_RGBA:
+ rgbFlag = GL_TRUE;
+ break;
+ case GLX_RED_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_GREEN_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_BLUE_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ALPHA_SIZE:
+ redBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_STENCIL_SIZE:
+ stencilBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_DEPTH_SIZE:
+ depthBits = attrib[1];
+ attrib++;
+ break;
+#if 0
+ case GLX_ACCUM_RED_SIZE:
+ accumRedBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ACCUM_GREEN_SIZE:
+ accumGreenBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ACCUM_BLUE_SIZE:
+ accumBlueBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_ACCUM_ALPHA_SIZE:
+ accumAlphaBits = attrib[1];
+ attrib++;
+ break;
+ case GLX_LEVEL:
+ /* ignored for now */
+ break;
+#endif
+ default:
+ /* unexpected token */
+ fprintf(stderr, "unexpected token in glXChooseVisual attrib list\n");
+ free(vis);
+ free(visInfo);
+ return NULL;
+ }
+ }
+
+ /* search screen configs for suitable visual */
+ (void) numSamples;
+ (void) indexBits;
+ (void) redBits;
+ (void) greenBits;
+ (void) blueBits;
+ (void) alphaBits;
+ (void) stereoFlag;
+ for (i = 0; i < dpy->numModes; i++) {
+ const __GLcontextModes *mode = dpy->modes + i;
+ if (mode->rgbMode == rgbFlag &&
+ mode->redBits >= redBits &&
+ mode->greenBits >= greenBits &&
+ mode->blueBits >= blueBits &&
+ mode->alphaBits >= alphaBits &&
+ mode->depthBits >= depthBits &&
+ mode->stencilBits >= stencilBits) {
+ /* found it */
+ visInfo->visualid = i;
+ vis->mode = mode;
+ break;
+ }
+ }
+ if (!vis->mode)
+ return NULL;
+
+ /* compute depth and bpp */
+ if (rgbFlag) {
+ /* XXX maybe support depth 16 someday */
+ visInfo->class = TrueColor;
+ visInfo->depth = dpy->driverContext.bpp;
+ visInfo->bits_per_rgb = dpy->driverContext.bpp;
+ if (dpy->driverContext.bpp == 32)
+ vis->pixelFormat = PF_B8G8R8A8;
+ else
+ vis->pixelFormat = PF_B5G6R5;
+ }
+ else {
+ /* color index mode */
+ visInfo->class = PseudoColor;
+ visInfo->depth = 8;
+ visInfo->bits_per_rgb = 8; /* bits/pixel */
+ vis->pixelFormat = PF_CI8;
+ }
+
+ return visInfo;
+}
+
+
+/**
+ * \brief Return information about GLX visuals.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param vis the visual to be queried, as returned by glXChooseVisual().
+ * \param attrib the visual attribute to be returned.
+ * \param value pointer to an integer in which the result of the query will be
+ * stored.
+ *
+ * \return zero if no error occurs, \c GLX_INVALID_ATTRIBUTE if the attribute
+ * parameter is invalid, or \c GLX_BAD_VISUAL if the \p vis parameter is
+ * invalid.
+ *
+ * Returns the appropriate attribute of ::__GLXvisualConfig pointed by
+ * MiniGLXVisualRec::glxConfig of XVisualInfo::visual.
+ *
+ * \sa data types.
+ */
+int
+glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value )
+{
+ const __GLcontextModes *mode = vis->visual->mode;
+ if (!mode) {
+ *value = 0;
+ return GLX_BAD_VISUAL;
+ }
+
+ switch (attrib) {
+ case GLX_USE_GL:
+ *value = True;
+ return 0;
+ case GLX_RGBA:
+ *value = mode->rgbMode;
+ return 0;
+ case GLX_DOUBLEBUFFER:
+ *value = mode->doubleBufferMode;
+ return 0;
+ case GLX_RED_SIZE:
+ *value = mode->redBits;
+ return 0;
+ case GLX_GREEN_SIZE:
+ *value = mode->greenBits;
+ return 0;
+ case GLX_BLUE_SIZE:
+ *value = mode->blueBits;
+ return 0;
+ case GLX_ALPHA_SIZE:
+ *value = mode->alphaBits;
+ return 0;
+ case GLX_DEPTH_SIZE:
+ *value = mode->depthBits;
+ return 0;
+ case GLX_STENCIL_SIZE:
+ *value = mode->stencilBits;
+ return 0;
+ default:
+ *value = 0;
+ return GLX_BAD_ATTRIBUTE;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Create a new GLX rendering context.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param vis the visual that defines the frame buffer resources available to
+ * the rendering context, as returned by glXChooseVisual().
+ * \param shareList If non-zero, texture objects and display lists are shared
+ * with the named rendering context. If zero, texture objects and display lists
+ * will (initially) be private to this context. They may be shared when a
+ * subsequent context is created.
+ * \param direct whether direct or indirect rendering is desired. For Mini GLX
+ * this value is ignored but it should be set to \c True.
+ *
+ * \return a ::GLXContext handle if it succeeds or zero if it fails due to
+ * invalid parameter or insufficient resources.
+ *
+ * This function creates and initializes a ::MiniGLXContextRec structure and
+ * calls the __DRIscreenRec::createContext method to initialize the client
+ * private data.
+ */
+GLXContext
+glXCreateContext( Display *dpy, XVisualInfo *vis,
+ GLXContext shareList, Bool direct )
+{
+ GLXContext ctx;
+ void *sharePriv;
+
+ ASSERT(vis);
+
+ ctx = (struct MiniGLXContextRec *)calloc(1, sizeof(struct MiniGLXContextRec));
+ if (!ctx)
+ return NULL;
+
+ ctx->vid = vis->visualid;
+
+ if (shareList)
+ sharePriv = shareList->driContext;
+ else
+ sharePriv = NULL;
+
+ ctx->driContext = (*dpy->driScreen->createContext)(dpy->driScreen,
+ vis->visual->mode,
+ sharePriv);
+ if (!ctx->driContext) {
+ free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+/**
+ * \brief Destroy a GLX context.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param ctx the GLX context to be destroyed.
+ *
+ * This function frees the \p ctx parameter after unbinding the current context
+ * by calling the __DRIcontextRec::bindContext method with zeros and calling
+ * the __DRIcontextRec::destroyContext method.
+ */
+void
+glXDestroyContext( Display *dpy, GLXContext ctx )
+{
+ GLXContext glxctx = glXGetCurrentContext();
+
+ if (ctx) {
+ if (glxctx == ctx) {
+ /* destroying current context */
+ (*ctx->driContext->bindContext)(dpy->driScreen, 0, 0);
+ CurrentContext = 0;
+ }
+ (*ctx->driContext->destroyContext)(ctx->driContext);
+ free(ctx);
+ }
+}
+
+
+/**
+ * \brief Bind a GLX context to a window or a pixmap.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param drawable the window or drawable to bind to the rendering context.
+ * This should be the value returned by XCreateWindow().
+ * \param ctx the GLX context to be destroyed.
+ *
+ * \return \c True if it succeeds, \c False otherwise to indicate an invalid
+ * display, window or context parameter.
+ *
+ * The current rendering context may be unbound by calling glXMakeCurrent()
+ * with the window and context parameters set to zero.
+ *
+ * An application may create any number of rendering contexts and bind them as
+ * needed. Note that binding a rendering context is generally not a
+ * light-weight operation. Most simple OpenGL applications create only one
+ * rendering context.
+ *
+ * This function first unbinds any old context via
+ * __DRIcontextRec::unbindContext and binds the new one via
+ * __DRIcontextRec::bindContext.
+ *
+ * If \p drawable is zero it unbinds the GLX context by calling
+ * __DRIcontextRec::bindContext with zeros.
+ */
+Bool
+glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx)
+{
+ if (dpy && drawable && ctx) {
+ GLXContext oldContext = glXGetCurrentContext();
+ GLXDrawable oldDrawable = glXGetCurrentDrawable();
+ /* unbind old */
+ if (oldContext) {
+ (*oldContext->driContext->unbindContext)(oldDrawable->driDrawable, oldContext->driContext);
+ }
+ /* bind new */
+ CurrentContext = ctx;
+ (*ctx->driContext->bindContext)(dpy->driScreen, drawable->driDrawable, ctx->driContext);
+ ctx->drawBuffer = drawable;
+ ctx->curBuffer = drawable;
+ }
+ else if (ctx && dpy) {
+ /* unbind */
+ (*ctx->driContext->bindContext)(dpy->driScreen, 0, 0);
+ }
+ else if (dpy) {
+ CurrentContext = 0; /* kw: this seems to be intended??? */
+ }
+
+ return True;
+}
+
+
+/**
+ * \brief Exchange front and back buffers.
+ *
+ * \param dpy the display handle, as returned by XOpenDisplay().
+ * \param drawable the drawable whose buffers are to be swapped.
+ *
+ * Any pending rendering commands will be completed before the buffer swap
+ * takes place.
+ *
+ * Calling glXSwapBuffers() on a window which is single-buffered has no effect.
+ *
+ * This function just calls the __DRIdrawableRec::swapBuffers method to do the
+ * work.
+ */
+void
+glXSwapBuffers( Display *dpy, GLXDrawable drawable )
+{
+ if (!dpy || !drawable)
+ return;
+
+ (*drawable->driDrawable->swapBuffers)(drawable->driDrawable);
+}
+
+
+/**
+ * \brief Return the current context
+ *
+ * \return the current context, as specified by glXMakeCurrent(), or zero if no
+ * context is currently bound.
+ *
+ * \sa glXCreateContext(), glXMakeCurrent()
+ *
+ * Returns the value of the ::CurrentContext global variable.
+ */
+GLXContext
+glXGetCurrentContext( void )
+{
+ return CurrentContext;
+}
+
+
+/**
+ * \brief Return the current drawable.
+ *
+ * \return the current drawable, as specified by glXMakeCurrent(), or zero if
+ * no drawable is currently bound.
+ *
+ * This function gets the current context via glXGetCurrentContext() and
+ * returns the MiniGLXContextRec::drawBuffer attribute.
+ */
+GLXDrawable
+glXGetCurrentDrawable( void )
+{
+ GLXContext glxctx = glXGetCurrentContext();
+ if (glxctx)
+ return glxctx->drawBuffer;
+ else
+ return NULL;
+}
+
+
+/**
+ * \brief Query function address.
+ *
+ * The glXGetProcAddress() function will return the address of any available
+ * OpenGL or Mini GLX function.
+ *
+ * \param procName name of the function to be returned.
+ *
+ * \return If \p procName is a valid function name, a pointer to that function
+ * will be returned. Otherwise, \c NULL will be returned.
+ *
+ * The purpose of glXGetProcAddress() is to facilitate using future extensions
+ * to OpenGL or Mini GLX. If a future version of the library adds new extension
+ * functions they'll be accessible via glXGetProcAddress(). The alternative is
+ * to hard-code calls to the new functions in the application but doing so will
+ * prevent linking the application with older versions of the library.
+ *
+ * Returns the function address by looking up its name in a static (name,
+ * address) pair list.
+ */
+const void *
+glXGetProcAddress( const GLubyte *procName )
+{
+ struct name_address {
+ const char *name;
+ const void *func;
+ };
+ static const struct name_address functions[] = {
+ { "glXChooseVisual", (void *) glXChooseVisual },
+ { "glXCreateContext", (void *) glXCreateContext },
+ { "glXDestroyContext", (void *) glXDestroyContext },
+ { "glXMakeCurrent", (void *) glXMakeCurrent },
+ { "glXSwapBuffers", (void *) glXSwapBuffers },
+ { "glXGetCurrentContext", (void *) glXGetCurrentContext },
+ { "glXGetCurrentDrawable", (void *) glXGetCurrentDrawable },
+ { "glXGetProcAddress", (void *) glXGetProcAddress },
+ { "XOpenDisplay", (void *) XOpenDisplay },
+ { "XCloseDisplay", (void *) XCloseDisplay },
+ { "XCreateWindow", (void *) XCreateWindow },
+ { "XDestroyWindow", (void *) XDestroyWindow },
+ { "XMapWindow", (void *) XMapWindow },
+ { "XCreateColormap", (void *) XCreateColormap },
+ { "XFreeColormap", (void *) XFreeColormap },
+ { "XFree", (void *) XFree },
+ { "XGetVisualinfo", (void *) XGetVisualInfo },
+ { NULL, NULL }
+ };
+ const struct name_address *entry;
+ for (entry = functions; entry->name; entry++) {
+ if (strcmp(entry->name, (const char *) procName) == 0) {
+ return entry->func;
+ }
+ }
+ return _glapi_get_proc_address((const char *) procName);
+}
+
+
+/**
+ * \brief Query the Mini GLX version.
+ *
+ * \param dpy the display handle. It is currently ignored, but should be the
+ * value returned by XOpenDisplay().
+ * \param major receives the major version number of Mini GLX.
+ * \param minor receives the minor version number of Mini GLX.
+ *
+ * \return \c True if the function succeeds, \c False if the function fails due
+ * to invalid parameters.
+ *
+ * \sa #MINI_GLX_VERSION_1_0.
+ *
+ * Returns the hard-coded Mini GLX version.
+ */
+Bool
+glXQueryVersion( Display *dpy, int *major, int *minor )
+{
+ (void) dpy;
+ *major = 1;
+ *minor = 0;
+ return True;
+}
+
+
+/*@}*/
diff --git a/src/glx/mini/miniglxP.h b/src/glx/mini/miniglxP.h
new file mode 100644
index 00000000000..a32429a677c
--- /dev/null
+++ b/src/glx/mini/miniglxP.h
@@ -0,0 +1,194 @@
+/**
+ * \file miniglxP.h
+ * \brief Define replacements for some X data types and define the DRI-related
+ * data structures.
+ *
+ * \note Cut down version of glxclient.h.
+ *
+ */
+
+#ifndef _mini_GLX_client_h_
+#define _mini_GLX_client_h_
+
+#include <signal.h>
+#include <linux/fb.h>
+
+#include <GL/miniglx.h>
+#include "glheader.h"
+#include "mtypes.h"
+
+#include "driver.h"
+#include "dri.h"
+
+/**
+ * \brief Supported pixel formats.
+ */
+enum PixelFormat {
+ PF_B8G8R8, /**< \brief 24-bit BGR */
+ PF_B8G8R8A8, /**< \brief 32-bit BGRA */
+ PF_B5G6R5, /**< \brief 16-bit BGR */
+ PF_B5G5R5, /**< \brief 15-bit BGR */
+ PF_CI8 /**< \brief 8-bit color index */
+};
+
+/**
+ * \brief X Visual type.
+ *
+ * \sa ::Visual, \ref datatypes.
+ */
+struct MiniGLXVisualRec {
+ /** \brief GLX visual information */
+ const __GLcontextModes *mode;
+
+ /** \brief pointer back to corresponding ::XVisualInfo */
+ XVisualInfo *visInfo;
+
+ /** \brief display handle */
+ Display *dpy;
+
+ /** \brief pixel format */
+ enum PixelFormat pixelFormat;
+};
+
+
+
+/**
+ * \brief X Window type.
+ *
+ * \sa ::Window, \ref datatypes.
+ */
+struct MiniGLXWindowRec {
+ Visual *visual;
+ /** \brief position (always 0,0) */
+ int x, y;
+ /** \brief size */
+ unsigned int w, h;
+ void *frontStart; /**< \brief start of front color buffer */
+ void *backStart; /**< \brief start of back color buffer */
+ size_t size; /**< \brief color buffer size, in bytes */
+ GLuint bytesPerPixel;
+ GLuint rowStride; /**< \brief in bytes */
+ GLubyte *frontBottom; /**< \brief pointer to last row */
+ GLubyte *backBottom; /**< \brief pointer to last row */
+ GLubyte *curBottom; /**< = frontBottom or backBottom */
+ __DRIdrawable *driDrawable;
+ GLuint ismapped;
+};
+
+
+/**
+ * \brief GLXContext type.
+ *
+ * \sa ::GLXContext, \ref datatypes.
+ */
+struct MiniGLXContextRec {
+ Window drawBuffer; /**< \brief drawing buffer */
+ Window curBuffer; /**< \brief current buffer */
+ VisualID vid; /**< \brief visual ID */
+ __DRIcontext *driContext; /**< \brief context dependent methods */
+};
+
+#define MINIGLX_BUF_SIZE 512
+#define MINIGLX_MAX_SERVER_FDS 10
+#define MINIGLX_MAX_CLIENT_FDS 1
+#define MINIGLX_EVENT_QUEUE_SZ 16
+#define MINIGLX_EVENT_QUEUE_MASK (MINIGLX_EVENT_QUEUE_SZ-1)
+
+/**
+ * A connection to/from the server
+ *
+ * All information is to/from the server is buffered and then dispatched by
+ * __miniglx_Select() to avoid blocking the server.
+ */
+struct MiniGLXConnection {
+ int fd; /**< \brief file descriptor */
+ char readbuf[MINIGLX_BUF_SIZE]; /**< \brief read buffer */
+ char writebuf[MINIGLX_BUF_SIZE]; /**< \brief write buffer */
+ int readbuf_count; /**< \brief count of bytes waiting to be read */
+ int writebuf_count; /**< \brief count of bytes waiting to be written */
+};
+
+
+/**
+ * \brief X Display type
+ *
+ * \sa ::Display, \ref datatypes.
+ */
+struct MiniGLXDisplayRec {
+ /** \brief fixed framebuffer screen info */
+ struct fb_fix_screeninfo FixedInfo;
+ /** \brief original and current variable framebuffer screen info */
+ struct fb_var_screeninfo OrigVarInfo, VarInfo;
+ struct sigaction OrigSigUsr1;
+ struct sigaction OrigSigUsr2;
+ int OriginalVT;
+ int ConsoleFD; /**< \brief console TTY device file descriptor */
+ int FrameBufferFD; /**< \brief framebuffer device file descriptor */
+ int NumWindows; /**< \brief number of open windows */
+ Window TheWindow; /**< \brief open window - only allow one window for now */
+ int rotateMode;
+
+
+ volatile int vtSignalFlag;
+ volatile int haveVT; /**< \brief whether the VT is hold */
+ int hwActive; /**< \brief whether the hardware is active -- mimics
+ the variations of MiniGLXDisplayRec::haveVT */
+
+
+ int IsClient; /**< \brief whether it's a client or the server */
+ int clientID;
+ int nrFds; /**< \brief number of connections (usually just one for the clients) */
+ struct MiniGLXConnection *fd; /**< \brief connections */
+
+ struct {
+ int nr, head, tail;
+ XEvent queue[MINIGLX_EVENT_QUEUE_SZ];
+ } eventqueue;
+
+ /**
+ * \name Visuals
+ *
+ * Visuals (configs) in this screen.
+ */
+ /*@{*/
+ int numModes; /**< \brief Number of modes. */
+ const __GLcontextModes *modes; /**< \brief Modes list pointer. */
+ /*@}*/
+
+ /**
+ * \name From __GLXdisplayPrivate
+ */
+ /*@{*/
+ driCreateScreenFunc *createScreen; /**< \brief \e __driCreateScreen hook */
+ __DRIscreen *driScreen; /**< \brief Screen dependent methods */
+ void *dlHandle; /**<
+ * \brief handle to the client dynamic
+ * library
+ */
+ /*@}*/
+
+ /**
+ * \brief Mini GLX specific driver hooks
+ */
+ struct DRIDriverRec *driver;
+ struct DRIDriverContextRec driverContext;
+
+ /**
+ * \name Configuration details
+ *
+ * They are read from a configuration file by __read_config_file().
+ */
+ /*@{*/
+ const char *fbdevDevice;
+ const char *clientDriverName;
+ /*@}*/
+};
+
+extern __DRIscreen *__glXFindDRIScreen(Display *dpy, int scrn);
+
+extern Bool __glXWindowExists(Display *dpy, GLXDrawable draw);
+
+extern int __miniglx_open_connections( Display *dpy );
+extern void __miniglx_close_connections( Display *dpy );
+
+#endif /* !_mini_GLX_client_h_ */
diff --git a/src/glx/mini/miniglx_events.c b/src/glx/mini/miniglx_events.c
new file mode 100644
index 00000000000..d367dba395a
--- /dev/null
+++ b/src/glx/mini/miniglx_events.c
@@ -0,0 +1,962 @@
+/**
+ * \file miniglx_events.c
+ * \brief Mini GLX client/server communication functions.
+ * \author Keith Whitwell
+ *
+ * The Mini GLX interface is a subset of the GLX interface, plus a
+ * minimal set of Xlib functions. This file adds interfaces to
+ * arbitrate a single cliprect between multiple direct rendering
+ * clients.
+ *
+ * A fairly complete client/server non-blocking communication
+ * mechanism. Probably overkill given that none of our messages
+ * currently exceed 1 byte in length and take place over the
+ * relatively benign channel provided by a Unix domain socket.
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.0
+ *
+ * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* $Id: miniglx_events.c,v 1.1 2003/08/22 20:11:43 brianp Exp $ */
+
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#include <linux/kd.h>
+#include <linux/vt.h>
+
+#include "miniglxP.h"
+
+#include "xf86drm.h"
+#include "sarea.h"
+
+#define MINIGLX_FIFO_NAME "/tmp/miniglx.fifo"
+
+/** Character messages. */
+enum msgs {
+ _CanIHaveFocus,
+ _IDontWantFocus,
+ _YouveGotFocus,
+ _YouveLostFocus,
+ _RepaintPlease,
+};
+
+/**
+ * \brief Allocate an XEvent structure on the event queue.
+ *
+ * \param dpy the display handle.
+ *
+ * \return Pointer to the queued event structure or NULL on failure.
+ *
+ * \internal
+ * If there is space on the XEvent queue, return a pointer
+ * to the next free event and increment the eventqueue tail value.
+ * Otherwise return null.
+ */
+static XEvent *queue_event( Display *dpy )
+{
+ int incr = (dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK;
+ if (incr == dpy->eventqueue.head) {
+ return 0;
+ }
+ else {
+ XEvent *ev = &dpy->eventqueue.queue[dpy->eventqueue.tail];
+ dpy->eventqueue.tail = incr;
+ return ev;
+ }
+}
+
+/**
+ * \brief Dequeue an XEvent and copy it into provided storage.
+ *
+ * \param dpy the display handle.
+ * \param event_return pointer to copy the queued event to.
+ *
+ * \return True or False depending on success.
+ *
+ * \internal
+ * If there is a queued XEvent on the queue, copy it to the provided
+ * pointer and increment the eventqueue head value. Otherwise return
+ * null.
+ */
+static int dequeue_event( Display *dpy, XEvent *event_return )
+{
+ if (dpy->eventqueue.tail == dpy->eventqueue.head) {
+ return False;
+ }
+ else {
+ *event_return = dpy->eventqueue.queue[dpy->eventqueue.head];
+ dpy->eventqueue.head += 1;
+ dpy->eventqueue.head &= MINIGLX_EVENT_QUEUE_MASK;
+ return True;
+ }
+}
+
+/**
+ * \brief Shutdown a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ *
+ * \internal
+ * Shutdown and close the file descriptor. If this is the special
+ * connection in fd[0], issue an error message and exit - there's been
+ * some sort of failure somewhere. Otherwise, let the application
+ * know about whats happened by issuing a DestroyNotify event.
+ */
+static void shut_fd( Display *dpy, int i )
+{
+ if (dpy->fd[i].fd < 0)
+ return;
+
+ shutdown (dpy->fd[i].fd, SHUT_RDWR);
+ close (dpy->fd[i].fd);
+ dpy->fd[i].fd = -1;
+ dpy->fd[i].readbuf_count = 0;
+ dpy->fd[i].writebuf_count = 0;
+
+ if (i == 0) {
+ fprintf(stderr, "server connection lost\n");
+ exit(1);
+ }
+ else {
+ /* Pass this to the application as a DestroyNotify event.
+ */
+ XEvent *er = queue_event(dpy);
+ if (!er) return;
+ er->xdestroywindow.type = DestroyNotify;
+ er->xdestroywindow.serial = 0;
+ er->xdestroywindow.send_event = 0;
+ er->xdestroywindow.display = dpy;
+ er->xdestroywindow.window = (Window)i;
+ }
+}
+
+/**
+ * \brief Send a message to a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ * \param msg the message to send.
+ * \param sz the size of the message
+ *
+ * \internal
+ * Copy the message to the write buffer for the nominated connection.
+ * This will be actually sent to that file descriptor from
+ * __miniglx_Select().
+ */
+static int send_msg( Display *dpy, int i,
+ const void *msg, size_t sz )
+{
+ int cnt = dpy->fd[i].writebuf_count;
+ if (MINIGLX_BUF_SIZE - cnt < sz) {
+ fprintf(stderr, "client %d: writebuf overflow\n", i);
+ return False;
+ }
+
+ memcpy( dpy->fd[i].writebuf + cnt, msg, sz ); cnt += sz;
+ dpy->fd[i].writebuf_count = cnt;
+ return True;
+}
+
+/**
+ * \brief Send a message to a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ * \param msg the message to send.
+ *
+ * \internal
+ * Use send_msg() to send a one-byte message to a socket.
+ */
+static int send_char_msg( Display *dpy, int i, char msg )
+{
+ return send_msg( dpy, i, &msg, sizeof(char));
+}
+
+
+/**
+ * \brief Block and receive a message from a socket connection.
+ *
+ * \param dpy the display handle.
+ * \param connection the index in dpy->fd of the socket connection.
+ * \param msg storage for the received message.
+ * \param msg_size the number of bytes to read.
+ *
+ * \internal
+ * Block and read from the connection's file descriptor
+ * until msg_size bytes have been received.
+ *
+ * Only called from welcome_message_part().
+ */
+static int blocking_read( Display *dpy, int connection,
+ char *msg, size_t msg_size )
+{
+ int i, r;
+
+ for (i = 0 ; i < msg_size ; i += r) {
+ r = read(dpy->fd[connection].fd, msg + i, msg_size - i);
+ if (r < 1) {
+ fprintf(stderr, "blocking_read: %d %s\n", r, strerror(errno));
+ shut_fd(dpy,connection);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+/**
+ * \brief Send/receive a part of the welcome message.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ * \param msg storage for the sent/received message.
+ * \param sz the number of bytes to write/read.
+ *
+ * \return True on success, or False on failure.
+ *
+ * This function is called by welcome_message_part(), to either send or receive
+ * (via blocking_read()) part of the welcome message, according to whether
+ * Display::IsClient is set.
+ *
+ * Each part of the welcome message on the wire consists of a count and then the
+ * actual message data with that number of bytes.
+ */
+static int welcome_message_part( Display *dpy, int i, void **msg, int sz )
+{
+ if (dpy->IsClient) {
+ int sz;
+ if (!blocking_read( dpy, i, (char *)&sz, sizeof(sz))) return False;
+ if (!*msg) *msg = malloc(sz);
+ if (!*msg) return False;
+ if (!blocking_read( dpy, i, *msg, sz )) return False;
+ }
+ else {
+ if (!send_msg( dpy, i, &sz, sizeof(sz))) return False;
+ if (!send_msg( dpy, i, *msg, sz )) return False;
+ }
+
+ return True;
+}
+
+/**
+ * \brief Send/receive the welcome message.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ *
+ * \return True on success, or False on failure.
+ *
+ * Using welcome_message_part(), sends/receives the client ID, the client
+ * configuration details in DRIDriverContext::shared, and the driver private
+ * message in DRIDriverContext::driverClientMsg.
+ */
+static int welcome_message( Display *dpy, int i )
+{
+ void *tmp = &dpy->driverContext.shared;
+ int *clientid = dpy->IsClient ? &dpy->clientID : &i;
+
+ if (!welcome_message_part( dpy, i, (void **)&clientid, sizeof(*clientid)))
+ return False;
+
+ if (!welcome_message_part( dpy, i, &tmp, sizeof(dpy->driverContext.shared)))
+ return False;
+
+ if (!welcome_message_part( dpy, i,
+ (void **)&dpy->driverContext.driverClientMsg,
+ dpy->driverContext.driverClientMsgSize ))
+ return False;
+
+ return True;
+}
+
+
+/**
+ * \brief Handle a new client connection.
+ *
+ * \param dpy the display handle.
+ *
+ * \return True on success or False on failure.
+ *
+ * Accepts the connection, sets it in non-blocking operation, and finds a free
+ * slot in Display::fd for it.
+ */
+static int handle_new_client( Display *dpy )
+{
+ struct sockaddr_un client_address;
+ unsigned int l = sizeof(client_address);
+ int r, i;
+
+ r = accept(dpy->fd[0].fd, (struct sockaddr *) &client_address, &l);
+ if (r < 0) {
+ perror ("accept()");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+ if (fcntl(r, F_SETFL, O_NONBLOCK) != 0) {
+ perror("fcntl");
+ close(r);
+ return False;
+ }
+
+
+ /* Some rough & ready adaption of the XEvent semantics.
+ */
+ for (i = 1 ; i < dpy->nrFds ; i++) {
+ if (dpy->fd[i].fd < 0) {
+ XEvent *er = queue_event(dpy);
+ if (!er) {
+ close(r);
+ return False;
+ }
+
+ dpy->fd[i].fd = r;
+ er->xcreatewindow.type = CreateNotify;
+ er->xcreatewindow.serial = 0;
+ er->xcreatewindow.send_event = 0;
+ er->xcreatewindow.display = dpy;
+ er->xcreatewindow.window = (Window)i; /* fd slot == window, now? */
+
+ /* Send the driver client message - this is expected as the
+ * first message on a new connection. The recpient already
+ * knows the size of the message.
+ */
+ welcome_message( dpy, i );
+ return True;
+ }
+ }
+
+
+ fprintf(stderr, "[miniglx] %s: Max nr clients exceeded\n", __FUNCTION__);
+ close(r);
+ return False;
+}
+
+/**
+ * This routine "puffs out" the very basic communications between
+ * client and server to full-sized X Events that can be handled by the
+ * application.
+ *
+ * \param dpy the display handle.
+ * \param i the index in dpy->fd of the socket connection.
+ *
+ * \return True on success or False on failure.
+ *
+ * \internal
+ * Interprets the message (see msg) into a XEvent and advances the file FIFO
+ * buffer.
+ */
+static int
+handle_fifo_read( Display *dpy, int i )
+{
+ while (dpy->fd[i].readbuf_count) {
+ char id = dpy->fd[i].readbuf[0];
+ XEvent *er;
+ int count = 1;
+
+ if (dpy->IsClient) {
+ switch (id) {
+ /* The server has called XMapWindow on a client window */
+ case _YouveGotFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xmap.type = MapNotify;
+ er->xmap.serial = 0;
+ er->xmap.send_event = False;
+ er->xmap.display = dpy;
+ er->xmap.event = dpy->TheWindow;
+ er->xmap.window = dpy->TheWindow;
+ er->xmap.override_redirect = False;
+ if (dpy->driver->notifyFocus)
+ dpy->driver->notifyFocus( 1 );
+ break;
+
+ /* The server has called XMapWindow on a client window */
+ case _RepaintPlease:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xexpose.type = Expose;
+ er->xexpose.serial = 0;
+ er->xexpose.send_event = False;
+ er->xexpose.display = dpy;
+ er->xexpose.window = dpy->TheWindow;
+ if (dpy->rotateMode) {
+ er->xexpose.x = dpy->TheWindow->y;
+ er->xexpose.y = dpy->TheWindow->x;
+ er->xexpose.width = dpy->TheWindow->h;
+ er->xexpose.height = dpy->TheWindow->w;
+ }
+ else {
+ er->xexpose.x = dpy->TheWindow->x;
+ er->xexpose.y = dpy->TheWindow->y;
+ er->xexpose.width = dpy->TheWindow->w;
+ er->xexpose.height = dpy->TheWindow->h;
+ }
+ er->xexpose.count = 0;
+ break;
+
+ /* The server has called 'XUnmapWindow' on a client
+ * window.
+ */
+ case _YouveLostFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xunmap.type = UnmapNotify;
+ er->xunmap.serial = 0;
+ er->xunmap.send_event = False;
+ er->xunmap.display = dpy;
+ er->xunmap.event = dpy->TheWindow;
+ er->xunmap.window = dpy->TheWindow;
+ er->xunmap.from_configure = False;
+ if (dpy->driver->notifyFocus)
+ dpy->driver->notifyFocus( 0 );
+ break;
+
+ default:
+ fprintf(stderr, "Client received unhandled message type %d\n", id);
+ shut_fd(dpy, i); /* Actually shuts down the client */
+ return False;
+ }
+ }
+ else {
+ switch (id) {
+ /* Lets the server know that the client is ready to render
+ * (having called 'XMapWindow' locally).
+ */
+ case _CanIHaveFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xmaprequest.type = MapRequest;
+ er->xmaprequest.serial = 0;
+ er->xmaprequest.send_event = False;
+ er->xmaprequest.display = dpy;
+ er->xmaprequest.parent = 0;
+ er->xmaprequest.window = (Window)i;
+ break;
+
+ /* Both _YouveLostFocus and _IDontWantFocus generate unmap
+ * events. The idea is that _YouveLostFocus lets the client
+ * know that it has had focus revoked by the server, whereas
+ * _IDontWantFocus lets the server know that the client has
+ * unmapped its own window.
+ */
+ case _IDontWantFocus:
+ er = queue_event(dpy);
+ if (!er) return False;
+ er->xunmap.type = UnmapNotify;
+ er->xunmap.serial = 0;
+ er->xunmap.send_event = False;
+ er->xunmap.display = dpy;
+ er->xunmap.event = (Window)i;
+ er->xunmap.window = (Window)i;
+ er->xunmap.from_configure = False;
+ break;
+
+ default:
+ fprintf(stderr, "Server received unhandled message type %d\n", id);
+ shut_fd(dpy, i); /* Generates DestroyNotify event */
+ return False;
+ }
+ }
+
+ dpy->fd[i].readbuf_count -= count;
+
+ if (dpy->fd[i].readbuf_count) {
+ memmove(dpy->fd[i].readbuf,
+ dpy->fd[i].readbuf + count,
+ dpy->fd[i].readbuf_count);
+ }
+ }
+
+ return True;
+}
+
+/**
+ * Handle a VT signal
+ *
+ * \param dpy display handle.
+ *
+ * The VT switches is detected by comparing Display::haveVT and
+ * Display::hwActive. When loosing the VT the hardware lock is acquired, the
+ * hardware is shutdown via a call to DRIDriverRec::shutdownHardware(), and the
+ * VT released. When acquiring the VT back the hardware state is restored via a
+ * call to DRIDriverRec::restoreHardware() and the hardware lock released.
+ */
+static void __driHandleVtSignals( Display *dpy )
+{
+ dpy->vtSignalFlag = 0;
+
+ fprintf(stderr, "%s: haveVT %d hwActive %d\n", __FUNCTION__,
+ dpy->haveVT, dpy->hwActive);
+
+ if (!dpy->haveVT && dpy->hwActive) {
+ /* Need to get lock and shutdown hardware */
+ DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ dpy->driver->shutdownHardware( &dpy->driverContext );
+
+ /* Can now give up control of the VT */
+ ioctl( dpy->ConsoleFD, VT_RELDISP, 1 );
+ dpy->hwActive = 0;
+ }
+ else if (dpy->haveVT && !dpy->hwActive) {
+ /* Get VT (wait??) */
+ ioctl( dpy->ConsoleFD, VT_RELDISP, VT_ACTIVATE );
+
+ /* restore HW state, release lock */
+ dpy->driver->restoreHardware( &dpy->driverContext );
+ DRM_UNLOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ dpy->hwActive = 1;
+ }
+}
+
+
+#undef max
+#define max(x,y) ((x) > (y) ? (x) : (y))
+
+/**
+ * Logic for the select() call.
+ *
+ * \param dpy display handle.
+ * \param n highest fd in any set plus one.
+ * \param rfds fd set to be watched for reading, or NULL to create one.
+ * \param wfds fd set to be watched for writing, or NULL to create one.
+ * \param xfds fd set to be watched for exceptions or error, or NULL to create one.
+ * \param tv timeout value, or NULL for no timeout.
+ *
+ * \return number of file descriptors contained in the sets, or a negative number on failure.
+ *
+ * \note
+ * This all looks pretty complex, but is necessary especially on the
+ * server side to prevent a poorly-behaved client from causing the
+ * server to block in a read or write and hence not service the other
+ * clients.
+ *
+ * \sa
+ * See select_tut in the Linux manual pages for more discussion.
+ *
+ * \internal
+ * Creates and initializes the file descriptor sets by inspecting Display::fd
+ * if these aren't passed in the function call. Calls select() and fulfill the
+ * demands by trying to fill MiniGLXConnection::readbuf and draining
+ * MiniGLXConnection::writebuf.
+ * The server fd[0] is handled specially for new connections, by calling
+ * handle_new_client().
+ *
+ */
+int
+__miniglx_Select( Display *dpy, int n, fd_set *rfds, fd_set *wfds, fd_set *xfds,
+ struct timeval *tv )
+{
+ int i;
+ int retval;
+ fd_set my_rfds, my_wfds;
+ struct timeval my_tv;
+
+ if (!rfds) {
+ rfds = &my_rfds;
+ FD_ZERO(rfds);
+ }
+
+ if (!wfds) {
+ wfds = &my_wfds;
+ FD_ZERO(wfds);
+ }
+
+ /* Don't block if there are events queued. Review this if the
+ * flush in XMapWindow is changed to blocking. (Test case:
+ * miniglxtest).
+ */
+ if (dpy->eventqueue.head != dpy->eventqueue.tail) {
+ my_tv.tv_sec = my_tv.tv_usec = 0;
+ tv = &my_tv;
+ }
+
+ for (i = 0 ; i < dpy->nrFds; i++) {
+ if (dpy->fd[i].fd < 0)
+ continue;
+
+ if (dpy->fd[i].writebuf_count)
+ FD_SET(dpy->fd[i].fd, wfds);
+
+ if (dpy->fd[i].readbuf_count < MINIGLX_BUF_SIZE)
+ FD_SET(dpy->fd[i].fd, rfds);
+
+ n = max(n, dpy->fd[i].fd + 1);
+ }
+
+ if (dpy->vtSignalFlag)
+ __driHandleVtSignals( dpy );
+
+ retval = select( n, rfds, wfds, xfds, tv );
+
+ if (dpy->vtSignalFlag) {
+ int tmp = errno;
+ __driHandleVtSignals( dpy );
+ errno = tmp;
+ }
+
+ if (retval < 0) {
+ FD_ZERO(rfds);
+ FD_ZERO(wfds);
+ return retval;
+ }
+
+ /* Handle server fd[0] specially on the server - accept new client
+ * connections.
+ */
+ if (!dpy->IsClient) {
+ if (FD_ISSET(dpy->fd[0].fd, rfds)) {
+ FD_CLR(dpy->fd[0].fd, rfds);
+ handle_new_client( dpy );
+ }
+ }
+
+ /* Otherwise, try and fill readbuffer and drain writebuffer:
+ */
+ for (i = 0 ; i < dpy->nrFds ; i++) {
+ if (dpy->fd[i].fd < 0)
+ continue;
+
+ /* If there aren't any event slots left, don't examine
+ * any more file events. This will prevent lost events.
+ */
+ if (dpy->eventqueue.head ==
+ ((dpy->eventqueue.tail + 1) & MINIGLX_EVENT_QUEUE_MASK)) {
+ fprintf(stderr, "leaving event loop as event queue is full\n");
+ return retval;
+ }
+
+ if (FD_ISSET(dpy->fd[i].fd, wfds)) {
+ int r = write(dpy->fd[i].fd,
+ dpy->fd[i].writebuf,
+ dpy->fd[i].writebuf_count);
+
+ if (r < 1)
+ shut_fd(dpy,i);
+ else {
+ dpy->fd[i].writebuf_count -= r;
+ if (dpy->fd[i].writebuf_count) {
+ memmove(dpy->fd[i].writebuf,
+ dpy->fd[i].writebuf + r,
+ dpy->fd[i].writebuf_count);
+ }
+ }
+ }
+
+ if (FD_ISSET(dpy->fd[i].fd, rfds)) {
+ int r = read(dpy->fd[i].fd,
+ dpy->fd[i].readbuf + dpy->fd[i].readbuf_count,
+ MINIGLX_BUF_SIZE - dpy->fd[i].readbuf_count);
+
+ if (r < 1)
+ shut_fd(dpy,i);
+ else {
+ dpy->fd[i].readbuf_count += r;
+
+ handle_fifo_read( dpy, i );
+ }
+ }
+ }
+
+ return retval;
+}
+
+/**
+ * \brief Handle socket events.
+ *
+ * \param dpy the display handle.
+ * \param nonblock whether to return immediately or wait for an event.
+ *
+ * \return True on success, False on failure. Aborts on critical error.
+ *
+ * \internal
+ * This function is the select() main loop.
+ */
+static int handle_fd_events( Display *dpy, int nonblock )
+{
+ while (1) {
+ struct timeval tv = {0, 0};
+ int r = __miniglx_Select( dpy, 0, 0, 0, 0, nonblock ? &tv : 0 );
+ if (r >= 0)
+ return True;
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ perror ("select()");
+ exit (1);
+ }
+}
+
+/**
+ * Initializes the connections.
+ *
+ * \param dpy the display handle.
+ *
+ * \return True on success or False on failure.
+ *
+ * Allocates and initializes the Display::fd array and create a Unix socket on
+ * the first entry. For a server binds the socket to a filename and listen for
+ * connections. For a client connects to the server and waits for a welcome
+ * message. Sets the socket in nonblocking mode.
+ */
+int __miniglx_open_connections( Display *dpy )
+{
+ struct sockaddr_un sa;
+ int i;
+
+ dpy->nrFds = dpy->IsClient ? 1 : MINIGLX_MAX_SERVER_FDS;
+ dpy->fd = calloc(1, dpy->nrFds * sizeof(struct MiniGLXConnection));
+ if (!dpy->fd)
+ return False;
+
+ for (i = 0 ; i < dpy->nrFds ; i++)
+ dpy->fd[i].fd = -1;
+
+ if (!dpy->IsClient) {
+ if (unlink(MINIGLX_FIFO_NAME) != 0 && errno != ENOENT) {
+ perror("unlink " MINIGLX_FIFO_NAME);
+ return False;
+ }
+
+ }
+
+ /* Create a Unix socket -- Note this is *not* a network connection!
+ */
+ dpy->fd[0].fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (dpy->fd[0].fd < 0) {
+ perror("socket " MINIGLX_FIFO_NAME);
+ return False;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, MINIGLX_FIFO_NAME);
+
+ if (dpy->IsClient) {
+ /* Connect to server
+ */
+ if (connect(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
+ perror("connect");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+ /* Wait for configuration messages from the server.
+ */
+ welcome_message( dpy, 0 );
+ }
+ else {
+ mode_t tmp = umask( 0000 ); /* open to everybody ? */
+
+ /* Bind socket to our filename
+ */
+ if (bind(dpy->fd[0].fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) {
+ perror("bind");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+ umask( tmp );
+
+ /* Listen for connections
+ */
+ if (listen(dpy->fd[0].fd, 5) != 0) {
+ perror("listen");
+ shut_fd(dpy,0);
+ return False;
+ }
+ }
+
+ if (fcntl(dpy->fd[0].fd, F_SETFL, O_NONBLOCK) != 0) {
+ perror("fcntl");
+ shut_fd(dpy,0);
+ return False;
+ }
+
+
+ return True;
+}
+
+
+/**
+ * Frees the connections initialized by __miniglx_open_connections().
+ *
+ * \param dpy the display handle.
+ */
+void __miniglx_close_connections( Display *dpy )
+{
+ int i;
+
+ for (i = 0 ; i < dpy->nrFds ; i++) {
+ if (dpy->fd[i].fd >= 0) {
+ shutdown (dpy->fd[i].fd, SHUT_RDWR);
+ close (dpy->fd[i].fd);
+ }
+ }
+
+ dpy->nrFds = 0;
+ free(dpy->fd);
+}
+
+
+/**
+ * Set a drawable flag.
+ *
+ * \param dpy the display handle.
+ * \param w drawable (window).
+ * \param flag flag.
+ *
+ * Sets the specified drawable flag in the SAREA and increment its stamp while
+ * holding the light hardware lock.
+ */
+static void set_drawable_flag( Display *dpy, int w, int flag )
+{
+ if (dpy->driverContext.pSAREA) {
+ if (dpy->hwActive)
+ DRM_LIGHT_LOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+
+ dpy->driverContext.pSAREA->drawableTable[w].stamp++;
+ dpy->driverContext.pSAREA->drawableTable[w].flags = flag;
+
+ if (dpy->hwActive)
+ DRM_UNLOCK( dpy->driverContext.drmFD,
+ dpy->driverContext.pSAREA,
+ dpy->driverContext.serverContext );
+ }
+}
+
+
+
+/**
+ * \brief Map Window.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param w the window handle.
+ *
+ * If called by a client, sends a request for focus to the server. If
+ * called by the server, will generate a MapNotify and Expose event at
+ * the client.
+ *
+ */
+void
+XMapWindow( Display *dpy, Window w )
+{
+ if (dpy->IsClient)
+ send_char_msg( dpy, 0, _CanIHaveFocus );
+ else {
+ set_drawable_flag( dpy, (int)w, 1 );
+ send_char_msg( dpy, (int)w, _YouveGotFocus );
+ send_char_msg( dpy, (int)w, _RepaintPlease );
+ dpy->TheWindow = w;
+ }
+ handle_fd_events( dpy, 0 ); /* flush write queue */
+}
+
+/**
+ * \brief Unmap Window.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param w the window handle.
+ *
+ * Called from the client: Lets the server know that the window won't
+ * be updated anymore.
+ *
+ * Called from the server: Tells the specified client that it no longer
+ * holds the focus.
+ */
+void
+XUnmapWindow( Display *dpy, Window w )
+{
+ if (dpy->IsClient) {
+ send_char_msg( dpy, 0, _IDontWantFocus );
+ }
+ else {
+ dpy->TheWindow = 0;
+ set_drawable_flag( dpy, (int)w, 0 );
+ send_char_msg( dpy, (int)w, _YouveLostFocus );
+ }
+ handle_fd_events( dpy, 0 ); /* flush write queue */
+}
+
+
+/**
+ * \brief Block and wait for next X event.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param event_return a pointer to an XEvent structure for the returned data.
+ *
+ * Wait until there is a new XEvent pending.
+ */
+int XNextEvent(Display *dpy, XEvent *event_return)
+{
+ for (;;) {
+ if ( dpy->eventqueue.head != dpy->eventqueue.tail )
+ return dequeue_event( dpy, event_return );
+
+ handle_fd_events( dpy, 0 );
+ }
+}
+
+/**
+ * \brief Non-blocking check for next X event.
+ *
+ * \param dpy the display handle as returned by XOpenDisplay().
+ * \param event_mask ignored.
+ * \param event_return a pointer to an XEvent structure for the returned data.
+ *
+ * Check if there is a new XEvent pending. Note that event_mask is
+ * ignored and any pending event will be returned.
+ */
+Bool XCheckMaskEvent(Display *dpy, long event_mask, XEvent *event_return)
+{
+ if ( dpy->eventqueue.head != dpy->eventqueue.tail )
+ return dequeue_event( dpy, event_return );
+
+ handle_fd_events( dpy, 1 );
+
+ return dequeue_event( dpy, event_return );
+}
diff --git a/src/glx/mini/sarea.h b/src/glx/mini/sarea.h
new file mode 100644
index 00000000000..47545e10e9e
--- /dev/null
+++ b/src/glx/mini/sarea.h
@@ -0,0 +1,96 @@
+/**
+ * \file sarea.h
+ * \brief SAREA definitions.
+ *
+ * The SAREA is a memory region is shared by the DRM device, the X server and
+ * the clients.
+ *
+ * This file defines its layout in user space.
+ *
+ * \author Kevin E. Martin <[email protected]>
+ * \author Jens Owen <[email protected]>
+ * \author Rickard E. (Rik) Faith <[email protected]>
+ */
+
+/*
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SAREA_H_
+#define _SAREA_H_
+
+#include "xf86drm.h"
+
+/* SAREA area needs to be at least a page */
+#if defined(__alpha__)
+#define SAREA_MAX 0x2000
+#elif defined(__ia64__)
+#define SAREA_MAX 0x10000 /* 64kB */
+#else
+/* Intel 830M driver needs at least 8k SAREA */
+#define SAREA_MAX 0x2000
+#endif
+
+#define SAREA_MAX_DRAWABLES 256
+
+#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000
+
+/**
+ * \brief SAREA per drawable information.
+ *
+ * \sa _XF86DRISAREA.
+ */
+typedef struct _XF86DRISAREADrawable {
+ unsigned int stamp;
+ unsigned int flags;
+} XF86DRISAREADrawableRec, *XF86DRISAREADrawablePtr;
+
+/**
+ * \brief SAREA frame information.
+ *
+ * \sa _XF86DRISAREA.
+ */
+typedef struct _XF86DRISAREAFrame {
+ unsigned int x;
+ unsigned int y;
+ unsigned int width;
+ unsigned int height;
+ unsigned int fullscreen;
+} XF86DRISAREAFrameRec, *XF86DRISAREAFramePtr;
+
+/**
+ * \brief SAREA definition.
+ */
+typedef struct _XF86DRISAREA {
+ /** first thing is always the DRM locking structure */
+ drmLock lock;
+ /** \todo Use readers/writer lock for drawable_lock */
+ drmLock drawable_lock;
+ XF86DRISAREADrawableRec drawableTable[SAREA_MAX_DRAWABLES];
+ XF86DRISAREAFrameRec frame;
+ drmContext dummy_context;
+} XF86DRISAREARec, *XF86DRISAREAPtr;
+
+#endif
diff --git a/src/glx/mini/xf86drm.c b/src/glx/mini/xf86drm.c
new file mode 100644
index 00000000000..bbb02e4032b
--- /dev/null
+++ b/src/glx/mini/xf86drm.c
@@ -0,0 +1,1587 @@
+/**
+ * \file xf86drm.c
+ * \brief User-level interface to DRM device
+ *
+ * This file is an user-friendly interface to the DRM ioctls defined in drm.h.
+ *
+ * This covers only the device-independent ioctls -- it is up to the driver to
+ * wrap the device-dependent ioctls.
+ *
+ * \author Rickard E. (Rik) Faith <[email protected]>
+ * \author Kevin E. Martin <[email protected]>
+ */
+
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <string.h>
+# include <ctype.h>
+# include <fcntl.h>
+# include <errno.h>
+# include <signal.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <sys/mman.h>
+# include <sys/time.h>
+# include <stdarg.h>
+# include "drm.h"
+
+/* Not all systems have MAP_FAILED defined */
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+#include "xf86drm.h"
+
+#ifndef DRM_MAJOR
+#define DRM_MAJOR 226 /* Linux */
+#endif
+
+#ifndef __linux__
+#undef DRM_MAJOR
+#define DRM_MAJOR 145 /* Should set in drm.h for *BSD */
+#endif
+
+#ifndef DRM_MAX_MINOR
+#define DRM_MAX_MINOR 16
+#endif
+
+#ifdef __linux__
+#include <sys/sysmacros.h> /* for makedev() */
+#endif
+
+#ifndef makedev
+ /* This definition needs to be changed on
+ some systems if dev_t is a structure.
+ If there is a header file we can get it
+ from, there would be best. */
+#define makedev(x,y) ((dev_t)(((x) << 8) | (y)))
+#endif
+
+
+/**
+ * \brief Output a message to stderr.
+ *
+ * \param format printf() like format string.
+ *
+ * \internal
+ * This function is a wrapper around vfprintf().
+ */
+static void
+drmMsg(const char *format, ...)
+{
+ va_list ap;
+
+ const char *env;
+ if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose"))
+ {
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ }
+}
+
+
+
+/**
+ * \brief Open the DRM device, creating it if necessary.
+ *
+ * \param dev major and minor numbers of the device.
+ * \param minor minor number of the device.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * Assembles the device name from \p minor and opens it, creating the device
+ * special file node with the major and minor numbers specified by \p dev and
+ * parent directory if necessary and was called by root.
+ */
+static int drmOpenDevice(long dev, int minor)
+{
+ struct stat st;
+ char buf[64];
+ int fd;
+ mode_t devmode = DRM_DEV_MODE;
+ int isroot = !geteuid();
+#if defined(XFree86Server)
+ uid_t user = DRM_DEV_UID;
+ gid_t group = DRM_DEV_GID;
+#endif
+
+ drmMsg("drmOpenDevice: minor is %d\n", minor);
+
+#if defined(XFree86Server)
+ devmode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE;
+ devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
+ group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID;
+#endif
+
+ if (stat(DRM_DIR_NAME, &st)) {
+ if (!isroot) return DRM_ERR_NOT_ROOT;
+ mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+ chown(DRM_DIR_NAME, 0, 0); /* root:root */
+ chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
+ }
+
+ sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
+ drmMsg("drmOpenDevice: node name is %s\n", buf);
+ if (stat(buf, &st)) {
+ if (!isroot) return DRM_ERR_NOT_ROOT;
+ remove(buf);
+ mknod(buf, S_IFCHR | devmode, dev);
+ }
+#if defined(XFree86Server)
+ chown(buf, user, group);
+ chmod(buf, devmode);
+#endif
+
+ fd = open(buf, O_RDWR, 0);
+ drmMsg("drmOpenDevice: open result is %d, (%s)\n",
+ fd, fd < 0 ? strerror(errno) : "OK");
+ if (fd >= 0) return fd;
+
+ if (st.st_rdev != dev) {
+ if (!isroot) return DRM_ERR_NOT_ROOT;
+ remove(buf);
+ mknod(buf, S_IFCHR | devmode, dev);
+ }
+ fd = open(buf, O_RDWR, 0);
+ drmMsg("drmOpenDevice: open result is %d, (%s)\n",
+ fd, fd < 0 ? strerror(errno) : "OK");
+ if (fd >= 0) return fd;
+
+ drmMsg("drmOpenDevice: Open failed\n");
+ remove(buf);
+ return -errno;
+}
+
+
+/**
+ * \brief Open the DRM device
+ *
+ * \param minor device minor number.
+ * \param create allow to create the device if set.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
+ * name from \p minor and opens it.
+ */
+static int drmOpenMinor(int minor, int create)
+{
+ int fd;
+ char buf[64];
+
+ if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
+
+ sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
+ if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd;
+ drmMsg("drmOpenMinor: open result is %d, (%s)\n",
+ fd, fd < 0 ? strerror(errno) : "OK");
+ return -errno;
+}
+
+
+/**
+ * \brief Determine whether the DRM kernel driver has been loaded.
+ *
+ * \return 1 if the DRM driver is loaded, 0 otherwise.
+ *
+ * \internal
+ * Determine the presence of the kernel driver by attempting to open the 0
+ * minor and get version information. For backward compatibility with older
+ * Linux implementations, /proc/dri is also checked.
+ */
+int drmAvailable(void)
+{
+ drmVersionPtr version;
+ int retval = 0;
+ int fd;
+
+ if ((fd = drmOpenMinor(0, 1)) < 0) {
+ /* Try proc for backward Linux compatibility */
+ if (!access("/proc/dri/0", R_OK)) return 1;
+ return 0;
+ }
+
+ if ((version = drmGetVersion(fd))) {
+ retval = 1;
+ drmFreeVersion(version);
+ }
+ close(fd);
+ drmMsg("close %d\n", fd);
+
+ return retval;
+}
+
+
+/**
+ * \brief Open the device by bus ID.
+ *
+ * \param busid bus ID.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
+ * comparing the device bus ID with the one supplied.
+ *
+ * \sa drmOpenMinor() and drmGetBusid().
+ */
+static int drmOpenByBusid(const char *busid)
+{
+ int i;
+ int fd;
+ const char *buf;
+
+ drmMsg("drmOpenByBusid: busid is %s\n", busid);
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ fd = drmOpenMinor(i, 1);
+ drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
+ if (fd >= 0) {
+ buf = drmGetBusid(fd);
+ drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
+ if (buf && !strcmp(buf, busid)) {
+ drmFreeBusid(buf);
+ return fd;
+ }
+ if (buf) drmFreeBusid(buf);
+ close(fd);
+ drmMsg("close %d\n", fd);
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * \brief Open the device by name.
+ *
+ * \param name driver name.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * This function opens the first minor number that matches the driver name and
+ * isn't already in use. If it's in use it then it will already have a bus ID
+ * assigned.
+ *
+ * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
+ */
+static int drmOpenByName(const char *name)
+{
+ int i;
+ int fd;
+ drmVersionPtr version;
+ char * id;
+
+ if (!drmAvailable()) {
+#if !defined(XFree86Server)
+ return -1;
+#else
+ /* try to load the kernel module now */
+ if (!xf86LoadKernelModule(name)) {
+ ErrorF("[drm] failed to load kernel module \"%s\"\n",
+ name);
+ return -1;
+ }
+#endif
+ }
+
+ for (i = 0; i < DRM_MAX_MINOR; i++) {
+ if ((fd = drmOpenMinor(i, 1)) >= 0) {
+ if ((version = drmGetVersion(fd))) {
+ if (!strcmp(version->name, name)) {
+ drmFreeVersion(version);
+
+/* return fd; */
+
+ id = drmGetBusid(fd);
+ drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
+ if (!id || !*id) {
+ if (id) {
+ drmFreeBusid(id);
+ }
+ return fd;
+ } else {
+ drmFreeBusid(id);
+ }
+ } else {
+ drmFreeVersion(version);
+ }
+ }
+ close(fd);
+ drmMsg("close %d\n", fd);
+ }
+ }
+
+ return -1;
+}
+
+
+/**
+ * \brief Open the DRM device.
+ *
+ * Looks up the specified name and bus ID, and opens the device found. The
+ * entry in /dev/dri is created if necessary and if called by root.
+ *
+ * \param name driver name. Not referenced if bus ID is supplied.
+ * \param busid bus ID. Zero if not known.
+ *
+ * \return a file descriptor on success, or a negative value on error.
+ *
+ * \internal
+ * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
+ * otherwise.
+ */
+int drmOpen(const char *name, const char *busid)
+{
+
+ if (busid) return drmOpenByBusid(busid);
+ return drmOpenByName(name);
+}
+
+
+/**
+ * \brief Free the version information returned by drmGetVersion().
+ *
+ * \param v pointer to the version information.
+ *
+ * \internal
+ * It frees the memory pointed by \p %v as well as all the non-null strings
+ * pointers in it.
+ */
+void drmFreeVersion(drmVersionPtr v)
+{
+ if (!v) return;
+ if (v->name) free(v->name);
+ if (v->date) free(v->date);
+ if (v->desc) free(v->desc);
+ free(v);
+}
+
+
+/**
+ * \brief Free the non-public version information returned by the kernel.
+ *
+ * \param v pointer to the version information.
+ *
+ * \internal
+ * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
+ * the non-null strings pointers in it.
+ */
+static void drmFreeKernelVersion(drm_version_t *v)
+{
+ if (!v) return;
+ if (v->name) free(v->name);
+ if (v->date) free(v->date);
+ if (v->desc) free(v->desc);
+ free(v);
+}
+
+
+/**
+ * \brief Copy version information.
+ *
+ * \param d destination pointer.
+ * \param s source pointer.
+ *
+ * \internal
+ * Used by drmGetVersion() to translate the information returned by the ioctl
+ * interface in a private structure into the public structure counterpart.
+ */
+static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
+{
+ d->version_major = s->version_major;
+ d->version_minor = s->version_minor;
+ d->version_patchlevel = s->version_patchlevel;
+ d->name_len = s->name_len;
+ d->name = strdup(s->name);
+ d->date_len = s->date_len;
+ d->date = strdup(s->date);
+ d->desc_len = s->desc_len;
+ d->desc = strdup(s->desc);
+}
+
+
+/**
+ * \brief Query the driver version information.
+ *
+ * \param fd file descriptor.
+ *
+ * \return pointer to a drmVersion structure which should be freed with
+ * drmFreeVersion().
+ *
+ * \note Similar information is available via /proc/dri.
+ *
+ * \internal
+ * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
+ * first with zeros to get the string lengths, and then the actually strings.
+ * It also null-terminates them since they might not be already.
+ */
+drmVersionPtr drmGetVersion(int fd)
+{
+ drmVersionPtr retval;
+ drm_version_t *version = malloc(sizeof(*version));
+
+ /* First, get the lengths */
+ version->name_len = 0;
+ version->name = NULL;
+ version->date_len = 0;
+ version->date = NULL;
+ version->desc_len = 0;
+ version->desc = NULL;
+
+ if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
+ drmFreeKernelVersion(version);
+ return NULL;
+ }
+
+ /* Now, allocate space and get the data */
+ if (version->name_len)
+ version->name = malloc(version->name_len + 1);
+ if (version->date_len)
+ version->date = malloc(version->date_len + 1);
+ if (version->desc_len)
+ version->desc = malloc(version->desc_len + 1);
+
+ if (ioctl(fd, DRM_IOCTL_VERSION, version)) {
+ drmFreeKernelVersion(version);
+ return NULL;
+ }
+
+ /* The results might not be null-terminated
+ strings, so terminate them. */
+
+ if (version->name_len) version->name[version->name_len] = '\0';
+ if (version->date_len) version->date[version->date_len] = '\0';
+ if (version->desc_len) version->desc[version->desc_len] = '\0';
+
+ /* Now, copy it all back into the
+ client-visible data structure... */
+ retval = malloc(sizeof(*retval));
+ drmCopyVersion(retval, version);
+ drmFreeKernelVersion(version);
+ return retval;
+}
+
+
+/**
+ * \brief Get version information for the DRM user space library.
+ *
+ * This version number is driver independent.
+ *
+ * \param fd file descriptor.
+ *
+ * \return version information.
+ *
+ * \internal
+ * This function allocates and fills a drm_version structure with a hard coded
+ * version number.
+ */
+drmVersionPtr drmGetLibVersion(int fd)
+{
+ drm_version_t *version = malloc(sizeof(*version));
+
+ /* Version history:
+ * revision 1.0.x = original DRM interface with no drmGetLibVersion
+ * entry point and many drm<Device> extensions
+ * revision 1.1.x = added drmCommand entry points for device extensions
+ * added drmGetLibVersion to identify libdrm.a version
+ */
+ version->version_major = 1;
+ version->version_minor = 1;
+ version->version_patchlevel = 0;
+
+ return (drmVersionPtr)version;
+}
+
+
+/**
+ * \brief Free the bus ID information.
+ *
+ * \param busid bus ID information string as given by drmGetBusid().
+ *
+ * \internal
+ * This function is just frees the memory pointed by \p busid.
+ */
+void drmFreeBusid(const char *busid)
+{
+ free((void *)busid);
+}
+
+
+/**
+ * \brief Get the bus ID of the device.
+ *
+ * \param fd file descriptor.
+ *
+ * \return bus ID string.
+ *
+ * \internal
+ * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
+ * get the string length and data, passing the arguments in a drm_unique
+ * structure.
+ */
+char *drmGetBusid(int fd)
+{
+ drm_unique_t u;
+
+ u.unique_len = 0;
+ u.unique = NULL;
+
+ if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
+ u.unique = malloc(u.unique_len + 1);
+ if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL;
+ u.unique[u.unique_len] = '\0';
+ return u.unique;
+}
+
+
+/**
+ * \brief Set the bus ID of the device.
+ *
+ * \param fd file descriptor.
+ * \param busid bus ID string.
+ *
+ * \return zero on success, negative on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
+ * the arguments in a drm_unique structure.
+ */
+int drmSetBusid(int fd, const char *busid)
+{
+ drm_unique_t u;
+
+ u.unique = (char *)busid;
+ u.unique_len = strlen(busid);
+
+ if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Specifies a range of memory that is available for mapping by a
+ * non-root process.
+ *
+ * \param fd file descriptor.
+ * \param offset usually the physical address. The actual meaning depends of
+ * the \p type parameter. See below.
+ * \param size of the memory in bytes.
+ * \param type type of the memory to be mapped.
+ * \param flags combination of several flags to modify the function actions.
+ * \param handle will be set to a value that may be used as the offset
+ * parameter for mmap().
+ *
+ * \return zero on success or a negative value on error.
+ *
+ * \par Mapping the frame buffer
+ * For the frame buffer
+ * - \p offset will be the physical address of the start of the frame buffer,
+ * - \p size will be the size of the frame buffer in bytes, and
+ * - \p type will be DRM_FRAME_BUFFER.
+ *
+ * \par
+ * The area mapped will be uncached. If MTRR support is available in the
+ * kernel, the frame buffer area will be set to write combining.
+ *
+ * \par Mapping the MMIO register area
+ * For the MMIO register area,
+ * - \p offset will be the physical address of the start of the register area,
+ * - \p size will be the size of the register area bytes, and
+ * - \p type will be DRM_REGISTERS.
+ * \par
+ * The area mapped will be uncached.
+ *
+ * \par Mapping the SAREA
+ * For the SAREA,
+ * - \p offset will be ignored and should be set to zero,
+ * - \p size will be the desired size of the SAREA in bytes,
+ * - \p type will be DRM_SHM.
+ *
+ * \par
+ * A shared memory area of the requested size will be created and locked in
+ * kernel memory. This area may be mapped into client-space by using the handle
+ * returned.
+ *
+ * \note May only be called by root.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
+ * the arguments in a drm_map structure.
+ */
+int drmAddMap(int fd,
+ drmHandle offset,
+ drmSize size,
+ drmMapType type,
+ drmMapFlags flags,
+ drmHandlePtr handle)
+{
+ drm_map_t map;
+
+ map.offset = offset;
+ map.size = size;
+ map.handle = 0;
+ map.type = type;
+ map.flags = flags;
+ if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno;
+ if (handle) *handle = (drmHandle)map.handle;
+ return 0;
+}
+
+
+/**
+ * \brief Make buffers available for DMA transfers.
+ *
+ * \param fd file descriptor.
+ * \param count number of buffers.
+ * \param size size of each buffer.
+ * \param flags buffer allocation flags.
+ * \param agp_offset offset in the AGP aperture
+ *
+ * \return number of buffers allocated, negative on error.
+ *
+ * \internal
+ * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
+ *
+ * \sa drm_buf_desc.
+ */
+int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
+ int agp_offset)
+{
+ drm_buf_desc_t request;
+
+ request.count = count;
+ request.size = size;
+ request.low_mark = 0;
+ request.high_mark = 0;
+ request.flags = flags;
+ request.agp_start = agp_offset;
+
+ if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno;
+ return request.count;
+}
+
+
+/**
+ * \brief Free buffers.
+ *
+ * \param fd file descriptor.
+ * \param count number of buffers to free.
+ * \param list list of buffers to be freed.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \note This function is primarily used for debugging.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
+ * the arguments in a drm_buf_free structure.
+ */
+int drmFreeBufs(int fd, int count, int *list)
+{
+ drm_buf_free_t request;
+
+ request.count = count;
+ request.list = list;
+ if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Close the device.
+ *
+ * \param fd file descriptor.
+ *
+ * \internal
+ * This function closes the file descriptor.
+ */
+int drmClose(int fd)
+{
+ drmMsg("close %d\n", fd);
+ return close(fd);
+}
+
+
+/**
+ * \brief Map a region of memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle returned by drmAddMap().
+ * \param size size in bytes. Must match the size used by drmAddMap().
+ * \param address will contain the user-space virtual address where the mapping
+ * begins.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper for mmap().
+ */
+int drmMap(int fd,
+ drmHandle handle,
+ drmSize size,
+ drmAddressPtr address)
+{
+ static unsigned long pagesize_mask = 0;
+
+ if (fd < 0) return -EINVAL;
+
+ if (!pagesize_mask)
+ pagesize_mask = getpagesize() - 1;
+
+ size = (size + pagesize_mask) & ~pagesize_mask;
+
+ *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
+ if (*address == MAP_FAILED) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Unmap mappings obtained with drmMap().
+ *
+ * \param address address as given by drmMap().
+ * \param size size in bytes. Must match the size used by drmMap().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper for unmap().
+ */
+int drmUnmap(drmAddress address, drmSize size)
+{
+ return munmap(address, size);
+}
+
+
+/**
+ * \brief Map all DMA buffers into client-virtual space.
+ *
+ * \param fd file descriptor.
+ *
+ * \return a pointer to a ::drmBufMap structure.
+ *
+ * \note The client may not use these buffers until obtaining buffer indices
+ * with drmDMA().
+ *
+ * \internal
+ * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
+ * information about the buffers in a drm_buf_map structure into the
+ * client-visible data structures.
+ */
+drmBufMapPtr drmMapBufs(int fd)
+{
+ drm_buf_map_t bufs;
+ drmBufMapPtr retval;
+ int i;
+
+ bufs.count = 0;
+ bufs.list = NULL;
+ if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL;
+
+ if (bufs.count) {
+ if (!(bufs.list = malloc(bufs.count * sizeof(*bufs.list))))
+ return NULL;
+
+ if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
+ free(bufs.list);
+ return NULL;
+ }
+ /* Now, copy it all back into the
+ client-visible data structures... */
+ retval = malloc(sizeof(*retval));
+ retval->count = bufs.count;
+ retval->list = malloc(bufs.count * sizeof(*retval->list));
+ for (i = 0; i < bufs.count; i++) {
+ retval->list[i].idx = bufs.list[i].idx;
+ retval->list[i].total = bufs.list[i].total;
+ retval->list[i].used = 0;
+ retval->list[i].address = bufs.list[i].address;
+ }
+ return retval;
+ }
+ return NULL;
+}
+
+
+/**
+ * \brief Unmap buffers allocated with drmMapBufs().
+ *
+ * \return zero on success, or negative value on failure.
+ *
+ * \internal
+ * Calls munmap() for every buffer stored in \p bufs.
+ */
+int drmUnmapBufs(drmBufMapPtr bufs)
+{
+ int i;
+
+ for (i = 0; i < bufs->count; i++) {
+ munmap(bufs->list[i].address, bufs->list[i].total);
+ }
+ return 0;
+}
+
+
+#define DRM_DMA_RETRY 16
+
+/**
+ * \brief Reserve DMA buffers.
+ *
+ * \param fd file descriptor.
+ * \param request
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * Assemble the arguments into a drm_dma structure and keeps issuing the
+ * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
+ */
+int drmDMA(int fd, drmDMAReqPtr request)
+{
+ drm_dma_t dma;
+ int ret, i = 0;
+
+ /* Copy to hidden structure */
+ dma.context = request->context;
+ dma.send_count = request->send_count;
+ dma.send_indices = request->send_list;
+ dma.send_sizes = request->send_sizes;
+ dma.flags = request->flags;
+ dma.request_count = request->request_count;
+ dma.request_size = request->request_size;
+ dma.request_indices = request->request_list;
+ dma.request_sizes = request->request_sizes;
+
+ do {
+ ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
+ } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
+
+ if ( ret == 0 ) {
+ request->granted_count = dma.granted_count;
+ return 0;
+ } else {
+ return -errno;
+ }
+}
+
+
+/**
+ * \brief Obtain heavyweight hardware lock.
+ *
+ * \param fd file descriptor.
+ * \param context context.
+ * \param flags flags that determine the sate of the hardware when the function
+ * returns.
+ *
+ * \return always zero.
+ *
+ * \internal
+ * This function translates the arguments into a drm_lock structure and issue
+ * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
+ */
+int drmGetLock(int fd, drmContext context, drmLockFlags flags)
+{
+ drm_lock_t lock;
+
+ lock.context = context;
+ lock.flags = 0;
+ if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
+ if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
+ if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
+ if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
+ if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
+ if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
+
+ while (ioctl(fd, DRM_IOCTL_LOCK, &lock))
+ ;
+ return 0;
+}
+
+static void (*drm_unlock_callback)( void ) = 0;
+
+/**
+ * \brief Release the hardware lock.
+ *
+ * \param fd file descriptor.
+ * \param context context.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
+ * argument in a drm_lock structure.
+ */
+int drmUnlock(int fd, drmContext context)
+{
+ drm_lock_t lock;
+ int ret;
+
+ lock.context = context;
+ lock.flags = 0;
+ ret = ioctl(fd, DRM_IOCTL_UNLOCK, &lock);
+
+ /* Need this to synchronize vt releasing. Could also teach fbdev
+ * about the drm lock...
+ */
+ if (drm_unlock_callback) {
+ drm_unlock_callback();
+ }
+
+ return ret;
+}
+
+
+/**
+ * \brief Create context.
+ *
+ * Used by the X server during GLXContext initialization. This causes
+ * per-context kernel-level resources to be allocated.
+ *
+ * \param fd file descriptor.
+ * \param handle is set on success. To be used by the client when requesting DMA
+ * dispatch with drmDMA().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \note May only be called by root.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
+ * argument in a drm_ctx structure.
+ */
+int drmCreateContext(int fd, drmContextPtr handle)
+{
+ drm_ctx_t ctx;
+
+ ctx.flags = 0; /* Modified with functions below */
+ if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno;
+ *handle = ctx.handle;
+ return 0;
+}
+
+
+/**
+ * \brief Destroy context.
+ *
+ * Free any kernel-level resources allocated with drmCreateContext() associated
+ * with the context.
+ *
+ * \param fd file descriptor.
+ * \param handle handle given by drmCreateContext().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \note May only be called by root.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
+ * argument in a drm_ctx structure.
+ */
+int drmDestroyContext(int fd, drmContext handle)
+{
+ drm_ctx_t ctx;
+ ctx.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Acquire the AGP device.
+ *
+ * Must be called before any of the other AGP related calls.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
+ */
+int drmAgpAcquire(int fd)
+{
+ if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Release the AGP device.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
+ */
+int drmAgpRelease(int fd)
+{
+ if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Set the AGP mode.
+ *
+ * \param fd file descriptor.
+ * \param mode AGP mode.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
+ * argument in a drm_agp_mode structure.
+ */
+int drmAgpEnable(int fd, unsigned long mode)
+{
+ drm_agp_mode_t m;
+
+ m.mode = mode;
+ if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Allocate a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param size requested memory size in bytes. Will be rounded to page boundary.
+ * \param type type of memory to allocate.
+ * \param address if not zero, will be set to the physical address of the
+ * allocated memory.
+ * \param handle on success will be set to a handle of the allocated memory.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
+ * arguments in a drm_agp_buffer structure.
+ */
+int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
+ unsigned long *address, unsigned long *handle)
+{
+ drm_agp_buffer_t b;
+ *handle = 0;
+ b.size = size;
+ b.handle = 0;
+ b.type = type;
+ if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno;
+ if (address != 0UL) *address = b.physical;
+ *handle = b.handle;
+ return 0;
+}
+
+
+/**
+ * \brief Free a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle to the allocated memory, as given by drmAgpAllocate().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
+ * argument in a drm_agp_buffer structure.
+ */
+int drmAgpFree(int fd, unsigned long handle)
+{
+ drm_agp_buffer_t b;
+
+ b.size = 0;
+ b.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Bind a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle to the allocated memory, as given by drmAgpAllocate().
+ * \param offset offset in bytes. It will round to page boundary.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
+ * argument in a drm_agp_binding structure.
+ */
+int drmAgpBind(int fd, unsigned long handle, unsigned long offset)
+{
+ drm_agp_binding_t b;
+
+ b.handle = handle;
+ b.offset = offset;
+ if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Unbind a chunk of AGP memory.
+ *
+ * \param fd file descriptor.
+ * \param handle handle to the allocated memory, as given by drmAgpAllocate().
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
+ * the argument in a drm_agp_binding structure.
+ */
+int drmAgpUnbind(int fd, unsigned long handle)
+{
+ drm_agp_binding_t b;
+
+ b.handle = handle;
+ b.offset = 0;
+ if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Get AGP driver major version number.
+ *
+ * \param fd file descriptor.
+ *
+ * \return major version number on success, or a negative value on failure..
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+int drmAgpVersionMajor(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
+ return i.agp_version_major;
+}
+
+
+/**
+ * \brief Get AGP driver minor version number.
+ *
+ * \param fd file descriptor.
+ *
+ * \return minor version number on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+int drmAgpVersionMinor(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno;
+ return i.agp_version_minor;
+}
+
+
+/**
+ * \brief Get AGP mode.
+ *
+ * \param fd file descriptor.
+ *
+ * \return mode on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpGetMode(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.mode;
+}
+
+
+/**
+ * \brief Get AGP aperture base.
+ *
+ * \param fd file descriptor.
+ *
+ * \return aperture base on success, zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpBase(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.aperture_base;
+}
+
+
+/**
+ * \brief Get AGP aperture size.
+ *
+ * \param fd file descriptor.
+ *
+ * \return aperture size on success, zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpSize(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.aperture_size;
+}
+
+
+/**
+ * \brief Get used AGP memory.
+ *
+ * \param fd file descriptor.
+ *
+ * \return memory used on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpMemoryUsed(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.memory_used;
+}
+
+
+/**
+ * \brief Get available AGP memory.
+ *
+ * \param fd file descriptor.
+ *
+ * \return memory available on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned long drmAgpMemoryAvail(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.memory_allowed;
+}
+
+
+/**
+ * \brief Get hardware vendor ID.
+ *
+ * \param fd file descriptor.
+ *
+ * \return vendor ID on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned int drmAgpVendorId(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.id_vendor;
+}
+
+
+/**
+ * \brief Get hardware device ID.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or zero on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
+ * necessary information in a drm_agp_info structure.
+ */
+unsigned int drmAgpDeviceId(int fd)
+{
+ drm_agp_info_t i;
+
+ if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0;
+ return i.id_device;
+}
+
+int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle)
+{
+ drm_scatter_gather_t sg;
+
+ *handle = 0;
+ sg.size = size;
+ sg.handle = 0;
+ if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno;
+ *handle = sg.handle;
+ return 0;
+}
+
+int drmScatterGatherFree(int fd, unsigned long handle)
+{
+ drm_scatter_gather_t sg;
+
+ sg.size = 0;
+ sg.handle = handle;
+ if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno;
+ return 0;
+}
+
+/**
+ * \brief Wait for VBLANK.
+ *
+ * \param fd file descriptor.
+ * \param vbl pointer to a drmVBlank structure.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
+ */
+int drmWaitVBlank(int fd, drmVBlankPtr vbl)
+{
+ int ret;
+
+ do {
+ ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
+ } while (ret && errno == EINTR);
+
+ return ret;
+}
+
+
+/**
+ * \brief Install IRQ handler.
+ *
+ * \param fd file descriptor.
+ * \param irq IRQ number.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
+ * argument in a drm_control structure.
+ */
+int drmCtlInstHandler(int fd, int irq)
+{
+ drm_control_t ctl;
+
+ ctl.func = DRM_INST_HANDLER;
+ ctl.irq = irq;
+ if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Uninstall IRQ handler.
+ *
+ * \param fd file descriptor.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
+ * argument in a drm_control structure.
+ */
+int drmCtlUninstHandler(int fd)
+{
+ drm_control_t ctl;
+
+ ctl.func = DRM_UNINST_HANDLER;
+ ctl.irq = 0;
+ if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno;
+ return 0;
+}
+
+
+/**
+ * \brief Get IRQ from bus ID.
+ *
+ * \param fd file descriptor.
+ * \param busnum bus number.
+ * \param devnum device number.
+ * \param funcnum function number.
+ *
+ * \return IRQ number on success, or a negative value on failure.
+ *
+ * \internal
+ * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
+ * arguments in a drm_irq_busid structure.
+ */
+int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
+{
+ drm_irq_busid_t p;
+
+ p.busnum = busnum;
+ p.devnum = devnum;
+ p.funcnum = funcnum;
+ if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno;
+ return p.irq;
+}
+
+
+/**
+ * \brief Send a device-specific command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandNone(int fd, unsigned long drmCommandIndex)
+{
+ void *data = NULL; /* dummy */
+ unsigned long request;
+
+ request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Send a device-specific read command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ * \param data destination pointer of the data to be read.
+ * \param size size of the data to be read.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a read ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size )
+{
+ unsigned long request;
+
+ request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
+ DRM_COMMAND_BASE + drmCommandIndex, size);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Send a device-specific write command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ * \param data source pointer of the data to be written.
+ * \param size size of the data to be written.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a write ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandWrite(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size )
+{
+ unsigned long request;
+
+ request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
+ DRM_COMMAND_BASE + drmCommandIndex, size);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
+
+/**
+ * \brief Send a device-specific read-write command.
+ *
+ * \param fd file descriptor.
+ * \param drmCommandIndex command index
+ * \param data source pointer of the data to be read and written.
+ * \param size size of the data to be read and written.
+ *
+ * \return zero on success, or a negative value on failure.
+ *
+ * \internal
+ * It issues a read-write ioctl given by
+ * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
+ */
+int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size )
+{
+ unsigned long request;
+
+ request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
+ DRM_COMMAND_BASE + drmCommandIndex, size);
+
+ if (ioctl(fd, request, data)) {
+ return -errno;
+ }
+ return 0;
+}
+
diff --git a/src/glx/mini/xf86drm.h b/src/glx/mini/xf86drm.h
new file mode 100644
index 00000000000..cee5ca5f696
--- /dev/null
+++ b/src/glx/mini/xf86drm.h
@@ -0,0 +1,609 @@
+/* xf86drm.h -- OS-independent header for DRM user-level library interface
+ * Created: Tue Jan 5 08:17:23 1999 by [email protected]
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Rickard E. (Rik) Faith <[email protected]>
+ *
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h,v 1.22 2003/06/12 14:12:35 eich Exp $
+ *
+ */
+
+#ifndef _XF86DRM_H_
+#define _XF86DRM_H_
+
+ /* Defaults, if nothing set in xf86config */
+#define DRM_DEV_UID 0
+#define DRM_DEV_GID 0
+/* Default /dev/dri directory permissions 0755 */
+#define DRM_DEV_DIRMODE \
+ (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+
+#define DRM_DIR_NAME "/dev/dri"
+#define DRM_DEV_NAME "%s/card%d"
+#define DRM_PROC_NAME "/proc/dri/" /* For backware Linux compatibility */
+
+#define DRM_ERR_NO_DEVICE (-1001)
+#define DRM_ERR_NO_ACCESS (-1002)
+#define DRM_ERR_NOT_ROOT (-1003)
+#define DRM_ERR_INVALID (-1004)
+#define DRM_ERR_NO_FD (-1005)
+
+#define DRM_AGP_NO_HANDLE 0
+
+typedef unsigned long drmHandle, *drmHandlePtr; /* To mapped regions */
+typedef unsigned int drmSize, *drmSizePtr; /* For mapped regions */
+typedef void *drmAddress, **drmAddressPtr; /* For mapped regions */
+typedef unsigned int drmContext, *drmContextPtr; /* GLXContext handle */
+typedef unsigned int drmDrawable, *drmDrawablePtr; /* Unused */
+typedef unsigned int drmMagic, *drmMagicPtr; /* Magic for auth */
+
+typedef struct _drmVersion {
+ int version_major; /* Major version */
+ int version_minor; /* Minor version */
+ int version_patchlevel; /* Patch level */
+ int name_len; /* Length of name buffer */
+ char *name; /* Name of driver */
+ int date_len; /* Length of date buffer */
+ char *date; /* User-space buffer to hold date */
+ int desc_len; /* Length of desc buffer */
+ char *desc; /* User-space buffer to hold desc */
+} drmVersion, *drmVersionPtr;
+
+typedef struct _drmStats {
+ unsigned long count; /* Number of data */
+ struct {
+ unsigned long value; /* Value from kernel */
+ const char *long_format; /* Suggested format for long_name */
+ const char *long_name; /* Long name for value */
+ const char *rate_format; /* Suggested format for rate_name */
+ const char *rate_name; /* Short name for value per second */
+ int isvalue; /* True if value (vs. counter) */
+ const char *mult_names; /* Multiplier names (e.g., "KGM") */
+ int mult; /* Multiplier value (e.g., 1024) */
+ int verbose; /* Suggest only in verbose output */
+ } data[15];
+} drmStatsT;
+
+
+ /* All of these enums *MUST* match with the
+ kernel implementation -- so do *NOT*
+ change them! (The drmlib implementation
+ will just copy the flags instead of
+ translating them.) */
+typedef enum {
+ DRM_FRAME_BUFFER = 0, /* WC, no caching, no core dump */
+ DRM_REGISTERS = 1, /* no caching, no core dump */
+ DRM_SHM = 2, /* shared, cached */
+ DRM_AGP = 3, /* AGP/GART */
+ DRM_SCATTER_GATHER = 4 /* PCI scatter/gather */
+} drmMapType;
+
+typedef enum {
+ DRM_RESTRICTED = 0x0001, /* Cannot be mapped to client-virtual */
+ DRM_READ_ONLY = 0x0002, /* Read-only in client-virtual */
+ DRM_LOCKED = 0x0004, /* Physical pages locked */
+ DRM_KERNEL = 0x0008, /* Kernel requires access */
+ DRM_WRITE_COMBINING = 0x0010, /* Use write-combining, if available */
+ DRM_CONTAINS_LOCK = 0x0020, /* SHM page that contains lock */
+ DRM_REMOVABLE = 0x0040 /* Removable mapping */
+} drmMapFlags;
+
+typedef enum { /* These values *MUST* match drm.h */
+ /* Flags for DMA buffer dispatch */
+ DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched. Note,
+ the buffer may not yet have been
+ processed by the hardware -- getting a
+ hardware lock with the hardware
+ quiescent will ensure that the buffer
+ has been processed. */
+ DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */
+ DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */
+
+ /* Flags for DMA buffer request */
+ DRM_DMA_WAIT = 0x10, /* Wait for free buffers */
+ DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */
+ DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */
+} drmDMAFlags;
+
+typedef enum {
+ DRM_PAGE_ALIGN = 0x01,
+ DRM_AGP_BUFFER = 0x02,
+ DRM_SG_BUFFER = 0x04
+} drmBufDescFlags;
+
+typedef enum {
+ DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */
+ DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */
+ DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */
+ DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */
+ /* These *HALT* flags aren't supported yet
+ -- they will be used to support the
+ full-screen DGA-like mode. */
+ DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */
+ DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */
+} drmLockFlags;
+
+typedef enum {
+ DRM_CONTEXT_PRESERVED = 0x01, /* This context is preserved and
+ never swapped. */
+ DRM_CONTEXT_2DONLY = 0x02 /* This context is for 2D rendering only. */
+} drmContextFlags, *drmContextFlagsPtr;
+
+typedef struct _drmBufDesc {
+ int count; /* Number of buffers of this size */
+ int size; /* Size in bytes */
+ int low_mark; /* Low water mark */
+ int high_mark; /* High water mark */
+} drmBufDesc, *drmBufDescPtr;
+
+typedef struct _drmBufInfo {
+ int count; /* Number of buffers described in list */
+ drmBufDescPtr list; /* List of buffer descriptions */
+} drmBufInfo, *drmBufInfoPtr;
+
+typedef struct _drmBuf {
+ int idx; /* Index into master buflist */
+ int total; /* Buffer size */
+ int used; /* Amount of buffer in use (for DMA) */
+ drmAddress address; /* Address */
+} drmBuf, *drmBufPtr;
+
+typedef struct _drmBufMap {
+ int count; /* Number of buffers mapped */
+ drmBufPtr list; /* Buffers */
+} drmBufMap, *drmBufMapPtr;
+
+typedef struct _drmLock {
+ volatile unsigned int lock;
+ char padding[60];
+ /* This is big enough for most current (and future?) architectures:
+ DEC Alpha: 32 bytes
+ Intel Merced: ?
+ Intel P5/PPro/PII/PIII: 32 bytes
+ Intel StrongARM: 32 bytes
+ Intel i386/i486: 16 bytes
+ MIPS: 32 bytes (?)
+ Motorola 68k: 16 bytes
+ Motorola PowerPC: 32 bytes
+ Sun SPARC: 32 bytes
+ */
+} drmLock, *drmLockPtr;
+
+typedef struct _drmDMAReq {
+ /* Indices here refer to the offset into
+ list in drmBufInfo */
+ drmContext context; /* Context handle */
+ int send_count; /* Number of buffers to send */
+ int *send_list; /* List of handles to buffers */
+ int *send_sizes; /* Lengths of data to send, in bytes */
+ drmDMAFlags flags; /* Flags */
+ int request_count; /* Number of buffers requested */
+ int request_size; /* Desired size of buffers requested */
+ int *request_list; /* Buffer information */
+ int *request_sizes; /* Minimum acceptable sizes */
+ int granted_count; /* Number of buffers granted at this size */
+} drmDMAReq, *drmDMAReqPtr;
+
+typedef struct _drmRegion {
+ drmHandle handle;
+ unsigned int offset;
+ drmSize size;
+ drmAddress map;
+} drmRegion, *drmRegionPtr;
+
+typedef struct _drmTextureRegion {
+ unsigned char next;
+ unsigned char prev;
+ unsigned char in_use;
+ unsigned char padding; /* Explicitly pad this out */
+ unsigned int age;
+} drmTextureRegion, *drmTextureRegionPtr;
+
+
+typedef struct _drmClipRect {
+ unsigned short x1; /* Upper left: inclusive */
+ unsigned short y1;
+ unsigned short x2; /* Lower right: exclusive */
+ unsigned short y2;
+} drmClipRect, *drmClipRectPtr;
+
+
+typedef enum {
+ DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */
+ DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */
+ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */
+} drmVBlankSeqType;
+
+typedef struct _drmVBlankReq {
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ unsigned long signal;
+} drmVBlankReq, *drmVBlankReqPtr;
+
+typedef struct _drmVBlankReply {
+ drmVBlankSeqType type;
+ unsigned int sequence;
+ long tval_sec;
+ long tval_usec;
+} drmVBlankReply, *drmVBlankReplyPtr;
+
+typedef union _drmVBlank {
+ drmVBlankReq request;
+ drmVBlankReply reply;
+} drmVBlank, *drmVBlankPtr;
+
+
+
+#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock)
+
+#define DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */
+#define DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */
+
+#if defined(__GNUC__) && (__GNUC__ >= 2)
+# if defined(__i386) || defined(__AMD64__)
+ /* Reflect changes here to drmP.h */
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ int __dummy; /* Can't mark eax as clobbered */ \
+ __asm__ __volatile__( \
+ "lock ; cmpxchg %4,%1\n\t" \
+ "setnz %0" \
+ : "=d" (__ret), \
+ "=m" (__drm_dummy_lock(lock)), \
+ "=a" (__dummy) \
+ : "2" (old), \
+ "r" (new)); \
+ } while (0)
+
+#elif defined(__alpha__)
+
+#define DRM_CAS(lock, old, new, ret) \
+ do { \
+ int old32; \
+ int cur32; \
+ __asm__ __volatile__( \
+ " mb\n" \
+ " zap %4, 0xF0, %0\n" \
+ " ldl_l %1, %2\n" \
+ " zap %1, 0xF0, %1\n" \
+ " cmpeq %0, %1, %1\n" \
+ " beq %1, 1f\n" \
+ " bis %5, %5, %1\n" \
+ " stl_c %1, %2\n" \
+ "1: xor %1, 1, %1\n" \
+ " stl %1, %3" \
+ : "+r" (old32), \
+ "+&r" (cur32), \
+ "=m" (__drm_dummy_lock(lock)),\
+ "=m" (ret) \
+ : "r" (old), \
+ "r" (new)); \
+ } while(0)
+
+#elif defined(__sparc__)
+
+#define DRM_CAS(lock,old,new,__ret) \
+do { register unsigned int __old __asm("o0"); \
+ register unsigned int __new __asm("o1"); \
+ register volatile unsigned int *__lock __asm("o2"); \
+ __old = old; \
+ __new = new; \
+ __lock = (volatile unsigned int *)lock; \
+ __asm__ __volatile__( \
+ /*"cas [%2], %3, %0"*/ \
+ ".word 0xd3e29008\n\t" \
+ /*"membar #StoreStore | #StoreLoad"*/ \
+ ".word 0x8143e00a" \
+ : "=&r" (__new) \
+ : "0" (__new), \
+ "r" (__lock), \
+ "r" (__old) \
+ : "memory"); \
+ __ret = (__new != __old); \
+} while(0)
+
+#elif defined(__ia64__)
+
+#if 0
+/* this currently generates bad code (missing stop bits)... */
+#include <ia64intrin.h>
+
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ __ret = (__sync_val_compare_and_swap(&__drm_dummy_lock(lock), \
+ (old), (new)) \
+ != (old)); \
+ } while (0)
+
+#else
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ unsigned int __result, __old = (old); \
+ __asm__ __volatile__( \
+ "mf\n" \
+ "mov ar.ccv=%2\n" \
+ ";;\n" \
+ "cmpxchg4.acq %0=%1,%3,ar.ccv" \
+ : "=r" (__result), "=m" (__drm_dummy_lock(lock)) \
+ : "r" (__old), "r" (new) \
+ : "memory"); \
+ __ret = (__result) != (__old); \
+ } while (0)
+
+#endif
+
+#elif defined(__powerpc__)
+
+#define DRM_CAS(lock,old,new,__ret) \
+ do { \
+ __asm__ __volatile__( \
+ "sync;" \
+ "0: lwarx %0,0,%1;" \
+ " xor. %0,%3,%0;" \
+ " bne 1f;" \
+ " stwcx. %2,0,%1;" \
+ " bne- 0b;" \
+ "1: " \
+ "sync;" \
+ : "=&r"(__ret) \
+ : "r"(lock), "r"(new), "r"(old) \
+ : "cr0", "memory"); \
+ } while (0)
+
+#endif /* architecture */
+#endif /* __GNUC__ >= 2 */
+
+#ifndef DRM_CAS
+#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */
+#endif
+
+#if defined(__alpha__) || defined(__powerpc__)
+#define DRM_CAS_RESULT(_result) int _result
+#else
+#define DRM_CAS_RESULT(_result) char _result
+#endif
+
+#define DRM_LIGHT_LOCK(fd,lock,context) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \
+ if (__ret) drmGetLock(fd,context,0); \
+ } while(0)
+
+ /* This one counts fast locks -- for
+ benchmarking only. */
+#define DRM_LIGHT_LOCK_COUNT(fd,lock,context,count) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \
+ if (__ret) drmGetLock(fd,context,0); \
+ else ++count; \
+ } while(0)
+
+#define DRM_LOCK(fd,lock,context,flags) \
+ do { \
+ if (flags) drmGetLock(fd,context,flags); \
+ else DRM_LIGHT_LOCK(fd,lock,context); \
+ } while(0)
+
+#define DRM_UNLOCK(fd,lock,context) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ DRM_CAS(lock,DRM_LOCK_HELD|context,context,__ret); \
+ if (__ret) drmUnlock(fd,context); \
+ } while(0)
+
+ /* Simple spin locks */
+#define DRM_SPINLOCK(spin,val) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ do { \
+ DRM_CAS(spin,0,val,__ret); \
+ if (__ret) while ((spin)->lock); \
+ } while (__ret); \
+ } while(0)
+
+#define DRM_SPINLOCK_TAKE(spin,val) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ int cur; \
+ do { \
+ cur = (*spin).lock; \
+ DRM_CAS(spin,cur,val,__ret); \
+ } while (__ret); \
+ } while(0)
+
+#define DRM_SPINLOCK_COUNT(spin,val,count,__ret) \
+ do { \
+ int __i; \
+ __ret = 1; \
+ for (__i = 0; __ret && __i < count; __i++) { \
+ DRM_CAS(spin,0,val,__ret); \
+ if (__ret) for (;__i < count && (spin)->lock; __i++); \
+ } \
+ } while(0)
+
+#define DRM_SPINUNLOCK(spin,val) \
+ do { \
+ DRM_CAS_RESULT(__ret); \
+ if ((*spin).lock == val) { /* else server stole lock */ \
+ do { \
+ DRM_CAS(spin,val,0,__ret); \
+ } while (__ret); \
+ } \
+ } while(0)
+
+/* General user-level programmer's API: unprivileged */
+extern int drmAvailable(void);
+extern int drmOpen(const char *name, const char *busid);
+extern int drmClose(int fd);
+extern drmVersionPtr drmGetVersion(int fd);
+extern drmVersionPtr drmGetLibVersion(int fd);
+extern void drmFreeVersion(drmVersionPtr);
+extern int drmGetMagic(int fd, drmMagicPtr magic);
+extern char *drmGetBusid(int fd);
+extern int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
+ int funcnum);
+extern int drmGetMap(int fd, int idx, drmHandle *offset,
+ drmSize *size, drmMapType *type,
+ drmMapFlags *flags, drmHandle *handle,
+ int *mtrr);
+extern int drmGetClient(int fd, int idx, int *auth, int *pid,
+ int *uid, unsigned long *magic,
+ unsigned long *iocs);
+extern int drmGetStats(int fd, drmStatsT *stats);
+extern int drmCommandNone(int fd, unsigned long drmCommandIndex);
+extern int drmCommandRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size);
+extern int drmCommandWrite(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size);
+extern int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
+ void *data, unsigned long size);
+
+/* General user-level programmer's API: X server (root) only */
+extern void drmFreeBusid(const char *busid);
+extern int drmSetBusid(int fd, const char *busid);
+extern int drmAuthMagic(int fd, drmMagic magic);
+extern int drmAddMap(int fd,
+ drmHandle offset,
+ drmSize size,
+ drmMapType type,
+ drmMapFlags flags,
+ drmHandlePtr handle);
+extern int drmRmMap(int fd, drmHandle handle);
+extern int drmAddContextPrivateMapping(int fd, drmContext ctx_id,
+ drmHandle handle);
+
+extern int drmAddBufs(int fd, int count, int size,
+ drmBufDescFlags flags,
+ int agp_offset);
+extern int drmMarkBufs(int fd, double low, double high);
+extern int drmCreateContext(int fd, drmContextPtr handle);
+extern int drmSetContextFlags(int fd, drmContext context,
+ drmContextFlags flags);
+extern int drmGetContextFlags(int fd, drmContext context,
+ drmContextFlagsPtr flags);
+extern int drmAddContextTag(int fd, drmContext context, void *tag);
+extern int drmDelContextTag(int fd, drmContext context);
+extern void *drmGetContextTag(int fd, drmContext context);
+extern drmContextPtr drmGetReservedContextList(int fd, int *count);
+extern void drmFreeReservedContextList(drmContextPtr);
+extern int drmSwitchToContext(int fd, drmContext context);
+extern int drmDestroyContext(int fd, drmContext handle);
+extern int drmCreateDrawable(int fd, drmDrawablePtr handle);
+extern int drmDestroyDrawable(int fd, drmDrawable handle);
+extern int drmCtlInstHandler(int fd, int irq);
+extern int drmCtlUninstHandler(int fd);
+extern int drmInstallSIGIOHandler(int fd,
+ void (*f)(int fd,
+ void *oldctx,
+ void *newctx));
+extern int drmRemoveSIGIOHandler(int fd);
+
+/* General user-level programmer's API: authenticated client and/or X */
+extern int drmMap(int fd,
+ drmHandle handle,
+ drmSize size,
+ drmAddressPtr address);
+extern int drmUnmap(drmAddress address, drmSize size);
+extern drmBufInfoPtr drmGetBufInfo(int fd);
+extern drmBufMapPtr drmMapBufs(int fd);
+extern int drmUnmapBufs(drmBufMapPtr bufs);
+extern int drmDMA(int fd, drmDMAReqPtr request);
+extern int drmFreeBufs(int fd, int count, int *list);
+extern int drmGetLock(int fd,
+ drmContext context,
+ drmLockFlags flags);
+extern int drmUnlock(int fd, drmContext context);
+extern int drmFinish(int fd, int context, drmLockFlags flags);
+extern int drmGetContextPrivateMapping(int fd, drmContext ctx_id,
+ drmHandlePtr handle);
+
+/* AGP/GART support: X server (root) only */
+extern int drmAgpAcquire(int fd);
+extern int drmAgpRelease(int fd);
+extern int drmAgpEnable(int fd, unsigned long mode);
+extern int drmAgpAlloc(int fd, unsigned long size,
+ unsigned long type, unsigned long *address,
+ unsigned long *handle);
+extern int drmAgpFree(int fd, unsigned long handle);
+extern int drmAgpBind(int fd, unsigned long handle,
+ unsigned long offset);
+extern int drmAgpUnbind(int fd, unsigned long handle);
+
+/* AGP/GART info: authenticated client and/or X */
+extern int drmAgpVersionMajor(int fd);
+extern int drmAgpVersionMinor(int fd);
+extern unsigned long drmAgpGetMode(int fd);
+extern unsigned long drmAgpBase(int fd); /* Physical location */
+extern unsigned long drmAgpSize(int fd); /* Bytes */
+extern unsigned long drmAgpMemoryUsed(int fd);
+extern unsigned long drmAgpMemoryAvail(int fd);
+extern unsigned int drmAgpVendorId(int fd);
+extern unsigned int drmAgpDeviceId(int fd);
+
+/* PCI scatter/gather support: X server (root) only */
+extern int drmScatterGatherAlloc(int fd, unsigned long size,
+ unsigned long *handle);
+extern int drmScatterGatherFree(int fd, unsigned long handle);
+
+extern int drmWaitVBlank(int fd, drmVBlankPtr vbl);
+
+/* Support routines */
+extern int drmError(int err, const char *label);
+extern void *drmMalloc(int size);
+extern void drmFree(void *pt);
+
+/* Hash table routines */
+extern void *drmHashCreate(void);
+extern int drmHashDestroy(void *t);
+extern int drmHashLookup(void *t, unsigned long key, void **value);
+extern int drmHashInsert(void *t, unsigned long key, void *value);
+extern int drmHashDelete(void *t, unsigned long key);
+extern int drmHashFirst(void *t, unsigned long *key, void **value);
+extern int drmHashNext(void *t, unsigned long *key, void **value);
+
+/* PRNG routines */
+extern void *drmRandomCreate(unsigned long seed);
+extern int drmRandomDestroy(void *state);
+extern unsigned long drmRandom(void *state);
+extern double drmRandomDouble(void *state);
+
+/* Skip list routines */
+
+extern void *drmSLCreate(void);
+extern int drmSLDestroy(void *l);
+extern int drmSLLookup(void *l, unsigned long key, void **value);
+extern int drmSLInsert(void *l, unsigned long key, void *value);
+extern int drmSLDelete(void *l, unsigned long key);
+extern int drmSLNext(void *l, unsigned long *key, void **value);
+extern int drmSLFirst(void *l, unsigned long *key, void **value);
+extern void drmSLDump(void *l);
+extern int drmSLLookupNeighbors(void *l, unsigned long key,
+ unsigned long *prev_key, void **prev_value,
+ unsigned long *next_key, void **next_value);
+
+#endif