commit fb6ccda5984eda96bcb394b23255143dcbc21f18
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Thu Sep 10 12:22:17 2009 +0000

    Don't link against libdrm to workaround XvBA / fglrx >= 8.66-RC1 bugs.

commit ab3c0f65182462b54729d2d82d4d645c8be5b2d1
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Wed Sep 9 13:24:46 2009 +0000

    Fix DRM device opening with fglrx >= 8.66-RC1.

diff --git a/src/x11/Makefile.am b/src/x11/Makefile.am
index c70380d..b6916f2 100644
--- a/src/x11/Makefile.am
+++ b/src/x11/Makefile.am
@@ -25,6 +25,6 @@ noinst_LTLIBRARIES = libva_x11.la
 libva_x11includedir = ${includedir}/va
 libva_x11include_HEADERS = va_x11.h va_dri.h va_dri2.h va_dricommon.h
 
-libva_x11_la_SOURCES = va_x11.c va_dri.c va_dri2.c va_dricommon.c dri2_util.c dri1_util.c va_nvctrl.c
+libva_x11_la_SOURCES = va_x11.c va_dri.c va_dri2.c va_dricommon.c dri2_util.c dri1_util.c va_nvctrl.c libdrm_glue.c
 
-EXTRA_DIST = va_dristr.h va_dri2str.h va_dri2tokens.h va_nvctrl.h
+EXTRA_DIST = va_dristr.h va_dri2str.h va_dri2tokens.h va_nvctrl.h libdrm_glue.h
diff --git a/src/x11/dri1_util.c b/src/x11/dri1_util.c
index b3db5b4..3bd490f 100644
--- a/src/x11/dri1_util.c
+++ b/src/x11/dri1_util.c
@@ -1,10 +1,12 @@
+#include "config.h"
+#include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <assert.h>
 
-#include <xf86drm.h>
+#include "libdrm_glue.h"
 
 #include "X11/Xlib.h"
 #include "va.h"
@@ -21,6 +23,75 @@ struct dri1_drawable
     int height;
 };
 
+static int
+firegl_drmOpenMinor(int minor)
+{
+    char buf[64];
+    int fd;
+
+    sprintf(buf, "/dev/ati/card%d", minor);
+    if ((fd = open(buf, O_RDWR, 0)) >= 0)
+        return fd;
+    return -1;
+}
+
+static int
+firegl_drmOpenByBusID(const char *busid)
+{
+    int i, fd;
+    drmSetVersion sv;
+    const char *buf;
+
+    for (i = 0; i < DRM_MAX_MINOR; i++) {
+        if ((fd = firegl_drmOpenMinor(i)) < 0)
+            continue;
+        sv.drm_di_major = 1;
+        sv.drm_di_minor = 1;
+        sv.drm_dd_major = -1;
+        sv.drm_dd_minor = -1;
+        libdrm_drmSetInterfaceVersion(fd, &sv);
+        buf = libdrm_drmGetBusid(fd);
+        if (buf && strcasecmp(buf, busid) == 0) { /* XXX: drmMatchBusID() */
+            libdrm_drmFreeBusid(buf);
+            return fd;
+        }
+        if (buf)
+            libdrm_drmFreeBusid(buf);
+        close(fd);
+    }
+    return -1;
+}
+
+static int
+drm_open_once(struct dri_state *dri_state, const char *BusID, int *newlyopened)
+{
+    dri_state->driConnectedFlag = VA_NONE;
+    dri_state->fd = libdrm_drmOpenOnce(NULL, BusID, newlyopened);
+    if (dri_state->fd < 0) {
+        dri_state->fd = firegl_drmOpenByBusID(BusID);
+        if (dri_state->fd >= 0) {
+            *newlyopened = 1;
+            dri_state->driConnectedFlag |= VA_DRI_AMD;
+        }
+    }
+    return dri_state->fd;
+}
+
+static void
+drm_close_once(struct dri_state *dri_state)
+{
+    /* XXX: dri_state->close() doesn't seem to be called, thus this
+       function is never called either */
+    if (dri_state->fd < 0)
+        return;
+    if (dri_state->driConnectedFlag & VA_DRI_AMD)
+        close(dri_state->fd);
+    else
+        libdrm_drmCloseOnce(dri_state->fd);
+    dri_state->fd = -1;
+    dri_state->driConnectedFlag = VA_NONE;
+}
+
 static struct dri_drawable * 
 dri1CreateDrawable(VADriverContextP ctx, XID x_drawable)
 {
@@ -64,9 +135,9 @@ dri1Close(VADriverContextP ctx)
     free_drawable_hashtable(ctx);
     VA_DRIDestroyContext(ctx->x11_dpy, ctx->x11_screen, dri_state->hwContextID);
     assert(dri_state->pSAREA != MAP_FAILED);
-    drmUnmap(dri_state->pSAREA, SAREA_MAX);
+    libdrm_drmUnmap(dri_state->pSAREA, SAREA_MAX);
     assert(dri_state->fd >= 0);
-    drmCloseOnce(dri_state->fd);
+    drm_close_once(dri_state);
     VA_DRICloseConnection(ctx->x11_dpy, ctx->x11_screen);
 }
 
@@ -104,21 +175,20 @@ isDRI1Connected(VADriverContextP ctx, char **driver_name)
                               &dri_state->hSAREA, &BusID))
         goto err_out0;
 
-    
-    dri_state->fd = drmOpenOnce(NULL, BusID, &newlyopened);
+    drm_open_once(dri_state, BusID, &newlyopened);
     XFree(BusID);
 
     if (dri_state->fd < 0)
         goto err_out1;
 
 
-    if (drmGetMagic(dri_state->fd, &magic))
+    if (libdrm_drmGetMagic(dri_state->fd, &magic))
         goto err_out1;
 
     if (newlyopened && !VA_DRIAuthConnection(ctx->x11_dpy, ctx->x11_screen, magic))
         goto err_out1;
 
-    if (drmMap(dri_state->fd, dri_state->hSAREA, SAREA_MAX, &dri_state->pSAREA))
+    if (libdrm_drmMap(dri_state->fd, dri_state->hSAREA, SAREA_MAX, &dri_state->pSAREA))
         goto err_out1;
 
     if (!VA_DRICreateContext(ctx->x11_dpy, ctx->x11_screen,
@@ -127,7 +196,8 @@ isDRI1Connected(VADriverContextP ctx, char **driver_name)
                              &dri_state->hwContextID, &dri_state->hwContext))
         goto err_out1;
 
-    dri_state->driConnectedFlag = VA_DRI1;
+    dri_state->driConnectedFlag &= VA_DRI_AMD; /* clear flags but AMD bit */
+    dri_state->driConnectedFlag |= VA_DRI1;
     dri_state->createDrawable = dri1CreateDrawable;
     dri_state->destroyDrawable = dri1DestroyDrawable;
     dri_state->swapBuffer = dri1SwapBuffer;
@@ -138,10 +208,10 @@ isDRI1Connected(VADriverContextP ctx, char **driver_name)
 
 err_out1:
     if (dri_state->pSAREA != MAP_FAILED)
-        drmUnmap(dri_state->pSAREA, SAREA_MAX);
+        libdrm_drmUnmap(dri_state->pSAREA, SAREA_MAX);
 
     if (dri_state->fd >= 0)
-        drmCloseOnce(dri_state->fd);
+        drm_close_once(dri_state);
 
     VA_DRICloseConnection(ctx->x11_dpy, ctx->x11_screen);
 
diff --git a/src/x11/dri2_util.c b/src/x11/dri2_util.c
index ebe7a2c..b727e97 100644
--- a/src/x11/dri2_util.c
+++ b/src/x11/dri2_util.c
@@ -3,7 +3,7 @@
 #include <unistd.h>
 #include <assert.h>
 
-#include <xf86drm.h>
+#include "libdrm_glue.h"
 
 #include <X11/Xlibint.h>
 #include <X11/Xlib.h>
@@ -166,7 +166,7 @@ isDRI2Connected(VADriverContextP ctx, char **driver_name)
     if (dri_state->fd < 0)
         goto err_out;
 
-    if (drmGetMagic(dri_state->fd, &magic))
+    if (libdrm_drmGetMagic(dri_state->fd, &magic))
         goto err_out;
 
     if (!VA_DRI2Authenticate(ctx->x11_dpy, RootWindow(ctx->x11_dpy, ctx->x11_screen),
diff --git a/src/x11/libdrm_glue.c b/src/x11/libdrm_glue.c
new file mode 100644
index 0000000..b72a2d1
--- /dev/null
+++ b/src/x11/libdrm_glue.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2009 Splitted-Desktop Systems. 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.
+ */
+
+#define _GNU_SOURCE 1
+#include "libdrm_glue.h"
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+#define LOAD_FUNC_(NAME, RET, ARGS, FALLBACK)   \
+    static RET (*lib_##NAME) ARGS;              \
+    if (lib_##NAME == NULL) {                   \
+        lib_##NAME = libdrm_symbol(#NAME);      \
+        if (!lib_##NAME)                        \
+            lib_##NAME = FALLBACK;              \
+    }                                           \
+    assert(lib_##NAME != NULL)
+
+#define LOAD_FUNC(NAME, RET, ARGS)              \
+    LOAD_FUNC_(NAME, RET, ARGS, NULL)
+
+static void *libdrm_handle;
+static int libdrm_handle_ok = -1;
+
+static inline void *libdrm_symbol(const char *name)
+{
+    if (!libdrm_open())
+        return NULL;
+    return dlsym(libdrm_handle, name);
+}
+
+int libdrm_open(void)
+{
+    if (libdrm_handle_ok < 0) {
+        libdrm_handle = dlopen("libdrm.so.2", RTLD_LOCAL|RTLD_LAZY);
+        libdrm_handle_ok = libdrm_handle != NULL;
+    }
+    assert(libdrm_handle);
+    return libdrm_handle_ok;
+}
+
+void libdrm_close(void)
+{
+    if (libdrm_handle)
+        dlclose(libdrm_handle);
+}
+
+// Default drmOpenOnce() and drmCloseOnce() implementations based on current GIT
+#define DRM_MAX_FDS 16
+static struct {
+    char *BusID;
+    int fd;
+    int refcount;
+} connection[DRM_MAX_FDS];
+
+static int nr_fds = 0;
+
+// Default implementation for drmOpenOnce() if none exists in the library
+static int
+libdrm_default_drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
+{
+    int i;
+    int fd;
+
+    for (i = 0; i < nr_fds; i++)
+        if (strcmp(BusID, connection[i].BusID) == 0) {
+            connection[i].refcount++;
+            *newlyopened = 0;
+            return connection[i].fd;
+        }
+
+    fd = libdrm_drmOpen(unused, BusID);
+    if (fd <= 0 || nr_fds == DRM_MAX_FDS)
+        return fd;
+
+    connection[nr_fds].BusID = strdup(BusID);
+    connection[nr_fds].fd = fd;
+    connection[nr_fds].refcount = 1;
+    *newlyopened = 1;
+
+    if (0)
+        fprintf(stderr, "saved connection %d for %s %d\n", 
+                nr_fds, connection[nr_fds].BusID, 
+                strcmp(BusID, connection[nr_fds].BusID));
+    nr_fds++;
+    return fd;
+}
+
+// Default implementation for drmCloseOnce() if none exists in the library
+static void libdrm_default_drmCloseOnce(int fd)
+{
+    int i;
+
+    for (i = 0; i < nr_fds; i++) {
+        if (fd == connection[i].fd) {
+            if (--connection[i].refcount == 0) {
+                libdrm_drmClose(connection[i].fd);
+                free(connection[i].BusID);
+                if (i < --nr_fds) 
+                    connection[i] = connection[nr_fds];
+                return;
+            }
+        }
+    }
+}
+
+// Determine whether the DRM kernel driver has been loaded
+int libdrm_drmAvailable(void)
+{
+    LOAD_FUNC(drmAvailable, int, (void));
+    return lib_drmAvailable();
+}
+
+// Open the DRM device
+int libdrm_drmOpen(const char *name, const char *busid)
+{
+    LOAD_FUNC(drmOpen, int, (const char *, const char *));
+    return lib_drmOpen(name, busid);
+}
+
+// Close the device
+int libdrm_drmClose(int fd)
+{
+    LOAD_FUNC(drmClose, int, (int));
+    return lib_drmClose(fd);
+}
+
+// Open the DRM device (re-use an existing connection)
+int libdrm_drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
+{
+    LOAD_FUNC_(drmOpenOnce, int, (void *, const char *, int *),
+               libdrm_default_drmOpenOnce);
+    return lib_drmOpenOnce(unused, BusID, newlyopened);
+}
+
+// Close the device (unref an existing connection prior to actually closing it)
+void libdrm_drmCloseOnce(int fd)
+{
+    LOAD_FUNC_(drmCloseOnce, void, (int), libdrm_default_drmCloseOnce);
+    lib_drmCloseOnce(fd);
+}
+
+// DRM connection cookie
+int libdrm_drmGetMagic(int fd, drm_magic_t * magic)
+{
+    LOAD_FUNC(drmGetMagic, int, (int, drm_magic_t *));
+    return lib_drmGetMagic(fd, magic);
+}
+
+// Issue a set-version ioctl
+int libdrm_drmSetInterfaceVersion(int fd, drmSetVersion *version)
+{
+    LOAD_FUNC(drmSetInterfaceVersion, int, (int, drmSetVersion *));
+    return lib_drmSetInterfaceVersion(fd, version);
+}
+
+// Get the bus ID of the device
+char *libdrm_drmGetBusid(int fd)
+{
+    LOAD_FUNC(drmGetBusid, char *, (int));
+    return lib_drmGetBusid(fd);
+}
+
+// Free the bus ID information
+void libdrm_drmFreeBusid(const char *busid)
+{
+    LOAD_FUNC(drmFreeBusid, void, (const char *));
+    lib_drmFreeBusid(busid);
+}
+
+// Map a region of memory
+int libdrm_drmMap(int fd,
+                  drm_handle_t handle,
+                  drmSize size,
+                  drmAddressPtr address)
+{
+    LOAD_FUNC(drmMap, int, (int, drm_handle_t, drmSize, drmAddressPtr));
+    return lib_drmMap(fd, handle, size, address);
+}
+
+// Unmap mappings obtained with drmMap()
+int libdrm_drmUnmap(drmAddress address, drmSize size)
+{
+    LOAD_FUNC(drmUnmap, int, (drmAddress, drmSize));
+    return lib_drmUnmap(address, size);
+}
diff --git a/src/x11/libdrm_glue.h b/src/x11/libdrm_glue.h
new file mode 100644
index 0000000..878470b
--- /dev/null
+++ b/src/x11/libdrm_glue.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 Splitted-Desktop Systems. 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 LIBDRM_GLUE_H
+#define LIBDRM_GLUE_H
+
+#include "config.h"
+#include <xf86drm.h>
+
+int libdrm_open(void)
+    ATTRIBUTE_HIDDEN;
+
+void libdrm_close(void)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmAvailable(void)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmOpen(const char *name, const char *busid)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmClose(int fd)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
+    ATTRIBUTE_HIDDEN;
+
+void libdrm_drmCloseOnce(int fd)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmGetMagic(int fd, drm_magic_t * magic)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmSetInterfaceVersion(int fd, drmSetVersion *version)
+    ATTRIBUTE_HIDDEN;
+
+char *libdrm_drmGetBusid(int fd)
+    ATTRIBUTE_HIDDEN;
+
+void libdrm_drmFreeBusid(const char *busid)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmMap(int fd,
+                  drm_handle_t handle,
+                  drmSize size,
+                  drmAddressPtr address)
+    ATTRIBUTE_HIDDEN;
+
+int libdrm_drmUnmap(drmAddress address, drmSize size)
+    ATTRIBUTE_HIDDEN;
+
+#endif /* LIBDRM_GLUE_H */
diff --git a/src/x11/va_dricommon.h b/src/x11/va_dricommon.h
index a2a51a6..0da35fe 100644
--- a/src/x11/va_dricommon.h
+++ b/src/x11/va_dricommon.h
@@ -13,7 +13,8 @@ enum
 {
     VA_NONE = 0,
     VA_DRI1 = 1,
-    VA_DRI2 = 2
+    VA_DRI2 = 2,
+    VA_DRI_AMD = 4 /* AMD DRI implementation */
 };
 
 union dri_buffer 
diff --git a/src/x11/va_x11.c b/src/x11/va_x11.c
index b8c60fa..414c261 100644
--- a/src/x11/va_x11.c
+++ b/src/x11/va_x11.c
@@ -31,6 +31,7 @@
 #include "va_dri2.h"
 #include "va_dricommon.h"
 #include "va_nvctrl.h"
+#include "libdrm_glue.h"
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
@@ -94,6 +75,8 @@ static void va_DisplayContextDestroy (
 	}
 	ctx = &((*ctx)->pNext);
     }
+
+    libdrm_close();
     free(pDisplayContext->pDriverContext->dri_state);
     free(pDisplayContext->pDriverContext);
     free(pDisplayContext);
diff --git a/src/Makefile.am b/src/Makefile.am
index e50a15f..d1f8f70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,7 +45,7 @@ libva_la_LDFLAGS = $(LDADD) -no-undefined
 libva_la_LIBADD = $(LIBVA_LIBS) -ldl
 
 libva_x11_la_SOURCES = 
-libva_x11_la_LIBADD  = $(libvacorelib) x11/libva_x11.la $(LIBVA_LIBS) $(X11_LIBS) $(XEXT_LIBS) $(DRM_LIBS) $(XFIXES_LIBS)
+libva_x11_la_LIBADD  = $(libvacorelib) x11/libva_x11.la $(LIBVA_LIBS) $(X11_LIBS) $(XEXT_LIBS) $(XFIXES_LIBS) -ldl
 libva_x11_la_LDFLAGS = $(LDADD)
 libva_x11_la_DEPENDENCIES = $(libvacorelib) x11/libva_x11.la
 
