diff --git a/Makefile.am b/Makefile.am
index 256a8cc..045add1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,7 +34,7 @@ INTEL_SUBDIR = intel
 endif
 
 if HAVE_NOUVEAU
-NOUVEAU_SUBDIR = nouveau
+NOUVEAU_SUBDIR = nouveau-1 nouveau
 endif
 
 if HAVE_RADEON
diff --git a/configure.ac b/configure.ac
index a1c8c69..6439b81 100644
--- a/configure.ac
+++ b/configure.ac
@@ -319,6 +319,8 @@ AC_CONFIG_FILES([
 	intel/libdrm_intel.pc
 	radeon/Makefile
 	radeon/libdrm_radeon.pc
+	nouveau-1/Makefile
+	nouveau-1/libdrm_nouveau1.pc
 	nouveau/Makefile
 	nouveau/libdrm_nouveau.pc
 	omap/Makefile
diff --git a/nouveau-1/Makefile.am b/nouveau-1/Makefile.am
new file mode 100644
index 0000000..7e6aa13
--- /dev/null
+++ b/nouveau-1/Makefile.am
@@ -0,0 +1,43 @@
+AM_CFLAGS = \
+	$(WARN_CFLAGS) \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/nouveau-1 \
+	$(PTHREADSTUBS_CFLAGS) \
+	-I$(top_srcdir)/include/drm
+
+libdrm_nouveau_la_LTLIBRARIES = libdrm_nouveau.la
+libdrm_nouveau_ladir = $(libdir)
+libdrm_nouveau_la_LDFLAGS = -version-number 1:0:0 -no-undefined
+libdrm_nouveau_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
+
+libdrm_nouveau_la_SOURCES = \
+			    nouveau_device.c \
+			    nouveau_channel.c \
+			    nouveau_pushbuf.c \
+			    nouveau_grobj.c \
+			    nouveau_notifier.c \
+			    nouveau_bo.c \
+			    nouveau_resource.c \
+			    nouveau_private.h \
+			    nouveau_reloc.c
+
+libdrm_nouveaucommonincludedir = ${includedir}/nouveau
+libdrm_nouveaucommoninclude_HEADERS = \
+				nouveau_device.h \
+				nouveau_channel.h \
+				nouveau_grobj.h \
+				nouveau_notifier.h \
+				nouveau_pushbuf.h \
+				nv04_pushbuf.h \
+				nvc0_pushbuf.h \
+				nouveau_bo.h \
+				nouveau_resource.h \
+				nouveau_reloc.h
+
+
+libdrm_nouveauincludedir = ${includedir}/libdrm
+libdrm_nouveauinclude_HEADERS = \
+				nouveau_drmif.h
+
+pkgconfigdir = @pkgconfigdir@
+pkgconfig_DATA = libdrm_nouveau1.pc
diff --git a/nouveau-1/libdrm_nouveau1.pc.in b/nouveau-1/libdrm_nouveau1.pc.in
new file mode 100644
index 0000000..8f3d40f
--- /dev/null
+++ b/nouveau-1/libdrm_nouveau1.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libdrm_nouveau
+Description: Userspace interface to nouveau kernel DRM services
+Version: 0.6
+Libs: -L${libdir} -ldrm_nouveau1
+Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/nouveau
+Requires.private: libdrm
diff --git a/nouveau-1/nouveau_bo.c b/nouveau-1/nouveau_bo.c
new file mode 100644
index 0000000..d6bb22d
--- /dev/null
+++ b/nouveau-1/nouveau_bo.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sys/mman.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_bo_init(struct nouveau_device *dev)
+{
+	return 0;
+}
+
+void
+nouveau_bo_takedown(struct nouveau_device *dev)
+{
+}
+
+static int
+nouveau_bo_info(struct nouveau_bo_priv *nvbo, struct drm_nouveau_gem_info *arg)
+{
+	nvbo->handle = nvbo->base.handle = arg->handle;
+	nvbo->domain = arg->domain;
+	nvbo->size = arg->size;
+	nvbo->offset = arg->offset;
+	nvbo->map_handle = arg->map_handle;
+	nvbo->base.tile_mode = arg->tile_mode;
+	/* XXX - flag inverted for backwards compatibility */
+	nvbo->base.tile_flags = arg->tile_flags ^ NOUVEAU_GEM_TILE_NONCONTIG;
+	return 0;
+}
+
+static int
+nouveau_bo_allocated(struct nouveau_bo_priv *nvbo)
+{
+	if (nvbo->sysmem || nvbo->handle)
+		return 1;
+	return 0;
+}
+
+static int
+nouveau_bo_ualloc(struct nouveau_bo_priv *nvbo)
+{
+	if (nvbo->user || nvbo->sysmem) {
+		assert(nvbo->sysmem);
+		return 0;
+	}
+
+	nvbo->sysmem = malloc(nvbo->size);
+	if (!nvbo->sysmem)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void
+nouveau_bo_ufree(struct nouveau_bo_priv *nvbo)
+{
+	if (nvbo->sysmem) {
+		if (!nvbo->user)
+			free(nvbo->sysmem);
+		nvbo->sysmem = NULL;
+	}
+}
+
+static void
+nouveau_bo_kfree(struct nouveau_bo_priv *nvbo)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
+	struct drm_gem_close req;
+
+	if (!nvbo->handle)
+		return;
+
+	if (nvbo->map) {
+		munmap(nvbo->map, nvbo->size);
+		nvbo->map = NULL;
+	}
+
+	req.handle = nvbo->handle;
+	nvbo->handle = 0;
+	drmIoctl(nvdev->fd, DRM_IOCTL_GEM_CLOSE, &req);
+}
+
+static int
+nouveau_bo_kalloc(struct nouveau_bo_priv *nvbo, struct nouveau_channel *chan)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
+	struct drm_nouveau_gem_new req;
+	struct drm_nouveau_gem_info *info = &req.info;
+	int ret;
+
+	if (nvbo->handle)
+		return 0;
+
+	req.channel_hint = chan ? chan->id : 0;
+	req.align = nvbo->align;
+
+
+	info->size = nvbo->size;
+	info->domain = 0;
+
+	if (nvbo->flags & NOUVEAU_BO_VRAM)
+		info->domain |= NOUVEAU_GEM_DOMAIN_VRAM;
+	if (nvbo->flags & NOUVEAU_BO_GART)
+		info->domain |= NOUVEAU_GEM_DOMAIN_GART;
+	if (!info->domain) {
+		info->domain |= (NOUVEAU_GEM_DOMAIN_VRAM |
+				 NOUVEAU_GEM_DOMAIN_GART);
+	}
+
+	if (nvbo->flags & NOUVEAU_BO_MAP)
+		info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE;
+
+	info->tile_mode = nvbo->base.tile_mode;
+	info->tile_flags = nvbo->base.tile_flags;
+	/* XXX - flag inverted for backwards compatibility */
+	info->tile_flags ^= NOUVEAU_GEM_TILE_NONCONTIG;
+	if (!nvdev->has_bo_usage)
+		info->tile_flags &= NOUVEAU_GEM_TILE_LAYOUT_MASK;
+
+	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_NEW,
+				  &req, sizeof(req));
+	if (ret)
+		return ret;
+
+	nouveau_bo_info(nvbo, &req.info);
+	return 0;
+}
+
+static int
+nouveau_bo_kmap(struct nouveau_bo_priv *nvbo)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device);
+
+	if (nvbo->map)
+		return 0;
+
+	if (!nvbo->map_handle)
+		return -EINVAL;
+
+	nvbo->map = mmap(0, nvbo->size, PROT_READ | PROT_WRITE,
+			 MAP_SHARED, nvdev->fd, nvbo->map_handle);
+	if (nvbo->map == MAP_FAILED) {
+		nvbo->map = NULL;
+		return -errno;
+	}
+
+	return 0;
+}
+
+int
+nouveau_bo_new_tile(struct nouveau_device *dev, uint32_t flags, int align,
+		    int size, uint32_t tile_mode, uint32_t tile_flags,
+		    struct nouveau_bo **bo)
+{
+	struct nouveau_bo_priv *nvbo;
+	int ret;
+
+	if (!dev || !bo || *bo)
+		return -EINVAL;
+
+	nvbo = calloc(1, sizeof(struct nouveau_bo_priv));
+	if (!nvbo)
+		return -ENOMEM;
+	nvbo->base.device = dev;
+	nvbo->base.size = size;
+	nvbo->base.tile_mode = tile_mode;
+	nvbo->base.tile_flags = tile_flags;
+
+	nvbo->refcount = 1;
+	nvbo->flags = flags;
+	nvbo->size = size;
+	nvbo->align = align;
+
+	if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
+		ret = nouveau_bo_kalloc(nvbo, NULL);
+		if (ret) {
+			nouveau_bo_ref(NULL, (void *)&nvbo);
+			return ret;
+		}
+	}
+
+	*bo = &nvbo->base;
+	return 0;
+}
+
+int
+nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align,
+	       int size, struct nouveau_bo **bo)
+{
+	return nouveau_bo_new_tile(dev, flags, align, size, 0, 0, bo);
+}
+
+int
+nouveau_bo_user(struct nouveau_device *dev, void *ptr, int size,
+		struct nouveau_bo **bo)
+{
+	struct nouveau_bo_priv *nvbo;
+	int ret;
+
+	ret = nouveau_bo_new(dev, NOUVEAU_BO_MAP, 0, size, bo);
+	if (ret)
+		return ret;
+	nvbo = nouveau_bo(*bo);
+
+	nvbo->sysmem = ptr;
+	nvbo->user = 1;
+	return 0;
+}
+
+int
+nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
+		struct nouveau_bo **bo)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(dev);
+	struct drm_nouveau_gem_info req;
+	struct nouveau_bo_priv *nvbo;
+	int ret;
+
+	ret = nouveau_bo_new(dev, 0, 0, 0, bo);
+	if (ret)
+		return ret;
+	nvbo = nouveau_bo(*bo);
+
+	req.handle = handle;
+	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_INFO,
+				  &req, sizeof(req));
+	if (ret) {
+		nouveau_bo_ref(NULL, bo);
+		return ret;
+	}
+
+	nouveau_bo_info(nvbo, &req);
+	nvbo->base.size = nvbo->size;
+	return 0;
+}
+
+int
+nouveau_bo_handle_get(struct nouveau_bo *bo, uint32_t *handle)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+	int ret;
+ 
+	if (!bo || !handle)
+		return -EINVAL;
+
+	if (!nvbo->global_handle) {
+		struct drm_gem_flink req;
+ 
+		ret = nouveau_bo_kalloc(nvbo, NULL);
+		if (ret)
+			return ret;
+
+		req.handle = nvbo->handle;
+		ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_FLINK, &req);
+		if (ret) {
+			nouveau_bo_kfree(nvbo);
+			return ret;
+		}
+
+		nvbo->global_handle = req.name;
+	}
+ 
+	*handle = nvbo->global_handle;
+	return 0;
+}
+ 
+int
+nouveau_bo_handle_ref(struct nouveau_device *dev, uint32_t handle,
+		      struct nouveau_bo **bo)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(dev);
+	struct nouveau_bo_priv *nvbo;
+	struct drm_gem_open req;
+	int ret;
+
+	req.name = handle;
+	ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_OPEN, &req);
+	if (ret) {
+		nouveau_bo_ref(NULL, bo);
+		return ret;
+	}
+
+	ret = nouveau_bo_wrap(dev, req.handle, bo);
+	if (ret) {
+		nouveau_bo_ref(NULL, bo);
+		return ret;
+	}
+
+	nvbo = nouveau_bo(*bo);
+	nvbo->base.handle = nvbo->handle;
+	return 0;
+} 
+
+static void
+nouveau_bo_del(struct nouveau_bo **bo)
+{
+	struct nouveau_bo_priv *nvbo;
+
+	if (!bo || !*bo)
+		return;
+	nvbo = nouveau_bo(*bo);
+	*bo = NULL;
+
+	if (--nvbo->refcount)
+		return;
+
+	if (nvbo->pending) {
+		nvbo->pending = NULL;
+		nouveau_pushbuf_flush(nvbo->pending_channel, 0);
+	}
+
+	nouveau_bo_ufree(nvbo);
+	nouveau_bo_kfree(nvbo);
+	free(nvbo);
+}
+
+int
+nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pbo)
+{
+	if (!pbo)
+		return -EINVAL;
+
+	if (ref)
+		nouveau_bo(ref)->refcount++;
+
+	if (*pbo)
+		nouveau_bo_del(pbo);
+
+	*pbo = ref;
+	return 0;
+}
+
+static int
+nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write, int no_wait, int no_block)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+	struct drm_nouveau_gem_cpu_prep req;
+	int ret;
+
+	if (!nvbo->global_handle && !nvbo->write_marker && !cpu_write)
+		return 0;
+
+	if (nvbo->pending &&
+	    (nvbo->pending->write_domains || cpu_write)) {
+		nvbo->pending = NULL;
+		nouveau_pushbuf_flush(nvbo->pending_channel, 0);
+	}
+
+	req.handle = nvbo->handle;
+	req.flags = 0;
+	if (cpu_write)
+		req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE;
+	if (no_wait)
+		req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT;
+	if (no_block)
+		req.flags |= NOUVEAU_GEM_CPU_PREP_NOBLOCK;
+
+	do {
+		ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_PREP,
+				      &req, sizeof(req));
+	} while (ret == -EAGAIN);
+	if (ret)
+		return ret;
+
+	if (ret == 0)
+		nvbo->write_marker = 0;
+	return 0;
+}
+
+int
+nouveau_bo_map_range(struct nouveau_bo *bo, uint32_t delta, uint32_t size,
+		     uint32_t flags)
+{
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+	int ret;
+
+	if (!nvbo || bo->map)
+		return -EINVAL;
+
+	if (!nouveau_bo_allocated(nvbo)) {
+		if (nvbo->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
+			ret = nouveau_bo_kalloc(nvbo, NULL);
+			if (ret)
+				return ret;
+		}
+
+		if (!nouveau_bo_allocated(nvbo)) {
+			ret = nouveau_bo_ualloc(nvbo);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (nvbo->sysmem) {
+		bo->map = (char *)nvbo->sysmem + delta;
+	} else {
+		ret = nouveau_bo_kmap(nvbo);
+		if (ret)
+			return ret;
+
+		if (!(flags & NOUVEAU_BO_NOSYNC)) {
+			ret = nouveau_bo_wait(bo, (flags & NOUVEAU_BO_WR),
+					      (flags & NOUVEAU_BO_NOWAIT), 0);
+			if (ret)
+				return ret;
+
+			nvbo->map_refcnt++;
+		}
+
+		bo->map = (char *)nvbo->map + delta;
+	}
+
+	return 0;
+}
+
+void
+nouveau_bo_map_flush(struct nouveau_bo *bo, uint32_t delta, uint32_t size)
+{
+}
+
+int
+nouveau_bo_map(struct nouveau_bo *bo, uint32_t flags)
+{
+	return nouveau_bo_map_range(bo, 0, bo->size, flags);
+}
+
+void
+nouveau_bo_unmap(struct nouveau_bo *bo)
+{
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+	if (bo->map && !nvbo->sysmem && nvbo->map_refcnt) {
+		struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
+		struct drm_nouveau_gem_cpu_fini req;
+
+		req.handle = nvbo->handle;
+		drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_FINI,
+				&req, sizeof(req));
+		nvbo->map_refcnt--;
+	}
+
+	bo->map = NULL;
+}
+
+int
+nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access)
+{
+	return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1);
+}
+
+uint32_t
+nouveau_bo_pending(struct nouveau_bo *bo)
+{
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+	uint32_t flags;
+
+	if (!nvbo->pending)
+		return 0;
+
+	flags = 0;
+	if (nvbo->pending->read_domains)
+		flags |= NOUVEAU_BO_RD;
+	if (nvbo->pending->write_domains)
+		flags |= NOUVEAU_BO_WR;
+
+	return flags;
+}
+
+struct drm_nouveau_gem_pushbuf_bo *
+nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo)
+{
+	struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+	struct drm_nouveau_gem_pushbuf_bo *pbbo;
+	struct nouveau_bo *ref = NULL;
+	int ret;
+
+	if (nvbo->pending)
+		return nvbo->pending;
+
+	if (!nvbo->handle) {
+		ret = nouveau_bo_kalloc(nvbo, chan);
+		if (ret)
+			return NULL;
+
+		if (nvbo->sysmem) {
+			void *sysmem_tmp = nvbo->sysmem;
+
+			nvbo->sysmem = NULL;
+			ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
+			if (ret)
+				return NULL;
+			nvbo->sysmem = sysmem_tmp;
+
+			memcpy(bo->map, nvbo->sysmem, nvbo->base.size);
+			nouveau_bo_ufree(nvbo);
+			nouveau_bo_unmap(bo);
+		}
+	}
+
+	if (nvpb->nr_buffers >= NOUVEAU_GEM_MAX_BUFFERS)
+		return NULL;
+	pbbo = nvpb->buffers + nvpb->nr_buffers++;
+	nvbo->pending = pbbo;
+	nvbo->pending_channel = chan;
+	nvbo->pending_refcnt = 0;
+
+	nouveau_bo_ref(bo, &ref);
+	pbbo->user_priv = (uint64_t)(unsigned long)ref;
+	pbbo->handle = nvbo->handle;
+	pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART;
+	pbbo->read_domains = 0;
+	pbbo->write_domains = 0;
+	pbbo->presumed.domain = nvbo->domain;
+	pbbo->presumed.offset = nvbo->offset;
+	pbbo->presumed.valid = 1;
+	return pbbo;
+}
diff --git a/nouveau-1/nouveau_bo.h b/nouveau-1/nouveau_bo.h
new file mode 100644
index 0000000..3a1f2d4
--- /dev/null
+++ b/nouveau-1/nouveau_bo.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_BO_H__
+#define __NOUVEAU_BO_H__
+
+/* Relocation/Buffer type flags */
+#define NOUVEAU_BO_VRAM   (1 << 0)
+#define NOUVEAU_BO_GART   (1 << 1)
+#define NOUVEAU_BO_RD     (1 << 2)
+#define NOUVEAU_BO_WR     (1 << 3)
+#define NOUVEAU_BO_RDWR   (NOUVEAU_BO_RD | NOUVEAU_BO_WR)
+#define NOUVEAU_BO_MAP    (1 << 4)
+#define NOUVEAU_BO_LOW    (1 << 6)
+#define NOUVEAU_BO_HIGH   (1 << 7)
+#define NOUVEAU_BO_OR     (1 << 8)
+#define NOUVEAU_BO_INVAL  (1 << 12)
+#define NOUVEAU_BO_NOSYNC (1 << 13)
+#define NOUVEAU_BO_NOWAIT (1 << 14)
+#define NOUVEAU_BO_IFLUSH (1 << 15)
+#define NOUVEAU_BO_DUMMY  (1 << 31)
+
+#define NOUVEAU_BO_TILE_LAYOUT_MASK 0x0000ff00
+#define NOUVEAU_BO_TILE_16BPP       0x00000001
+#define NOUVEAU_BO_TILE_32BPP       0x00000002
+#define NOUVEAU_BO_TILE_ZETA        0x00000004
+#define NOUVEAU_BO_TILE_SCANOUT     0x00000008
+
+struct nouveau_bo {
+	struct nouveau_device *device;
+	uint32_t handle;
+
+	uint64_t size;
+	void *map;
+
+	uint32_t tile_mode;
+	uint32_t tile_flags;
+};
+
+int
+nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size,
+	       struct nouveau_bo **);
+
+int
+nouveau_bo_new_tile(struct nouveau_device *, uint32_t flags, int align,
+		    int size, uint32_t tile_mode, uint32_t tile_flags,
+		    struct nouveau_bo **);
+
+int
+nouveau_bo_user(struct nouveau_device *, void *ptr, int size,
+		struct nouveau_bo **);
+
+int
+nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, struct nouveau_bo **);
+
+int
+nouveau_bo_handle_get(struct nouveau_bo *, uint32_t *);
+
+int
+nouveau_bo_handle_ref(struct nouveau_device *, uint32_t handle,
+		      struct nouveau_bo **);
+
+int
+nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **);
+
+int
+nouveau_bo_map_range(struct nouveau_bo *, uint32_t delta, uint32_t size,
+		     uint32_t flags);
+
+void
+nouveau_bo_map_flush(struct nouveau_bo *, uint32_t delta, uint32_t size);
+
+int
+nouveau_bo_map(struct nouveau_bo *, uint32_t flags);
+
+void
+nouveau_bo_unmap(struct nouveau_bo *);
+
+int
+nouveau_bo_busy(struct nouveau_bo *, uint32_t access);
+
+uint32_t
+nouveau_bo_pending(struct nouveau_bo *);
+
+#endif
diff --git a/nouveau-1/nouveau_channel.c b/nouveau-1/nouveau_channel.c
new file mode 100644
index 0000000..96fa03b
--- /dev/null
+++ b/nouveau-1/nouveau_channel.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_channel_alloc(struct nouveau_device *dev, uint32_t fb_ctxdma,
+		      uint32_t tt_ctxdma, int pushbuf_size,
+		      struct nouveau_channel **chan)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(dev);
+	struct nouveau_channel_priv *nvchan;
+	unsigned i;
+	int ret;
+
+	if (!nvdev || !chan || *chan)
+	    return -EINVAL;
+
+	nvchan = calloc(1, sizeof(struct nouveau_channel_priv));
+	if (!nvchan)
+		return -ENOMEM;
+	nvchan->base.device = dev;
+
+	nvchan->drm.fb_ctxdma_handle = fb_ctxdma;
+	nvchan->drm.tt_ctxdma_handle = tt_ctxdma;
+	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_CHANNEL_ALLOC,
+				  &nvchan->drm, sizeof(nvchan->drm));
+	if (ret) {
+		free(nvchan);
+		return ret;
+	}
+
+	nvchan->base.id = nvchan->drm.channel;
+	if (nouveau_grobj_ref(&nvchan->base, nvchan->drm.fb_ctxdma_handle,
+			      &nvchan->base.vram) ||
+	    nouveau_grobj_ref(&nvchan->base, nvchan->drm.tt_ctxdma_handle,
+		    	      &nvchan->base.gart)) {
+		nouveau_channel_free((void *)&nvchan);
+		return -EINVAL;
+	}
+
+	/* Mark all DRM-assigned subchannels as in-use */
+	for (i = 0; i < nvchan->drm.nr_subchan; i++) {
+		struct nouveau_grobj_priv *gr = calloc(1, sizeof(*gr));
+
+		gr->base.bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
+		gr->base.subc = i;
+		gr->base.handle = nvchan->drm.subchan[i].handle;
+		gr->base.grclass = nvchan->drm.subchan[i].grclass;
+		gr->base.channel = &nvchan->base;
+
+		nvchan->base.subc[i].gr = &gr->base;
+	}
+
+	if (dev->chipset < 0xc0) {
+		ret = nouveau_bo_wrap(dev, nvchan->drm.notifier_handle,
+				      &nvchan->notifier_bo);
+		if (!ret)
+			ret = nouveau_bo_map(nvchan->notifier_bo,
+					     NOUVEAU_BO_RDWR);
+		if (ret) {
+			nouveau_channel_free((void *)&nvchan);
+			return ret;
+		}
+
+		ret = nouveau_grobj_alloc(&nvchan->base, 0x00000000, 0x0030,
+					  &nvchan->base.nullobj);
+		if (ret) {
+			nouveau_channel_free((void *)&nvchan);
+			return ret;
+		}
+	}
+
+	ret = nouveau_pushbuf_init(&nvchan->base, pushbuf_size);
+	if (ret) {
+		nouveau_channel_free((void *)&nvchan);
+		return ret;
+	}
+
+	*chan = &nvchan->base;
+	return 0;
+}
+
+void
+nouveau_channel_free(struct nouveau_channel **chan)
+{
+	struct nouveau_channel_priv *nvchan;
+	struct nouveau_device_priv *nvdev;
+	struct drm_nouveau_channel_free cf;
+	unsigned i;
+
+	if (!chan || !*chan)
+		return;
+	nvchan = nouveau_channel(*chan);
+	(*chan)->flush_notify = NULL;
+	*chan = NULL;
+	nvdev = nouveau_device(nvchan->base.device);
+
+	FIRE_RING(&nvchan->base);
+
+	nouveau_pushbuf_fini(&nvchan->base);
+	if (nvchan->notifier_bo) {
+		nouveau_bo_unmap(nvchan->notifier_bo);
+		nouveau_bo_ref(NULL, &nvchan->notifier_bo);
+	}
+
+	for (i = 0; i < nvchan->drm.nr_subchan; i++)
+		free(nvchan->base.subc[i].gr);
+
+	nouveau_grobj_free(&nvchan->base.vram);
+	nouveau_grobj_free(&nvchan->base.gart);
+	nouveau_grobj_free(&nvchan->base.nullobj);
+
+	cf.channel = nvchan->drm.channel;
+	drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf));
+	free(nvchan);
+}
+
+
diff --git a/nouveau-1/nouveau_channel.h b/nouveau-1/nouveau_channel.h
new file mode 100644
index 0000000..d61a4c0
--- /dev/null
+++ b/nouveau-1/nouveau_channel.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_CHANNEL_H__
+#define __NOUVEAU_CHANNEL_H__
+
+struct nouveau_subchannel {
+	struct nouveau_grobj *gr;
+	unsigned sequence;
+};
+
+struct nouveau_channel {
+	uint32_t *cur;
+	uint32_t *end;
+
+	struct nouveau_device *device;
+	int id;
+
+	struct nouveau_grobj *nullobj;
+	struct nouveau_grobj *vram;
+	struct nouveau_grobj *gart;
+
+	void *user_private;
+	void (*hang_notify)(struct nouveau_channel *);
+	void (*flush_notify)(struct nouveau_channel *);
+
+	struct nouveau_subchannel subc[8];
+	unsigned subc_sequence;
+};
+
+int
+nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt,
+		      int pushbuf_size, struct nouveau_channel **);
+
+void
+nouveau_channel_free(struct nouveau_channel **);
+
+#endif
diff --git a/nouveau-1/nouveau_device.c b/nouveau-1/nouveau_device.c
new file mode 100644
index 0000000..425c5d2
--- /dev/null
+++ b/nouveau-1/nouveau_device.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_device_open_existing(struct nouveau_device **dev, int close,
+			     int fd, drm_context_t ctx)
+{
+	struct nouveau_device_priv *nvdev;
+	drmVersionPtr ver;
+	uint64_t value;
+	int ret;
+
+	if (!dev || *dev)
+	    return -EINVAL;
+
+	nvdev = calloc(1, sizeof(*nvdev));
+	if (!nvdev)
+	    return -ENOMEM;
+	nvdev->fd = fd;
+	nvdev->ctx = ctx;
+	nvdev->needs_close = close;
+
+	ver = drmGetVersion(fd);
+	if (!ver) {
+		nouveau_device_close((void *)&nvdev);
+		return -EINVAL;
+	}
+
+	if ((ver->version_major == 0 && ver->version_patchlevel != 16) ||
+	     ver->version_major > 1) {
+		nouveau_device_close((void *)&nvdev);
+		return -EINVAL;
+	}
+
+	drmFreeVersion(ver);
+
+	ret = nouveau_device_get_param(&nvdev->base,
+				       NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
+	if (ret) {
+		nouveau_device_close((void *)&nvdev);
+		return ret;
+	}
+	nvdev->base.vm_vram_base = value;
+
+	ret = nouveau_device_get_param(&nvdev->base,
+				       NOUVEAU_GETPARAM_FB_SIZE, &value);
+	if (ret) {
+		nouveau_device_close((void *)&nvdev);
+		return ret;
+	}
+	nvdev->base.vm_vram_size = value;
+
+	ret = nouveau_device_get_param(&nvdev->base,
+				       NOUVEAU_GETPARAM_AGP_SIZE, &value);
+	if (ret) {
+		nouveau_device_close((void *)&nvdev);
+		return ret;
+	}
+	nvdev->base.vm_gart_size = value;
+
+	ret = nouveau_bo_init(&nvdev->base);
+	if (ret) {
+		nouveau_device_close((void *)&nvdev);
+		return ret;
+	}
+
+	ret = nouveau_device_get_param(&nvdev->base,
+				       NOUVEAU_GETPARAM_CHIPSET_ID, &value);
+	if (ret) {
+		nouveau_device_close((void *)&nvdev);
+		return ret;
+	}
+	nvdev->base.chipset = value;
+
+	ret = nouveau_device_get_param(&nvdev->base,
+				       NOUVEAU_GETPARAM_HAS_BO_USAGE, &value);
+	if (!ret)
+		nvdev->has_bo_usage = value;
+
+	*dev = &nvdev->base;
+	return 0;
+}
+
+int
+nouveau_device_open(struct nouveau_device **dev, const char *busid)
+{
+	drm_context_t ctx;
+	int fd, ret;
+
+	if (!dev || *dev)
+		return -EINVAL;
+
+	fd = drmOpen("nouveau", busid);
+	if (fd < 0)
+		return -EINVAL;
+
+	ret = drmCreateContext(fd, &ctx);
+	if (ret) {
+		drmClose(fd);
+		return ret;
+	}
+
+	ret = nouveau_device_open_existing(dev, 1, fd, ctx);
+	if (ret) {
+	    drmDestroyContext(fd, ctx);
+	    drmClose(fd);
+	    return ret;
+	}
+
+	return 0;
+}
+
+void
+nouveau_device_close(struct nouveau_device **dev)
+{
+	struct nouveau_device_priv *nvdev;
+
+	if (!dev || !*dev)
+		return;
+	nvdev = nouveau_device(*dev);
+	*dev = NULL;
+
+	nouveau_bo_takedown(&nvdev->base);
+
+	if (nvdev->needs_close) {
+		drmDestroyContext(nvdev->fd, nvdev->ctx);
+		drmClose(nvdev->fd);
+	}
+	free(nvdev);
+}
+
+int
+nouveau_device_get_param(struct nouveau_device *dev,
+			 uint64_t param, uint64_t *value)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(dev);
+	struct drm_nouveau_getparam g;
+	int ret;
+
+	if (!nvdev || !value)
+		return -EINVAL;
+
+	g.param = param;
+	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GETPARAM,
+				  &g, sizeof(g));
+	if (ret)
+		return ret;
+
+	*value = g.value;
+	return 0;
+}
+
+int
+nouveau_device_set_param(struct nouveau_device *dev,
+			 uint64_t param, uint64_t value)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(dev);
+	struct drm_nouveau_setparam s;
+	int ret;
+
+	if (!nvdev)
+		return -EINVAL;
+
+	s.param = param;
+	s.value = value;
+	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_SETPARAM,
+				  &s, sizeof(s));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
diff --git a/nouveau-1/nouveau_device.h b/nouveau-1/nouveau_device.h
new file mode 100644
index 0000000..c0d9333
--- /dev/null
+++ b/nouveau-1/nouveau_device.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_DEVICE_H__
+#define __NOUVEAU_DEVICE_H__
+
+struct nouveau_device {
+	unsigned chipset;
+	uint64_t vm_vram_base;
+	uint64_t vm_vram_size;
+	uint64_t vm_gart_size;
+};
+
+#endif
diff --git a/nouveau-1/nouveau_drmif.h b/nouveau-1/nouveau_drmif.h
new file mode 100644
index 0000000..ec226a2
--- /dev/null
+++ b/nouveau-1/nouveau_drmif.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_DRMIF_H__
+#define __NOUVEAU_DRMIF_H__
+
+#include <stdint.h>
+#include <xf86drm.h>
+
+#include "nouveau_device.h"
+
+struct nouveau_device_priv {
+	struct nouveau_device base;
+
+	int fd;
+	drm_context_t ctx;
+	drmLock *lock;
+	int needs_close;
+	int has_bo_usage;
+};
+#define nouveau_device(n) ((struct nouveau_device_priv *)(n))
+
+int
+nouveau_device_open_existing(struct nouveau_device **, int close,
+			     int fd, drm_context_t ctx);
+
+int
+nouveau_device_open(struct nouveau_device **, const char *busid);
+
+void
+nouveau_device_close(struct nouveau_device **);
+
+int
+nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v);
+
+int
+nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val);
+
+#endif
diff --git a/nouveau-1/nouveau_grobj.c b/nouveau-1/nouveau_grobj.c
new file mode 100644
index 0000000..36344b9
--- /dev/null
+++ b/nouveau-1/nouveau_grobj.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_grobj_alloc(struct nouveau_channel *chan, uint32_t handle,
+		    int class, struct nouveau_grobj **grobj)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
+	struct nouveau_grobj_priv *nvgrobj;
+	struct drm_nouveau_grobj_alloc g;
+	int ret;
+
+	if (!nvdev || !grobj || *grobj)
+		return -EINVAL;
+
+	nvgrobj = calloc(1, sizeof(*nvgrobj));
+	if (!nvgrobj)
+		return -ENOMEM;
+	nvgrobj->base.channel = chan;
+	nvgrobj->base.handle  = handle;
+	nvgrobj->base.grclass = class;
+	nvgrobj->base.bound   = NOUVEAU_GROBJ_UNBOUND;
+	nvgrobj->base.subc    = -1;
+
+	g.channel = chan->id;
+	g.handle  = handle;
+	g.class   = class;
+	ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
+			      &g, sizeof(g));
+	if (ret) {
+		nouveau_grobj_free((void *)&nvgrobj);
+		return ret;
+	}
+
+	*grobj = &nvgrobj->base;
+	return 0;
+}
+
+int
+nouveau_grobj_ref(struct nouveau_channel *chan, uint32_t handle,
+		  struct nouveau_grobj **grobj)
+{
+	struct nouveau_grobj_priv *nvgrobj;
+
+	if (!chan || !grobj || *grobj)
+		return -EINVAL;
+
+	nvgrobj = calloc(1, sizeof(struct nouveau_grobj_priv));
+	if (!nvgrobj)
+		return -ENOMEM;
+	nvgrobj->base.channel = chan;
+	nvgrobj->base.handle = handle;
+	nvgrobj->base.grclass = 0;
+
+	*grobj = &nvgrobj->base;
+	return 0;
+}
+
+void
+nouveau_grobj_free(struct nouveau_grobj **grobj)
+{
+	struct nouveau_device_priv *nvdev;
+	struct nouveau_channel_priv *chan;
+	struct nouveau_grobj_priv *nvgrobj;
+
+	if (!grobj || !*grobj)
+		return;
+	nvgrobj = nouveau_grobj(*grobj);
+	*grobj = NULL;
+
+
+	chan = nouveau_channel(nvgrobj->base.channel);
+	nvdev = nouveau_device(chan->base.device);
+
+	if (nvgrobj->base.grclass) {
+		struct drm_nouveau_gpuobj_free f;
+
+		FIRE_RING(&chan->base);
+		f.channel = chan->drm.channel;
+		f.handle  = nvgrobj->base.handle;
+		drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
+				&f, sizeof(f));	
+	}
+	if (nvgrobj->base.bound != NOUVEAU_GROBJ_UNBOUND)
+		chan->base.subc[nvgrobj->base.subc].gr = NULL;
+	free(nvgrobj);
+}
+
+void
+nouveau_grobj_autobind(struct nouveau_grobj *grobj)
+{
+	struct nouveau_channel *chan = grobj->channel;
+	struct nouveau_subchannel *subc = NULL;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		struct nouveau_subchannel *scc = &grobj->channel->subc[i];
+
+		if (scc->gr && scc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
+			continue;
+
+		if (!subc || scc->sequence < subc->sequence)
+			subc = scc;
+	}
+
+	if (subc->gr) {
+		subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
+		subc->gr->subc  = -1;
+	}
+
+	subc->gr = grobj;
+	subc->gr->bound = NOUVEAU_GROBJ_BOUND;
+	subc->gr->subc  = subc - &grobj->channel->subc[0];
+
+	WAIT_RING(chan, 2);
+	if (chan->device->chipset < 0xc0) {
+		OUT_RING (chan, (1 << 18) | (grobj->subc << 13));
+		OUT_RING (chan, grobj->handle);
+	} else {
+		OUT_RING (chan, (2 << 28) | (1 << 16) | (grobj->subc << 13));
+		OUT_RING (chan, grobj->grclass);
+	}
+}
+
diff --git a/nouveau-1/nouveau_grobj.h b/nouveau-1/nouveau_grobj.h
new file mode 100644
index 0000000..51ac7d9
--- /dev/null
+++ b/nouveau-1/nouveau_grobj.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_GROBJ_H__
+#define __NOUVEAU_GROBJ_H__
+
+#include "nouveau_channel.h"
+
+struct nouveau_grobj {
+	struct nouveau_channel *channel;
+	int grclass;
+	uint32_t handle;
+
+	enum {
+		NOUVEAU_GROBJ_UNBOUND = 0,
+		NOUVEAU_GROBJ_BOUND = 1,
+		NOUVEAU_GROBJ_BOUND_EXPLICIT = 2
+	} bound;
+	int subc;
+};
+
+int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle,
+			       int class, struct nouveau_grobj **);
+int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle,
+			     struct nouveau_grobj **);
+void nouveau_grobj_free(struct nouveau_grobj **);
+void nouveau_grobj_autobind(struct nouveau_grobj *);
+
+#endif
diff --git a/nouveau-1/nouveau_notifier.c b/nouveau-1/nouveau_notifier.c
new file mode 100644
index 0000000..513fa63
--- /dev/null
+++ b/nouveau-1/nouveau_notifier.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#include "nouveau_private.h"
+
+#define NOTIFIER(__v)                                                          \
+	struct nouveau_notifier_priv *nvnotify = nouveau_notifier(notifier);   \
+	volatile uint32_t *__v = (uint32_t *)((char *)nvnotify->map + (id * 32))
+
+int
+nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
+		       int count, struct nouveau_notifier **notifier)
+{
+	struct nouveau_notifier_priv *nvnotify;
+	int ret;
+
+	if (!chan || !notifier || *notifier)
+		return -EINVAL;
+
+	nvnotify = calloc(1, sizeof(struct nouveau_notifier_priv));
+	if (!nvnotify)
+		return -ENOMEM;
+	nvnotify->base.channel = chan;
+	nvnotify->base.handle  = handle;
+
+	nvnotify->drm.channel = chan->id;
+	nvnotify->drm.handle  = handle;
+	nvnotify->drm.size    = (count * 32);
+	if ((ret = drmCommandWriteRead(nouveau_device(chan->device)->fd,
+				       DRM_NOUVEAU_NOTIFIEROBJ_ALLOC,
+				       &nvnotify->drm,
+				       sizeof(nvnotify->drm)))) {
+		nouveau_notifier_free((void *)&nvnotify);
+		return ret;
+	}
+
+	nvnotify->map = (char *)nouveau_channel(chan)->notifier_bo->map +
+				nvnotify->drm.offset;
+	*notifier = &nvnotify->base;
+	return 0;
+}
+
+void
+nouveau_notifier_free(struct nouveau_notifier **notifier)
+{
+
+	struct nouveau_notifier_priv *nvnotify;
+	struct nouveau_channel_priv *nvchan;
+	struct nouveau_device_priv *nvdev;
+	struct drm_nouveau_gpuobj_free f;
+
+	if (!notifier || !*notifier)
+		return;
+	nvnotify = nouveau_notifier(*notifier);
+	*notifier = NULL;
+
+	nvchan = nouveau_channel(nvnotify->base.channel);
+	nvdev   = nouveau_device(nvchan->base.device);
+
+	FIRE_RING(&nvchan->base);
+
+	f.channel = nvchan->drm.channel;
+	f.handle  = nvnotify->base.handle;
+	drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f));		
+	free(nvnotify);
+}
+
+void
+nouveau_notifier_reset(struct nouveau_notifier *notifier, int id)
+{
+	NOTIFIER(n);
+
+	n[NV_NOTIFY_TIME_0      /4] = 0x00000000;
+	n[NV_NOTIFY_TIME_1      /4] = 0x00000000;
+	n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000;
+	n[NV_NOTIFY_STATE       /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS <<
+				       NV_NOTIFY_STATE_STATUS_SHIFT);
+}
+
+uint32_t
+nouveau_notifier_status(struct nouveau_notifier *notifier, int id)
+{
+	NOTIFIER(n);
+
+	return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
+}
+
+uint32_t
+nouveau_notifier_return_val(struct nouveau_notifier *notifier, int id)
+{
+	NOTIFIER(n);
+
+	return n[NV_NOTIFY_RETURN_VALUE/4];
+}
+
+static inline double
+gettime(void)
+{
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+	return (double)tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+int
+nouveau_notifier_wait_status(struct nouveau_notifier *notifier, int id,
+			     uint32_t status, double timeout)
+{
+	NOTIFIER(n);
+	double time = 0, t_start = gettime();
+
+	while (time <= timeout) {
+		uint32_t v;
+
+		v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT;
+		if (v == status)
+			return 0;
+
+		if (timeout)
+			time = gettime() - t_start;
+	}
+
+	return -EBUSY;
+}
+
diff --git a/nouveau-1/nouveau_notifier.h b/nouveau-1/nouveau_notifier.h
new file mode 100644
index 0000000..dbc6a3b
--- /dev/null
+++ b/nouveau-1/nouveau_notifier.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_NOTIFIER_H__
+#define __NOUVEAU_NOTIFIER_H__
+
+#define NV_NOTIFIER_SIZE                                                      32
+#define NV_NOTIFY_TIME_0                                              0x00000000
+#define NV_NOTIFY_TIME_1                                              0x00000004
+#define NV_NOTIFY_RETURN_VALUE                                        0x00000008
+#define NV_NOTIFY_STATE                                               0x0000000C
+#define NV_NOTIFY_STATE_STATUS_MASK                                   0xFF000000
+#define NV_NOTIFY_STATE_STATUS_SHIFT                                          24
+#define NV_NOTIFY_STATE_STATUS_COMPLETED                                    0x00
+#define NV_NOTIFY_STATE_STATUS_IN_PROCESS                                   0x01
+#define NV_NOTIFY_STATE_ERROR_CODE_MASK                               0x0000FFFF
+#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT                                       0
+
+struct nouveau_notifier {
+	struct nouveau_channel *channel;
+	uint32_t handle;
+};
+
+int
+nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count,
+		       struct nouveau_notifier **);
+
+void
+nouveau_notifier_free(struct nouveau_notifier **);
+
+void
+nouveau_notifier_reset(struct nouveau_notifier *, int id);
+
+uint32_t
+nouveau_notifier_status(struct nouveau_notifier *, int id);
+
+uint32_t
+nouveau_notifier_return_val(struct nouveau_notifier *, int id);
+
+int
+nouveau_notifier_wait_status(struct nouveau_notifier *, int id, uint32_t status,
+			     double timeout);
+
+#endif
diff --git a/nouveau-1/nouveau_private.h b/nouveau-1/nouveau_private.h
new file mode 100644
index 0000000..124fe87
--- /dev/null
+++ b/nouveau-1/nouveau_private.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_PRIVATE_H__
+#define __NOUVEAU_PRIVATE_H__
+
+#include <stdint.h>
+#include <xf86drm.h>
+#include <nouveau_drm.h>
+
+#include "nouveau_drmif.h"
+#include "nouveau_device.h"
+#include "nouveau_channel.h"
+#include "nouveau_grobj.h"
+#include "nouveau_notifier.h"
+#include "nouveau_bo.h"
+#include "nouveau_resource.h"
+#include "nouveau_pushbuf.h"
+#include "nouveau_reloc.h"
+
+#define CALPB_BUFFERS 3
+
+struct nouveau_pushbuf_priv {
+	uint32_t cal_suffix0;
+	uint32_t cal_suffix1;
+	struct nouveau_bo *buffer[CALPB_BUFFERS];
+	int current;
+	int current_offset;
+
+	unsigned *pushbuf;
+	unsigned size;
+
+	uint32_t *marker;
+	unsigned marker_offset;
+	unsigned marker_relocs;
+	unsigned marker_push;
+
+	struct drm_nouveau_gem_pushbuf_bo *buffers;
+	unsigned nr_buffers;
+	struct drm_nouveau_gem_pushbuf_reloc *relocs;
+	unsigned nr_relocs;
+	struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH];
+	unsigned nr_push;
+};
+#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
+
+int
+nouveau_pushbuf_init(struct nouveau_channel *, int buf_size);
+void
+nouveau_pushbuf_fini(struct nouveau_channel *);
+
+struct nouveau_channel_priv {
+	struct nouveau_channel base;
+
+	struct drm_nouveau_channel_alloc drm;
+
+	struct nouveau_bo *notifier_bo;
+
+	struct nouveau_pushbuf_priv pb;
+};
+#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n))
+
+struct nouveau_grobj_priv {
+	struct nouveau_grobj base;
+};
+#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n))
+
+struct nouveau_notifier_priv {
+	struct nouveau_notifier base;
+
+	struct drm_nouveau_notifierobj_alloc drm;
+	volatile void *map;
+};
+#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n))
+
+struct nouveau_bo_priv {
+	struct nouveau_bo base;
+	int refcount;
+
+	/* Buffer configuration + usage hints */
+	unsigned flags;
+	unsigned size;
+	unsigned align;
+	int user;
+
+	/* Tracking */
+	struct drm_nouveau_gem_pushbuf_bo *pending;
+	struct nouveau_channel *pending_channel;
+	int pending_refcnt;
+	int write_marker;
+
+	/* Userspace object */
+	void *sysmem;
+
+	/* Kernel object */
+	uint32_t global_handle;
+	drm_handle_t handle;
+	uint64_t map_handle;
+	int map_refcnt;
+	void *map;
+
+	/* Last known information from kernel on buffer status */
+	uint64_t offset;
+	uint32_t domain;
+};
+#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n))
+
+int
+nouveau_bo_init(struct nouveau_device *);
+
+void
+nouveau_bo_takedown(struct nouveau_device *);
+
+struct drm_nouveau_gem_pushbuf_bo *
+nouveau_bo_emit_buffer(struct nouveau_channel *, struct nouveau_bo *);
+
+#endif
diff --git a/nouveau-1/nouveau_pushbuf.c b/nouveau-1/nouveau_pushbuf.c
new file mode 100644
index 0000000..59f60d9
--- /dev/null
+++ b/nouveau-1/nouveau_pushbuf.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nouveau_private.h"
+
+#define PB_BUFMGR_DWORDS   (4096 / 2)
+#define PB_MIN_USER_DWORDS  2048
+
+static int
+nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min)
+{
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	struct nouveau_bo *bo;
+	int ret;
+
+	if (min < PB_MIN_USER_DWORDS)
+		min = PB_MIN_USER_DWORDS;
+
+	nvpb->current_offset = chan->cur - nvpb->pushbuf;
+	if (chan->cur + min + 2 <= chan->end)
+		return 0;
+
+	nvpb->current++;
+	if (nvpb->current == CALPB_BUFFERS)
+		nvpb->current = 0;
+	bo = nvpb->buffer[nvpb->current];
+
+	ret = nouveau_bo_map(bo, NOUVEAU_BO_WR);
+	if (ret)
+		return ret;
+
+	nvpb->size = (bo->size - 8) / 4;
+	nvpb->pushbuf = bo->map;
+	nvpb->current_offset = 0;
+
+	chan->cur = nvpb->pushbuf;
+	chan->end = nvpb->pushbuf + nvpb->size;
+
+	nouveau_bo_unmap(bo);
+	return 0;
+}
+
+static void
+nouveau_pushbuf_fini_call(struct nouveau_channel *chan)
+{
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	int i;
+
+	for (i = 0; i < CALPB_BUFFERS; i++)
+		nouveau_bo_ref(NULL, &nvpb->buffer[i]);
+	nvpb->pushbuf = NULL;
+}
+
+static int
+nouveau_pushbuf_init_call(struct nouveau_channel *chan, int buf_size)
+{
+	struct drm_nouveau_gem_pushbuf req;
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	struct nouveau_device *dev = chan->device;
+	uint32_t flags = 0;
+	int i, ret;
+
+	if (nvchan->drm.pushbuf_domains & NOUVEAU_GEM_DOMAIN_GART)
+		flags |= NOUVEAU_BO_GART;
+	else
+		flags |= NOUVEAU_BO_VRAM;
+
+	req.channel = chan->id;
+	req.nr_push = 0;
+	ret = drmCommandWriteRead(nouveau_device(dev)->fd,
+				  DRM_NOUVEAU_GEM_PUSHBUF, &req, sizeof(req));
+	if (ret)
+		return ret;
+
+	for (i = 0; i < CALPB_BUFFERS; i++) {
+		ret = nouveau_bo_new(dev, flags | NOUVEAU_BO_MAP,
+				     0, buf_size, &nvpb->buffer[i]);
+		if (ret) {
+			nouveau_pushbuf_fini_call(chan);
+			return ret;
+		}
+	}
+
+	nvpb->cal_suffix0 = req.suffix0;
+	nvpb->cal_suffix1 = req.suffix1;
+	return 0;
+}
+
+int
+nouveau_pushbuf_init(struct nouveau_channel *chan, int buf_size)
+{
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	int ret;
+
+	ret = nouveau_pushbuf_init_call(chan, buf_size);
+	if (ret)
+		return ret;
+
+	ret = nouveau_pushbuf_space(chan, 0);
+	if (ret)
+		return ret;
+
+	nvpb->buffers = calloc(NOUVEAU_GEM_MAX_BUFFERS,
+			       sizeof(struct drm_nouveau_gem_pushbuf_bo));
+	nvpb->relocs = calloc(NOUVEAU_GEM_MAX_RELOCS,
+			      sizeof(struct drm_nouveau_gem_pushbuf_reloc));
+	return 0;
+}
+
+void
+nouveau_pushbuf_fini(struct nouveau_channel *chan)
+{
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	nouveau_pushbuf_fini_call(chan);
+	free(nvpb->buffers);
+	free(nvpb->relocs);
+}
+
+static int
+nouveau_pushbuf_bo_add(struct nouveau_channel *chan, struct nouveau_bo *bo,
+		       unsigned offset, unsigned length)
+{
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	struct drm_nouveau_gem_pushbuf_push *p = &nvpb->push[nvpb->nr_push++];
+	struct drm_nouveau_gem_pushbuf_bo *pbbo;
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+	pbbo = nouveau_bo_emit_buffer(chan, bo);
+	if (!pbbo)
+		return -ENOMEM;
+	pbbo->valid_domains &= nvchan->drm.pushbuf_domains;
+	pbbo->read_domains |= nvchan->drm.pushbuf_domains;
+	nvbo->pending_refcnt++;
+
+	p->bo_index = pbbo - nvpb->buffers;
+	p->offset = offset;
+	p->length = length;
+	return 0;
+}
+
+int
+nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
+		       unsigned offset, unsigned length)
+{
+	struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+	int ret, len;
+
+	if ((AVAIL_RING(chan) + nvpb->current_offset) != nvpb->size) {
+		if (nvpb->cal_suffix0 || nvpb->cal_suffix1) {
+			*(chan->cur++) = nvpb->cal_suffix0;
+			*(chan->cur++) = nvpb->cal_suffix1;
+		}
+
+		len = (chan->cur - nvpb->pushbuf) - nvpb->current_offset;
+
+		ret = nouveau_pushbuf_bo_add(chan, nvpb->buffer[nvpb->current],
+					     nvpb->current_offset * 4, len * 4);
+		if (ret)
+			return ret;
+
+		nvpb->current_offset += len;
+	}
+
+	return bo ? nouveau_pushbuf_bo_add(chan, bo, offset, length) : 0;
+}
+
+static void
+nouveau_pushbuf_bo_unref(struct nouveau_pushbuf_priv *nvpb, int index)
+{
+	struct drm_nouveau_gem_pushbuf_bo *pbbo = &nvpb->buffers[index];
+	struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv;
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+
+	if (--nvbo->pending_refcnt)
+		return;
+
+	if (pbbo->presumed.valid == 0) {
+		nvbo->domain = pbbo->presumed.domain;
+		nvbo->offset = pbbo->presumed.offset;
+	}
+
+	nvbo->pending = NULL;
+	nouveau_bo_ref(NULL, &bo);
+
+	/* we only ever remove from the tail of the pending lists,
+	 * so this is safe.
+	 */
+	nvpb->nr_buffers--;
+}
+
+int
+nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min)
+{
+	struct nouveau_device_priv *nvdev = nouveau_device(chan->device);
+	struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+	struct nouveau_pushbuf_priv *nvpb = &nvchan->pb;
+	struct drm_nouveau_gem_pushbuf req;
+	unsigned i;
+	int ret;
+
+	ret = nouveau_pushbuf_submit(chan, NULL, 0, 0);
+	if (ret)
+		return ret;
+
+	if (!nvpb->nr_push)
+		return 0;
+
+	req.channel = chan->id;
+	req.nr_push = nvpb->nr_push;
+	req.push = (uint64_t)(unsigned long)nvpb->push;
+	req.nr_buffers = nvpb->nr_buffers;
+	req.buffers = (uint64_t)(unsigned long)nvpb->buffers;
+	req.nr_relocs = nvpb->nr_relocs;
+	req.relocs = (uint64_t)(unsigned long)nvpb->relocs;
+	req.suffix0 = nvpb->cal_suffix0;
+	req.suffix1 = nvpb->cal_suffix1;
+
+	do {
+		ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
+					  &req, sizeof(req));
+	} while (ret == -EAGAIN);
+	nvpb->cal_suffix0 = req.suffix0;
+	nvpb->cal_suffix1 = req.suffix1;
+	nvdev->base.vm_vram_size = req.vram_available;
+	nvdev->base.vm_gart_size = req.gart_available;
+
+	/* Update presumed offset/domain for any buffers that moved.
+	 * Dereference all buffers on validate list
+	 */
+	for (i = 0; i < nvpb->nr_relocs; i++) {
+		nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
+		nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
+	}
+
+	for (i = 0; i < nvpb->nr_push; i++)
+		nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
+
+	nvpb->nr_buffers = 0;
+	nvpb->nr_relocs = 0;
+	nvpb->nr_push = 0;
+
+	/* Allocate space for next push buffer */
+	if (nouveau_pushbuf_space(chan, min))
+		assert(0);
+
+	if (chan->flush_notify)
+		chan->flush_notify(chan);
+
+	nvpb->marker = NULL;
+	return ret;
+}
+
+int
+nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+			    unsigned wait_dwords, unsigned wait_relocs)
+{
+	struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+
+	if (AVAIL_RING(chan) < wait_dwords)
+		return nouveau_pushbuf_flush(chan, wait_dwords);
+
+	if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS)
+		return nouveau_pushbuf_flush(chan, wait_dwords);
+
+	nvpb->marker = chan->cur;
+	nvpb->marker_offset = nvpb->current_offset;
+	nvpb->marker_push = nvpb->nr_push;
+	nvpb->marker_relocs = nvpb->nr_relocs;
+	return 0;
+}
+
+void
+nouveau_pushbuf_marker_undo(struct nouveau_channel *chan)
+{
+	struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+	unsigned i;
+
+	if (!nvpb->marker)
+		return;
+
+	/* undo any relocs/buffers added to the list since last marker */
+	for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) {
+		nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index);
+		nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index);
+	}
+	nvpb->nr_relocs = nvpb->marker_relocs;
+
+	for (i = nvpb->marker_push; i < nvpb->nr_push; i++)
+		nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index);
+	nvpb->nr_push = nvpb->marker_push;
+
+	/* reset pushbuf back to last marker */
+	chan->cur = nvpb->marker;
+	nvpb->current_offset = nvpb->marker_offset;
+	nvpb->marker = NULL;
+}
+
+int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr,
+			   struct nouveau_bo *bo, uint32_t data, uint32_t data2,
+			   uint32_t flags, uint32_t vor, uint32_t tor)
+{
+	struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+	int ret;
+
+	ret = nouveau_reloc_emit(chan, nvpb->buffer[nvpb->current],
+				 (char *)ptr - (char *)nvpb->pushbuf, ptr,
+				 bo, data, data2, flags, vor, tor);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
diff --git a/nouveau-1/nouveau_pushbuf.h b/nouveau-1/nouveau_pushbuf.h
new file mode 100644
index 0000000..2a98789
--- /dev/null
+++ b/nouveau-1/nouveau_pushbuf.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_PUSHBUF_H__
+#define __NOUVEAU_PUSHBUF_H__
+
+#include <assert.h>
+#include <string.h>
+
+#include "nouveau_bo.h"
+#include "nouveau_grobj.h"
+
+int
+nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min);
+
+int
+nouveau_pushbuf_marker_emit(struct nouveau_channel *chan,
+			    unsigned wait_dwords, unsigned wait_relocs);
+
+void
+nouveau_pushbuf_marker_undo(struct nouveau_channel *chan);
+
+int
+nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr,
+			   struct nouveau_bo *, uint32_t data, uint32_t data2,
+			   uint32_t flags, uint32_t vor, uint32_t tor);
+
+int
+nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo,
+		       unsigned offset, unsigned length);
+
+/* Push buffer access macros */
+static __inline__ int
+MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs)
+{
+	return nouveau_pushbuf_marker_emit(chan, dwords, relocs);
+}
+
+static __inline__ void
+MARK_UNDO(struct nouveau_channel *chan)
+{
+	nouveau_pushbuf_marker_undo(chan);
+}
+
+static __inline__ void
+OUT_RING(struct nouveau_channel *chan, unsigned data)
+{
+	*(chan->cur++) = (data);
+}
+
+static __inline__ void
+OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size)
+{
+	memcpy(chan->cur, data, size * 4);
+	chan->cur += size;
+}
+
+static __inline__ void
+OUT_RINGf(struct nouveau_channel *chan, float f)
+{
+	union { uint32_t i; float f; } c;
+	c.f = f;
+	OUT_RING(chan, c.i);
+}
+
+static __inline__ unsigned
+AVAIL_RING(struct nouveau_channel *chan)
+{
+	return chan->end - chan->cur;
+}
+
+static __inline__ void
+WAIT_RING(struct nouveau_channel *chan, unsigned size)
+{
+	if (chan->cur + size > chan->end)
+		nouveau_pushbuf_flush(chan, size);
+}
+
+static __inline__ void
+FIRE_RING(struct nouveau_channel *chan)
+{
+	nouveau_pushbuf_flush(chan, 0);
+}
+
+static __inline__ int
+OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	  unsigned data, unsigned flags, unsigned vor, unsigned tor)
+{
+	return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
+					  data, 0, flags, vor, tor);
+}
+
+static __inline__ int
+OUT_RELOC2(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	   unsigned data, unsigned data2, unsigned flags,
+	   unsigned vor, unsigned tor)
+{
+	return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo,
+					  data, data2, flags, vor, tor);
+}
+
+/* Raw data + flags depending on FB/TT buffer */
+static __inline__ int
+OUT_RELOCd(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	   unsigned data, unsigned flags, unsigned vor, unsigned tor)
+{
+	return OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor);
+}
+
+/* FB/TT object handle */
+static __inline__ int
+OUT_RELOCo(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	   unsigned flags)
+{
+	return OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR,
+			 chan->vram->handle, chan->gart->handle);
+}
+
+/* Low 32-bits of offset */
+static __inline__ int
+OUT_RELOCl(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	   unsigned delta, unsigned flags)
+{
+	return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0);
+}
+
+/* Low 32-bits of offset + GPU linear access range info */
+static __inline__ int
+OUT_RELOCr(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	   unsigned delta, unsigned size, unsigned flags)
+{
+	return OUT_RELOC2(chan, bo, delta, size, flags | NOUVEAU_BO_LOW, 0, 0);
+}
+
+/* High 32-bits of offset */
+static __inline__ int
+OUT_RELOCh(struct nouveau_channel *chan, struct nouveau_bo *bo,
+	   unsigned delta, unsigned flags)
+{
+	return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0);
+}
+
+#endif
diff --git a/nouveau-1/nouveau_reloc.c b/nouveau-1/nouveau_reloc.c
new file mode 100644
index 0000000..cd219db
--- /dev/null
+++ b/nouveau-1/nouveau_reloc.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2010 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "nouveau_private.h"
+
+static uint32_t
+nouveau_reloc_calc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
+		   struct drm_nouveau_gem_pushbuf_reloc *r)
+{
+	uint32_t push = 0;
+
+	if (r->flags & NOUVEAU_GEM_RELOC_LOW)
+		push = (pbbo->presumed.offset + r->data);
+	else
+	if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
+		push = (pbbo->presumed.offset + r->data) >> 32;
+	else
+		push = r->data;
+
+	if (r->flags & NOUVEAU_GEM_RELOC_OR) {
+		if (pbbo->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM)
+			push |= r->vor;
+		else
+			push |= r->tor;
+	}
+
+	return push;
+}
+
+int
+nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
+		   uint32_t reloc_offset, uint32_t *reloc_ptr,
+		   struct nouveau_bo *bo, uint32_t data, uint32_t data2,
+		   uint32_t flags, uint32_t vor, uint32_t tor)
+{
+	struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
+	struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
+	struct drm_nouveau_gem_pushbuf_reloc *r;
+	struct drm_nouveau_gem_pushbuf_bo *pbbo, *rpbbo;
+	uint32_t domains = 0;
+
+	if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) {
+		fprintf(stderr, "too many relocs!!\n");
+		return -ENOMEM;
+	}
+
+	if (nvbo->user && (flags & NOUVEAU_BO_WR)) {
+		fprintf(stderr, "write to user buffer!!\n");
+		return -EINVAL;
+	}
+
+	/* We're about to reloc a user buffer, better make sure we don't cause
+	 * a double migration.
+	 */
+	if (!(nvbo->flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM)))
+		nvbo->flags |= (flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM));
+
+	/* add buffer to validation list */
+	pbbo = nouveau_bo_emit_buffer(chan, bo);
+	if (!pbbo) {
+		fprintf(stderr, "buffer emit fail :(\n");
+		return -ENOMEM;
+	}
+	nouveau_bo(bo)->pending_refcnt++;
+
+	if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) {
+		if (flags & NOUVEAU_BO_VRAM)
+			domains |= NOUVEAU_GEM_DOMAIN_VRAM;
+		if (flags & NOUVEAU_BO_GART)
+			domains |= NOUVEAU_GEM_DOMAIN_GART;
+	} else
+		domains |= nvbo->domain;
+
+	if (!(pbbo->valid_domains & domains)) {
+		fprintf(stderr, "no valid domains remain!\n");
+		return -EINVAL;
+	}
+	pbbo->valid_domains &= domains;
+
+	assert(flags & NOUVEAU_BO_RDWR);
+	if (flags & NOUVEAU_BO_RD) {
+		pbbo->read_domains |= domains;
+	}
+	if (flags & NOUVEAU_BO_WR) {
+		pbbo->write_domains |= domains;
+		nvbo->write_marker = 1;
+	}
+
+	/* nvc0 gallium driver uses reloc_emit() with NULL target buffer
+	 * to inform bufmgr of a buffer's use - however, we need something
+	 * to track, so create a reloc for now, and hope it never triggers
+	 * (it shouldn't, constant virtual address..)..
+	 */
+	if (!reloc_bo) {
+		reloc_bo  = nvpb->buffer[nvpb->current];
+		reloc_offset = 0;
+		reloc_ptr = NULL;
+	}
+
+	/* add reloc target bo to validation list, and create the reloc */
+	rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo);
+	if (!rpbbo)
+		return -ENOMEM;
+	nouveau_bo(reloc_bo)->pending_refcnt++;
+
+	r = nvpb->relocs + nvpb->nr_relocs++;
+	r->reloc_bo_index = rpbbo - nvpb->buffers;
+	r->reloc_bo_offset = reloc_offset;
+	r->bo_index = pbbo - nvpb->buffers;
+	r->flags = 0;
+	if (flags & NOUVEAU_BO_LOW)
+		r->flags |= NOUVEAU_GEM_RELOC_LOW;
+	if (flags & NOUVEAU_BO_HIGH)
+		r->flags |= NOUVEAU_GEM_RELOC_HIGH;
+	if (flags & NOUVEAU_BO_OR)
+		r->flags |= NOUVEAU_GEM_RELOC_OR;
+	r->data = data;
+	r->vor = vor;
+	r->tor = tor;
+
+	if (reloc_ptr) {
+		if (flags & NOUVEAU_BO_DUMMY)
+			*reloc_ptr = 0;
+		else
+			*reloc_ptr = nouveau_reloc_calc(pbbo, r);
+	}
+
+	return 0;
+}
+
diff --git a/nouveau-1/nouveau_reloc.h b/nouveau-1/nouveau_reloc.h
new file mode 100644
index 0000000..24ddb52
--- /dev/null
+++ b/nouveau-1/nouveau_reloc.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_RELOC_H__
+#define __NOUVEAU_RELOC_H__
+
+int
+nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
+		   uint32_t reloc_offset, uint32_t *reloc_ptr,
+		   struct nouveau_bo *bo, uint32_t data, uint32_t data2,
+		   uint32_t flags, uint32_t vor, uint32_t tor);
+
+#endif
diff --git a/nouveau-1/nouveau_resource.c b/nouveau-1/nouveau_resource.c
new file mode 100644
index 0000000..7acaf7d
--- /dev/null
+++ b/nouveau-1/nouveau_resource.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "nouveau_private.h"
+
+int
+nouveau_resource_init(struct nouveau_resource **heap,
+		      unsigned start, unsigned size)
+{
+	struct nouveau_resource *r;
+
+	r = calloc(1, sizeof(struct nouveau_resource));
+	if (!r)
+		return 1;
+
+	r->start = start;
+	r->size  = size;
+	*heap = r;
+	return 0;
+}
+
+void
+nouveau_resource_destroy(struct nouveau_resource **heap)
+{
+	if (!*heap)
+		return;
+	free(*heap);
+	*heap = NULL;
+}
+
+int
+nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
+		       struct nouveau_resource **res)
+{
+	struct nouveau_resource *r;
+
+	if (!heap || !size || !res || *res)
+		return 1;
+
+	while (heap) {
+		if (!heap->in_use && heap->size >= size) {
+			r = calloc(1, sizeof(struct nouveau_resource));
+			if (!r)
+				return 1;
+
+			r->start  = (heap->start + heap->size) - size;
+			r->size   = size;
+			r->in_use = 1;
+			r->priv   = priv;
+
+			heap->size -= size;
+
+			r->next = heap->next;
+			if (heap->next)
+				heap->next->prev = r;
+			r->prev = heap;
+			heap->next = r;
+
+			*res = r;
+			return 0;
+		}
+			
+		heap = heap->next;
+	}
+
+	return 1;
+}
+
+void
+nouveau_resource_free(struct nouveau_resource **res)
+{
+	struct nouveau_resource *r;
+
+	if (!res || !*res)
+		return;
+	r = *res;
+	*res = NULL;
+
+	r->in_use = 0;
+
+	if (r->next && !r->next->in_use) {
+		struct nouveau_resource *new = r->next;
+
+		new->prev = r->prev;
+		if (r->prev)
+			r->prev->next = new;
+		new->size += r->size;
+		new->start = r->start;
+
+		free(r);
+		r = new;
+	}
+
+	if (r->prev && !r->prev->in_use) {
+		r->prev->next = r->next;
+		if (r->next)
+			r->next->prev = r->prev;
+		r->prev->size += r->size;
+		free(r);
+	}
+	
+}
diff --git a/nouveau-1/nouveau_resource.h b/nouveau-1/nouveau_resource.h
new file mode 100644
index 0000000..b760dfb
--- /dev/null
+++ b/nouveau-1/nouveau_resource.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NOUVEAU_RESOURCE_H__
+#define __NOUVEAU_RESOURCE_H__
+
+struct nouveau_resource {
+	struct nouveau_resource *prev;
+	struct nouveau_resource *next;
+
+	int in_use;
+	void *priv;
+
+	unsigned int start;
+	unsigned int size;
+};
+
+int
+nouveau_resource_init(struct nouveau_resource **heap, unsigned start,
+		      unsigned size);
+
+void
+nouveau_resource_destroy(struct nouveau_resource **heap);
+
+int
+nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv,
+		       struct nouveau_resource **);
+
+void
+nouveau_resource_free(struct nouveau_resource **);
+
+#endif
diff --git a/nouveau-1/nv04_pushbuf.h b/nouveau-1/nv04_pushbuf.h
new file mode 100644
index 0000000..586b284
--- /dev/null
+++ b/nouveau-1/nv04_pushbuf.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NV04_PUSHBUF_H__
+#define __NV04_PUSHBUF_H__
+
+#include "nouveau_pushbuf.h"
+
+static __inline__ void
+BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+	   unsigned mthd, unsigned size)
+{
+	if (gr->bound == NOUVEAU_GROBJ_UNBOUND)
+		nouveau_grobj_autobind(gr);
+	chan->subc[gr->subc].sequence = chan->subc_sequence++;
+
+	WAIT_RING(chan, size + 1);
+	OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd);
+}
+
+/* non-incrementing BEGIN_RING */
+static __inline__ void
+BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+	   unsigned mthd, unsigned size)
+{
+	BEGIN_RING(chan, gr, mthd | 0x40000000, size);
+}
+
+static __inline__ void
+BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
+{
+	struct nouveau_subchannel *subc = &gr->channel->subc[sc];
+
+	if (subc->gr) {
+		if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
+			assert(0);
+		subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
+	}
+	subc->gr = gr;
+	subc->gr->subc = sc;
+	subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
+
+	BEGIN_RING(chan, gr, 0x0000, 1);
+	OUT_RING  (chan, gr->handle);
+}
+
+#endif
diff --git a/nouveau-1/nvc0_pushbuf.h b/nouveau-1/nvc0_pushbuf.h
new file mode 100644
index 0000000..40dc7e6
--- /dev/null
+++ b/nouveau-1/nvc0_pushbuf.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS 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 __NVC0_PUSHBUF_H__
+#define __NVC0_PUSHBUF_H__
+
+#include "nouveau_pushbuf.h"
+
+#define SUBC_BIND(chan, gr) do {                                               \
+	if (gr->bound == NOUVEAU_GROBJ_UNBOUND)                                \
+		nouveau_grobj_autobind(gr);                                    \
+	chan->subc[gr->subc].sequence = chan->subc_sequence++;                 \
+} while (0)
+
+/* incremental methods */
+static __inline__ void
+BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+	   unsigned mthd, unsigned size)
+{
+	SUBC_BIND(chan, gr);
+	WAIT_RING(chan, size + 1);
+	OUT_RING (chan, (0x2 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+/* non-incremental */
+static __inline__ void
+BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+	      unsigned mthd, unsigned size)
+{
+	SUBC_BIND(chan, gr);
+	WAIT_RING(chan, size + 1);
+	OUT_RING (chan, (0x6 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+/* increment-once */
+static __inline__ void
+BEGIN_RING_1I(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+	      unsigned mthd, unsigned size)
+{
+	SUBC_BIND(chan, gr);
+	WAIT_RING(chan, size + 1);
+	OUT_RING (chan, (0xa << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+/* inline-data */
+static __inline__ void
+IMMED_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr,
+	   unsigned mthd, unsigned data)
+{
+	SUBC_BIND(chan, gr);
+	WAIT_RING(chan, 1);
+	OUT_RING (chan, (0x8 << 28) | (data << 16) | (gr->subc << 13) | (mthd >> 2));
+}
+
+static __inline__ void
+BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc)
+{
+	struct nouveau_subchannel *subc = &gr->channel->subc[sc];
+
+	if (subc->gr) {
+		if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT)
+			assert(0);
+		subc->gr->bound = NOUVEAU_GROBJ_UNBOUND;
+	}
+	subc->gr = gr;
+	subc->gr->subc = sc;
+	subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT;
+
+	BEGIN_RING(chan, gr, 0x0000, 1);
+	OUT_RING  (chan, gr->grclass);
+}
+
+#endif
