xf86-video-ati: Branch 'master'

Dave Airlie airlied at kemper.freedesktop.org
Wed Jul 1 21:47:44 PDT 2009


 configure.ac               |   10 
 src/Makefile.am            |    9 
 src/drmmode_display.c      | 1035 +++++++++++++++++++++++++++++++++++++++++++++
 src/drmmode_display.h      |   74 +++
 src/pcidb/parse_pci_ids.pl |    2 
 src/radeon.h               |   18 
 src/radeon_accel.c         |    6 
 src/radeon_chipinfo_gen.h  |    2 
 src/radeon_commonfuncs.c   |   59 ++
 src/radeon_dri2.c          |  318 +++++++++++++
 src/radeon_dri2.h          |   42 +
 src/radeon_driver.c        |   13 
 src/radeon_exa.c           |    7 
 src/radeon_exa_funcs.c     |    5 
 src/radeon_kms.c           |  837 ++++++++++++++++++++++++++++++++++++
 src/radeon_legacy_memory.c |   22 
 src/radeon_probe.c         |   71 ++-
 src/radeon_probe.h         |   11 
 18 files changed, 2504 insertions(+), 37 deletions(-)

New commits:
commit 1782ce28953184776c90eb1255208a3e0ad245f0
Author: Dave Airlie <airlied at redhat.com>
Date:   Tue Jun 30 16:55:26 2009 +1000

    radeon: add KMS support (still disabled)
    
    This adds DRI2 + KMS + driver pixmaps support to the driver.
    
    I've decided to just do a completely separate KMS driver file
    instead of hacking the crap out of radeon_driver.c. So now
    I do the KMS check in radeon_probe.c time and set the DDX
    pointed up to a completely different set at this stage.
    
    This avoids a lot of if (kms) type crap in the code at
    the expense of making sure we make changes to both files
    if necessary.
    
    This code is still disabled in configure.ac as I broke EXA composite
    rendering somehow in KMS mode

diff --git a/configure.ac b/configure.ac
index 0cf24e6..2d3ac4b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,16 +118,16 @@ if test "$DRI" = yes; then
 
         save_CFLAGS="$CFLAGS"
         CFLAGS="$XORG_CFLAGS $DRI_CFLAGS $CFLAGS"
-#	AC_CHECK_HEADER(xf86drmMode.h,[DRM_MODE=yes],[DRM_MODE=no],[#include <stdint.h>
-	DRM_MODE=no
+#AC_CHECK_HEADER(xf86drmMode.h,[DRM_MODE=yes],[DRM_MODE=no],[#include <stdint.h>
 #include <stdlib.h>])
-	 if test "x$DRM_MODE" = xyes; then
+	DRM_MODE = no
+	if test "x$DRM_MODE" = xyes; then
 		PKG_CHECK_MODULES(LIBDRM_RADEON, [xorg-server >= 1.6 libdrm_radeon],
 		[LIBDRM_RADEON=yes], [LIBDRM_RADEON=no])
 		
 		if test "x$LIBDRM_RADEON" = xyes; then
 			AC_DEFINE(XF86DRM_MODE,1,[DRM kernel modesetting])
-			AC_DEFINE(DRI2, 1,[Enable DRI2 code])
+			AC_DEFINE(RADEON_DRI2, 1,[Enable DRI2 code])
 		fi
         fi
 	CFLAGS="$save_CFLAGS"
@@ -254,6 +254,8 @@ CPPFLAGS="$SAVE_CPPFLAGS"
 
 AM_CONDITIONAL(USE_EXA, test "x$USE_EXA" = xyes)
 
+AM_CONDITIONAL(XF86DRM_MODE, test "x$DRM_MODE" = xyes)
+
 if test "x$XSERVER_LIBPCIACCESS" = xyes; then
     PKG_CHECK_MODULES([PCIACCESS], [pciaccess >= 0.8.0])
     XORG_CFLAGS="$XORG_CFLAGS $PCIACCESS_CFLAGS"
diff --git a/src/Makefile.am b/src/Makefile.am
index 1864f96..421d163 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,7 @@
 # _ladir passes a dummy rpath to libtool so the thing will actually link
 # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
 
-radeon_drv_la_LIBADD =
+radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS)
 
 if DRI
 RADEON_DRI_SRCS = radeon_dri.c
@@ -65,6 +65,10 @@ XMODE_SRCS=\
         modes/xf86Rotate.c \
         modes/xf86DiDGA.c
 
+if XF86DRM_MODE
+RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c
+endif
+
 if USE_EXA
 RADEON_EXA_SOURCES = radeon_exa.c r600_exa.c r6xx_accel.c r600_textured_videofuncs.c r600_shader.c
 endif
@@ -95,7 +99,8 @@ radeon_drv_la_SOURCES = \
 	radeon_textured_video.c radeon_pm.c \
 	radeon_crtc.c radeon_output.c radeon_modes.c radeon_tv.c \
 	$(RADEON_ATOMBIOS_SOURCES) radeon_atombios.c radeon_atomwrapper.c \
-	$(RADEON_DRI_SRCS) $(RADEON_EXA_SOURCES) atombios_output.c atombios_crtc.c
+	$(RADEON_DRI_SRCS) $(RADEON_EXA_SOURCES) atombios_output.c atombios_crtc.c \
+	$(RADEON_KMS_SRCS)
 
 if XMODES
 radeon_drv_la_SOURCES += \
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
new file mode 100644
index 0000000..644727d
--- /dev/null
+++ b/src/drmmode_display.c
@@ -0,0 +1,1035 @@
+/*
+ * Copyright © 2007 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Dave Airlie <airlied at redhat.com>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef XF86DRM_MODE
+#include <sys/ioctl.h>
+#include "micmap.h"
+#include "xf86cmap.h"
+#include "radeon.h"
+#include "radeon_reg.h"
+#include "radeon_drm.h"
+#include "sarea.h"
+
+#include "drmmode_display.h"
+
+/* DPMS */
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+static void
+drmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
+		     drmModeModeInfo *kmode,
+		     DisplayModePtr	mode)
+{
+	memset(mode, 0, sizeof(DisplayModeRec));
+	mode->status = MODE_OK;
+
+	mode->Clock = kmode->clock;
+
+	mode->HDisplay = kmode->hdisplay;
+	mode->HSyncStart = kmode->hsync_start;
+	mode->HSyncEnd = kmode->hsync_end;
+	mode->HTotal = kmode->htotal;
+	mode->HSkew = kmode->hskew;
+
+	mode->VDisplay = kmode->vdisplay;
+	mode->VSyncStart = kmode->vsync_start;
+	mode->VSyncEnd = kmode->vsync_end;
+	mode->VTotal = kmode->vtotal;
+	mode->VScan = kmode->vscan;
+
+	mode->Flags = kmode->flags; //& FLAG_BITS;
+	mode->name = strdup(kmode->name);
+
+	if (kmode->type & DRM_MODE_TYPE_DRIVER)
+		mode->type = M_T_DRIVER;
+	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
+		mode->type |= M_T_PREFERRED;
+	xf86SetModeCrtc (mode, scrn->adjustFlags);
+}
+
+static void
+drmmode_ConvertToKMode(ScrnInfoPtr	scrn,
+		     drmModeModeInfo *kmode,
+		     DisplayModePtr	mode)
+{
+	memset(kmode, 0, sizeof(*kmode));
+
+	kmode->clock = mode->Clock;
+	kmode->hdisplay = mode->HDisplay;
+	kmode->hsync_start = mode->HSyncStart;
+	kmode->hsync_end = mode->HSyncEnd;
+	kmode->htotal = mode->HTotal;
+	kmode->hskew = mode->HSkew;
+
+	kmode->vdisplay = mode->VDisplay;
+	kmode->vsync_start = mode->VSyncStart;
+	kmode->vsync_end = mode->VSyncEnd;
+	kmode->vtotal = mode->VTotal;
+	kmode->vscan = mode->VScan;
+
+	kmode->flags = mode->Flags; //& FLAG_BITS;
+	if (mode->name)
+		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
+	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+
+}
+
+static void
+drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+#if 0
+	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+//	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+//	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+
+	/* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */
+	if (mode == DPMSModeOff) {
+//		drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+//			       0, 0, 0, NULL, 0, NULL);
+	}
+#endif
+}
+
+static PixmapPtr
+create_pixmap_for_fbcon(drmmode_ptr drmmode,
+			ScrnInfoPtr pScrn, int crtc_id)
+{
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	drmmode_crtc_private_ptr drmmode_crtc;
+	ScreenPtr pScreen = pScrn->pScreen;
+	PixmapPtr pixmap;
+	struct radeon_bo *bo;
+	drmModeFBPtr fbcon;
+	struct drm_gem_flink flink;
+
+	drmmode_crtc = xf86_config->crtc[crtc_id]->driver_private;
+
+	fbcon = drmModeGetFB(drmmode->fd, drmmode_crtc->mode_crtc->buffer_id);
+	if (fbcon == NULL)
+		return NULL;
+
+	flink.handle = fbcon->handle;
+	if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Couldn't flink fbcon handle\n");
+		return NULL;
+	}
+
+	bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
+	if (bo == NULL) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Couldn't allocate bo for fbcon handle\n");
+		return NULL;
+	}
+
+	pixmap = GetScratchPixmapHeader(pScreen,
+					fbcon->width, fbcon->height,
+					fbcon->depth, fbcon->bpp,
+					fbcon->pitch, NULL);
+	if (pixmap == NULL) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Couldn't allocate pixmap fbcon contents\n");
+		return NULL;
+	}
+
+	radeon_set_pixmap_bo(pixmap, bo);
+
+	radeon_bo_unref(bo);
+	drmModeFreeFB(fbcon);
+	return pixmap;
+}
+
+void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
+{
+	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	RADEONInfoPtr info = RADEONPTR(pScrn);
+	PixmapPtr src, dst;
+	ScreenPtr pScreen = pScrn->pScreen;
+	int crtc_id = 0;
+	int i;
+	int pitch = pScrn->displayWidth * info->CurrentLayout.pixel_bytes;
+
+	if (info->ChipFamily >= CHIP_FAMILY_R600)
+		return;
+
+	for (i = 0; i < xf86_config->num_crtc; i++) {
+		xf86CrtcPtr crtc = xf86_config->crtc[i];
+		drmmode_crtc_private_ptr drmmode_crtc;
+
+		drmmode_crtc = crtc->driver_private;
+		if (drmmode_crtc->mode_crtc->buffer_id)
+			crtc_id = i;
+	}
+
+	src = create_pixmap_for_fbcon(drmmode, pScrn, crtc_id);
+	if (!src)
+		return;
+
+	dst = GetScratchPixmapHeader(pScreen,
+				     pScrn->virtualX, pScrn->virtualY,
+				     pScrn->depth, pScrn->bitsPerPixel,
+				     pitch, NULL);
+	radeon_set_pixmap_bo(dst, info->front_bo);
+	info->accel_state->exa->PrepareCopy (src, dst,
+					     -1, -1, GXcopy, FB_ALLONES);
+	info->accel_state->exa->Copy (dst, 0, 0, 0, 0,
+				      pScrn->virtualX, pScrn->virtualY);
+	info->accel_state->exa->DoneCopy (dst);
+	radeon_cs_flush_indirect(pScrn);
+
+	(*pScreen->DestroyPixmap)(dst);
+	(*pScreen->DestroyPixmap)(src);
+
+}
+
+static Bool
+drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
+		     Rotation rotation, int x, int y)
+{
+	ScrnInfoPtr pScrn = crtc->scrn;
+	RADEONInfoPtr info = RADEONPTR(pScrn);
+	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	int saved_x, saved_y;
+	Rotation saved_rotation;
+	DisplayModeRec saved_mode;
+	uint32_t *output_ids;
+	int output_count = 0;
+	Bool ret = TRUE;
+	int i;
+	int fb_id;
+	drmModeModeInfo kmode;
+	int pitch = pScrn->displayWidth * info->CurrentLayout.pixel_bytes;
+
+	if (drmmode->fb_id == 0) {
+		ret = drmModeAddFB(drmmode->fd,
+				   pScrn->virtualX, pScrn->virtualY,
+                                   pScrn->depth, pScrn->bitsPerPixel,
+				   pitch,
+				   info->front_bo->handle,
+                                   &drmmode->fb_id);
+                if (ret < 0) {
+                        ErrorF("failed to add fb\n");
+                        return FALSE;
+                }
+        }
+
+	saved_mode = crtc->mode;
+	saved_x = crtc->x;
+	saved_y = crtc->y;
+	saved_rotation = crtc->rotation;
+
+	if (mode) {
+		crtc->mode = *mode;
+		crtc->x = x;
+		crtc->y = y;
+		crtc->rotation = rotation;
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0)
+		crtc->transformPresent = FALSE;
+#endif
+	}
+
+	output_ids = xcalloc(sizeof(uint32_t), xf86_config->num_output);
+	if (!output_ids) {
+		ret = FALSE;
+		goto done;
+	}
+
+	if (mode) {
+		for (i = 0; i < xf86_config->num_output; i++) {
+			xf86OutputPtr output = xf86_config->output[i];
+			drmmode_output_private_ptr drmmode_output;
+
+			if (output->crtc != crtc)
+				continue;
+
+			drmmode_output = output->driver_private;
+			output_ids[output_count] = drmmode_output->mode_output->connector_id;
+			output_count++;
+		}
+
+		if (!xf86CrtcRotate(crtc)) {
+			goto done;
+		}
+
+		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
+
+		fb_id = drmmode->fb_id;
+		if (drmmode_crtc->rotate_fb_id) {
+			fb_id = drmmode_crtc->rotate_fb_id;
+			x = y = 0;
+		}
+		ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+				     fb_id, x, y, output_ids, output_count, &kmode);
+		if (ret)
+			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
+				   "failed to set mode: %s", strerror(-ret));
+		else
+			ret = TRUE;
+
+		if (crtc->scrn->pScreen)
+			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
+		/* go through all the outputs and force DPMS them back on? */
+		for (i = 0; i < xf86_config->num_output; i++) {
+			xf86OutputPtr output = xf86_config->output[i];
+			drmmode_output_private_ptr drmmode_output;
+
+			if (output->crtc != crtc)
+				continue;
+
+			output->funcs->dpms(output, DPMSModeOn);
+		}
+	}
+
+
+
+done:
+	if (!ret) {
+		crtc->x = saved_x;
+		crtc->y = saved_y;
+		crtc->rotation = saved_rotation;
+		crtc->mode = saved_mode;
+	}
+	return ret;
+}
+
+static void
+drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
+{
+
+}
+
+static void
+drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+
+	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
+}
+
+static void
+drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	void *ptr;
+
+	/* cursor should be mapped already */
+	ptr = drmmode_crtc->cursor_bo->ptr;
+
+	memcpy (ptr, image, 64 * 64 * 4);
+
+	return;
+}
+
+
+static void
+drmmode_hide_cursor (xf86CrtcPtr crtc)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+
+	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64);
+
+}
+
+static void
+drmmode_show_cursor (xf86CrtcPtr crtc)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	uint32_t handle = drmmode_crtc->cursor_bo->handle;
+
+	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64);
+}
+
+static void *
+drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	int size;
+	struct radeon_bo *rotate_bo;
+	int ret;
+	unsigned long rotate_pitch;
+
+	width = RADEON_ALIGN(width, 63);
+	rotate_pitch = width * drmmode->cpp;
+
+	size = rotate_pitch * height;
+
+	rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
+	if (rotate_bo == NULL)
+		return NULL;
+
+	radeon_bo_map(rotate_bo, 1);
+
+	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
+			   crtc->scrn->bitsPerPixel, rotate_pitch,
+			   rotate_bo->handle,
+			   &drmmode_crtc->rotate_fb_id);
+	if (ret) {
+		ErrorF("failed to add rotate fb\n");
+	}
+
+	drmmode_crtc->rotate_bo = rotate_bo;
+	return drmmode_crtc->rotate_bo->ptr;
+}
+
+static PixmapPtr
+drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
+{
+	ScrnInfoPtr pScrn = crtc->scrn;
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	unsigned long rotate_pitch;
+	PixmapPtr rotate_pixmap;
+
+	if (!data)
+		data = drmmode_crtc_shadow_allocate (crtc, width, height);
+
+	rotate_pitch = RADEON_ALIGN(width, 63) * drmmode->cpp;
+
+	rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
+					       width, height,
+					       pScrn->depth,
+					       pScrn->bitsPerPixel,
+					       rotate_pitch,
+					       data);
+
+	if (rotate_pixmap == NULL) {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
+	}
+
+	if (drmmode_crtc->rotate_bo)
+		radeon_set_pixmap_bo(rotate_pixmap, drmmode_crtc->rotate_bo);
+	return rotate_pixmap;
+
+}
+
+static void
+drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+
+	if (rotate_pixmap)
+	    FreeScratchPixmapHeader(rotate_pixmap);
+
+	if (data) {
+		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
+		drmmode_crtc->rotate_fb_id = 0;
+		radeon_bo_unmap(drmmode_crtc->rotate_bo);
+		radeon_bo_unref(drmmode_crtc->rotate_bo);
+		drmmode_crtc->rotate_bo = NULL;
+	}
+
+}
+
+static void
+drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
+                      uint16_t *blue, int size)
+{
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+
+	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+			    size, red, green, blue);
+}
+
+static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
+    .dpms = drmmode_crtc_dpms,
+    .set_mode_major = drmmode_set_mode_major,
+    .set_cursor_colors = drmmode_set_cursor_colors,
+    .set_cursor_position = drmmode_set_cursor_position,
+    .show_cursor = drmmode_show_cursor,
+    .hide_cursor = drmmode_hide_cursor,
+    .load_cursor_argb = drmmode_load_cursor_argb,
+
+    .gamma_set = drmmode_crtc_gamma_set,
+    .shadow_create = drmmode_crtc_shadow_create,
+    .shadow_allocate = drmmode_crtc_shadow_allocate,
+    .shadow_destroy = drmmode_crtc_shadow_destroy,
+    .destroy = NULL, /* XXX */
+};
+
+
+static void
+drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
+{
+	xf86CrtcPtr crtc;
+	drmmode_crtc_private_ptr drmmode_crtc;
+
+	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
+	if (crtc == NULL)
+		return;
+
+	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
+	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
+	drmmode_crtc->drmmode = drmmode;
+	crtc->driver_private = drmmode_crtc;
+
+	return;
+}
+
+static xf86OutputStatus
+drmmode_output_detect(xf86OutputPtr output)
+{
+	/* go to the hw and retrieve a new output struct */
+	drmmode_output_private_ptr drmmode_output = output->driver_private;
+	drmmode_ptr drmmode = drmmode_output->drmmode;
+	xf86OutputStatus status;
+	drmModeFreeConnector(drmmode_output->mode_output);
+
+	drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
+
+	switch (drmmode_output->mode_output->connection) {
+	case DRM_MODE_CONNECTED:
+		status = XF86OutputStatusConnected;
+		break;
+	case DRM_MODE_DISCONNECTED:
+		status = XF86OutputStatusDisconnected;
+		break;
+	default:
+	case DRM_MODE_UNKNOWNCONNECTION:
+		status = XF86OutputStatusUnknown;
+		break;
+	}
+	return status;
+}
+
+static Bool
+drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
+{
+	return MODE_OK;
+}
+
+static DisplayModePtr
+drmmode_output_get_modes(xf86OutputPtr output)
+{
+	drmmode_output_private_ptr drmmode_output = output->driver_private;
+	drmModeConnectorPtr koutput = drmmode_output->mode_output;
+	drmmode_ptr drmmode = drmmode_output->drmmode;
+	int i;
+	DisplayModePtr Modes = NULL, Mode;
+	drmModePropertyPtr props;
+
+	/* look for an EDID property */
+	for (i = 0; i < koutput->count_props; i++) {
+		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
+			if (!strcmp(props->name, "EDID")) {
+				if (drmmode_output->edid_blob)
+					drmModeFreePropertyBlob(drmmode_output->edid_blob);
+				drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
+			}
+			drmModeFreeProperty(props);
+		}
+	}
+
+	if (drmmode_output->edid_blob)
+		xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, drmmode_output->edid_blob->data));
+	else
+		xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, NULL));
+
+	/* modes should already be available */
+	for (i = 0; i < koutput->count_modes; i++) {
+		Mode = xnfalloc(sizeof(DisplayModeRec));
+
+		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
+		Modes = xf86ModesAdd(Modes, Mode);
+
+	}
+	return Modes;
+}
+
+static void
+drmmode_output_destroy(xf86OutputPtr output)
+{
+	drmmode_output_private_ptr drmmode_output = output->driver_private;
+
+	if (drmmode_output->edid_blob)
+		drmModeFreePropertyBlob(drmmode_output->edid_blob);
+	drmModeFreeConnector(drmmode_output->mode_output);
+	xfree(drmmode_output);
+	output->driver_private = NULL;
+}
+
+static void
+drmmode_output_dpms(xf86OutputPtr output, int mode)
+{
+	drmmode_output_private_ptr drmmode_output = output->driver_private;
+	drmModeConnectorPtr koutput = drmmode_output->mode_output;
+	drmmode_ptr drmmode = drmmode_output->drmmode;
+
+	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
+				    drmmode_output->dpms_enum_id, mode);
+	return;
+}
+
+static const xf86OutputFuncsRec drmmode_output_funcs = {
+    .dpms = drmmode_output_dpms,
+#if 0
+
+    .save = drmmode_crt_save,
+    .restore = drmmode_crt_restore,
+    .mode_fixup = drmmode_crt_mode_fixup,
+    .prepare = drmmode_output_prepare,
+    .mode_set = drmmode_crt_mode_set,
+    .commit = drmmode_output_commit,
+#endif
+    .detect = drmmode_output_detect,
+    .mode_valid = drmmode_output_mode_valid,
+
+    .get_modes = drmmode_output_get_modes,
+    .destroy = drmmode_output_destroy
+};
+
+static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
+				      SubPixelHorizontalRGB,
+				      SubPixelHorizontalBGR,
+				      SubPixelVerticalRGB,
+				      SubPixelVerticalBGR,
+				      SubPixelNone };
+
+const char *output_names[] = { "None",
+			       "VGA",
+			       "DVI",
+			       "DVI",
+			       "DVI",
+			       "Composite",
+			       "TV",
+			       "LVDS",
+			       "CTV",
+			       "DIN",
+			       "DP",
+			       "HDMI",
+			       "HDMI",
+};
+
+static void
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
+{
+	xf86OutputPtr output;
+	drmModeConnectorPtr koutput;
+	drmModeEncoderPtr kencoder;
+	drmmode_output_private_ptr drmmode_output;
+	drmModePropertyPtr props;
+	char name[32];
+	int i;
+
+	koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
+	if (!koutput)
+		return;
+
+	kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
+	if (!kencoder) {
+		drmModeFreeConnector(koutput);
+		return;
+	}
+
+	/* need to do smart conversion here for compat with non-kms ATI driver */
+	if (koutput->connector_type_id == 1) {
+	    switch(koutput->connector_type) {
+	    case DRM_MODE_CONNECTOR_VGA:
+	    case DRM_MODE_CONNECTOR_DVII:
+	    case DRM_MODE_CONNECTOR_DVID:
+	    case DRM_MODE_CONNECTOR_DVIA:
+	    case DRM_MODE_CONNECTOR_HDMIA:
+	    case DRM_MODE_CONNECTOR_HDMIB:
+		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
+		break;
+	    default:
+		snprintf(name, 32, "%s", output_names[koutput->connector_type]);
+		break;
+	    }
+	} else {
+	    snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
+	}
+
+	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
+	if (!output) {
+		drmModeFreeEncoder(kencoder);
+		drmModeFreeConnector(koutput);
+		return;
+	}
+
+	drmmode_output = xcalloc(sizeof(drmmode_output_private_rec), 1);
+	if (!drmmode_output) {
+		xf86OutputDestroy(output);
+		drmModeFreeConnector(koutput);
+		drmModeFreeEncoder(kencoder);
+		return;
+	}
+
+	drmmode_output->output_id = drmmode->mode_res->connectors[num];
+	drmmode_output->mode_output = koutput;
+	drmmode_output->mode_encoder = kencoder;
+	drmmode_output->drmmode = drmmode;
+	output->mm_width = koutput->mmWidth;
+	output->mm_height = koutput->mmHeight;
+
+	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
+	output->driver_private = drmmode_output;
+
+	output->possible_crtcs = kencoder->possible_crtcs;
+	output->possible_clones = kencoder->possible_clones;
+
+	for (i = 0; i < koutput->count_props; i++) {
+		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+		if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
+			if (!strcmp(props->name, "DPMS")) {
+				drmmode_output->dpms_enum_id = koutput->props[i];
+				drmModeFreeProperty(props);
+				break;
+			}
+			drmModeFreeProperty(props);
+		}
+	}
+
+	return;
+}
+
+static Bool
+drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
+{
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	drmmode_crtc_private_ptr
+		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
+	drmmode_ptr drmmode = drmmode_crtc->drmmode;
+	RADEONInfoPtr info = RADEONPTR(scrn);
+	struct radeon_bo *old_front = NULL;
+	Bool	    ret;
+	ScreenPtr   screen = screenInfo.screens[scrn->scrnIndex];
+	uint32_t    old_fb_id;
+	int	    i, pitch, old_width, old_height, old_pitch;
+	int screen_size;
+	int cpp = info->CurrentLayout.pixel_bytes;
+	struct radeon_bo *front_bo;
+
+	if (scrn->virtualX == width && scrn->virtualY == height)
+		return TRUE;
+
+	front_bo = radeon_get_pixmap_bo(screen->GetScreenPixmap(screen));
+	radeon_cs_flush_indirect(scrn);
+
+	if (front_bo)
+		radeon_bo_wait(front_bo);
+
+	pitch = RADEON_ALIGN(width, 63);
+	height = RADEON_ALIGN(height, 16);
+
+	screen_size = pitch * height * cpp;
+
+	xf86DrvMsg(scrn->scrnIndex, X_INFO,
+		   "Allocate new frame buffer %dx%d stride %d\n",
+		   width, height, pitch);
+
+	old_width = scrn->virtualX;
+	old_height = scrn->virtualY;
+	old_pitch = scrn->displayWidth;
+	old_fb_id = drmmode->fb_id;
+	old_front = info->front_bo;
+
+	scrn->virtualX = width;
+	scrn->virtualY = height;
+	scrn->displayWidth = pitch;
+
+	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
+	if (!info->front_bo)
+		goto fail;
+
+	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
+			   scrn->bitsPerPixel, pitch * cpp,
+			   info->front_bo->handle,
+			   &drmmode->fb_id);
+	if (ret)
+		goto fail;
+
+	radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), info->front_bo);
+	screen->ModifyPixmapHeader(screen->GetScreenPixmap(screen),
+				   width, height, -1, -1, pitch * cpp, NULL);
+
+	//	xf86DrvMsg(scrn->scrnIndex, X_INFO, "New front buffer at 0x%lx\n",
+	//		   info->front_bo-);
+
+	for (i = 0; i < xf86_config->num_crtc; i++) {
+		xf86CrtcPtr crtc = xf86_config->crtc[i];
+
+		if (!crtc->enabled)
+			continue;
+
+		drmmode_set_mode_major(crtc, &crtc->mode,
+				       crtc->rotation, crtc->x, crtc->y);
+	}
+
+	if (old_fb_id)
+		drmModeRmFB(drmmode->fd, old_fb_id);
+	if (old_front)
+		radeon_bo_unref(old_front);
+
+	return TRUE;
+
+ fail:
+	if (info->front_bo)
+		radeon_bo_unref(info->front_bo);
+	info->front_bo = old_front;
+	scrn->virtualX = old_width;
+	scrn->virtualY = old_height;
+	scrn->displayWidth = old_pitch;
+	drmmode->fb_id = old_fb_id;
+
+	return FALSE;
+}
+
+static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
+	drmmode_xf86crtc_resize
+};
+
+
+Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, char *busId, char *driver_name, int cpp, int zaphod_mask)
+{
+	xf86CrtcConfigPtr   xf86_config;
+	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+	int i;
+	Bool ret;
+
+	/* Create a bus Id */
+	/* Low level DRM open */
+	if (!pRADEONEnt->fd) {
+		ret = DRIOpenDRMMaster(pScrn, SAREA_MAX, busId, driver_name);
+		if (!ret) {
+			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+				   "[dri] DRIGetVersion failed to open the DRM\n"
+				   "[dri] Disabling DRI.\n");
+			return FALSE;
+		}
+
+		drmmode->fd = DRIMasterFD(pScrn);
+		pRADEONEnt->fd = drmmode->fd;
+	} else {
+		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+				" reusing fd for second head\n");
+		drmmode->fd = pRADEONEnt->fd;
+	}
+	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
+	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+	drmmode->cpp = cpp;
+	drmmode->mode_res = drmModeGetResources(drmmode->fd);
+	if (!drmmode->mode_res)
+		return FALSE;
+
+	xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
+	for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
+		if (zaphod_mask & (1 << i))
+			drmmode_crtc_init(pScrn, drmmode, i);
+
+	for (i = 0; i < drmmode->mode_res->count_connectors; i++)
+		if (zaphod_mask & (1 << i))
+			drmmode_output_init(pScrn, drmmode, i);
+
+	xf86InitialConfiguration(pScrn, TRUE);
+
+	return TRUE;
+}
+
+Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
+{
+	drmmode->bufmgr = bufmgr;
+	return TRUE;
+}
+
+
+
+void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
+{
+	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+	xf86CrtcPtr crtc = xf86_config->crtc[id];
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+	drmmode_crtc->cursor_bo = bo;
+}
+
+void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y, int flags)
+{
+	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
+	xf86OutputPtr  output = config->output[config->compat_output];
+	xf86CrtcPtr	crtc = output->crtc;
+
+	if (crtc && crtc->enabled) {
+		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
+				       x, y);
+	}
+}
+
+Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
+{
+	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
+	int c;
+
+	drmmode_copy_fb(pScrn, drmmode);
+
+	for (c = 0; c < config->num_crtc; c++) {
+		xf86CrtcPtr	crtc = config->crtc[c];
+		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+		xf86OutputPtr	output = NULL;
+		int		o;
+
+		/* Skip disabled CRTCs */
+		if (!crtc->enabled) {
+			drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+				       0, 0, 0, NULL, 0, NULL);
+			continue;
+		}
+
+		if (config->output[config->compat_output]->crtc == crtc)
+			output = config->output[config->compat_output];
+		else
+		{
+			for (o = 0; o < config->num_output; o++)
+				if (config->output[o]->crtc == crtc)
+				{
+					output = config->output[o];
+					break;
+				}
+		}
+		/* paranoia */
+		if (!output)
+			continue;
+
+		/* Mark that we'll need to re-set the mode for sure */
+		memset(&crtc->mode, 0, sizeof(crtc->mode));
+		if (!crtc->desiredMode.CrtcHDisplay)
+		{
+			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
+
+			if (!mode)
+				return FALSE;
+			crtc->desiredMode = *mode;
+			crtc->desiredRotation = RR_Rotate_0;
+			crtc->desiredX = 0;
+			crtc->desiredY = 0;
+		}
+
+		if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
+						 crtc->desiredX, crtc->desiredY))
+			return FALSE;
+	}
+	return TRUE;
+}
+
+static void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
+                                 int *indices, LOCO *colors, VisualPtr pVisual)
+{
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    uint16_t       lut_r[256], lut_g[256], lut_b[256];
+    int index, j, i;
+    int c;
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+        xf86CrtcPtr crtc = xf86_config->crtc[c];
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+        for (i = 0 ; i < 256; i++) {
+            lut_r[i] = drmmode_crtc->lut_r[i] << 6;
+            lut_g[i] = drmmode_crtc->lut_g[i] << 6;
+            lut_b[i] = drmmode_crtc->lut_b[i] << 6;
+        }
+
+        switch(pScrn->depth) {
+        case 15:
+            for (i = 0; i < numColors; i++) {
+                index = indices[i];
+                for (j = 0; j < 8; j++) {
+                    lut_r[index * 8 + j] = colors[index].red << 6;
+                    lut_g[index * 8 + j] = colors[index].green << 6;
+                    lut_b[index * 8 + j] = colors[index].blue << 6;
+                }
+            }
+         break;
+         case 16:
+             for (i = 0; i < numColors; i++) {
+                 index = indices[i];
+
+                  if (i <= 31) {
+                      for (j = 0; j < 8; j++) {
+                          lut_r[index * 8 + j] = colors[index].red << 6;
+                          lut_b[index * 8 + j] = colors[index].blue << 6;
+                      }
+                  }
+
+                  for (j = 0; j < 4; j++) {
+                      lut_g[index * 4 + j] = colors[index].green << 6;
+                  }
+              }
+	  break;
+          default:
+              for (i = 0; i < numColors; i++) {
+                  index = indices[i];
+                  lut_r[index] = colors[index].red << 6;
+                  lut_g[index] = colors[index].green << 6;
+                  lut_b[index] = colors[index].blue << 6;
+              }
+              break;
+          }
+
+    /* Make the change through RandR */
+#ifdef RANDR_12_INTERFACE
+        if (crtc->randr_crtc)
+            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
+        else
+#endif
+            crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
+     }
+}
+
+Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
+{
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+                  "Initializing kms color map\n");
+    if (!miCreateDefColormap(pScreen))
+        return FALSE;
+    /* all radeons support 10 bit CLUTs */
+    if (!xf86HandleColormaps(pScreen, 256, 10,
+                             drmmode_load_palette, NULL,
+                             CMAP_PALETTED_TRUECOLOR
+#if 0 /* This option messes up text mode! (eich at suse.de) */
+                             | CMAP_LOAD_EVEN_IF_OFFSCREEN
+#endif
+                             | CMAP_RELOAD_ON_MODE_SWITCH))
+         return FALSE;
+    return TRUE;
+}
+#endif
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
new file mode 100644
index 0000000..b8f921d
--- /dev/null
+++ b/src/drmmode_display.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2007 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *     Dave Airlie <airlied at redhat.com>
+ *
+ */
+#ifndef DRMMODE_DISPLAY_H
+#define DRMMODE_DISPLAY_H
+
+#ifdef XF86DRM_MODE
+
+#include "xf86drmMode.h"
+
+#include "radeon_probe.h"
+
+typedef struct {
+  int fd;
+  int fb_id;
+  drmModeResPtr mode_res;
+  drmModeFBPtr mode_fb;
+  int cpp;
+  struct radeon_bo_manager *bufmgr;
+} drmmode_rec, *drmmode_ptr;
+
+typedef struct {
+
+    drmmode_ptr drmmode;
+    drmModeCrtcPtr mode_crtc;
+    struct radeon_bo *cursor_bo;
+    struct radeon_bo *rotate_bo;
+    int rotate_fb_id;
+    uint16_t lut_r[256], lut_g[256], lut_b[256];
+} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
+
+typedef struct {
+    drmmode_ptr drmmode;
+    int output_id;
+    drmModeConnectorPtr mode_output;
+    drmModeEncoderPtr mode_encoder;
+    drmModePropertyBlobPtr edid_blob;
+    int dpms_enum_id;
+} drmmode_output_private_rec, *drmmode_output_private_ptr;
+
+
+extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, char *busId, char *driver_name, int cpp, int zaphod_mask);
+extern Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr);
+extern void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo);
+void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y, int flags);
+extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
+extern void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
+extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn);
+#endif
+
+#endif
diff --git a/src/pcidb/parse_pci_ids.pl b/src/pcidb/parse_pci_ids.pl
index a3a8af8..d1900a4 100755
--- a/src/pcidb/parse_pci_ids.pl
+++ b/src/pcidb/parse_pci_ids.pl
@@ -33,7 +33,7 @@ print PCICHIPSET "PciChipsets RADEONPciChipsets[] = {\n";
 print PCIDEVICEMATCH "/* This file is autogenerated please do not edit */\n";
 print PCIDEVICEMATCH "static const struct pci_id_match radeon_device_match[] = {\n";
 print RADEONCHIPINFO "/* This file is autogenerated please do not edit */\n";
-print RADEONCHIPINFO "RADEONCardInfo RADEONCards[] = {\n";
+print RADEONCHIPINFO "static RADEONCardInfo RADEONCards[] = {\n";
 while (<CSV>) {
   if ($csv->parse($_)) {
     my @columns = $csv->fields();
diff --git a/src/radeon.h b/src/radeon.h
index 0dce081..82136c8 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -89,6 +89,8 @@
 #ifdef XF86DRM_MODE
 #include "radeon_bo.h"
 #include "radeon_cs.h"
+#include "radeon_dri2.h"
+#include "drmmode_display.h"
 #else
 #include "radeon_dummy_bufmgr.h"
 #endif
@@ -857,6 +859,9 @@ typedef struct {
     RADEONCardType    cardType;            /* Current card is a PCI card */
     struct radeon_cp  *cp;
     struct radeon_dri  *dri;
+#ifdef XF86DRM_MODE
+    struct radeon_dri2  dri2;
+#endif
 #ifdef USE_EXA
     Bool              accelDFS;
 #endif
@@ -972,10 +977,17 @@ typedef struct {
     int can_resize;
     void (*reemit_current2d)(ScrnInfoPtr pScrn, int op); // emit the current 2D state into the IB 
     struct radeon_2d_state state_2d;
+    Bool kms_enabled;
+    struct radeon_bo *front_bo;
 #ifdef XF86DRM_MODE
     struct radeon_bo_manager *bufmgr;
     struct radeon_cs_manager *csm;
     struct radeon_cs *cs;
+
+    struct radeon_bo *cursor_bo[2];
+    uint64_t vram_size;
+    uint64_t gart_size;
+    drmmode_rec drmmode;
 #else
     /* fake bool */
     Bool cs;
@@ -1163,6 +1175,12 @@ extern void RADEONInitMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
 extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
 					 RADEONSavePtr restore);
 
+Bool RADEONGetRec(ScrnInfoPtr pScrn);
+void RADEONFreeRec(ScrnInfoPtr pScrn);
+Bool RADEONPreInitVisual(ScrnInfoPtr pScrn);
+Bool RADEONPreInitWeight(ScrnInfoPtr pScrn);
+
+
 /* radeon_pm.c */
 extern void RADEONPMInit(ScrnInfoPtr pScrn);
 extern void RADEONPMBlockHandler(ScrnInfoPtr pScrn);
diff --git a/src/radeon_accel.c b/src/radeon_accel.c
index 5e24683..79052a1 100644
--- a/src/radeon_accel.c
+++ b/src/radeon_accel.c
@@ -1131,8 +1131,10 @@ void RADEONInit3DEngine(ScrnInfoPtr pScrn)
     if (info->directRenderingEnabled) {
 	drm_radeon_sarea_t *pSAREAPriv;
 
-	pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
-	pSAREAPriv->ctx_owner = DRIGetContext(pScrn->pScreen);
+	if (!info->kms_enabled) {
+	    pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
+	    pSAREAPriv->ctx_owner = DRIGetContext(pScrn->pScreen);
+	}
 	RADEONInit3DEngineCP(pScrn);
     } else
 #endif
diff --git a/src/radeon_chipinfo_gen.h b/src/radeon_chipinfo_gen.h
index bffe88e..641361d 100644
--- a/src/radeon_chipinfo_gen.h
+++ b/src/radeon_chipinfo_gen.h
@@ -1,5 +1,5 @@
 /* This file is autogenerated please do not edit */
-RADEONCardInfo RADEONCards[] = {
+static RADEONCardInfo RADEONCards[] = {
  { 0x3150, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 },
  { 0x3151, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 },
  { 0x3152, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 },
diff --git a/src/radeon_commonfuncs.c b/src/radeon_commonfuncs.c
index 6ea0513..a947143 100644
--- a/src/radeon_commonfuncs.c
+++ b/src/radeon_commonfuncs.c
@@ -811,6 +811,39 @@ static void FUNC_NAME(RADEONInit3DEngine)(ScrnInfoPtr pScrn)
 
 }
 
+#if defined(ACCEL_CP) && defined(XF86DRM_MODE)
+void drmmode_wait_for_vline(ScrnInfoPtr pScrn, PixmapPtr pPix,
+			    int crtc, int start, int stop)
+{
+    RADEONInfoPtr  info = RADEONPTR(pScrn);
+    xf86CrtcConfigPtr  xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    uint32_t offset;
+    drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[crtc]->driver_private;
+    ACCEL_PREAMBLE();
+
+    BEGIN_ACCEL(3);
+
+    if (IS_AVIVO_VARIANT) {
+	uint32_t reg = AVIVO_D1MODE_VLINE_START_END; /* this is just a marker */
+	OUT_ACCEL_REG(reg,
+		      ((start << AVIVO_D1MODE_VLINE_START_SHIFT) |
+		       (stop << AVIVO_D1MODE_VLINE_END_SHIFT) |
+		       AVIVO_D1MODE_VLINE_INV));
+    } else {
+	OUT_ACCEL_REG(RADEON_CRTC_GUI_TRIG_VLINE, /* another placeholder */
+		      ((start << RADEON_CRTC_GUI_TRIG_VLINE_START_SHIFT) |
+		      (stop << RADEON_CRTC_GUI_TRIG_VLINE_END_SHIFT) |
+		      RADEON_CRTC_GUI_TRIG_VLINE_INV));
+    }
+    OUT_ACCEL_REG(RADEON_WAIT_UNTIL, (RADEON_WAIT_CRTC_VLINE |
+				      RADEON_ENG_DISPLAY_SELECT_CRTC0));
+
+    OUT_RING(CP_PACKET3(RADEON_CP_PACKET3_NOP, 0));
+    OUT_RING(drmmode_crtc->mode_crtc->crtc_id);
+    FINISH_ACCEL();
+}
+#endif
+
 /* inserts a wait for vline in the command stream */
 void FUNC_NAME(RADEONWaitForVLine)(ScrnInfoPtr pScrn, PixmapPtr pPix,
 	int crtc, int start, int stop)
@@ -829,16 +862,21 @@ void FUNC_NAME(RADEONWaitForVLine)(ScrnInfoPtr pScrn, PixmapPtr pPix,
     if (!xf86_config->crtc[crtc]->enabled)
 	return;
 
+    if (info->cs) {
+        if (pPix != pScrn->pScreen->GetScreenPixmap(pScrn->pScreen))
+	    return;
+    } else {
 #ifdef USE_EXA
-    if (info->useEXA)
-	offset = exaGetPixmapOffset(pPix);
-    else
+	if (info->useEXA)
+	    offset = exaGetPixmapOffset(pPix);
+	else
 #endif
-	offset = pPix->devPrivate.ptr - info->FB;
+	    offset = pPix->devPrivate.ptr - info->FB;
 
-    /* if drawing to front buffer */
-    if (offset != 0)
-	return;
+	/* if drawing to front buffer */
+	if (offset != 0)
+	    return;
+    }
 
     start = max(start, 0);
     stop = min(stop, xf86_config->crtc[crtc]->mode.VDisplay);
@@ -846,6 +884,13 @@ void FUNC_NAME(RADEONWaitForVLine)(ScrnInfoPtr pScrn, PixmapPtr pPix,
     if (start > xf86_config->crtc[crtc]->mode.VDisplay)
 	return;
 
+#if defined(ACCEL_CP) && defined(XF86DRM_MODE)
+    if (info->kms_enabled) {
+	drmmode_wait_for_vline(pScrn, pPix, crtc, start, stop);
+	return;
+    }
+#endif
+
     BEGIN_ACCEL(2);
 
     if (IS_AVIVO_VARIANT) {
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
new file mode 100644
index 0000000..0a30f8f
--- /dev/null
+++ b/src/radeon_dri2.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2008 Kristian Høgsberg 
+ * Copyright 2008 Jérôme Glisse
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation on the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "radeon.h"
+#include "radeon_dri2.h"
+#include "radeon_version.h"
+
+#ifdef RADEON_DRI2
+
+#if DRI2INFOREC_VERSION >= 1
+#define USE_DRI2_1_1_0
+#endif
+
+struct dri2_buffer_priv {
+    PixmapPtr   pixmap;
+    unsigned int attachment;
+};
+
+
+#ifndef USE_DRI2_1_1_0
+static DRI2BufferPtr
+radeon_dri2_create_buffers(DrawablePtr drawable,
+                           unsigned int *attachments,
+                           int count)
+{
+    ScreenPtr pScreen = drawable->pScreen;
+    DRI2BufferPtr buffers;
+    struct dri2_buffer_priv *privates;
+    PixmapPtr pixmap, depth_pixmap;
+    struct radeon_exa_pixmap_priv *driver_priv;
+    int i, r;
+
+    buffers = xcalloc(count, sizeof *buffers);
+    if (buffers == NULL) {
+        return NULL;
+    }
+    privates = xcalloc(count, sizeof(struct dri2_buffer_priv));
+    if (privates == NULL) {
+        xfree(buffers);
+        return NULL;
+    }
+
+    depth_pixmap = NULL;
+    for (i = 0; i < count; i++) {
+        if (attachments[i] == DRI2BufferFrontLeft) {
+            if (drawable->type == DRAWABLE_PIXMAP) {
+                pixmap = (Pixmap*)drawable;
+            } else {
+                pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
+            }
+            pixmap->refcnt++;
+        } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) {
+            pixmap = depth_pixmap;
+            pixmap->refcnt++;
+        } else {
+            pixmap = (*pScreen->CreatePixmap)(pScreen,
+                                              drawable->width,
+                                              drawable->height,
+                                              drawable->depth,
+                                              0);
+        }
+
+        if (attachments[i] == DRI2BufferDepth) {
+            depth_pixmap = pixmap;
+        }
+        driver_priv = exaGetPixmapDriverPrivate(pixmap);
+	buffers[i].name = radeon_gem_name_bo(driver_priv->bo);
+
+        buffers[i].attachment = attachments[i];
+        buffers[i].pitch = pixmap->devKind;
+        buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
+        buffers[i].driverPrivate = &privates[i];
+        buffers[i].flags = 0;
+        privates[i].pixmap = pixmap;
+        privates[i].attachment = attachments[i];
+    }
+    return buffers;
+}
+#else
+static DRI2BufferPtr
+radeon_dri2_create_buffer(DrawablePtr drawable,
+                          unsigned int attachment,
+                          unsigned int format)
+{
+    ScreenPtr pScreen = drawable->pScreen;
+    DRI2BufferPtr buffers;
+    struct dri2_buffer_priv *privates;
+    PixmapPtr pixmap, depth_pixmap;
+    struct radeon_exa_pixmap_priv *driver_priv;
+    int r;
+
+    buffers = xcalloc(1, sizeof *buffers);
+    if (buffers == NULL) {
+        return NULL;
+    }
+    privates = xcalloc(1, sizeof(struct dri2_buffer_priv));
+    if (privates == NULL) {
+        xfree(buffers);
+        return NULL;
+    }
+
+    depth_pixmap = NULL;
+
+    if (attachment == DRI2BufferFrontLeft) {
+        if (drawable->type == DRAWABLE_PIXMAP) {
+            pixmap = (PixmapPtr)drawable;
+        } else {
+            pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable);
+        }
+        pixmap->refcnt++;
+    } else if (attachment == DRI2BufferStencil && depth_pixmap) {
+        pixmap = depth_pixmap;
+        pixmap->refcnt++;
+    } else {
+        pixmap = (*pScreen->CreatePixmap)(pScreen,
+                drawable->width,
+                drawable->height,
+                (format != 0)?format:drawable->depth,
+                0);
+    }
+
+    if (attachment == DRI2BufferDepth) {
+        depth_pixmap = pixmap;
+    }
+    driver_priv = exaGetPixmapDriverPrivate(pixmap);
+    buffers->name = radeon_bo_name_bo(driver_priv->bo);
+    buffers->attachment = attachment;
+    buffers->pitch = pixmap->devKind;
+    buffers->cpp = pixmap->drawable.bitsPerPixel / 8;
+    buffers->driverPrivate = privates;
+    buffers->format = format;
+    buffers->flags = 0; /* not tiled */
+    privates->pixmap = pixmap;
+    privates->attachment = attachment;
+
+    return buffers;
+}
+#endif
+
+#ifndef USE_DRI2_1_1_0
+static void
+radeon_dri2_destroy_buffers(DrawablePtr drawable,
+                            DRI2BufferPtr buffers,
+                            int count)
+{
+    ScreenPtr pScreen = drawable->pScreen;
+    struct dri2_buffer_priv *private;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        private = buffers[i].driverPrivate;
+        (*pScreen->DestroyPixmap)(private->pixmap);
+    }
+    if (buffers) {
+        xfree(buffers[0].driverPrivate);
+        xfree(buffers);
+    }
+}
+#else
+static void
+radeon_dri2_destroy_buffer(DrawablePtr drawable, DRI2BufferPtr buffers)
+{
+    if(buffers)
+    {
+        ScreenPtr pScreen = drawable->pScreen;
+        struct dri2_buffer_priv *private;
+
+        private = buffers->driverPrivate;
+        (*pScreen->DestroyPixmap)(private->pixmap);
+
+        xfree(buffers->driverPrivate);
+        xfree(buffers);
+    }
+}
+#endif
+
+static void
+radeon_dri2_copy_region(DrawablePtr drawable,
+                        RegionPtr region,
+                        DRI2BufferPtr dest_buffer,
+                        DRI2BufferPtr src_buffer)
+{
+    struct dri2_buffer_priv *src_private = src_buffer->driverPrivate;
+    struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate;
+    ScreenPtr pScreen = drawable->pScreen;
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    PixmapPtr src_pixmap;
+    PixmapPtr dst_pixmap;
+    RegionPtr copy_clip;
+    GCPtr gc;
+
+    src_pixmap = src_private->pixmap;
+    dst_pixmap = dst_private->pixmap;
+    if (src_private->attachment == DRI2BufferFrontLeft) {
+        src_pixmap = (PixmapPtr)drawable;
+    }
+    if (dst_private->attachment == DRI2BufferFrontLeft) {
+        dst_pixmap = (PixmapPtr)drawable;
+    }
+    gc = GetScratchGC(drawable->depth, pScreen);
+    copy_clip = REGION_CREATE(pScreen, NULL, 0);
+    REGION_COPY(pScreen, copy_clip, region);
+    (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0);
+    ValidateGC(&dst_pixmap->drawable, gc);
+    (*gc->ops->CopyArea)(&src_pixmap->drawable, &dst_pixmap->drawable, gc,
+                         0, 0, drawable->width, drawable->height, 0, 0);
+    FreeScratchGC(gc);
+    radeon_cs_flush_indirect(pScrn);
+}
+
+Bool
+radeon_dri2_screen_init(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    DRI2InfoRec dri2_info;
+    int fd;
+    char *bus_id;
+    char *tmp_bus_id;
+    int cmp;
+    int i;
+
+    if (!info->useEXA) {
+        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requires EXA\n");
+        return FALSE;
+    }
+
+    /* The whole drmOpen thing is a fiasco and we need to find a way
+     * back to just using open(2).  For now, however, lets just make
+     * things worse with even more ad hoc directory walking code to
+     * discover the device file name. */
+    bus_id = DRICreatePCIBusID(info->PciInfo);
+    for (i = 0; i < DRM_MAX_MINOR; i++) {
+        sprintf(info->dri2.device_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
+        fd = open(info->dri2.device_name, O_RDWR);
+        if (fd < 0)
+            continue;
+
+        tmp_bus_id = drmGetBusid(fd);
+        close(fd);
+        if (tmp_bus_id == NULL)
+            continue;
+
+        cmp = strcmp(tmp_bus_id, bus_id);
+        drmFree(tmp_bus_id);
+        if (cmp == 0)
+            break;
+    }
+    xfree(bus_id);
+
+    if (i == DRM_MAX_MINOR) {
+        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                   "DRI2: failed to open drm device\n");
+        return FALSE;
+    }
+
+    if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) {
+        dri2_info.driverName = R300_DRIVER_NAME;
+    } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) {
+        dri2_info.driverName = R200_DRIVER_NAME;
+    } else {
+        dri2_info.driverName = RADEON_DRIVER_NAME;
+    }
+    dri2_info.fd = info->dri2.drm_fd;
+    dri2_info.deviceName = info->dri2.device_name;
+#ifndef USE_DRI2_1_1_0
+    dri2_info.version = 1;
+    dri2_info.CreateBuffers = radeon_dri2_create_buffers;
+    dri2_info.DestroyBuffers = radeon_dri2_destroy_buffers;
+#else
+    dri2_info.version = 2;
+    dri2_info.CreateBuffer = radeon_dri2_create_buffer;
+    dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer;
+#endif
+    dri2_info.CopyRegion = radeon_dri2_copy_region;
+    info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info);
+    return info->dri2.enabled;
+}
+
+void radeon_dri2_close_screen(ScreenPtr pScreen)
+{
+    DRI2CloseScreen(pScreen);
+}
+
+#endif
diff --git a/src/radeon_dri2.h b/src/radeon_dri2.h
new file mode 100644
index 0000000..899a626
--- /dev/null
+++ b/src/radeon_dri2.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Jerome Glisse
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation on the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef RADEON_DRI2_H
+#define RADEON_DRI2_H
+
+struct radeon_dri2 {
+    int         drm_fd;
+    Bool        enabled;
+    char        device_name[64];
+};
+
+#ifdef RADEON_DRI2
+#include "dri2.h"
+Bool radeon_dri2_screen_init(ScreenPtr pScreen);
+void radeon_dri2_close_screen(ScreenPtr pScreen);
+#endif
+
+#endif
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 9a1d4d7..317612d 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -340,7 +340,7 @@ RADEONPostInt10Check(ScrnInfoPtr pScrn, void *ptr)
 }
 
 /* Allocate our private RADEONInfoRec */
-static Bool RADEONGetRec(ScrnInfoPtr pScrn)
+Bool RADEONGetRec(ScrnInfoPtr pScrn)
 {
     if (pScrn->driverPrivate) return TRUE;
 
@@ -349,7 +349,7 @@ static Bool RADEONGetRec(ScrnInfoPtr pScrn)
 }
 
 /* Free our private RADEONInfoRec */
-static void RADEONFreeRec(ScrnInfoPtr pScrn)
+void RADEONFreeRec(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr  info;
     int i;
@@ -1251,7 +1251,7 @@ static void RADEONGetClockInfo(ScrnInfoPtr pScrn)
 
 
 /* This is called by RADEONPreInit to set up the default visual */
-static Bool RADEONPreInitVisual(ScrnInfoPtr pScrn)
+Bool RADEONPreInitVisual(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr  info = RADEONPTR(pScrn);
 
@@ -1308,7 +1308,7 @@ static Bool RADEONPreInitVisual(ScrnInfoPtr pScrn)
 }
 
 /* This is called by RADEONPreInit to handle all color weight issues */
-static Bool RADEONPreInitWeight(ScrnInfoPtr pScrn)
+Bool RADEONPreInitWeight(ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr  info = RADEONPTR(pScrn);
 
@@ -2813,6 +2813,7 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
 
     info->IsSecondary  = FALSE;
     info->IsPrimary = FALSE;
+    info->kms_enabled = FALSE;
 
     info->pEnt         = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
     if (info->pEnt->location.type != BUS_PCI) goto fail;
@@ -5627,7 +5628,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
         RADEONRestoreSurfaces(pScrn, info->ModeReg);
 #ifdef XF86DRI
     if (info->directRenderingEnabled) {
-    	if (info->cardType == CARD_PCIE &&
+	if (info->cardType == CARD_PCIE &&
 	    info->dri->pKernelDRMVersion->version_minor >= 19 &&
 	    info->FbSecureSize) {
 #if X_BYTE_ORDER == X_BIG_ENDIAN
@@ -5641,7 +5642,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
 #if X_BYTE_ORDER == X_BIG_ENDIAN
 	    OUTREG(RADEON_SURFACE_CNTL, sctrl);
 #endif
-    	}
+	}
 
 	/* get the DRI back into shape after resume */
 	RADEONDRISetVBlankInterrupt (pScrn, TRUE);
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index 5b20eca..9444da3 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -344,7 +344,7 @@ static Bool RADEONPrepareAccess_CS(PixmapPtr pPix, int index)
 
     /* if we have more refs than just the BO then flush */
     if (driver_priv->bo->cref > 1)
-      RADEONCPFlushIndirect(pScrn, 0);
+      radeon_cs_flush_indirect(pScrn);
     
     radeon_bo_wait(driver_priv->bo);
 
@@ -387,7 +387,7 @@ void *RADEONEXACreatePixmap(ScreenPtr pScreen, int size, int align)
 	return new_priv;
 
     new_priv->bo = radeon_bo_open(info->bufmgr, 0, size,
-				align, 0, 0);
+				  align, 0, 0);
     if (!new_priv->bo) {
 	xfree(new_priv);
 	ErrorF("Failed to alloc memory\n");
@@ -404,6 +404,9 @@ static void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
     RADEONInfoPtr info = RADEONPTR(pScrn);
     struct radeon_exa_pixmap_priv *driver_priv = driverPriv;
 
+    if (!driverPriv)
+      return;
+
     radeon_bo_unref(driver_priv->bo);
     xfree(driverPriv);
 }
diff --git a/src/radeon_exa_funcs.c b/src/radeon_exa_funcs.c
index 42a5ebc..5b72360 100644
--- a/src/radeon_exa_funcs.c
+++ b/src/radeon_exa_funcs.c
@@ -376,7 +376,7 @@ RADEONUploadToScreenCP(PixmapPtr pDst, int x, int y, int w, int h,
 
     TRACE;
 
-    if (info->cs)
+    if (info->kms_enabled)
 	return FALSE;
 
     if (bpp < 8)
@@ -454,6 +454,9 @@ RADEONDownloadFromScreenCP(PixmapPtr pSrc, int x, int y, int w, int h,
 
     TRACE;
 
+    if (info->kms_enabled)
+      return FALSE;
+
     /*
      * Try to accelerate download. Use an indirect buffer as scratch space,
      * blitting the bits to one half while copying them out of the other one and
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
new file mode 100644
index 0000000..9fc6643
--- /dev/null
+++ b/src/radeon_kms.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright © 2009 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Dave Airlie <airlied at redhat.com>
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <sys/ioctl.h>
+/* Driver data structures */
+#include "radeon.h"
+#include "radeon_reg.h"
+#include "radeon_probe.h"
+#include "micmap.h"
+
+#include "shadow.h"
+
+#include "atipciids.h"
+
+
+
+#ifdef XF86DRM_MODE
+
+#include "radeon_chipset_gen.h"
+#include "radeon_chipinfo_gen.h"
+
+#define CURSOR_WIDTH	64
+#define CURSOR_HEIGHT	64
+
+#include "radeon_bo_gem.h"
+#include "radeon_cs_gem.h"
+static Bool radeon_setup_kernel_mem(ScreenPtr pScreen);
+
+const OptionInfoRec RADEONOptions_KMS[] = {
+    { OPTION_NOACCEL,        "NoAccel",          OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_SW_CURSOR,      "SWcursor",         OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_PAGE_FLIP,      "EnablePageFlip",   OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_ACCEL_DFS,      "AccelDFS",         OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_IGNORE_EDID,    "IgnoreEDID",       OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_COLOR_TILING,   "ColorTiling",      OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_RENDER_ACCEL,   "RenderAccel",      OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_SUBPIXEL_ORDER, "SubPixelOrder",    OPTV_ANYSTR,  {0}, FALSE },
+    { OPTION_ACCELMETHOD,    "AccelMethod",      OPTV_STRING,  {0}, FALSE },
+    { OPTION_DRI,            "DRI",       	 OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_TVSTD,          "TVStandard",         OPTV_STRING,  {0}, FALSE },
+    { OPTION_EXA_VSYNC,         "EXAVSync",        OPTV_BOOLEAN, {0}, FALSE },
+    { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
+};
+
+extern _X_EXPORT int gRADEONEntityIndex;
+
+static int getRADEONEntityIndex(void)
+{
+    return gRADEONEntityIndex;
+}
+
+static void *
+radeonShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode,
+		   CARD32 *size, void *closure)
+{
+    ScrnInfoPtr pScrn = xf86Screens[screen->myNum];
+    RADEONInfoPtr  info   = RADEONPTR(pScrn);
+    int stride;
+
+    stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8;
+    *size = stride;
+
+    return ((uint8_t *)info->front_bo->ptr + row * stride + offset);
+}
+
+static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    RADEONInfoPtr  info   = RADEONPTR(pScrn);
+    PixmapPtr pixmap;
+
+    pScreen->CreateScreenResources = info->CreateScreenResources;
+    if (!(*pScreen->CreateScreenResources)(pScreen))
+	return FALSE;
+    pScreen->CreateScreenResources = RADEONCreateScreenResources_KMS;
+
+    if (info->r600_shadow_fb) {
+	pixmap = pScreen->GetScreenPixmap(pScreen);
+
+	if (!shadowAdd(pScreen, pixmap, shadowUpdatePackedWeak(),
+		       radeonShadowWindow, 0, NULL))
+	    return FALSE;
+    }
+
+    if (info->dri2.enabled) {
+	if (info->front_bo) {
+	    PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
+	    radeon_set_pixmap_bo(pPix, info->front_bo);
+	}
+    }
+    return TRUE;
+}
+
+static void RADEONBlockHandler_KMS(int i, pointer blockData,
+				   pointer pTimeout, pointer pReadmask)
+{
+    ScreenPtr      pScreen = screenInfo.screens[i];
+    ScrnInfoPtr    pScrn   = xf86Screens[i];
+    RADEONInfoPtr  info    = RADEONPTR(pScrn);
+
+    pScreen->BlockHandler = info->BlockHandler;
+    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+    pScreen->BlockHandler = RADEONBlockHandler_KMS;
+
+    if (info->VideoTimerCallback)
+	(*info->VideoTimerCallback)(pScrn, currentTime.milliseconds);
+
+    info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
+    radeon_cs_flush_indirect(pScrn);
+}
+
+static Bool RADEONPreInitAccel_KMS(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info = RADEONPTR(pScrn);
+
+    if (!(info->accel_state = xcalloc(1, sizeof(struct radeon_accel_state)))) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to allocate accel_state rec!\n");
+	return FALSE;
+    }
+    info->accel_state->fifo_slots                 = 0;
+
+    if (info->ChipFamily >= CHIP_FAMILY_R600) {
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "Using shadowfb for KMS on R600+\n");
+	info->r600_shadow_fb = TRUE;
+	if (!xf86LoadSubModule(pScrn, "shadow"))
+	    info->r600_shadow_fb = FALSE;
+	return TRUE;
+    }
+
+
+    if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
+	(info->ChipFamily == CHIP_FAMILY_RS200) ||
+	(info->ChipFamily == CHIP_FAMILY_RS300) ||
+	(info->ChipFamily == CHIP_FAMILY_RS400) ||
+	(info->ChipFamily == CHIP_FAMILY_RS480) ||
+	(info->ChipFamily == CHIP_FAMILY_RS600) ||
+	(info->ChipFamily == CHIP_FAMILY_RS690) ||
+	(info->ChipFamily == CHIP_FAMILY_RS740))
+	info->accel_state->has_tcl = FALSE;
+    else {
+	info->accel_state->has_tcl = TRUE;
+    }
+
+    info->useEXA = TRUE;
+
+    if (info->useEXA) {
+	int errmaj = 0, errmin = 0;
+	info->exaReq.majorversion = EXA_VERSION_MAJOR;
+	info->exaReq.minorversion = EXA_VERSION_MINOR;
+	if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL,
+			   &info->exaReq, &errmaj, &errmin)) {
+	    LoaderErrorMsg(NULL, "exa", errmaj, errmin);
+	    return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+static Bool RADEONPreInitChipType_KMS(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info   = RADEONPTR(pScrn);
+    uint32_t cmd_stat;
+    int i;
+
+    info->Chipset = PCI_DEV_DEVICE_ID(info->PciInfo);
+    pScrn->chipset = (char *)xf86TokenToString(RADEONChipsets, info->Chipset);
+    if (!pScrn->chipset) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "ChipID 0x%04x is not recognized\n", info->Chipset);
+	return FALSE;
+    }
+
+    if (info->Chipset < 0) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "Chipset \"%s\" is not recognized\n", pScrn->chipset);
+	return FALSE;
+    }
+    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+	       "Chipset: \"%s\" (ChipID = 0x%04x)\n",
+	       pScrn->chipset,
+	       info->Chipset);
+
+    for (i = 0; i < sizeof(RADEONCards) / sizeof(RADEONCardInfo); i++) {
+	if (info->Chipset == RADEONCards[i].pci_device_id) {
+	    RADEONCardInfo *card = &RADEONCards[i];
+	    info->ChipFamily = card->chip_family;
+	    info->IsMobility = card->mobility;
+	    info->IsIGP = card->igp;
+	    break;
+	}
+    }
+
+    info->cardType = CARD_PCI;
+
+    PCI_READ_LONG(info->PciInfo, &cmd_stat, PCI_CMD_STAT_REG);
+    if (cmd_stat & RADEON_CAP_LIST) {
+	uint32_t cap_ptr, cap_id;
+
+	PCI_READ_LONG(info->PciInfo, &cap_ptr, RADEON_CAPABILITIES_PTR_PCI_CONFIG);
+	cap_ptr &= RADEON_CAP_PTR_MASK;
+
+	while(cap_ptr != RADEON_CAP_ID_NULL) {
+	    PCI_READ_LONG(info->PciInfo, &cap_id, cap_ptr);
+	    if ((cap_id & 0xff)== RADEON_CAP_ID_AGP) {
+		info->cardType = CARD_AGP;
+		break;
+	    }
+	    if ((cap_id & 0xff)== RADEON_CAP_ID_EXP) {
+		info->cardType = CARD_PCIE;
+		break;
+	    }
+	    cap_ptr = (cap_id >> 8) & RADEON_CAP_PTR_MASK;
+	}
+    }
+
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s card detected\n",
+	       (info->cardType==CARD_PCI) ? "PCI" :
+		(info->cardType==CARD_PCIE) ? "PCIE" : "AGP");
+
+    /* treat PCIE IGP cards as PCI */
+    if (info->cardType == CARD_PCIE && info->IsIGP)
+	info->cardType = CARD_PCI;
+
+    if ((info->ChipFamily >= CHIP_FAMILY_R600) && info->IsIGP)
+	info->cardType = CARD_PCIE;
+
+    /* not sure about gart table requirements */
+    if ((info->ChipFamily == CHIP_FAMILY_RS600) && info->IsIGP)
+	info->cardType = CARD_PCIE;
+
+#ifdef RENDER
+    info->RenderAccel = xf86ReturnOptValBool(info->Options, OPTION_RENDER_ACCEL,
+					     info->Chipset != PCI_CHIP_RN50_515E &&
+					     info->Chipset != PCI_CHIP_RN50_5969);
+#endif
+    return TRUE;
+}
+
+static Bool radeon_alloc_dri(ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr  info   = RADEONPTR(pScrn);
+    if (!(info->dri = xcalloc(1, sizeof(struct radeon_dri)))) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"Unable to allocate dri rec!\n");
+	return FALSE;
+    }
+
+    if (!(info->cp = xcalloc(1, sizeof(struct radeon_cp)))) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,"Unable to allocate cp rec!\n");
+	return FALSE;
+    }
+    return TRUE;
+}
+
+Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
+{
+    RADEONInfoPtr     info;
+    RADEONEntPtr pRADEONEnt;
+    DevUnion* pPriv;
+    int zaphod_mask = 0;
+    char *bus_id;
+    Gamma  zeros = { 0.0, 0.0, 0.0 };
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONPreInit_KMS\n");
+    if (pScrn->numEntities != 1) return FALSE;
+    if (!RADEONGetRec(pScrn)) return FALSE;
+
+    info               = RADEONPTR(pScrn);
+    info->MMIO         = NULL;
+    info->IsSecondary  = FALSE;
+    info->IsPrimary = FALSE;
+    info->kms_enabled = TRUE;
+    info->pEnt         = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
+    if (info->pEnt->location.type != BUS_PCI) goto fail;
+
+    pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+				 getRADEONEntityIndex());
+    pRADEONEnt = pPriv->ptr;
+
+    if(xf86IsEntityShared(pScrn->entityList[0]))
+    {
+        if(xf86IsPrimInitDone(pScrn->entityList[0]))
+        {
+            info->IsSecondary = TRUE;
+            pRADEONEnt->pSecondaryScrn = pScrn;
+        }
+        else
+        {
+	    info->IsPrimary = TRUE;
+            xf86SetPrimInitDone(pScrn->entityList[0]);
+            pRADEONEnt->pPrimaryScrn = pScrn;
+            pRADEONEnt->HasSecondary = FALSE;
+        }
+    }
+
+    info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index);
+    pScrn->monitor     = pScrn->confScreen->monitor;
+
+    if (!RADEONPreInitVisual(pScrn))
+	goto fail;
+
+    xf86CollectOptions(pScrn, NULL);
+    if (!(info->Options = xalloc(sizeof(RADEONOptions_KMS))))
+	goto fail;
+
+    memcpy(info->Options, RADEONOptions_KMS, sizeof(RADEONOptions_KMS));
+    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
+
+    if (!RADEONPreInitWeight(pScrn))
+	goto fail;
+
+    if (!RADEONPreInitChipType_KMS(pScrn))
+        goto fail;
+
+    if (!radeon_alloc_dri(pScrn))
+	return FALSE;
+
+    zaphod_mask = 0xf;
+    if (info->IsPrimary)
+	zaphod_mask = 0xd;
+    if (info->IsSecondary)
+	zaphod_mask = 0x2;
+
+    bus_id = DRICreatePCIBusID(info->PciInfo);
+    if (drmmode_pre_init(pScrn, &info->drmmode, bus_id, "radeon", pScrn->bitsPerPixel / 8, zaphod_mask) == FALSE) {
+	xfree(bus_id);
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n");
+	goto fail;
+    }
+
+    info->dri->drmFD = info->drmmode.fd;
+    info->dri2.drm_fd = info->drmmode.fd;
+    info->dri2.enabled = FALSE;
+    xfree(bus_id);
+    info->dri->pKernelDRMVersion = drmGetVersion(info->dri->drmFD);
+    if (info->dri->pKernelDRMVersion == NULL) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "RADEONDRIGetVersion failed to get the DRM version\n");
+	goto fail;
+    }
+
+    {
+	struct drm_radeon_gem_info mminfo;
+
+	if (!drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)))
+	{
+	    info->vram_size = mminfo.vram_visible;
+	    info->gart_size = mminfo.gart_size;
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n",
+		       mminfo.gart_size, mminfo.vram_size, mminfo.vram_visible);
+	}
+    }
+
+    if (info->ChipFamily < CHIP_FAMILY_R600) {
+	info->useEXA = TRUE;
+	info->directRenderingEnabled = TRUE;
+    }
+
+    RADEONSetPitch(pScrn);
+
+    /* Set display resolution */
+    xf86SetDpi(pScrn, 0, 0);
+
+	/* Get ScreenInit function */
+    if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
+
+    if (!xf86SetGamma(pScrn, zeros)) return FALSE;
+
+    if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
+	if (!xf86LoadSubModule(pScrn, "ramdac")) return FALSE;
+    }
+
+    if (!RADEONPreInitAccel_KMS(pScrn))              goto fail;
+
+    if (pScrn->modes == NULL) {
+      xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+      goto fail;
+   }
+
+    return TRUE;
+ fail:
+    RADEONFreeRec(pScrn);
+    return FALSE;
+
+}
+
+static Bool RADEONCursorInit_KMS(ScreenPtr pScreen)
+{
+    return xf86_cursors_init (pScreen, CURSOR_WIDTH, CURSOR_HEIGHT,
+			      (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
+			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
+			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
+			       HARDWARE_CURSOR_ARGB));
+}
+
+static Bool RADEONSaveScreen_KMS(ScreenPtr pScreen, int mode)
+{
+    ScrnInfoPtr  pScrn = xf86Screens[pScreen->myNum];
+    Bool         unblank;
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONSaveScreen(%d)\n", mode);
+
+    unblank = xf86IsUnblank(mode);
+    if (unblank) SetTimeSinceLastInputEvent();
+
+    if ((pScrn != NULL) && pScrn->vtSema) {
+	if (unblank)
+	    RADEONUnblank(pScrn);
+	else
+	    RADEONBlank(pScrn);
+    }
+    return TRUE;
+}
+
+/* Called at the end of each server generation.  Restore the original
+ * text mode, unmap video memory, and unwrap and call the saved
+ * CloseScreen function.
+ */
+static Bool RADEONCloseScreen_KMS(int scrnIndex, ScreenPtr pScreen)
+{
+    ScrnInfoPtr    pScrn = xf86Screens[scrnIndex];
+    RADEONInfoPtr  info  = RADEONPTR(pScrn);
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONCloseScreen\n");
+
+    if (info->accel_state->exa) {
+	exaDriverFini(pScreen);
+	xfree(info->accel_state->exa);
+	info->accel_state->exa = NULL;
+    }
+
+    if (info->cursor) xf86DestroyCursorInfoRec(info->cursor);
+    info->cursor = NULL;
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Disposing DGA\n");
+    if (info->DGAModes) xfree(info->DGAModes);
+    info->DGAModes = NULL;
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Unmapping memory\n");
+
+    pScrn->vtSema = FALSE;
+    xf86ClearPrimInitDone(info->pEnt->index);
+    pScreen->BlockHandler = info->BlockHandler;
+    pScreen->CloseScreen = info->CloseScreen;
+    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+
+void RADEONFreeScreen_KMS(int scrnIndex, int flags)
+{
+    ScrnInfoPtr  pScrn = xf86Screens[scrnIndex];
+    RADEONInfoPtr  info  = RADEONPTR(pScrn);
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONFreeScreen\n");
+
+    /* when server quits at PreInit, we don't need do this anymore*/
+    if (!info) return;
+
+    RADEONFreeRec(pScrn);
+}
+
+Bool RADEONScreenInit_KMS(int scrnIndex, ScreenPtr pScreen,
+			  int argc, char **argv)
+{
+    ScrnInfoPtr    pScrn = xf86Screens[pScreen->myNum];
+    RADEONInfoPtr  info  = RADEONPTR(pScrn);
+    int            subPixelOrder = SubPixelUnknown;
+    char*          s;
+    void *front_ptr;
+
+    pScrn->fbOffset = 0;
+
+    miClearVisualTypes();
+    if (!miSetVisualTypes(pScrn->depth,
+			  miGetDefaultVisualMask(pScrn->depth),
+			  pScrn->rgbBits,
+			  pScrn->defaultVisual)) return FALSE;
+    miSetPixmapDepths ();
+
+    info->directRenderingEnabled = radeon_dri2_screen_init(pScreen);
+
+    front_ptr = info->FB;
+
+    info->bufmgr = radeon_bo_manager_gem_ctor(info->dri->drmFD);
+    if (!info->bufmgr) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "failed to initialise GEM buffer manager");
+	return FALSE;
+    }
+    drmmode_set_bufmgr(pScrn, &info->drmmode, info->bufmgr);
+
+    info->csm = radeon_cs_manager_gem_ctor(info->dri->drmFD);
+    if (!info->csm) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "failed to initialise command submission manager");
+	return FALSE;
+    }
+
+    info->cs = radeon_cs_create(info->csm, RADEON_BUFFER_SIZE/4);
+    if (!info->cs) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "failed to initialise command submission buffer");
+	return FALSE;
+    }
+
+    radeon_cs_set_limit(info->cs, RADEON_GEM_DOMAIN_GTT, info->gart_size);
+
+    radeon_setup_kernel_mem(pScreen);
+    front_ptr = info->front_bo->ptr;
+
+    if (info->r600_shadow_fb) {
+	info->fb_shadow = xcalloc(1,
+				  pScrn->displayWidth * pScrn->virtualY *
+				  ((pScrn->bitsPerPixel + 7) >> 3));
+	if (info->fb_shadow == NULL) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                       "Failed to allocate shadow framebuffer\n");
+	    info->r600_shadow_fb = FALSE;
+	} else {
+	    if (!fbScreenInit(pScreen, info->fb_shadow,
+			      pScrn->virtualX, pScrn->virtualY,
+			      pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
+			      pScrn->bitsPerPixel))
+		return FALSE;
+	}
+    }
+
+    if (info->r600_shadow_fb == FALSE) {
+	/* Init fb layer */
+	if (!fbScreenInit(pScreen, front_ptr,
+			  pScrn->virtualX, pScrn->virtualY,
+			  pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
+			  pScrn->bitsPerPixel))
+	    return FALSE;
+    }
+
+    xf86SetBlackWhitePixels(pScreen);
+
+    if (pScrn->bitsPerPixel > 8) {
+	VisualPtr  visual;
+
+	visual = pScreen->visuals + pScreen->numVisuals;
+	while (--visual >= pScreen->visuals) {
+	    if ((visual->class | DynamicClass) == DirectColor) {
+		visual->offsetRed   = pScrn->offset.red;
+		visual->offsetGreen = pScrn->offset.green;
+		visual->offsetBlue  = pScrn->offset.blue;
+		visual->redMask     = pScrn->mask.red;
+		visual->greenMask   = pScrn->mask.green;
+		visual->blueMask    = pScrn->mask.blue;
+	    }
+	}
+    }
+
+    /* Must be after RGB order fixed */
+    fbPictureInit (pScreen, 0, 0);
+
+#ifdef RENDER
+    if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) {
+	if (strcmp(s, "RGB") == 0) subPixelOrder = SubPixelHorizontalRGB;
+	else if (strcmp(s, "BGR") == 0) subPixelOrder = SubPixelHorizontalBGR;
+	else if (strcmp(s, "NONE") == 0) subPixelOrder = SubPixelNone;
+	PictureSetSubpixelOrder (pScreen, subPixelOrder);
+    }
+#endif
+
+    pScrn->vtSema = TRUE;
+    /* Backing store setup */
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Initializing backing store\n");
+    miInitializeBackingStore(pScreen);
+    xf86SetBackingStore(pScreen);
+
+
+    if (info->directRenderingEnabled) {
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
+    } else {
+	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+		   "Direct rendering disabled\n");
+    }
+
+    if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) {
+	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		       "Initializing Acceleration\n");
+	if (RADEONAccelInit(pScreen)) {
+	    xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n");
+	    info->accelOn = TRUE;
+	} else {
+	    xf86DrvMsg(scrnIndex, X_ERROR,
+		       "Acceleration initialization failed\n");
+	    xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n");
+	    info->accelOn = FALSE;
+	}
+    } else {
+	xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n");
+	info->accelOn = FALSE;
+    }
+
+    /* Init DPMS */
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Initializing DPMS\n");
+    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Initializing Cursor\n");
+
+    /* Set Silken Mouse */
+    xf86SetSilkenMouse(pScreen);
+
+    /* Cursor setup */
+    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+    if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
+	if (RADEONCursorInit_KMS(pScreen)) {
+	}
+    }
+
+    /* DGA setup */
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Initializing DGA\n");
+    RADEONDGAInit(pScreen);
+
+    /* Init Xv */
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Initializing Xv\n");
+    RADEONInitVideo(pScreen);
+
+    if (info->r600_shadow_fb == TRUE) {
+        if (!shadowSetup(pScreen)) {
+            return FALSE;
+        }
+    }
+    pScrn->pScreen = pScreen;
+
+    if (!drmmode_set_desired_modes(pScrn, &info->drmmode))
+	return FALSE;
+
+    /* Provide SaveScreen & wrap BlockHandler and CloseScreen */
+    /* Wrap CloseScreen */
+    info->CloseScreen    = pScreen->CloseScreen;
+    pScreen->CloseScreen = RADEONCloseScreen_KMS;
+    pScreen->SaveScreen  = RADEONSaveScreen_KMS;
+    info->BlockHandler = pScreen->BlockHandler;
+    pScreen->BlockHandler = RADEONBlockHandler_KMS;
+    info->CreateScreenResources = pScreen->CreateScreenResources;
+    pScreen->CreateScreenResources = RADEONCreateScreenResources_KMS;
+
+   if (!xf86CrtcScreenInit (pScreen))
+       return FALSE;
+
+   /* Wrap pointer motion to flip touch screen around */
+//    info->PointerMoved = pScrn->PointerMoved;
+//    pScrn->PointerMoved = RADEONPointerMoved;
+
+    if (!drmmode_setup_colormap(pScreen, pScrn))
+	return FALSE;
+
+   /* Note unused options */
+    if (serverGeneration == 1)
+	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONScreenInit finished\n");
+
+    return TRUE;
+}
+
+Bool RADEONEnterVT_KMS(int scrnIndex, int flags)
+{
+    ScrnInfoPtr    pScrn = xf86Screens[scrnIndex];
+    RADEONInfoPtr  info  = RADEONPTR(pScrn);
+    int ret;
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONEnterVT_KMS\n");
+
+
+    ret = ioctl(info->dri->drmFD, DRM_IOCTL_SET_MASTER, NULL);
+    if (ret == -EINVAL)
+	ErrorF("Unable to retrieve master\n");
+
+    info->accel_state->XInited3D = FALSE;
+    info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
+
+    pScrn->vtSema = TRUE;
+
+    if (!drmmode_set_desired_modes(pScrn, &info->drmmode))
+	return FALSE;
+
+    if (info->adaptor)
+	RADEONResetVideo(pScrn);
+
+    return TRUE;
+}
+
+
+void RADEONLeaveVT_KMS(int scrnIndex, int flags)
+{
+    ScrnInfoPtr    pScrn = xf86Screens[scrnIndex];
+    RADEONInfoPtr  info  = RADEONPTR(pScrn);
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "RADEONLeaveVT_KMS\n");
+
+    ioctl(info->dri->drmFD, DRM_IOCTL_DROP_MASTER, NULL);
+
+#ifdef HAVE_FREE_SHADOW
+    xf86RotateFreeShadow(pScrn);
+#endif
+
+    xf86_hide_cursors (pScrn);
+    info->accel_state->XInited3D = FALSE;
+    info->accel_state->engineMode = EXA_ENGINEMODE_UNKNOWN;
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+		   "Ok, leaving now...\n");
+}
+
+
+Bool RADEONSwitchMode_KMS(int scrnIndex, DisplayModePtr mode, int flags)
+{
+    ScrnInfoPtr    pScrn       = xf86Screens[scrnIndex];
+    Bool ret;
+    ret = xf86SetSingleMode (pScrn, mode, RR_Rotate_0);
+    return ret;
+
+}
+
+void RADEONAdjustFrame_KMS(int scrnIndex, int x, int y, int flags)
+{
+    ScrnInfoPtr    pScrn       = xf86Screens[scrnIndex];
+    RADEONInfoPtr  info        = RADEONPTR(pScrn);
+    drmmode_adjust_frame(pScrn, &info->drmmode, x, y, flags);
+    return;
+}
+
+static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    int cpp = info->CurrentLayout.pixel_bytes;
+    int screen_size;
+    int stride = pScrn->displayWidth * cpp;
+    int total_size_bytes = 0, remain_size_bytes;
+    int pagesize = 4096;
+
+    if (info->accel_state->exa != NULL) {
+	xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map already initialized\n");
+	return FALSE;
+    }
+    info->accel_state->exa = exaDriverAlloc();
+    if (info->accel_state->exa == NULL)
+	return FALSE;
+
+    screen_size = RADEON_ALIGN(pScrn->virtualY, 16) * stride;
+    {
+	int cursor_size = 64 * 4 * 64;
+	int c;
+
+	cursor_size = RADEON_ALIGN(cursor_size, pagesize);
+	for (c = 0; c < xf86_config->num_crtc; c++) {
+	    /* cursor objects */
+	    info->cursor_bo[c] = radeon_bo_open(info->bufmgr, 0, cursor_size,
+					      0, RADEON_GEM_DOMAIN_VRAM, 0);
+	    if (!info->cursor_bo[c]) {
+		return FALSE;
+	    }
+
+	    if (radeon_bo_map(info->cursor_bo[c], 1)) {
+	      ErrorF("Failed to map cursor buffer memory\n");
+	    }
+
+	    drmmode_set_cursor(pScrn, &info->drmmode, c, info->cursor_bo[c]);
+	    total_size_bytes += cursor_size;
+	}
+    }
+
+    screen_size = RADEON_ALIGN(screen_size, pagesize);
+    /* keep area front front buffer - but don't allocate it yet */
+    total_size_bytes += screen_size;
+
+    /* work out from the mm size what the exa / tex sizes need to be */
+    remain_size_bytes = info->vram_size - total_size_bytes;
+
+    info->dri->textureSize = 0;
+
+    info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size,
+				    0, RADEON_GEM_DOMAIN_VRAM, 0);
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer size: %dK\n", info->front_bo->size/1024);
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Remaining VRAM size (used for pixmaps): %dK\n", remain_size_bytes/1024);
+
+    /* set the emit limit at 90% of VRAM */
+    remain_size_bytes = (remain_size_bytes / 10) * 9;
+
+    radeon_cs_set_limit(info->cs, RADEON_GEM_DOMAIN_VRAM, remain_size_bytes);
+    return TRUE;
+}
+
+#endif
diff --git a/src/radeon_legacy_memory.c b/src/radeon_legacy_memory.c
index 861fd97..02b95ed 100644
--- a/src/radeon_legacy_memory.c
+++ b/src/radeon_legacy_memory.c
@@ -21,6 +21,20 @@ radeon_legacy_allocate_memory(ScrnInfoPtr pScrn,
     RADEONInfoPtr info = RADEONPTR(pScrn);
     uint32_t offset = 0;
 
+#ifdef XF86DRM_MODE
+    if (info->cs) {
+	struct radeon_bo *video_bo;
+
+	video_bo = radeon_bo_open(info->bufmgr, 0, size, 4096, 0, 0);
+
+	*mem_struct = video_bo;
+
+	if (!video_bo)
+	    return 0;
+
+	return (uint32_t)-1;
+    }
+#endif
 #ifdef USE_EXA
     if (info->useEXA) {
 	ExaOffscreenArea *area = *mem_struct;
@@ -94,6 +108,14 @@ radeon_legacy_free_memory(ScrnInfoPtr pScrn,
 		   void *mem_struct)
 {
     RADEONInfoPtr info = RADEONPTR(pScrn);
+
+#ifdef XF86DRM_MODE
+    if (info->cs) {
+        struct radeon_bo *bo = mem_struct;
+	radeon_bo_unref(bo);
+	return;
+    }
+#endif
 #ifdef USE_EXA
     ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
 
diff --git a/src/radeon_probe.c b/src/radeon_probe.c
index 041bab6..38fe0b0 100644
--- a/src/radeon_probe.c
+++ b/src/radeon_probe.c
@@ -36,6 +36,7 @@
  * Authors:
  *   Kevin E. Martin <martin at xfree86.org>
  *   Rickard E. Faith <faith at valinux.com>
+ * KMS support - Dave Airlie <airlied at redhat.com>
  */
 
 #include "radeon_probe.h"
@@ -76,11 +77,42 @@ RADEONIdentify(int flags)
 		      RADEONChipsets);
 }
 
+
+#ifdef XF86DRM_MODE
+static Bool radeon_kernel_mode_enabled(ScrnInfoPtr pScrn, struct pci_device *pci_dev)
+{
+    char *busIdString;
+    int ret;
+
+    if (!xf86LoaderCheckSymbol("DRICreatePCIBusID")) {
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
+		   "[KMS] No DRICreatePCIBusID symbol, no kernel modesetting.\n");
+	return FALSE;
+    }
+
+    busIdString = DRICreatePCIBusID(pci_dev);
+    ret = drmCheckModesettingSupported(busIdString);
+    xfree(busIdString);
+    if (ret) {
+      xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
+		   "[KMS] drm report modesetting isn't supported.\n");
+	return FALSE;
+    }
+
+    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
+		   "[KMS] Kernel modesetting enabled.\n");
+    return TRUE;
+}
+#else
+#define radeon_kernel_mode_enabled(x, y) FALSE
+#endif
+
 static Bool
-radeon_get_scrninfo(int entity_num)
+radeon_get_scrninfo(int entity_num, void *pci_dev)
 {
     ScrnInfoPtr   pScrn = NULL;
     EntityInfoPtr pEnt;
+    int kms = 0;
 
     pScrn = xf86ConfigPciEntity(pScrn, 0, entity_num, RADEONPciChipsets,
                                 NULL,
@@ -89,6 +121,11 @@ radeon_get_scrninfo(int entity_num)
     if (!pScrn)
         return FALSE;
 
+    if (pci_dev) {
+      if (radeon_kernel_mode_enabled(pScrn, pci_dev))
+	kms = 1;
+    }
+
     pScrn->driverVersion = RADEON_VERSION_CURRENT;
     pScrn->driverName    = RADEON_DRIVER_NAME;
     pScrn->name          = RADEON_NAME;
@@ -97,14 +134,26 @@ radeon_get_scrninfo(int entity_num)
 #else
     pScrn->Probe         = RADEONProbe;
 #endif
-    pScrn->PreInit       = RADEONPreInit;
-    pScrn->ScreenInit    = RADEONScreenInit;
-    pScrn->SwitchMode    = RADEONSwitchMode;
-    pScrn->AdjustFrame   = RADEONAdjustFrame;
-    pScrn->EnterVT       = RADEONEnterVT;
-    pScrn->LeaveVT       = RADEONLeaveVT;
-    pScrn->FreeScreen    = RADEONFreeScreen;
-    pScrn->ValidMode     = RADEONValidMode;
+
+    if (kms == 1) {
+      pScrn->PreInit       = RADEONPreInit_KMS;
+      pScrn->ScreenInit    = RADEONScreenInit_KMS;
+      pScrn->SwitchMode    = RADEONSwitchMode_KMS;
+      pScrn->AdjustFrame   = RADEONAdjustFrame_KMS;
+      pScrn->EnterVT       = RADEONEnterVT_KMS;
+      pScrn->LeaveVT       = RADEONLeaveVT_KMS;
+      pScrn->FreeScreen    = RADEONFreeScreen_KMS;
+      pScrn->ValidMode     = RADEONValidMode;
+    } else {
+      pScrn->PreInit       = RADEONPreInit;
+      pScrn->ScreenInit    = RADEONScreenInit;
+      pScrn->SwitchMode    = RADEONSwitchMode;
+      pScrn->AdjustFrame   = RADEONAdjustFrame;
+      pScrn->EnterVT       = RADEONEnterVT;
+      pScrn->LeaveVT       = RADEONLeaveVT;
+      pScrn->FreeScreen    = RADEONFreeScreen;
+      pScrn->ValidMode     = RADEONValidMode;
+    }
 
     pEnt = xf86GetEntityInfo(entity_num);
 
@@ -178,7 +227,7 @@ RADEONProbe(DriverPtr drv, int flags)
 	foundScreen = TRUE;
     } else {
 	for (i = 0; i < numUsed; i++) {
-	    if (radeon_get_scrninfo(usedChips[i]))
+	    if (radeon_get_scrninfo(usedChips[i], NULL))
 		foundScreen = TRUE;
 	}
     }
@@ -199,7 +248,7 @@ radeon_pci_probe(
     intptr_t           match_data
 )
 {
-    return radeon_get_scrninfo(entity_num);
+    return radeon_get_scrninfo(entity_num, (void *)device);
 }
 
 #endif /* XSERVER_LIBPCIACCESS */
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index 31709e8..9cac15c 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -615,6 +615,7 @@ typedef struct
     RADEONSaveRec     SavedReg;         /* Original (text) mode              */
 
     void              *MMIO;            /* Map of MMIO region                */
+    int fd;                             /* for sharing across zaphod heads   */
 } RADEONEntRec, *RADEONEntPtr;
 
 /* radeon_probe.c */
@@ -636,4 +637,14 @@ extern ModeStatus           RADEONValidMode(int, DisplayModePtr, Bool, int);
 
 extern const OptionInfoRec *RADEONOptionsWeak(void);
 
+#ifdef XF86DRM_MODE
+extern Bool                 RADEONPreInit_KMS(ScrnInfoPtr, int);
+extern Bool                 RADEONScreenInit_KMS(int, ScreenPtr, int, char **);
+extern Bool                 RADEONSwitchMode_KMS(int, DisplayModePtr, int);
+extern void                 RADEONAdjustFrame_KMS(int, int, int, int);
+extern Bool                 RADEONEnterVT_KMS(int, int);
+extern void                 RADEONLeaveVT_KMS(int, int);
+extern void RADEONFreeScreen_KMS(int scrnIndex, int flags);
+#endif
+
 #endif /* _RADEON_PROBE_H_ */


More information about the xorg-commit mailing list