Initial i810_dri.c for miniglx isn't fully functional yet...
authorDave Airlie <airliedfreedesktop.org>
Mon, 15 Mar 2004 05:20:08 +0000 (05:20 +0000)
committerDave Airlie <airliedfreedesktop.org>
Mon, 15 Mar 2004 05:20:08 +0000 (05:20 +0000)
src/mesa/drivers/dri/i810/server/i810_dri.c [new file with mode: 0644]

diff --git a/src/mesa/drivers/dri/i810/server/i810_dri.c b/src/mesa/drivers/dri/i810/server/i810_dri.c
new file mode 100644 (file)
index 0000000..82c04bf
--- /dev/null
@@ -0,0 +1,1024 @@
+/**
+ * \file server/i810_dri.c
+ * \brief File to perform the device-specific initialization tasks typically
+ * done in the X server.
+ *
+ * Here they are converted to run in the client (or perhaps a standalone
+ * process), and to work with the frame buffer device rather than the X
+ * server infrastructure.
+ * 
+ * Copyright (C) 2004 Dave Airlie (airlied@linux.ie)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "driver.h"
+#include "drm.h"
+
+#include "i810.h"
+#include "i810_dri.h"
+#include "i810_reg.h"
+
+
+/* HACK - for now, put this here... */
+/* Alpha - this may need to be a variable to handle UP1x00 vs TITAN */
+#if defined(__alpha__)
+# define DRM_PAGE_SIZE 8192
+#elif defined(__ia64__)
+# define DRM_PAGE_SIZE getpagesize()
+#else
+# define DRM_PAGE_SIZE 4096
+#endif
+
+static int i810_pitches[] = {
+   512,
+   1024,
+   2048,
+   4096,
+   0
+};
+
+static int i810_pitch_flags[] = {
+   0x0,
+   0x1,
+   0x2,
+   0x3,
+   0
+};
+
+static unsigned int i810_drm_version = 0;
+
+static int
+I810AllocLow(I810MemRange * result, I810MemRange * pool, int size)
+{
+   if (size > pool->Size)
+      return 0;
+
+   pool->Size -= size;
+   result->Size = size;
+   result->Start = pool->Start;
+   result->End = pool->Start += size;
+
+   return 1;
+}
+
+static int
+I810AllocHigh(I810MemRange * result, I810MemRange * pool, int size)
+{
+   if (size > pool->Size)
+      return 0;
+
+   pool->Size -= size;
+   result->Size = size;
+   result->End = pool->End;
+   result->Start = pool->End -= size;
+
+   return 1;
+}
+
+
+/**
+ * \brief Wait for free FIFO entries.
+ *
+ * \param ctx display handle.
+ * \param entries number of free entries to wait.
+ *
+ * It polls the free entries from the chip until it reaches the requested value
+ * or a timeout (3000 tries) occurs. Aborts the program if the FIFO times out.
+ */
+static void I810WaitForFifo( const DRIDriverContext *ctx,
+                              int entries )
+{
+}
+
+/**
+ * \brief Reset graphics card to known state.
+ *
+ * \param ctx display handle.
+ *
+ * Resets the values of several I810 registers.
+ */
+static void I810EngineReset( const DRIDriverContext *ctx )
+{
+   unsigned char *I810MMIO = ctx->MMIOAddress;
+}
+
+/**
+ * \brief Restore the drawing engine.
+ *
+ * \param ctx display handle
+ *
+ * Resets the graphics card and sets initial values for several registers of
+ * the card's drawing engine.
+ *
+ * Turns on the i810 command processor engine (i.e., the ringbuffer).
+ */
+static int I810EngineRestore( const DRIDriverContext *ctx )
+{
+   I810Ptr info = ctx->driverPrivate;
+   unsigned char *I810MMIO = ctx->MMIOAddress;
+
+   fprintf(stderr, "%s\n", __FUNCTION__);
+
+   return 1;
+}
+
+
+/**
+ * \brief Shutdown the drawing engine.
+ *
+ * \param ctx display handle
+ *
+ * Turns off the command processor engine & restores the graphics card
+ * to a state that fbdev understands.
+ */
+static int I810EngineShutdown( const DRIDriverContext *ctx )
+{
+  drmI810Init info;
+  int ret;
+
+  memset(&info, 0, sizeof(drmI810Init));
+  info.func = I810_CLEANUP_DMA;
+  
+  ret = drmCommandWrite(ctx->drmFD, DRM_I810_INIT, &info, sizeof(drmI810Init));
+  if (ret>0)
+  {
+    fprintf(stderr,"[dri] I810 DMA Cleanup failed\n");
+    return -errno;
+  }
+  return 0;
+}
+
+/**
+ * \brief Compute base 2 logarithm.
+ *
+ * \param val value.
+ * 
+ * \return base 2 logarithm of \p val.
+ */
+static int I810MinBits(int val)
+{
+   int  bits;
+
+   if (!val) return 1;
+   for (bits = 0; val; val >>= 1, ++bits);
+   return bits;
+}
+
+static int I810DRIAgpPreInit( const DRIDriverContext *ctx, I810Ptr info)
+{
+
+  if (drmAgpAcquire(ctx->drmFD) < 0) {
+    fprintf(stderr, "[gart] AGP not available\n");
+    return 0;
+  }
+  
+  
+  if (drmAgpEnable(ctx->drmFD, 0) < 0) {
+    fprintf(stderr, "[gart] AGP not enabled\n");
+    drmAgpRelease(ctx->drmFD);
+    return 0;
+  }
+}
+
+/**
+ * \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 I810
+ * registers to point to that memory and add client mappings.
+ */
+static int I810DRIAgpInit( const DRIDriverContext *ctx, I810Ptr info)
+{
+   unsigned char *I810MMIO = ctx->MMIOAddress;
+   int            ret;
+   int            s, l;
+   unsigned long dcacheHandle;
+   unsigned long agpHandle;
+   int pitch_idx = 0;
+   int back_size = 0;
+   int sysmem_size = 0;
+   int width = ctx->shared.virtualWidth;
+
+
+   info->backHandle = DRM_AGP_NO_HANDLE;
+   info->zHandle = DRM_AGP_NO_HANDLE;
+   info->sysmemHandle = DRM_AGP_NO_HANDLE;
+   info->dcacheHandle = DRM_AGP_NO_HANDLE;
+
+   memset(&info->DcacheMem, 0, sizeof(I810MemRange));
+   memset(&info->BackBuffer, 0, sizeof(I810MemRange));
+   memset(&info->DepthBuffer, 0, sizeof(I810MemRange));
+   
+   drmAgpAlloc(ctx->drmFD, 4096 * 1024, 1, NULL, &dcacheHandle);
+   info->dcacheHandle = dcacheHandle;
+   
+   fprintf(stderr, "[agp] dcacheHandle : %p\n", dcacheHandle);
+
+#define Elements(x) sizeof(x)/sizeof(*x)
+   for (pitch_idx = 0; pitch_idx < Elements(i810_pitches); pitch_idx++)
+     if (width <= i810_pitches[pitch_idx])
+       break;
+   
+   if (pitch_idx == Elements(i810_pitches)) {
+     fprintf(stderr,"[dri] Couldn't find depth/back buffer pitch\n");
+     exit(-1);
+   }
+   else
+   {
+     int lines = (ctx->shared.virtualWidth + 15) / 16 * 16;
+     back_size = i810_pitches[pitch_idx] * lines;
+     back_size = ((back_size + 4096 - 1) / 4096) * 4096;
+   }
+
+   sysmem_size = ctx->shared.fbSize;
+   fprintf(stderr,"sysmem_size is %lu back_size is %lu\n", sysmem_size, back_size);
+   if (dcacheHandle != DRM_AGP_NO_HANDLE) {
+     if (back_size > 4 * 1024 * 1024) {
+       fprintf(stderr,"[dri] Backsize is larger then 4 meg\n");
+       sysmem_size = sysmem_size - 2 * back_size;
+       drmAgpFree(ctx->drmFD, dcacheHandle);
+       info->dcacheHandle = dcacheHandle = DRM_AGP_NO_HANDLE;
+     } else {
+       sysmem_size = sysmem_size - back_size;
+     }
+   } else {
+     sysmem_size = sysmem_size - 2 * back_size;
+   }
+   
+   info->SysMem.Start=0;
+   info->SysMem.Size = sysmem_size;
+   info->SysMem.End = sysmem_size;
+   
+   if (dcacheHandle != DRM_AGP_NO_HANDLE) {
+      if (drmAgpBind(ctx->drmFD, dcacheHandle, info->DepthOffset) == 0) {
+       memset(&info->DcacheMem, 0, sizeof(I810MemRange));
+       fprintf(stderr,"[agp] GART: Found 4096K Z buffer memory\n");
+       info->DcacheMem.Start = info->DepthOffset;
+        info->DcacheMem.Size = 1024 * 4096;
+        info->DcacheMem.End =  info->DcacheMem.Start + info->DcacheMem.Size;
+      } else {
+       fprintf(stderr, "[agp] GART: dcache bind failed\n");
+       drmAgpFree(ctx->drmFD, dcacheHandle);
+       info->dcacheHandle = dcacheHandle = DRM_AGP_NO_HANDLE;
+      }
+   } else {
+     fprintf(stderr, "[agp] GART: no dcache memory found\n");
+   }
+   
+   drmAgpAlloc(ctx->drmFD, back_size, 0, NULL, &agpHandle);
+   info->backHandle = agpHandle;
+
+   if (agpHandle != DRM_AGP_NO_HANDLE) {
+      if (drmAgpBind(ctx->drmFD, agpHandle, info->BackOffset) == 0) {
+       fprintf(stderr, "[agp] Bound backbuffer memory\n");
+
+       info->BackBuffer.Start = info->BackOffset;
+       info->BackBuffer.Size = back_size;
+       info->BackBuffer.End = (info->BackBuffer.Start +
+                                info->BackBuffer.Size);
+      } else {
+       fprintf(stderr,"[agp] Unable to bind backbuffer.  Disabling DRI.\n");
+       return 0;
+      }
+   } else {
+     fprintf(stderr, "[dri] Unable to allocate backbuffer memory.  Disabling DRI.\n");
+     return 0;
+   }
+
+   if (dcacheHandle == DRM_AGP_NO_HANDLE) {
+     drmAgpAlloc(ctx->drmFD, back_size, 0, NULL, &agpHandle);
+
+     info->zHandle = agpHandle;
+
+     if (agpHandle != DRM_AGP_NO_HANDLE) {
+       if (drmAgpBind(ctx->drmFD, agpHandle, info->DepthOffset) == 0) {
+        fprintf(stderr,"[agp] Bound depthbuffer memory\n");
+        info->DepthBuffer.Start = info->DepthOffset;
+        info->DepthBuffer.Size = back_size;
+        info->DepthBuffer.End = (info->DepthBuffer.Start +
+                                  info->DepthBuffer.Size);
+       } else {
+        fprintf(stderr,"[agp] Unable to bind depthbuffer.  Disabling DRI.\n");
+        return 0;
+       }
+     } else {
+       fprintf(stderr,"[agp] Unable to allocate depthbuffer memory.  Disabling DRI.\n");
+       return 0;
+     }
+   }
+
+   /* Now allocate and bind the agp space.  This memory will include the
+    * regular framebuffer as well as texture memory.
+    */
+   drmAgpAlloc(ctx->drmFD, sysmem_size, 0, NULL, &agpHandle);
+   info->sysmemHandle = agpHandle;
+   
+   if (agpHandle != DRM_AGP_NO_HANDLE) {
+     if (drmAgpBind(ctx->drmFD, agpHandle, 0) == 0) {
+       fprintf(stderr, "[agp] Bound System Texture Memory\n");
+     } else {
+       fprintf(stderr, "[agp] Unable to bind system texture memory. Disabling DRI.\n");
+       return 0;
+     }
+   } else {
+     fprintf(stderr, "[agp] Unable to allocate system texture memory. Disabling DRI.\n");
+     return 0;
+   }
+   
+   info->auxPitch = i810_pitches[pitch_idx];
+   info->auxPitchBits = i810_pitch_flags[pitch_idx];
+   
+   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_I810_CP_INIT command, passing
+ * all the parameters in a drmI810Init structure.
+ */
+static int I810DRIKernelInit( const DRIDriverContext *ctx,
+                              I810Ptr info)
+{
+   int cpp = ctx->bpp / 8;
+   drmI810Init  drmInfo;
+   int ret;
+   I810RingBuffer *ring = &(info->LpRing);
+
+   /* This is the struct passed to the kernel module for its initialization */
+   memset(&drmInfo, 0, sizeof(drmI810Init));
+   
+   /* make sure we have at least 1.4 */
+   drmInfo.func             = I810_INIT_DMA_1_4;
+
+   drmInfo.ring_start = ring->mem.Start;
+   drmInfo.ring_end = ring->mem.End;
+   drmInfo.ring_size = ring->mem.Size;
+
+   drmInfo.mmio_offset         = (unsigned int)info->regs;
+   drmInfo.buffers_offset      = (unsigned int)info->buffer_map;
+   drmInfo.sarea_priv_offset   = sizeof(drm_sarea_t);
+
+   drmInfo.front_offset        = 0;
+   drmInfo.back_offset         = info->BackBuffer.Start;
+   drmInfo.depth_offset        = info->DepthBuffer.Start;
+
+   drmInfo.w                   = ctx->shared.virtualWidth;
+   drmInfo.h                   = ctx->shared.virtualHeight;
+   drmInfo.pitch               = info->auxPitch;
+   drmInfo.pitch_bits          = info->auxPitchBits;
+   
+
+   ret = drmCommandWrite(ctx->drmFD, DRM_I810_INIT, &drmInfo, 
+                        sizeof(drmI810Init));
+
+   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 I810DRIBufInit( const DRIDriverContext *ctx, I810Ptr info )
+{
+   /* Initialize vertex buffers */
+   info->bufNumBufs = drmAddBufs(ctx->drmFD,
+                                I810_DMA_BUF_NR,
+                                I810_DMA_BUF_SZ,
+                                DRM_AGP_BUFFER,
+                                info->BufferMem.Start);
+
+   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, I810_DMA_BUF_SZ);
+   
+   return 1;
+}
+
+/**
+ * \brief Install an IRQ handler.
+ * 
+ * \param ctx 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 I810DRIIrqInit(const DRIDriverContext *ctx,
+                            I810Ptr info)
+{
+   if (!info->irq) {
+      info->irq = drmGetInterruptFromBusID(ctx->drmFD,
+                                          ctx->pciBus,
+                                          ctx->pciDevice,
+                                          ctx->pciFunc);
+
+      if ((drmCtlInstHandler(ctx->drmFD, info->irq)) != 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");
+        info->irq = 0;
+      }
+   }
+
+   if (info->irq)
+      fprintf(stderr,
+             "[drm] dma control initialized, using IRQ %d\n",
+             info->irq);
+}
+
+static int I810CheckDRMVersion( const DRIDriverContext *ctx,
+                                 I810Ptr info )
+{
+   drmVersionPtr  version;
+
+   version = drmGetVersion(ctx->drmFD);
+   if (version) {
+      int req_minor, req_patch;
+
+      req_minor = 4;
+      req_patch = 0;   
+
+      i810_drm_version = (version->version_major<<16) | version->version_minor;
+      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] I810DRIScreenInit failed because of a version "
+                "mismatch.\n"
+                "[dri] i810.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;
+}
+
+static int I810MemoryInit( const DRIDriverContext *ctx, I810Ptr info )
+{
+   int        width_bytes = ctx->shared.virtualWidth * ctx->cpp;
+   int        cpp         = ctx->cpp;
+   int        bufferSize  = (ctx->shared.virtualHeight * width_bytes);
+   int        depthSize   = (((ctx->shared.virtualHeight+15) & ~15) * width_bytes);
+   int        l;
+
+   if (drmAddMap(ctx->drmFD, (drmHandle) info->BackBuffer.Start,
+                info->BackBuffer.Size, DRM_AGP, 0,
+                &info->backbuffer) < 0) {
+     fprintf(stderr, "[drm] drmAddMap(backbuffer) failed.  Disabling DRI\n");
+     return 0;
+   }
+   
+   if (drmAddMap(ctx->drmFD, (drmHandle) info->DepthBuffer.Start,
+                info->DepthBuffer.Size, DRM_AGP, 0,
+                &info->depthbuffer) < 0) {
+     fprintf(stderr, "[drm] drmAddMap(depthbuffer) failed.  Disabling DRI.\n");
+      return 0;
+   }
+
+   if (!I810AllocLow(&(info->FrontBuffer), &(info->SysMem), (((ctx->shared.virtualHeight * width_bytes) + 4095) & ~4095)))
+   {
+     fprintf(stderr,"Framebuffer allocation failed\n");
+     return 0;
+   }
+   else
+     fprintf(stderr,"Frame buffer at 0x%.8x (%luk, %lu bytes)\n",
+            info->FrontBuffer.Start,
+            info->FrontBuffer.Size / 1024, info->FrontBuffer.Size);
+   
+   memset(&(info->LpRing), 0, sizeof(I810RingBuffer));
+   if (I810AllocLow(&(info->LpRing.mem), &(info->SysMem), 16 * 4096)) {
+     fprintf(stderr,
+           "Ring buffer at 0x%.8x (%luk, %lu bytes)\n",
+            info->LpRing.mem.Start,
+            info->LpRing.mem.Size / 1024, info->LpRing.mem.Size);
+     
+     info->LpRing.tail_mask = info->LpRing.mem.Size - 1;
+     info->LpRing.virtual_start = info->FbBase + info->LpRing.mem.Start;
+     info->LpRing.head = 0;
+     info->LpRing.tail = 0;
+     info->LpRing.space = 0;
+   } else {
+     fprintf(stderr, "Ring buffer allocation failed\n");
+     return (0);
+   }
+
+   /* Allocate buffer memory */
+   I810AllocHigh(&(info->BufferMem), &(info->SysMem),
+                I810_DMA_BUF_NR * I810_DMA_BUF_SZ);
+   
+
+   fprintf(stderr, "[dri] Buffer map : %lx\n",
+             info->BufferMem.Start);
+
+   if (info->BufferMem.Start == 0 ||
+       info->BufferMem.End - info->BufferMem.Start >
+       I810_DMA_BUF_NR * I810_DMA_BUF_SZ) {
+     fprintf(stderr,"[dri] Not enough memory for dma buffers.  Disabling DRI.\n");
+     return 0;
+   }
+
+   if (drmAddMap(ctx->drmFD, (drmHandle) info->BufferMem.Start,
+                info->BufferMem.Size, DRM_AGP, 0, &info->buffer_map) < 0) {
+     fprintf(stderr, "[drm] drmAddMap(buffer_map) failed.  Disabling DRI.\n");
+     return 0;
+   }
+
+   if (drmAddMap(ctx->drmFD, (drmHandle) info->LpRing.mem.Start,
+                info->LpRing.mem.Size, DRM_AGP, 0, &info->ring_map) < 0) {
+     fprintf(stderr, "[drm] drmAddMap(ring_map) failed.  Disabling DRI. \n");
+     return 0;
+   }
+
+   /* Front, back and depth buffers - everything else texture??
+    */
+   info->textureSize = info->SysMem.Size;
+
+   if (info->textureSize < 0) 
+      return 0;
+
+   
+   l = I810MinBits((info->textureSize-1) / I810_NR_TEX_REGIONS);
+   if (l < I810_LOG_MIN_TEX_REGION_SIZE) l = I810_LOG_MIN_TEX_REGION_SIZE;
+
+   /* Round the texture size up to the nearest whole number of
+    * texture regions.  Again, be greedy about this, don't
+    * round down.
+    */
+   info->logTextureGranularity = 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;
+   }
+
+   I810AllocLow(&(info->TexMem), &(info->SysMem), info->textureSize);
+
+   if (drmAddMap(ctx->drmFD, (drmHandle) info->TexMem.Start,
+                info->TexMem.Size, DRM_AGP, 0, &info->textures) < 0) {
+     fprintf(stderr,
+                "[drm] drmAddMap(textures) failed.  Disabling DRI.\n");
+      return 0;
+   }
+
+   /* Reserve space for textures */
+   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->TexMem.Size/1024, info->TexMem.Start);
+
+   return 1;
+} 
+
+
+
+/**
+ * Called at the start of each server generation.
+ *
+ * \param ctx 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_I810_CP_START command.
+ *
+ * Setups a I810DRIRec structure to be passed to i810_dri.so for its
+ * initialization.
+ */
+static int I810ScreenInit( DRIDriverContext *ctx, I810Ptr info )
+{
+   I810DRIPtr   pI810DRI;
+   int err;
+
+   usleep(100);
+   /*assert(!ctx->IsClient);*/
+
+   /* from XFree86 driver */
+   info->DepthOffset = 0x3000000;
+   info->BackOffset = 0x3800000;
+   {
+      int  width_bytes = (ctx->shared.virtualWidth * ctx->cpp);
+      int  maxy        = ctx->shared.fbSize / width_bytes;
+
+
+      if (maxy <= ctx->shared.virtualHeight * 3) {
+        fprintf(stderr, 
+                "Static buffer allocation failed -- "
+                "need at least %d kB video memory (have %d kB)\n",
+                (ctx->shared.virtualWidth * ctx->shared.virtualHeight *
+                 ctx->cpp * 3 + 1023) / 1024,
+                ctx->shared.fbSize / 1024);
+        return 0;
+      } 
+   }
+
+
+   info->regsSize = ctx->MMIOSize;
+   ctx->shared.SAREASize = 0x2000;
+
+   /* Note that drmOpen will try to load the kernel module, if needed. */
+   ctx->drmFD = drmOpen("i810", NULL );
+   if (ctx->drmFD < 0) {
+      fprintf(stderr, "[drm] drmOpen failed\n");
+      return 0;
+   }
+
+   if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) {
+      fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
+             ctx->drmFD, ctx->pciBusID, strerror(-err));
+      return 0;
+   }
+
+   if (drmAddMap( ctx->drmFD,
+                 0,
+                 ctx->shared.SAREASize,
+                 DRM_SHM,
+                 DRM_CONTAINS_LOCK,
+                 &ctx->shared.hSAREA) < 0)
+   {
+      fprintf(stderr, "[drm] drmAddMap failed\n");
+      return 0;
+   }
+   fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n",
+          ctx->shared.SAREASize, ctx->shared.hSAREA);
+
+   if (drmMap( ctx->drmFD,
+              ctx->shared.hSAREA,
+              ctx->shared.SAREASize,
+              (drmAddressPtr)(&ctx->pSAREA)) < 0)
+   {
+      fprintf(stderr, "[drm] drmMap failed\n");
+      return 0;
+   }
+   memset(ctx->pSAREA, 0, ctx->shared.SAREASize);
+   fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
+          ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize);
+
+   if (drmAddMap(ctx->drmFD, 
+                ctx->MMIOStart,
+                ctx->MMIOSize,
+                DRM_REGISTERS, 
+                DRM_READ_ONLY, 
+                &info->regs) < 0) {
+      fprintf(stderr, "[drm] drmAddMap mmio failed\n");        
+      return 0;
+   }
+   fprintf(stderr,
+          "[drm] register handle = 0x%08lx\n", info->regs);
+
+   I810DRIAgpPreInit(ctx, info);
+   /* Need to AddMap the framebuffer and mmio regions here:
+    */
+   if (drmAddMap( ctx->drmFD,
+                 (drmHandle)ctx->FBStart,
+                 ctx->FBSize,
+                 DRM_FRAME_BUFFER,
+#ifndef _EMBEDDED
+                 0,
+#else
+                 DRM_READ_ONLY,
+#endif
+                 &ctx->shared.hFrameBuffer) < 0)
+   {
+      fprintf(stderr, "[drm] drmAddMap framebuffer failed\n");
+      return 0;
+   }
+
+   fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n",
+          ctx->shared.hFrameBuffer);
+
+
+
+
+   /* Check the i810 DRM version */
+   if (!I810CheckDRMVersion(ctx, info)) {
+      return 0;
+   }
+
+   /* Initialize AGP */
+   if (!I810DRIAgpInit(ctx, info)) {
+      return 0;
+   }
+
+
+   /* Memory manager setup */
+   if (!I810MemoryInit(ctx, info)) {
+      return 0;
+   }
+
+   /* Create a 'server' context so we can grab the lock for
+    * initialization ioctls.
+    */
+   if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) {
+      fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
+      return 0;
+   }
+
+   DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0); 
+
+   /* Initialize the kernel data structures */
+   if (!I810DRIKernelInit(ctx, info)) {
+      fprintf(stderr, "I810DRIKernelInit failed\n");
+      DRM_UNLOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext);
+      return 0;
+   }
+
+   /* Initialize the vertex buffers list */
+   if (!I810DRIBufInit(ctx, info)) {
+      fprintf(stderr, "I810DRIBufInit failed\n");
+      DRM_UNLOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext);
+      return 0;
+   }
+
+   /* Initialize IRQ */
+   I810DRIIrqInit(ctx, info);
+
+   /* Initialize the SAREA private data structure */
+   {
+      I810SAREAPtr pSAREAPriv;
+      pSAREAPriv = (I810SAREAPtr)(((char*)ctx->pSAREA) + 
+                                       sizeof(drm_sarea_t));
+      memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
+      //      pSAREAPriv->pf_enabled=1;
+   }
+
+
+   /* 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.
+    */
+#if 0
+   memset((char *)ctx->FBAddress,
+         0,
+         info->auxPitch * ctx->cpp * ctx->shared.virtualHeight );
+
+   memset((char *)info->backbuffer,
+         0,
+         info->auxPitch * ctx->cpp * ctx->shared.virtualHeight );
+#endif
+
+   /* This is the struct passed to i810_dri.so for its initialization */
+   ctx->driverClientMsg = malloc(sizeof(I810DRIRec));
+   ctx->driverClientMsgSize = sizeof(I810DRIRec);
+   pI810DRI                    = (I810DRIPtr)ctx->driverClientMsg;
+
+   pI810DRI->regs              = info->regs;
+   pI810DRI->regsSize          = info->regsSize;
+   // regsMap is unused
+
+   pI810DRI->backbufferSize    = info->BackBuffer.Size;
+   pI810DRI->backbuffer        = info->backbuffer;
+
+   pI810DRI->depthbufferSize   = info->DepthBuffer.Size;
+   pI810DRI->depthbuffer       = info->depthbuffer;
+
+   pI810DRI->textures          = info->textures;
+   pI810DRI->textureSize       = info->textureSize;
+
+   pI810DRI->agp_buffers       = info->buffer_map;
+   pI810DRI->agp_buf_size      = info->BufferMem.Size;
+
+   pI810DRI->deviceID          = info->Chipset;
+   pI810DRI->width             = ctx->shared.virtualWidth;
+   pI810DRI->height            = ctx->shared.virtualHeight;
+   pI810DRI->mem               = ctx->shared.fbSize;
+   pI810DRI->cpp               = ctx->bpp / 8;
+   pI810DRI->bitsPerPixel      = ctx->bpp;
+   pI810DRI->fbOffset          = info->FrontBuffer.Start;
+   pI810DRI->fbStride          = info->auxPitch;
+   
+   pI810DRI->backOffset        = info->BackBuffer.Start;
+   pI810DRI->depthOffset       = info->DepthBuffer.Start;
+
+   pI810DRI->auxPitch          = info->auxPitch;
+   pI810DRI->auxPitchBits      = info->auxPitchBits;
+
+   pI810DRI->logTextureGranularity = info->logTextureGranularity;
+   pI810DRI->textureOffset     = info->TexMem.Start;
+  
+   pI810DRI->ringOffset        = info->LpRing.mem.Start;
+   pI810DRI->ringSize          = info->LpRing.mem.Size;
+
+   // drmBufs looks unused 
+   pI810DRI->irq               = info->irq;
+   pI810DRI->sarea_priv_offset = sizeof(drm_sarea_t);
+
+   /* Don't release the lock now - let the VT switch handler do it. */
+   return 1;
+}
+
+
+/**
+ * \brief Establish the set of modes available for the display.
+ *
+ * \param ctx display handle.
+ * \param numModes will receive the number of supported modes.
+ * \param modes will point to the list of supported modes.
+ *
+ * \return one on success, or zero on failure.
+ * 
+ * Allocates a single visual and fills it with information according to the
+ * display bit depth. Supports only 16 and 32 bpp bit depths, aborting
+ * otherwise.
+ */
+const __GLcontextModes __glModes[] = {
+    
+    /* 16 bit, RGB Depth=16 */
+    {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
+     .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_FALSE,
+     .redBits = 5, .greenBits = 6, .blueBits = 5, .alphaBits = 0,
+     .redMask = 0xf800, .greenMask = 0x07e0, .blueMask = 0x001f, .alphaMask = 0x0,
+     .rgbBits = 16, .indexBits = 0,
+     .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
+     .depthBits = 16, .stencilBits = 0,
+     .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
+};
+static int i810InitContextModes( const DRIDriverContext *ctx,
+                                  int *numModes, const __GLcontextModes **modes)
+{
+   *numModes = sizeof(__glModes)/sizeof(__GLcontextModes *);
+   *modes = &__glModes[0];
+   return 1;
+}
+
+
+/**
+ * \brief Validate the fbdev mode.
+ * 
+ * \param ctx display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Saves some registers and returns 1.
+ *
+ * \sa i810ValidateMode().
+ */
+static int i810ValidateMode( const DRIDriverContext *ctx )
+{
+   unsigned char *I810MMIO = ctx->MMIOAddress;
+   I810Ptr info = ctx->driverPrivate;
+
+   return 1;
+}
+
+
+/**
+ * \brief Examine mode returned by fbdev.
+ * 
+ * \param ctx display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Restores registers that fbdev has clobbered and returns 1.
+ *
+ * \sa i810ValidateMode().
+ */
+static int i810PostValidateMode( const DRIDriverContext *ctx )
+{
+   unsigned char *I810MMIO = ctx->MMIOAddress;
+   I810Ptr info = ctx->driverPrivate;
+
+   return 1;
+}
+
+
+/**
+ * \brief Initialize the framebuffer device mode
+ *
+ * \param ctx display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Fills in \p info with some default values and some information from \p ctx
+ * and then calls I810ScreenInit() for the screen initialization.
+ * 
+ * Before exiting clears the framebuffer memory accessing it directly.
+ */
+static int i810InitFBDev( DRIDriverContext *ctx )
+{
+  I810Ptr info = calloc(1, sizeof(*info));
+
+   {
+      int  dummy = ctx->shared.virtualWidth;
+
+      switch (ctx->bpp / 8) {
+      case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break;
+      case 2: dummy = (ctx->shared.virtualWidth +  31) &  ~31; break;
+      case 3:
+      case 4: dummy = (ctx->shared.virtualWidth +  15) &  ~15; break;
+      }
+
+      ctx->shared.virtualWidth = dummy;
+   }
+
+   ctx->driverPrivate = (void *)info;
+   
+   info->Chipset = ctx->chipset;
+
+   if (!I810ScreenInit( ctx, info ))
+      return 0;
+
+
+   return 1;
+}
+
+
+/**
+ * \brief The screen is being closed, so clean up any state and free any
+ * resources used by the DRI.
+ *
+ * \param ctx display handle.
+ *
+ * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
+ * private data.
+ */
+static void i810HaltFBDev( DRIDriverContext *ctx )
+{
+    drmUnmap( ctx->pSAREA, ctx->shared.SAREASize );
+    drmClose(ctx->drmFD);
+
+    if (ctx->driverPrivate) {
+       free(ctx->driverPrivate);
+       ctx->driverPrivate = 0;
+    }
+}
+
+
+extern void i810NotifyFocus( int );
+
+/**
+ * \brief Exported driver interface for Mini GLX.
+ *
+ * \sa DRIDriverRec.
+ */
+const struct DRIDriverRec __driDriver = {
+   i810InitContextModes,
+   i810ValidateMode,
+   i810PostValidateMode,
+   i810InitFBDev,
+   i810HaltFBDev,
+   I810EngineShutdown,
+   I810EngineRestore,  
+#ifndef _EMBEDDED
+   0,
+#else
+   i810NotifyFocus, 
+#endif
+};