New files for radeon egl driver.
authorJon Smirl <jonsmirl@gmail.com>
Thu, 4 Aug 2005 22:23:34 +0000 (22:23 +0000)
committerJon Smirl <jonsmirl@gmail.com>
Thu, 4 Aug 2005 22:23:34 +0000 (22:23 +0000)
Still a work in progress.

src/egl/drivers/dri/Makefile [new file with mode: 0644]
src/egl/drivers/dri/egldri.c [new file with mode: 0644]
src/mesa/drivers/dri/radeon/server/radeon_egl.c [new file with mode: 0644]

diff --git a/src/egl/drivers/dri/Makefile b/src/egl/drivers/dri/Makefile
new file mode 100644 (file)
index 0000000..6b50959
--- /dev/null
@@ -0,0 +1,64 @@
+# src/egl/drivers/dri/Makefile
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+
+### Include directories
+INCLUDE_DIRS = \
+       -I. \
+       -I$(DRM_SOURCE_PATH)/shared-core \
+       -I$(DRM_SOURCE_PATH)/libdrm \
+       -I$(TOP)/include \
+       -I$(TOP)/include/GL/internal \
+       -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/shader \
+       -I$(TOP)/src/mesa/swrast \
+       -I$(TOP)/src/mesa/swrast_setup \
+       -I$(TOP)/src/egl/main \
+       -I$(TOP)/src/mesa/drivers/dri/common
+
+
+HEADERS = egldri.h
+
+SOURCES = egldri.c \
+          $(DRM_SOURCE_PATH)/libdrm/xf86drm.c \
+          $(DRM_SOURCE_PATH)/libdrm/xf86drmHash.c \
+          $(DRM_SOURCE_PATH)/libdrm/xf86drmRandom.c
+
+OBJECTS = $(SOURCES:.c=.o)
+
+
+.c.o:
+       $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@
+
+
+
+default: depend library Makefile
+
+
+# EGLdri Library
+library: $(LIB_DIR)/libEGLdri.so
+
+$(LIB_DIR)/libEGLdri.so: $(OBJECTS)
+       $(TOP)/bin/mklib -o EGLdri -major 1 -minor 0 \
+               -install $(LIB_DIR) -ldl $(OBJECTS)
+
+
+clean:
+       rm -f *.o
+       rm -f *.so
+
+depend: $(SOURCES) $(HEADERS)
+       @ echo "running $(MKDEP)"
+       @ touch depend
+       $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) \
+               $(SOURCES) $(HEADERS) > /dev/null 
+
+include depend
+# DO NOT DELETE
+
diff --git a/src/egl/drivers/dri/egldri.c b/src/egl/drivers/dri/egldri.c
new file mode 100644 (file)
index 0000000..2d45127
--- /dev/null
@@ -0,0 +1,1001 @@
+/*
+ * Generic EGL driver for DRI
+ */
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/fb.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "egldriver.h"
+#include "egldisplay.h"
+#include "eglcontext.h"
+#include "eglconfig.h"
+#include "eglsurface.h"
+#include "eglscreen.h"
+#include "eglglobals.h"
+#include "eglmode.h"
+
+#include "egldri.h"
+
+const char *sysfs = "/sys/class";
+#define None 0
+static const int empty_attribute_list[1] = { None };
+
+/**
+ * The bootstrap function.  Return a new driDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *dpy)
+{
+   int length;
+   char path[NAME_MAX];
+   struct dirent *dirent;
+   FILE *file;
+   DIR *dir;
+   _EGLDriver *driver = NULL;;
+
+   snprintf(path, sizeof(path), "%s/drm", sysfs);
+   if (!(dir = opendir(path))) {
+      printf("EGL - %s DRM devices not found.", path);
+      return EGL_FALSE;
+   }
+   while ((dirent = readdir(dir))) {
+
+      if (strncmp(&dirent->d_name[0], "card", 4) != 0)
+         continue;
+      if (strcmp(&dirent->d_name[4], &dpy->Name[1]) != 0)
+         continue;
+
+      snprintf(path, sizeof(path), "%s/drm/card%s/dri_library_name", sysfs, &dpy->Name[1]);
+      file = fopen(path, "r");
+      fgets(path, sizeof(path), file);
+      fclose(file);
+
+      if ((length = strlen(path)) > 0)
+         path[length - 1] = '\0';  /* remove the trailing newline from sysfs */
+      strncat(path, "_dri", sizeof(path));
+
+      driver = _eglOpenDriver(dpy, path);
+
+      break;
+   }
+   closedir(dir);
+
+   return driver;
+}
+
+
+static EGLContext
+_eglDRICreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list)
+{
+   _EGLConfig *conf;
+   driContext *c;
+   driDisplay *disp = Lookup_driDisplay(dpy);
+   driContext *share = Lookup_driContext(share_list);
+   void *sharePriv;
+   __GLcontextModes mode;
+   int i;
+
+   conf = _eglLookupConfig(drv, dpy, config);
+   if (!conf) {
+      _eglError(EGL_BAD_CONFIG, "eglCreateContext");
+      return EGL_NO_CONTEXT;
+   }
+
+   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+      switch (attrib_list[i]) {
+         /* no attribs defined for now */
+      default:
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext");
+         return EGL_NO_CONTEXT;
+      }
+   }
+
+   c = (driContext *) calloc(1, sizeof(*c));
+   if (!c)
+      return EGL_NO_CONTEXT;
+
+   _eglInitContext(&c->Base);
+   c->Base.Display = &disp->Base;
+   c->Base.Config = conf;
+   c->Base.DrawSurface = EGL_NO_SURFACE;
+   c->Base.ReadSurface = EGL_NO_SURFACE;
+
+   _eglConfigToContextModesRec(conf, &mode);
+
+   if (share)
+      sharePriv = share->driContext.private;
+   else
+      sharePriv = NULL;
+
+   c->driContext.private = disp->driScreen.createNewContext(disp, &mode,
+           GLX_WINDOW_BIT, sharePriv, &c->driContext);
+
+   if (!c->driContext.private) {
+      free(c);
+      return EGL_FALSE;
+   }
+
+   /* generate handle and insert into hash table */
+   _eglSaveContext(&c->Base);
+   assert(c->Base.Handle);
+
+   return c->Base.Handle;
+}
+
+
+static EGLBoolean
+_eglDRIMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context)
+{
+   driDisplay *disp = Lookup_driDisplay(dpy);
+   driContext *ctx = Lookup_driContext(context);
+   EGLBoolean b;
+
+   b = _eglMakeCurrent(drv, dpy, draw, read, context);
+   if (!b)
+      return EGL_FALSE;
+
+   if (ctx) {
+      ctx->driContext.bindContext(disp, 0, read, draw, &ctx->driContext);
+   } else {
+//      _mesa_make_current( NULL, NULL, NULL );
+   }
+   return EGL_TRUE;
+}
+
+
+static EGLSurface
+_eglDRICreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
+{
+   int i;
+   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+      switch (attrib_list[i]) {
+         /* no attribs at this time */
+      default:
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateWindowSurface");
+         return EGL_NO_SURFACE;
+      }
+   }
+   printf("eglCreateWindowSurface()\n");
+   /* XXX unfinished */
+
+   return EGL_NO_SURFACE;
+}
+
+
+static EGLSurface
+_eglDRICreatePixmapSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
+{
+   _EGLConfig *conf;
+   EGLint i;
+
+   conf = _eglLookupConfig(drv, dpy, config);
+   if (!conf) {
+      _eglError(EGL_BAD_CONFIG, "eglCreatePixmapSurface");
+      return EGL_NO_SURFACE;
+   }
+
+   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
+      switch (attrib_list[i]) {
+         /* no attribs at this time */
+      default:
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePixmapSurface");
+         return EGL_NO_SURFACE;
+      }
+   }
+
+   if (conf->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] == 0) {
+      _eglError(EGL_BAD_MATCH, "eglCreatePixmapSurface");
+      return EGL_NO_SURFACE;
+   }
+
+   printf("eglCreatePixmapSurface()\n");
+   return EGL_NO_SURFACE;
+}
+
+
+static EGLSurface
+_eglDRICreatePbufferSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
+{
+   driSurface *surf;
+
+   surf = (driSurface *) calloc(1, sizeof(*surf));
+   if (!surf) {
+      return EGL_NO_SURFACE;
+   }
+
+   if (_eglInitPbufferSurface(&surf->Base, drv, dpy, config, attrib_list) == EGL_NO_SURFACE) {
+      free(surf);
+      return EGL_NO_SURFACE;
+   }
+
+   /* create software-based pbuffer */
+   {
+//      GLcontext *ctx = NULL; /* this _should_ be OK */
+      GLvisual vis;
+      _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
+      assert(conf); /* bad config should be caught earlier */
+      _eglConfigToContextModesRec(conf, &vis);
+
+#if 0
+      surf->mesa_framebuffer = _mesa_create_framebuffer(&vis);
+      _mesa_add_soft_renderbuffers(surf->mesa_framebuffer,
+                                   GL_TRUE, /* color bufs */
+                                   vis.haveDepthBuffer,
+                                   vis.haveStencilBuffer,
+                                   vis.haveAccumBuffer,
+                                   GL_FALSE, /* alpha */
+                                   GL_FALSE /* aux */ );
+
+      /* set pbuffer/framebuffer size */
+      _mesa_resize_framebuffer(ctx, surf->mesa_framebuffer,
+                               surf->Base.Width, surf->Base.Height);
+#endif
+   }
+
+   return surf->Base.Handle;
+}
+
+
+static EGLBoolean
+_eglDRIDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
+{
+   driDisplay *disp = Lookup_driDisplay(dpy);
+   driSurface *fs = Lookup_driSurface(surface);
+   _eglRemoveSurface(&fs->Base);
+
+   fs->drawable.destroyDrawable(disp, fs->drawable.private);
+
+   if (fs->Base.IsBound) {
+      fs->Base.DeletePending = EGL_TRUE;
+   }
+   else {
+      free(fs);
+   }
+   return EGL_TRUE;
+}
+
+
+static EGLBoolean
+_eglDRIDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext context)
+{
+   driDisplay *disp = Lookup_driDisplay(dpy);
+   driContext *fc = Lookup_driContext(context);
+
+   _eglRemoveContext(&fc->Base);
+
+   fc->driContext.destroyContext(disp, 0, fc->driContext.private);
+
+   if (fc->Base.IsBound) {
+      fc->Base.DeletePending = EGL_TRUE;
+   } else {
+      free(fc);
+   }
+   return EGL_TRUE;
+}
+
+
+/**
+ * Create a drawing surface which can be directly displayed on a screen.
+ */
+static EGLSurface
+_eglDRICreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
+                          const EGLint *attrib_list)
+{
+   _EGLConfig *config = _eglLookupConfig(drv, dpy, cfg);
+   driDisplay *disp = Lookup_driDisplay(dpy);
+   driSurface *surface;
+   EGLSurface surf;
+   GLvisual vis;
+
+   surface = (driSurface *) malloc(sizeof(*surface));
+   if (!surface) {
+      return EGL_NO_SURFACE;
+   }
+
+   /* init base class, error check, etc. */
+   surf = _eglInitScreenSurface(&surface->Base, drv, dpy, cfg, attrib_list);
+   if (surf == EGL_NO_SURFACE) {
+      free(surface);
+      return EGL_NO_SURFACE;
+   }
+
+   /* convert EGLConfig to GLvisual */
+   _eglConfigToContextModesRec(config, &vis);
+
+   /* Create a new drawable */
+   if (!disp->driScreen.createNewDrawable(disp, &vis, surf, &surface->drawable,
+                           GLX_WINDOW_BIT, empty_attribute_list)) {
+      free(surface);
+      _eglRemoveSurface(&surface->Base);
+      return EGL_NO_SURFACE;
+   }
+   return surf;
+}
+
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ */
+EGLBoolean
+_eglDRIShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+                    EGLSurface surface, EGLModeMESA m)
+{
+   driDisplay *display = Lookup_driDisplay(dpy);
+   driScreen *scrn = Lookup_driScreen(dpy, screen);
+   driSurface *surf = Lookup_driSurface(surface);
+   FILE *file;
+   char buffer[NAME_MAX];
+   _EGLMode *mode = _eglLookupMode(dpy, m);
+   int width, height, temp;
+
+   _eglQuerySurface(drv, dpy, surface, EGL_WIDTH, &width);
+   _eglQuerySurface(drv, dpy, surface, EGL_HEIGHT, &height);
+
+   if (!_eglShowSurfaceMESA(drv, dpy, screen, surface, m))
+      return EGL_FALSE;
+
+   snprintf(buffer, sizeof(buffer), "%s/graphics/%s/blank", sysfs, scrn->fb);
+
+   file = fopen(buffer, "r+");
+   if (!file) {
+err:
+      printf("kernel patch?? chown all fb sysfs attrib to allow write - %s\n", buffer);
+      _eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
+      return EGL_FALSE;
+   }
+   snprintf(buffer, sizeof(buffer), "%d", (m == EGL_NO_MODE_MESA ? VESA_POWERDOWN : VESA_VSYNC_SUSPEND));
+   fputs(buffer, file);
+   fclose(file);
+
+   if (m == EGL_NO_MODE_MESA)
+      return EGL_TRUE;
+
+   snprintf(buffer, sizeof(buffer), "%s/graphics/%s/mode", sysfs, scrn->fb);
+
+   file = fopen(buffer, "r+");
+   if (!file)
+      goto err;
+   fputs(mode->Name, file);
+   fclose(file);
+
+   snprintf(buffer, sizeof(buffer), "%s/graphics/%s/bits_per_pixel", sysfs, scrn->fb);
+
+   file = fopen(buffer, "r+");
+   if (!file)
+      goto err;
+   display->bpp = GET_CONFIG_ATTRIB(surf->Base.Config, EGL_BUFFER_SIZE);
+   display->cpp = display->bpp / 8;
+   snprintf(buffer, sizeof(buffer), "%d", display->bpp);
+   fputs(buffer, file);
+   fclose(file);
+
+   snprintf(buffer, sizeof(buffer), "%s/graphics/%s/blank", sysfs, scrn->fb);
+
+   file = fopen(buffer, "r+");
+   if (!file)
+      goto err;
+
+   snprintf(buffer, sizeof(buffer), "%d", VESA_NO_BLANKING);
+   fputs(buffer, file);
+   fclose(file);
+
+   snprintf(buffer, sizeof(buffer), "%s/graphics/%s/virtual_size", sysfs, scrn->fb);
+   file = fopen(buffer, "r+");
+   snprintf(buffer, sizeof(buffer), "%d,%d", width, height);
+   fputs(buffer, file);
+   rewind(file);
+   fgets(buffer, sizeof(buffer), file);
+   sscanf(buffer, "%d,%d", &display->virtualWidth, &display->virtualHeight);
+   fclose(file);
+
+   temp = display->virtualWidth;
+   switch (display->bpp / 8) {
+   case 1: temp = (display->virtualWidth + 127) & ~127; break;
+   case 2: temp = (display->virtualWidth +  31) &  ~31; break;
+   case 3:
+   case 4: temp = (display->virtualWidth +  15) &  ~15; break;
+   }
+   display->virtualWidth = temp;
+
+   if ((width != display->virtualWidth) || (height != display->virtualHeight))
+      goto err;
+
+   return EGL_TRUE;
+}
+
+
+/* If the backbuffer is on a videocard, this is extraordinarily slow!
+ */
+static EGLBoolean
+_eglDRISwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
+{
+   driSurface *drawable = Lookup_driSurface(draw);
+
+   if (!_eglSwapBuffers(drv, dpy, draw))
+      return EGL_FALSE;
+
+   drawable->drawable.swapBuffers(NULL, drawable->drawable.private);
+
+   return EGL_TRUE;
+}
+
+
+EGLBoolean
+_eglDRIGetDisplayInfo( driDisplay *dpy) {
+   char path[ NAME_MAX ];
+   FILE *file;
+   int rc, mtrr;
+   unsigned int i;
+   drmMapType type;
+   drmMapFlags flags;
+   drm_handle_t handle, offset;
+   drmSize size;
+   drmSetVersion sv;
+   drm_magic_t magic;
+
+   snprintf( path, sizeof( path ), "%s/graphics/fb%d/device/device", sysfs, dpy->minor );
+   file = fopen( path, "r" );
+   fgets( path, sizeof( path ), file );
+   sscanf( path, "%x", &dpy->chipset );
+   fclose( file );
+
+   sprintf(path, DRM_DEV_NAME, DRM_DIR_NAME, dpy->minor);
+   if ( ( dpy->drmFD = open(path, O_RDWR, 0) ) < 0 ) {
+      fprintf( stderr, "[drm] drmOpen failed\n" );
+      return EGL_FALSE;
+   }
+
+   /* Set the interface version, asking for 1.2 */
+   sv.drm_di_major = 1;
+   sv.drm_di_minor = 2;
+   sv.drm_dd_major = -1;
+   if ((rc = drmSetInterfaceVersion(dpy->drmFD, &sv)))
+      return EGL_FALSE;
+
+   /* self authorize */
+   if (drmGetMagic(dpy->drmFD, &magic))
+      return EGL_FALSE;
+   if (drmAuthMagic(dpy->drmFD, magic))
+      return EGL_FALSE;
+
+   for ( i = 0;; i++ ) {
+      if ( ( rc = drmGetMap( dpy->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) ) != 0 )
+         break;
+      if ( type == DRM_FRAME_BUFFER ) {
+         if ( ( rc = drmMap( dpy->drmFD, offset, size, ( drmAddressPtr ) & dpy->pFB ) ) < 0 )
+            return EGL_FALSE;
+         dpy->fbSize = size;
+         break;
+      }
+   }
+   if ( !dpy->pFB )
+      return EGL_FALSE;
+
+   dpy->SAREASize = SAREA_MAX;
+
+   for ( i = 0;; i++ ) {
+      if ( drmGetMap( dpy->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) != 0 )
+         break;
+      if ( type == DRM_SHM ) {
+         if ( drmMap( dpy->drmFD, offset, size, ( drmAddressPtr ) ( &dpy->pSAREA ) ) < 0 ) {
+            fprintf( stderr, "[drm] drmMap failed\n" );
+            return 0;
+         }
+         break;
+      }
+   }
+   if ( !dpy->pSAREA )
+      return 0;
+
+   memset( dpy->pSAREA, 0, dpy->SAREASize );
+   fprintf( stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
+            offset, dpy->pSAREA, dpy->SAREASize );
+   return EGL_TRUE;
+}
+
+
+ /* Return the DRI per screen structure */
+static __DRIscreen *__eglFindDRIScreen(__DRInativeDisplay *ndpy, int scrn)
+{
+   driDisplay *disp = (driDisplay *)ndpy;
+   return &disp->driScreen;
+}
+
+static GLboolean __eglCreateContextWithConfig(__DRInativeDisplay* ndpy, int screen, int configID, void* context, drm_context_t * hHWContext)
+{
+    __DRIscreen *pDRIScreen;
+    __DRIscreenPrivate *psp;
+
+    pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+    if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+        return GL_FALSE;
+    }
+    psp = (__DRIscreenPrivate *) pDRIScreen->private;
+    if (psp->fd) {
+        if (drmCreateContext(psp->fd, hHWContext)) {
+            fprintf(stderr, ">>> drmCreateContext failed\n");
+            return GL_FALSE;
+        }
+        *(void**)context = (void*) *hHWContext;
+    }
+#if 0
+    __DRIscreen *pDRIScreen;
+    __DRIscreenPrivate *psp;
+
+    pDRIScreen = __glXFindDRIScreen(dpy, screen);
+    if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+        return GL_FALSE;
+    }
+
+    psp = (__DRIscreenPrivate *) pDRIScreen->private;
+
+    if (psp->fd) {
+        if (drmCreateContext(psp->fd, hHWContext)) {
+            fprintf(stderr, ">>> drmCreateContext failed\n");
+            return GL_FALSE;
+        }
+        *(void**)contextID = (void*) *hHWContext;
+    }
+#endif
+    return GL_TRUE;
+}
+
+static GLboolean __eglDestroyContext( __DRInativeDisplay * ndpy, int screen,  __DRIid context )
+{
+    __DRIscreen *pDRIScreen;
+    __DRIscreenPrivate *psp;
+
+    pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+    if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+        return GL_FALSE;
+    }
+    psp = (__DRIscreenPrivate *) pDRIScreen->private;
+    if (psp->fd)
+      drmDestroyContext(psp->fd, context);
+
+   return GL_TRUE;
+}
+
+static GLboolean __eglCreateDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable, drm_drawable_t * hHWDrawable )
+{
+    __DRIscreen *pDRIScreen;
+    __DRIscreenPrivate *psp;
+
+    pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+    if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+        return GL_FALSE;
+    }
+    psp = (__DRIscreenPrivate *) pDRIScreen->private;
+    if (psp->fd) {
+        if (drmCreateDrawable(psp->fd, hHWDrawable)) {
+            fprintf(stderr, ">>> drmCreateDrawable failed\n");
+            return GL_FALSE;
+        }
+    }
+    return GL_TRUE;
+}
+
+static GLboolean __eglDestroyDrawable( __DRInativeDisplay * ndpy, int screen, __DRIid drawable )
+{
+    __DRIscreen *pDRIScreen;
+    __DRIscreenPrivate *psp;
+
+    pDRIScreen = __eglFindDRIScreen(ndpy, screen);
+    if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
+        return GL_FALSE;
+    }
+    psp = (__DRIscreenPrivate *) pDRIScreen->private;
+    if (psp->fd)
+      drmDestroyDrawable(psp->fd, drawable);
+
+   return GL_TRUE;
+}
+
+static GLboolean __eglGetDrawableInfo(__DRInativeDisplay * ndpy, int screen, __DRIid drawable,
+    unsigned int* index, unsigned int* stamp,
+    int* X, int* Y, int* W, int* H,
+    int* numClipRects, drm_clip_rect_t ** pClipRects,
+    int* backX, int* backY,
+    int* numBackClipRects, drm_clip_rect_t ** pBackClipRects )
+{
+   driSurface *surf = Lookup_driSurface(drawable);
+
+   *X = 0;
+   *Y = 0;
+   *W = surf->Base.Width;
+   *H = surf->Base.Height;
+
+   *numClipRects = 1;
+   *pClipRects = malloc(sizeof(**pClipRects));
+   **pClipRects = (drm_clip_rect_t){0, 0, surf->Base.Width, surf->Base.Height};
+
+#if 0
+    GLXDrawable drawable = (GLXDrawable) draw;
+    drm_clip_rect_t * cliprect;
+    Display* display = (Display*)dpy;
+    __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private;
+    if (drawable == 0) {
+        return GL_FALSE;
+    }
+
+    cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t));
+    cliprect->x1 = drawable->x;
+    cliprect->y1 = drawable->y;
+    cliprect->x2 = drawable->x + drawable->w;
+    cliprect->y2 = drawable->y + drawable->h;
+    
+    /* the drawable index is by client id */
+    *index = display->clientID;
+
+    *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
+    *x = drawable->x;
+    *y = drawable->y;
+    *width = drawable->w;
+    *height = drawable->h;
+    *numClipRects = 1;
+    *pClipRects = cliprect;
+    
+    *backX = drawable->x;
+    *backY = drawable->y;
+    *numBackClipRects = 0;
+    *pBackClipRects = 0;
+#endif
+   return GL_TRUE;
+}
+
+/**
+ * Implement \c __DRIinterfaceMethods::getProcAddress.
+ */
+static __DRIfuncPtr get_proc_address( const char * proc_name )
+{
+#if 0
+   if (strcmp( proc_name, "glxEnableExtension" ) == 0) {
+      return (__DRIfuncPtr) __glXScrEnableExtension;
+   }
+#endif
+   return NULL;
+}
+
+
+/**
+ * Destroy a linked list of \c __GLcontextModes structures created by
+ * \c _gl_context_modes_create.
+ * 
+ * \param modes  Linked list of structures to be destroyed.  All structres
+ *               in the list will be freed.
+ */
+void
+__egl_context_modes_destroy( __GLcontextModes * modes )
+{
+   while ( modes != NULL ) {
+      __GLcontextModes * const next = modes->next;
+
+      free( modes );
+      modes = next;
+   }
+}
+
+
+/**
+ * Allocate a linked list of \c __GLcontextModes structures.  The fields of
+ * each structure will be initialized to "reasonable" default values.  In
+ * most cases this is the default value defined by table 3.4 of the GLX
+ * 1.3 specification.  This means that most values are either initialized to
+ * zero or \c GLX_DONT_CARE (which is -1).  As support for additional
+ * extensions is added, the new values will be initialized to appropriate
+ * values from the extension specification.
+ * 
+ * \param count         Number of structures to allocate.
+ * \param minimum_size  Minimum size of a structure to allocate.  This allows
+ *                      for differences in the version of the
+ *                      \c __GLcontextModes stucture used in libGL and in a
+ *                      DRI-based driver.
+ * \returns A pointer to the first element in a linked list of \c count
+ *          stuctures on success, or \c NULL on failure.
+ * 
+ * \warning Use of \c minimum_size does \b not guarantee binary compatibility.
+ *          The fundamental assumption is that if the \c minimum_size
+ *          specified by the driver and the size of the \c __GLcontextModes
+ *          structure in libGL is the same, then the meaning of each byte in
+ *          the structure is the same in both places.  \b Be \b careful!
+ *          Basically this means that fields have to be added in libGL and
+ *          then propagated to drivers.  Drivers should \b never arbitrarilly
+ *          extend the \c __GLcontextModes data-structure.
+ */
+__GLcontextModes *
+__egl_context_modes_create( unsigned count, size_t minimum_size )
+{
+   const size_t size = (minimum_size > sizeof( __GLcontextModes ))
+       ? minimum_size : sizeof( __GLcontextModes );
+   __GLcontextModes * base = NULL;
+   __GLcontextModes ** next;
+   unsigned   i;
+
+   next = & base;
+   for ( i = 0 ; i < count ; i++ ) {
+      *next = (__GLcontextModes *) malloc( size );
+      if ( *next == NULL ) {
+        __egl_context_modes_destroy( base );
+        base = NULL;
+        break;
+      }
+
+      (void) memset( *next, 0, size );
+      (*next)->visualID = GLX_DONT_CARE;
+      (*next)->visualType = GLX_DONT_CARE;
+      (*next)->visualRating = GLX_NONE;
+      (*next)->transparentPixel = GLX_NONE;
+      (*next)->transparentRed = GLX_DONT_CARE;
+      (*next)->transparentGreen = GLX_DONT_CARE;
+      (*next)->transparentBlue = GLX_DONT_CARE;
+      (*next)->transparentAlpha = GLX_DONT_CARE;
+      (*next)->transparentIndex = GLX_DONT_CARE;
+      (*next)->xRenderable = GLX_DONT_CARE;
+      (*next)->fbconfigID = GLX_DONT_CARE;
+      (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
+
+      next = & ((*next)->next);
+   }
+
+   return base;
+}
+
+
+GLboolean __eglWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
+{
+    return EGL_TRUE;
+}
+
+
+/**
+ * Get the unadjusted system time (UST).  Currently, the UST is measured in
+ * microseconds since Epoc.  The actual resolution of the UST may vary from
+ * system to system, and the units may vary from release to release.
+ * Drivers should not call this function directly.  They should instead use
+ * \c glXGetProcAddress to obtain a pointer to the function.
+ *
+ * \param ust Location to store the 64-bit UST
+ * \returns Zero on success or a negative errno value on failure.
+ * 
+ * \sa glXGetProcAddress, PFNGLXGETUSTPROC
+ *
+ * \since Internal API version 20030317.
+ */
+int __eglGetUST( int64_t * ust )
+{
+    struct timeval  tv;
+    
+    if ( ust == NULL ) {
+       return -EFAULT;
+    }
+
+    if ( gettimeofday( & tv, NULL ) == 0 ) {
+       ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
+       return 0;
+    } else {
+       return -errno;
+    }
+}
+
+/**
+ * Determine the refresh rate of the specified drawable and display.
+ * 
+ * \param dpy          Display whose refresh rate is to be determined.
+ * \param drawable     Drawable whose refresh rate is to be determined.
+ * \param numerator    Numerator of the refresh rate.
+ * \param demoninator  Denominator of the refresh rate.
+ * \return  If the refresh rate for the specified display and drawable could
+ *          be calculated, True is returned.  Otherwise False is returned.
+ * 
+ * \note This function is implemented entirely client-side.  A lot of other
+ *       functionality is required to export GLX_OML_sync_control, so on
+ *       XFree86 this function can be called for direct-rendering contexts
+ *       when GLX_OML_sync_control appears in the client extension string.
+ */
+GLboolean __eglGetMSCRate(__DRInativeDisplay * dpy, __DRIid drawable, int32_t * numerator, int32_t * denominator)
+{
+   return EGL_TRUE;
+}
+
+/**
+ * Table of functions exported by the loader to the driver.
+ */
+static const __DRIinterfaceMethods interface_methods = {
+    get_proc_address,
+
+    __egl_context_modes_create,
+    __egl_context_modes_destroy,
+
+    __eglFindDRIScreen,
+    __eglWindowExists,
+
+    __eglCreateContextWithConfig,
+    __eglDestroyContext,
+
+    __eglCreateDrawable,
+    __eglDestroyDrawable,
+    __eglGetDrawableInfo,
+
+    __eglGetUST,
+    __eglGetMSCRate,
+};
+
+
+int __glXGetInternalVersion(void)
+{
+    return 20050725;
+}
+
+static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
+
+EGLBoolean
+_eglDRICreateDisplay( driDisplay *dpy, __DRIframebuffer *framebuffer) {
+   PFNCREATENEWSCREENFUNC createNewScreen;
+    int api_ver = __glXGetInternalVersion();
+   __DRIversion ddx_version;
+   __DRIversion dri_version;
+   __DRIversion drm_version;
+   drmVersionPtr version;
+
+   version = drmGetVersion( dpy->drmFD );
+   if ( version ) {
+      drm_version.major = version->version_major;
+      drm_version.minor = version->version_minor;
+      drm_version.patch = version->version_patchlevel;
+      drmFreeVersion( version );
+   } else {
+      drm_version.major = -1;
+      drm_version.minor = -1;
+      drm_version.patch = -1;
+   }
+
+   /*
+    * Get device name (like "tdfx") and the ddx version numbers.
+    * We'll check the version in each DRI driver's "createScreen"
+    * function.
+    */
+   ddx_version.major = 4;
+   ddx_version.minor = 0;
+   ddx_version.patch = 0;
+
+   /*
+    * Get the DRI X extension version.
+    */
+   dri_version.major = 4;
+   dri_version.minor = 0;
+   dri_version.patch = 0;
+
+   createNewScreen = ( PFNCREATENEWSCREENFUNC ) dlsym( dpy->Base.Driver->LibHandle, createNewScreenName );
+   if ( !createNewScreen ) {
+      fprintf( stderr, "Couldn't find %s in CallCreateNewScreen\n", createNewScreenName );
+      return EGL_FALSE;
+   }
+
+   dpy->driScreen.private = createNewScreen( dpy, 0, &dpy->driScreen, NULL,
+                            &ddx_version, &dri_version,
+                            &drm_version, framebuffer,
+                            dpy->pSAREA, dpy->drmFD,
+                            api_ver,
+                            & interface_methods,
+                            ( __GLcontextModes ** ) & dpy->driver_modes );
+   if (!dpy->driScreen.private)
+      return EGL_FALSE;
+
+   DRM_UNLOCK( dpy->drmFD, dpy->pSAREA, dpy->serverContext );
+
+   return EGL_TRUE;
+}
+
+
+EGLBoolean
+_eglDRICreateScreen( driDisplay *dpy) {
+   char c, *buffer, path[ NAME_MAX ];
+   unsigned int i, x, y, r;
+   int fd;
+   FILE *file;
+   driScreen *s;
+   _EGLScreen *scrn;
+
+   /* Create a screen */
+   if ( !( s = ( driScreen * ) calloc( 1, sizeof( *s ) ) ) )
+      return EGL_FALSE;
+
+   snprintf( s->fb, NAME_MAX, "fb%d", dpy->minor );
+   scrn = &s->Base;
+   _eglInitScreen( scrn );
+   _eglAddScreen( &dpy->Base, scrn );
+
+   snprintf( path, sizeof( path ), "%s/graphics/%s/modes", sysfs, s->fb );
+   file = fopen( path, "r" );
+   while ( fgets( path, sizeof( path ), file ) ) {
+      path[ strlen( path ) - 1 ] = '\0';  /* strip off \n from sysfs */
+      sscanf( path, "%c:%ux%u-%u", &c, &x, &y, &r );
+      _eglAddMode( scrn, x, y, r * 1000, path );
+   }
+   fclose( file );
+
+   /* cmap attribute uses 256 lines of 16 bytes */
+   if ( !( buffer = malloc( 256 * 16 ) ) )
+      return EGL_FALSE;
+
+   /* cmap attribute uses 256 lines of 16 bytes */
+   for ( i = 0; i < 256; i++ )
+      sprintf( &buffer[ i * 16 ], "%02x%c%4x%4x%4x\n",
+               i, ' ', 256 * i, 256 * i, 256 * i );
+
+   snprintf( path, sizeof( path ), "%s/graphics/%s/color_map", sysfs, s->fb );
+   if ( !( fd = open( path, O_RDWR ) ) )
+      return EGL_FALSE;
+   write( fd, buffer, 256 * 16 );
+   close( fd );
+
+   free( buffer );
+
+   return EGL_TRUE;
+}
+
+EGLBoolean
+_eglDRIInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+   _EGLDisplay *disp = _eglLookupDisplay(dpy);
+   driDisplay *display;
+
+   /* Switch display structure to one with our private fields */
+   display = calloc(1, sizeof(*display));
+   display->Base = *disp;
+   _eglHashInsert(_eglGlobal.Displays, disp->Handle, display);
+   free(disp);
+
+   *major = 1;
+   *minor = 0;
+
+   sscanf(&disp->Name[1], "%d", &display->minor);
+
+   drv->Initialized = EGL_TRUE;
+   return EGL_TRUE;
+}
+
+
+static EGLBoolean
+_eglDRITerminate(_EGLDriver *drv, EGLDisplay dpy)
+{
+   driDisplay *display = Lookup_driDisplay(dpy);
+   _eglCleanupDisplay(&display->Base);
+   free(display);
+   free(drv);
+   return EGL_TRUE;
+}
+
+
+void
+_eglDRIInitDriverFallbacks(_EGLDriver *drv)
+{
+   _eglInitDriverFallbacks(drv);
+
+   drv->Initialize = _eglDRIInitialize;
+   drv->Terminate = _eglDRITerminate;
+   drv->CreateContext = _eglDRICreateContext;
+   drv->MakeCurrent = _eglDRIMakeCurrent;
+   drv->CreateWindowSurface = _eglDRICreateWindowSurface;
+   drv->CreatePixmapSurface = _eglDRICreatePixmapSurface;
+   drv->CreatePbufferSurface = _eglDRICreatePbufferSurface;
+   drv->DestroySurface = _eglDRIDestroySurface;
+   drv->DestroyContext = _eglDRIDestroyContext;
+   drv->CreateScreenSurfaceMESA = _eglDRICreateScreenSurfaceMESA;
+   drv->ShowSurfaceMESA = _eglDRIShowSurfaceMESA;
+   drv->SwapBuffers = _eglDRISwapBuffers;
+
+   /* enable supported extensions */
+   drv->MESA_screen_surface = EGL_TRUE;
+   drv->MESA_copy_context = EGL_TRUE;
+
+}
diff --git a/src/mesa/drivers/dri/radeon/server/radeon_egl.c b/src/mesa/drivers/dri/radeon/server/radeon_egl.c
new file mode 100644 (file)
index 0000000..e491bba
--- /dev/null
@@ -0,0 +1,980 @@
+/*
+ * EGL driver for radeon_dri.so
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+
+#include "eglconfig.h"
+#include "eglcontext.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglglobals.h"
+#include "eglmode.h"
+#include "eglscreen.h"
+#include "eglsurface.h"
+#include "egldri.h"
+
+#include "mtypes.h"
+#include "memops.h"
+#include "drm.h"
+#include "drm_sarea.h"
+#include "radeon_drm.h"
+#include "radeon_dri.h"
+#include "radeon.h"
+
+static size_t radeon_drm_page_size;
+const char *sysfs = "/sys/class/graphics";
+
+/**
+ * radeon driver-specific driver class derived from _EGLDriver
+ */
+typedef struct radeon_driver
+{
+   _EGLDriver Base;  /* base class/object */
+   GLuint radeonStuff;
+} radeonDriver;
+
+static int RADEONCheckDRMVersion( driDisplay *disp,
+                                  RADEONInfoPtr info )
+{
+   drmVersionPtr  version;
+
+   version = drmGetVersion(disp->drmFD);
+   if (version) {
+      int req_minor, req_patch;
+
+      /* Need 1.8.x for proper cleanup-on-client-exit behaviour.
+       */
+      req_minor = 8;
+      req_patch = 0;
+
+      if (version->version_major != 1 ||
+          version->version_minor < req_minor ||
+          (version->version_minor == req_minor &&
+           version->version_patchlevel < req_patch)) {
+         /* Incompatible drm version */
+         fprintf(stderr,
+                 "[dri] RADEONDRIScreenInit failed because of a version "
+                 "mismatch.\n"
+                 "[dri] radeon.o kernel module version is %d.%d.%d "
+                 "but version 1.%d.%d or newer is needed.\n"
+                 "[dri] Disabling DRI.\n",
+                 version->version_major,
+                 version->version_minor,
+                 version->version_patchlevel,
+                 req_minor,
+                 req_patch);
+         drmFreeVersion(version);
+         return 0;
+      }
+
+      info->drmMinor = version->version_minor;
+      drmFreeVersion(version);
+   }
+
+   return 1;
+}
+
+
+/**
+ * \brief Compute base 2 logarithm.
+ *
+ * \param val value.
+ *
+ * \return base 2 logarithm of \p val.
+ */
+static int RADEONMinBits(int val)
+{
+   int  bits;
+
+   if (!val) return 1;
+   for (bits = 0; val; val >>= 1, ++bits);
+   return bits;
+}
+
+
+/* Initialize the PCI GART state.  Request memory for use in PCI space,
+ * and initialize the Radeon registers to point to that memory.
+ */
+static int RADEONDRIPciInit(driDisplay *disp, RADEONInfoPtr info)
+{
+    int  ret;
+    int  flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
+    int            s, l;
+
+    ret = drmScatterGatherAlloc(disp->drmFD, info->gartSize*1024*1024,
+                                &info->gartMemHandle);
+    if (ret < 0) {
+        fprintf(stderr, "[pci] Out of memory (%d)\n", ret);
+        return 0;
+    }
+    fprintf(stderr,
+               "[pci] %d kB allocated with handle 0x%04lx\n",
+               info->gartSize*1024, info->gartMemHandle);
+
+   info->gartOffset = 0;
+
+   /* Initialize the CP ring buffer data */
+   info->ringStart       = info->gartOffset;
+   info->ringMapSize     = info->ringSize*1024*1024 + radeon_drm_page_size;
+
+   info->ringReadOffset  = info->ringStart + info->ringMapSize;
+   info->ringReadMapSize = radeon_drm_page_size;
+
+   /* Reserve space for vertex/indirect buffers */
+   info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
+   info->bufMapSize      = info->bufSize*1024*1024;
+
+   /* Reserve the rest for AGP textures */
+   info->gartTexStart     = info->bufStart + info->bufMapSize;
+   s = (info->gartSize*1024*1024 - info->gartTexStart);
+   l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS);
+   if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+   info->gartTexMapSize   = (s >> l) << l;
+   info->log2GARTTexGran  = l;
+
+    if (drmAddMap(disp->drmFD, info->ringStart, info->ringMapSize,
+                  DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
+        fprintf(stderr,
+                   "[pci] Could not add ring mapping\n");
+        return 0;
+    }
+    fprintf(stderr,
+               "[pci] ring handle = 0x%08lx\n", info->ringHandle);
+
+    if (drmAddMap(disp->drmFD, info->ringReadOffset, info->ringReadMapSize,
+                  DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
+        fprintf(stderr,
+                   "[pci] Could not add ring read ptr mapping\n");
+        return 0;
+    }
+    fprintf(stderr,
+               "[pci] ring read ptr handle = 0x%08lx\n",
+               info->ringReadPtrHandle);
+
+    if (drmAddMap(disp->drmFD, info->bufStart, info->bufMapSize,
+                  DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
+        fprintf(stderr,
+                   "[pci] Could not add vertex/indirect buffers mapping\n");
+        return 0;
+    }
+    fprintf(stderr,
+               "[pci] vertex/indirect buffers handle = 0x%08lx\n",
+               info->bufHandle);
+
+    if (drmAddMap(disp->drmFD, info->gartTexStart, info->gartTexMapSize,
+                  DRM_SCATTER_GATHER, 0, &info->gartTexHandle) < 0) {
+        fprintf(stderr,
+                   "[pci] Could not add GART texture map mapping\n");
+        return 0;
+    }
+    fprintf(stderr,
+               "[pci] GART texture map handle = 0x%08lx\n",
+               info->gartTexHandle);
+
+    return 1;
+}
+
+
+/**
+ * \brief Initialize the AGP state
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Acquires and enables the AGP device. Reserves memory in the AGP space for
+ * the ring buffer, vertex buffers and textures. Initialize the Radeon
+ * registers to point to that memory and add client mappings.
+ */
+static int RADEONDRIAgpInit( driDisplay *disp, RADEONInfoPtr info)
+{
+   int            mode, ret;
+   int            s, l;
+   int agpmode = 1;
+
+   if (drmAgpAcquire(disp->drmFD) < 0) {
+      fprintf(stderr, "[gart] AGP not available\n");
+      return 0;
+   }
+
+   mode = drmAgpGetMode(disp->drmFD);  /* Default mode */
+   /* Disable fast write entirely - too many lockups.
+    */
+   mode &= ~RADEON_AGP_MODE_MASK;
+   switch (agpmode) {
+   case 4:          mode |= RADEON_AGP_4X_MODE;
+   case 2:          mode |= RADEON_AGP_2X_MODE;
+   case 1: default: mode |= RADEON_AGP_1X_MODE;
+   }
+
+   if (drmAgpEnable(disp->drmFD, mode) < 0) {
+      fprintf(stderr, "[gart] AGP not enabled\n");
+      drmAgpRelease(disp->drmFD);
+      return 0;
+   }
+
+#if 0
+   /* Workaround for some hardware bugs */
+   if (info->ChipFamily < CHIP_FAMILY_R200)
+      OUTREG(RADEON_AGP_CNTL, INREG(RADEON_AGP_CNTL) | 0x000e0000);
+#endif
+   info->gartOffset = 0;
+
+   if ((ret = drmAgpAlloc(disp->drmFD, info->gartSize*1024*1024, 0, NULL,
+                          &info->gartMemHandle)) < 0) {
+      fprintf(stderr, "[gart] Out of memory (%d)\n", ret);
+      drmAgpRelease(disp->drmFD);
+      return 0;
+   }
+   fprintf(stderr,
+           "[gart] %d kB allocated with handle 0x%08x\n",
+           info->gartSize*1024, (unsigned)info->gartMemHandle);
+
+   if (drmAgpBind(disp->drmFD,
+                  info->gartMemHandle, info->gartOffset) < 0) {
+      fprintf(stderr, "[gart] Could not bind\n");
+      drmAgpFree(disp->drmFD, info->gartMemHandle);
+      drmAgpRelease(disp->drmFD);
+      return 0;
+   }
+
+   /* Initialize the CP ring buffer data */
+   info->ringStart       = info->gartOffset;
+   info->ringMapSize     = info->ringSize*1024*1024 + radeon_drm_page_size;
+
+   info->ringReadOffset  = info->ringStart + info->ringMapSize;
+   info->ringReadMapSize = radeon_drm_page_size;
+
+   /* Reserve space for vertex/indirect buffers */
+   info->bufStart        = info->ringReadOffset + info->ringReadMapSize;
+   info->bufMapSize      = info->bufSize*1024*1024;
+
+   /* Reserve the rest for AGP textures */
+   info->gartTexStart     = info->bufStart + info->bufMapSize;
+   s = (info->gartSize*1024*1024 - info->gartTexStart);
+   l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS);
+   if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+   info->gartTexMapSize   = (s >> l) << l;
+   info->log2GARTTexGran  = l;
+
+   if (drmAddMap(disp->drmFD, info->ringStart, info->ringMapSize,
+                 DRM_AGP, DRM_READ_ONLY, &info->ringHandle) < 0) {
+      fprintf(stderr, "[gart] Could not add ring mapping\n");
+      return 0;
+   }
+   fprintf(stderr, "[gart] ring handle = 0x%08lx\n", info->ringHandle);
+
+
+   if (drmAddMap(disp->drmFD, info->ringReadOffset, info->ringReadMapSize,
+                 DRM_AGP, DRM_READ_ONLY, &info->ringReadPtrHandle) < 0) {
+      fprintf(stderr,
+              "[gart] Could not add ring read ptr mapping\n");
+      return 0;
+   }
+
+   fprintf(stderr,
+           "[gart] ring read ptr handle = 0x%08lx\n",
+           info->ringReadPtrHandle);
+
+   if (drmAddMap(disp->drmFD, info->bufStart, info->bufMapSize,
+                 DRM_AGP, 0, &info->bufHandle) < 0) {
+      fprintf(stderr,
+              "[gart] Could not add vertex/indirect buffers mapping\n");
+      return 0;
+   }
+   fprintf(stderr,
+           "[gart] vertex/indirect buffers handle = 0x%08lx\n",
+           info->bufHandle);
+
+   if (drmAddMap(disp->drmFD, info->gartTexStart, info->gartTexMapSize,
+                 DRM_AGP, 0, &info->gartTexHandle) < 0) {
+      fprintf(stderr,
+              "[gart] Could not add AGP texture map mapping\n");
+      return 0;
+   }
+   fprintf(stderr,
+           "[gart] AGP texture map handle = 0x%08lx\n",
+           info->gartTexHandle);
+
+   return 1;
+}
+
+
+static int RADEONMemoryInit( driDisplay *disp, RADEONInfoPtr info )
+{
+   int        width_bytes = disp->virtualWidth * disp->cpp;
+   int        cpp         = disp->cpp;
+   int        bufferSize  = ((disp->virtualHeight * width_bytes
+                              + RADEON_BUFFER_ALIGN)
+                             & ~RADEON_BUFFER_ALIGN);
+   int        depthSize   = ((((disp->virtualHeight+15) & ~15) * width_bytes
+                              + RADEON_BUFFER_ALIGN)
+                             & ~RADEON_BUFFER_ALIGN);
+   int        l;
+
+   info->frontOffset = 0;
+   info->frontPitch = disp->virtualWidth;
+
+   fprintf(stderr,
+           "Using %d MB AGP aperture\n", info->gartSize);
+   fprintf(stderr,
+           "Using %d MB for the ring buffer\n", info->ringSize);
+   fprintf(stderr,
+           "Using %d MB for vertex/indirect buffers\n", info->bufSize);
+   fprintf(stderr,
+           "Using %d MB for AGP textures\n", info->gartTexSize);
+
+   /* Front, back and depth buffers - everything else texture??
+    */
+   info->textureSize = disp->fbSize - 2 * bufferSize - depthSize;
+
+   if (info->textureSize < 0)
+      return 0;
+
+   l = RADEONMinBits((info->textureSize-1) / RADEON_NR_TEX_REGIONS);
+   if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+
+   /* Round the texture size up to the nearest whole number of
+    * texture regions.  Again, be greedy about this, don't
+    * round down.
+    */
+   info->log2TexGran = l;
+   info->textureSize = (info->textureSize >> l) << l;
+
+   /* Set a minimum usable local texture heap size.  This will fit
+    * two 256x256x32bpp textures.
+    */
+   if (info->textureSize < 512 * 1024) {
+      info->textureOffset = 0;
+      info->textureSize = 0;
+   }
+
+   /* Reserve space for textures */
+   info->textureOffset = ((disp->fbSize - info->textureSize +
+                           RADEON_BUFFER_ALIGN) &
+                          ~RADEON_BUFFER_ALIGN);
+
+   /* Reserve space for the shared depth
+    * buffer.
+    */
+   info->depthOffset = ((info->textureOffset - depthSize +
+                         RADEON_BUFFER_ALIGN) &
+                        ~RADEON_BUFFER_ALIGN);
+   info->depthPitch = disp->virtualWidth;
+
+   info->backOffset = ((info->depthOffset - bufferSize +
+                        RADEON_BUFFER_ALIGN) &
+                       ~RADEON_BUFFER_ALIGN);
+   info->backPitch = disp->virtualWidth;
+
+
+   fprintf(stderr,
+           "Will use back buffer at offset 0x%x\n",
+           info->backOffset);
+   fprintf(stderr,
+           "Will use depth buffer at offset 0x%x\n",
+           info->depthOffset);
+   fprintf(stderr,
+           "Will use %d kb for textures at offset 0x%x\n",
+           info->textureSize/1024, info->textureOffset);
+
+   info->frontPitchOffset = (((info->frontPitch * cpp / 64) << 22) |
+                             (info->frontOffset >> 10));
+
+   info->backPitchOffset = (((info->backPitch * cpp / 64) << 22) |
+                            (info->backOffset >> 10));
+
+   info->depthPitchOffset = (((info->depthPitch * cpp / 64) << 22) |
+                             (info->depthOffset >> 10));
+
+   return 1;
+}
+
+
+/**
+ * \brief Initialize the kernel data structures and enable the CP engine.
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * This function is a wrapper around the DRM_RADEON_CP_INIT command, passing
+ * all the parameters in a drm_radeon_init_t structure.
+ */
+static int RADEONDRIKernelInit( driDisplay *disp,
+                               RADEONInfoPtr info)
+{
+   int cpp = disp->bpp / 8;
+   drm_radeon_init_t  drmInfo;
+   int ret;
+
+   memset(&drmInfo, 0, sizeof(drmInfo));
+
+   if ( (info->ChipFamily == CHIP_FAMILY_R200) ||
+        (info->ChipFamily == CHIP_FAMILY_RV250) ||
+        (info->ChipFamily == CHIP_FAMILY_M9) ||
+        (info->ChipFamily == CHIP_FAMILY_RV280) )
+      drmInfo.func             = RADEON_INIT_R200_CP;
+   else
+      drmInfo.func             = RADEON_INIT_CP;
+
+   /* This is the struct passed to the kernel module for its initialization */
+   drmInfo.sarea_priv_offset   = sizeof(drm_sarea_t);
+   drmInfo.cp_mode             = RADEON_DEFAULT_CP_BM_MODE;
+   drmInfo.gart_size            = info->gartSize*1024*1024;
+   drmInfo.ring_size           = info->ringSize*1024*1024;
+   drmInfo.usec_timeout        = 1000;
+   drmInfo.fb_bpp              = disp->bpp;
+   drmInfo.depth_bpp           = disp->bpp;
+   drmInfo.front_offset        = info->frontOffset;
+   drmInfo.front_pitch         = info->frontPitch * cpp;
+   drmInfo.back_offset         = info->backOffset;
+   drmInfo.back_pitch          = info->backPitch * cpp;
+   drmInfo.depth_offset        = info->depthOffset;
+   drmInfo.depth_pitch         = info->depthPitch * cpp;
+   drmInfo.ring_offset         = info->ringHandle;
+   drmInfo.ring_rptr_offset    = info->ringReadPtrHandle;
+   drmInfo.buffers_offset      = info->bufHandle;
+   drmInfo.gart_textures_offset = info->gartTexHandle;
+
+   ret = drmCommandWrite(disp->drmFD, DRM_RADEON_CP_INIT, &drmInfo,
+                         sizeof(drm_radeon_init_t));
+
+   return ret >= 0;
+}
+
+
+/**
+ * \brief Add a map for the vertex buffers that will be accessed by any
+ * DRI-based clients.
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Calls drmAddBufs() with the previously allocated vertex buffers.
+ */
+static int RADEONDRIBufInit( driDisplay *disp, RADEONInfoPtr info )
+{
+   /* Initialize vertex buffers */
+   info->bufNumBufs = drmAddBufs(disp->drmFD,
+                                 info->bufMapSize / RADEON_BUFFER_SIZE,
+                                 RADEON_BUFFER_SIZE,
+                                 disp->isPCI ? DRM_SG_BUFFER : DRM_AGP_BUFFER,
+                                 info->bufStart);
+
+   if (info->bufNumBufs <= 0) {
+      fprintf(stderr,
+              "[drm] Could not create vertex/indirect buffers list\n");
+      return 0;
+   }
+   fprintf(stderr,
+           "[drm] Added %d %d byte vertex/indirect buffers\n",
+           info->bufNumBufs, RADEON_BUFFER_SIZE);
+
+   return 1;
+}
+
+
+/**
+ * \brief Install an IRQ handler.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * Attempts to install an IRQ handler via drmCtlInstHandler(), falling back to
+ * IRQ-free operation on failure.
+ */
+static void RADEONDRIIrqInit(driDisplay *disp, RADEONInfoPtr info)
+{
+   if ((drmCtlInstHandler(disp->drmFD, 0)) != 0)
+      fprintf(stderr, "[drm] failure adding irq handler, "
+                 "there is a device already using that irq\n"
+                 "[drm] falling back to irq-free operation\n");
+}
+
+
+/**
+ * \brief Initialize the AGP heap.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * This function is a wrapper around the DRM_RADEON_INIT_HEAP command, passing
+ * all the parameters in a drm_radeon_mem_init_heap structure.
+ */
+static void RADEONDRIAgpHeapInit(driDisplay *disp,
+                                 RADEONInfoPtr info)
+{
+   drm_radeon_mem_init_heap_t drmHeap;
+
+   /* Start up the simple memory manager for gart space */
+   drmHeap.region = RADEON_MEM_REGION_GART;
+   drmHeap.start  = 0;
+   drmHeap.size   = info->gartTexMapSize;
+
+   if (drmCommandWrite(disp->drmFD, DRM_RADEON_INIT_HEAP,
+                       &drmHeap, sizeof(drmHeap))) {
+      fprintf(stderr,
+              "[drm] Failed to initialized gart heap manager\n");
+   } else {
+      fprintf(stderr,
+              "[drm] Initialized kernel gart heap manager, %d\n",
+              info->gartTexMapSize);
+   }
+}
+
+
+/**
+ * Called at the start of each server generation.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * Performs static frame buffer allocation. Opens the DRM device and add maps
+ * to the SAREA, framebuffer and MMIO regions. Fills in \p info with more
+ * information. Creates a \e server context to grab the lock for the
+ * initialization ioctls and calls the other initilization functions in this
+ * file. Starts the CP engine via the DRM_RADEON_CP_START command.
+ *
+ * Setups a RADEONDRIRec structure to be passed to radeon_dri.so for its
+ * initialization.
+ */
+static int RADEONScreenInit( driDisplay *disp, RADEONInfoPtr info, RADEONDRIPtr pRADEONDRI)
+{
+   int i, err;
+
+   {
+      int  width_bytes = (disp->virtualWidth * disp->cpp);
+      int  maxy        = disp->fbSize / width_bytes;
+
+
+      if (maxy <= disp->virtualHeight * 3) {
+         fprintf(stderr,
+                 "Static buffer allocation failed -- "
+                 "need at least %d kB video memory (have %d kB)\n",
+                 (disp->virtualWidth * disp->virtualHeight *
+                  disp->cpp * 3 + 1023) / 1024,
+                 disp->fbSize / 1024);
+         return 0;
+      }
+   }
+   if (info->ChipFamily >= CHIP_FAMILY_R300) {
+      fprintf(stderr,
+              "Direct rendering not yet supported on "
+              "Radeon 9700 and newer cards\n");
+      return 0;
+   }
+
+   radeon_drm_page_size = getpagesize();
+
+   /* Check the radeon DRM version */
+   if (!RADEONCheckDRMVersion(disp, info)) {
+      return 0;
+   }
+
+   if (disp->isPCI) {
+      /* Initialize PCI */
+      if (!RADEONDRIPciInit(disp, info))
+         return 0;
+   }
+   else {
+      /* Initialize AGP */
+      if (!RADEONDRIAgpInit(disp, info))
+         return 0;
+   }
+
+   /* Memory manager setup */
+   if (!RADEONMemoryInit(disp, info)) {
+      return 0;
+   }
+
+   /* Create a 'server' context so we can grab the lock for
+    * initialization ioctls.
+    */
+   if ((err = drmCreateContext(disp->drmFD, &disp->serverContext)) != 0) {
+      fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+      return 0;
+   }
+
+   DRM_LOCK(disp->drmFD, disp->pSAREA, disp->serverContext, 0);
+
+   /* Initialize the kernel data structures */
+   if (!RADEONDRIKernelInit(disp, info)) {
+      fprintf(stderr, "RADEONDRIKernelInit failed\n");
+      DRM_UNLOCK(disp->drmFD, disp->pSAREA, disp->serverContext);
+      return 0;
+   }
+
+   /* Initialize the vertex buffers list */
+   if (!RADEONDRIBufInit(disp, info)) {
+      fprintf(stderr, "RADEONDRIBufInit failed\n");
+      DRM_UNLOCK(disp->drmFD, disp->pSAREA, disp->serverContext);
+      return 0;
+   }
+
+   /* Initialize IRQ */
+   RADEONDRIIrqInit(disp, info);
+
+   /* Initialize kernel gart memory manager */
+   RADEONDRIAgpHeapInit(disp, info);
+
+   fprintf(stderr,"page flipping %sabled\n", info->page_flip_enable?"en":"dis");
+   /* Initialize the SAREA private data structure */
+   {
+      drm_radeon_sarea_t *pSAREAPriv;
+      pSAREAPriv = (drm_radeon_sarea_t *)(((char*)disp->pSAREA) +
+                                        sizeof(drm_sarea_t));
+      memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
+      pSAREAPriv->pfState = info->page_flip_enable;
+   }
+
+   for ( i = 0;; i++ ) {
+      drmMapType type;
+      drmMapFlags flags;
+      drm_handle_t handle, offset;
+      drmSize size;
+      int rc, mtrr;
+
+      if ( ( rc = drmGetMap( disp->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) ) != 0 )
+         break;
+      if ( type == DRM_REGISTERS ) {
+         pRADEONDRI->registerHandle = offset;
+         pRADEONDRI->registerSize = size;
+         break;
+      }
+   }
+   /* Quick hack to clear the front & back buffers.  Could also use
+    * the clear ioctl to do this, but would need to setup hw state
+    * first.
+    */
+   drimemsetio((char *)disp->pFB + info->frontOffset,
+          0xEE,
+          info->frontPitch * disp->cpp * disp->virtualHeight );
+
+   drimemsetio((char *)disp->pFB + info->backOffset,
+          0x30,
+          info->backPitch * disp->cpp * disp->virtualHeight );
+
+
+   /* This is the struct passed to radeon_dri.so for its initialization */
+   pRADEONDRI->deviceID          = info->Chipset;
+   pRADEONDRI->width             = disp->virtualWidth;
+   pRADEONDRI->height            = disp->virtualHeight;
+   pRADEONDRI->depth             = disp->bpp; /* XXX: depth */
+   pRADEONDRI->bpp               = disp->bpp;
+   pRADEONDRI->IsPCI             = disp->isPCI;
+   pRADEONDRI->frontOffset       = info->frontOffset;
+   pRADEONDRI->frontPitch        = info->frontPitch;
+   pRADEONDRI->backOffset        = info->backOffset;
+   pRADEONDRI->backPitch         = info->backPitch;
+   pRADEONDRI->depthOffset       = info->depthOffset;
+   pRADEONDRI->depthPitch        = info->depthPitch;
+   pRADEONDRI->textureOffset     = info->textureOffset;
+   pRADEONDRI->textureSize       = info->textureSize;
+   pRADEONDRI->log2TexGran       = info->log2TexGran;
+   pRADEONDRI->statusHandle      = info->ringReadPtrHandle;
+   pRADEONDRI->statusSize        = info->ringReadMapSize;
+   pRADEONDRI->gartTexHandle      = info->gartTexHandle;
+   pRADEONDRI->gartTexMapSize     = info->gartTexMapSize;
+   pRADEONDRI->log2GARTTexGran    = info->log2GARTTexGran;
+   pRADEONDRI->gartTexOffset      = info->gartTexStart;
+   pRADEONDRI->sarea_priv_offset = sizeof(drm_sarea_t);
+
+   /* Don't release the lock now - let the VT switch handler do it. */
+
+   return 1;
+}
+
+
+/**
+ * \brief Get Radeon chip family from chipset number.
+ *
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * Called by radeonInitFBDev() to set RADEONInfoRec::ChipFamily
+ * according to the value of RADEONInfoRec::Chipset.  Fails if the
+ * chipset is unrecognized or not appropriate for this driver (i.e., not
+ * an r100 style radeon)
+ */
+static int get_chipfamily_from_chipset( RADEONInfoPtr info )
+{
+    switch (info->Chipset) {
+    case PCI_CHIP_RADEON_LY:
+    case PCI_CHIP_RADEON_LZ:
+        info->ChipFamily = CHIP_FAMILY_M6;
+        break;
+
+    case PCI_CHIP_RADEON_QY:
+    case PCI_CHIP_RADEON_QZ:
+        info->ChipFamily = CHIP_FAMILY_VE;
+        break;
+
+    case PCI_CHIP_R200_QL:
+    case PCI_CHIP_R200_QN:
+    case PCI_CHIP_R200_QO:
+    case PCI_CHIP_R200_Ql:
+    case PCI_CHIP_R200_BB:
+        info->ChipFamily = CHIP_FAMILY_R200;
+        break;
+
+    case PCI_CHIP_RV200_QW: /* RV200 desktop */
+    case PCI_CHIP_RV200_QX:
+        info->ChipFamily = CHIP_FAMILY_RV200;
+        break;
+
+    case PCI_CHIP_RADEON_LW:
+    case PCI_CHIP_RADEON_LX:
+        info->ChipFamily = CHIP_FAMILY_M7;
+        break;
+
+    case PCI_CHIP_RV250_Id:
+    case PCI_CHIP_RV250_Ie:
+    case PCI_CHIP_RV250_If:
+    case PCI_CHIP_RV250_Ig:
+        info->ChipFamily = CHIP_FAMILY_RV250;
+        break;
+
+    case PCI_CHIP_RV250_Ld:
+    case PCI_CHIP_RV250_Le:
+    case PCI_CHIP_RV250_Lf:
+    case PCI_CHIP_RV250_Lg:
+        info->ChipFamily = CHIP_FAMILY_M9;
+        break;
+
+    case PCI_CHIP_RV280_Y_:
+    case PCI_CHIP_RV280_Ya:
+    case PCI_CHIP_RV280_Yb:
+    case PCI_CHIP_RV280_Yc:
+        info->ChipFamily = CHIP_FAMILY_RV280;
+        break;
+
+    case PCI_CHIP_R300_ND:
+    case PCI_CHIP_R300_NE:
+    case PCI_CHIP_R300_NF:
+    case PCI_CHIP_R300_NG:
+        info->ChipFamily = CHIP_FAMILY_R300;
+        break;
+
+    default:
+        /* Original Radeon/7200 */
+        info->ChipFamily = CHIP_FAMILY_RADEON;
+    }
+
+    return 1;
+}
+
+
+/**
+ * \brief Initialize the framebuffer device mode
+ *
+ * \param disp display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Fills in \p info with some default values and some information from \p disp
+ * and then calls RADEONScreenInit() for the screen initialization.
+ *
+ * Before exiting clears the framebuffer memory accessing it directly.
+ */
+static int radeonInitFBDev( driDisplay *disp, RADEONDRIPtr pRADEONDRI )
+{
+   int err;
+   RADEONInfoPtr info = calloc(1, sizeof(*info));
+
+   disp->driverPrivate = (void *)info;
+
+   info->gartFastWrite  = RADEON_DEFAULT_AGP_FAST_WRITE;
+   info->gartSize       = RADEON_DEFAULT_AGP_SIZE;
+   info->gartTexSize    = RADEON_DEFAULT_AGP_TEX_SIZE;
+   info->bufSize       = RADEON_DEFAULT_BUFFER_SIZE;
+   info->ringSize      = RADEON_DEFAULT_RING_SIZE;
+   info->page_flip_enable = RADEON_DEFAULT_PAGE_FLIP;
+
+   info->Chipset = disp->chipset;
+
+   if (!get_chipfamily_from_chipset( info )) {
+      fprintf(stderr, "Unknown or non-radeon chipset -- cannot continue\n");
+      fprintf(stderr, "==> Verify PCI BusID is correct in miniglx.conf\n");
+      return 0;
+   }
+
+   info->frontPitch = disp->virtualWidth;
+
+   if (!RADEONScreenInit( disp, info, pRADEONDRI))
+      return 0;
+
+   /* Initialize and start the CP if required */
+   if ((err = drmCommandNone(disp->drmFD, DRM_RADEON_CP_START)) != 0) {
+      fprintf(stderr, "%s: CP start %d\n", __FUNCTION__, err);
+      return 0;
+   }
+
+   return 1;
+}
+
+static EGLBoolean
+radeonFillInConfigs(_EGLDisplay *disp, unsigned pixel_bits, unsigned depth_bits,
+               unsigned stencil_bits, GLboolean have_back_buffer) {
+   _EGLConfig *configs;
+   _EGLConfig *c;
+   unsigned int i, num_configs;
+   unsigned int depth_buffer_factor;
+   unsigned int back_buffer_factor;
+   GLenum fb_format;
+   GLenum fb_type;
+
+   /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
+   * enough to add support.  Basically, if a context is created with an
+   * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
+   * will never be used.
+   */
+   static const GLenum back_buffer_modes[] = {
+            GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
+         };
+
+   u_int8_t depth_bits_array[2];
+   u_int8_t stencil_bits_array[2];
+
+   depth_bits_array[0] = depth_bits;
+   depth_bits_array[1] = depth_bits;
+
+   /* Just like with the accumulation buffer, always provide some modes
+   * with a stencil buffer.  It will be a sw fallback, but some apps won't
+   * care about that.
+   */
+   stencil_bits_array[0] = 0;
+   stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+   depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
+   back_buffer_factor = (have_back_buffer) ? 2 : 1;
+
+   num_configs = depth_buffer_factor * back_buffer_factor * 2;
+
+   if (pixel_bits == 16) {
+      fb_format = GL_RGB;
+      fb_type = GL_UNSIGNED_SHORT_5_6_5;
+   } else {
+      fb_format = GL_RGBA;
+      fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+   }
+
+   configs = calloc(sizeof(*configs), num_configs);
+   c = configs;
+   if (!_eglFillInConfigs(c, fb_format, fb_type,
+                          depth_bits_array, stencil_bits_array, depth_buffer_factor,
+                          back_buffer_modes, back_buffer_factor,
+                          GLX_TRUE_COLOR)) {
+      fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
+               __func__, __LINE__);
+      return EGL_FALSE;
+   }
+
+   /* Mark the visual as slow if there are "fake" stencil bits.
+   */
+   for (i = 0, c = configs; i < num_configs; i++, c++) {
+      int stencil = GET_CONFIG_ATTRIB(c, EGL_STENCIL_SIZE);
+      if ((stencil != 0)  && (stencil != stencil_bits)) {
+         SET_CONFIG_ATTRIB(c, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG);
+      }
+   }
+
+   for (i = 0, c = configs; i < num_configs; i++, c++)
+      _eglAddConfig(disp, c);
+
+   free(configs);
+
+   return EGL_TRUE;
+}
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ */
+static EGLBoolean
+radeonShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+                    EGLSurface surface, EGLModeMESA m)
+{
+   _eglDRIShowSurfaceMESA(drv, dpy, screen, surface, m);
+   return EGL_FALSE;
+}
+
+static EGLBoolean
+radeonInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+   __DRIframebuffer framebuffer;
+   driDisplay *display;
+
+   if (!_eglDRIInitialize(drv, dpy, major, minor))
+      return EGL_FALSE;
+
+   display = Lookup_driDisplay(dpy);
+
+   framebuffer.dev_priv_size = sizeof(RADEONDRIRec);
+   framebuffer.dev_priv = malloc(sizeof(RADEONDRIRec));
+
+   display->virtualWidth = 1024;
+   display->virtualHeight = 768;
+   display->bpp = 32;
+   display->cpp = 4;
+
+   if (!_eglDRIGetDisplayInfo(display))
+      return EGL_FALSE;
+
+   framebuffer.base = display->pFB;
+   radeonInitFBDev( display, framebuffer.dev_priv );
+
+   if (!_eglDRICreateDisplay(display, &framebuffer))
+      return EGL_FALSE;
+
+   if (!_eglDRICreateScreen(display))
+      return EGL_FALSE;
+
+   radeonFillInConfigs(&display->Base, 32, 24, 8, 1);
+   radeonFillInConfigs(&display->Base, 16, 16, 0, 1);
+
+   drv->Initialized = EGL_TRUE;
+   return EGL_TRUE;
+}
+
+
+/**
+ * The bootstrap function.  Return a new radeonDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *dpy)
+{
+   radeonDriver *radeon;
+
+   radeon = (radeonDriver *) calloc(1, sizeof(*radeon));
+   if (!radeon) {
+      return NULL;
+   }
+
+   /* First fill in the dispatch table with defaults */
+   _eglDRIInitDriverFallbacks(&radeon->Base);
+
+   /* then plug in our radeon-specific functions */
+   radeon->Base.Initialize = radeonInitialize;
+   radeon->Base.ShowSurfaceMESA = radeonShowSurfaceMESA;
+
+   return &radeon->Base;
+}