add android-x86 files

Bring in gralloc_drm files verbatim from the kitkat-x86 branch of Android-x86:
http://git.android-x86.org/

BUG=chromium:358029
TEST=none

Change-Id: Ic18bc41b91ce3d5841a26876b7a55c09f4b13240
Reviewed-on: https://chromium-review.googlesource.com/201365
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
Commit-Queue: Frank Henigman <fjhenigman@chromium.org>
Tested-by: Frank Henigman <fjhenigman@chromium.org>
diff --git a/src/drm_gralloc/gralloc.c b/src/drm_gralloc/gralloc.c
new file mode 100644
index 0000000..92866ca
--- /dev/null
+++ b/src/drm_gralloc/gralloc.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG 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 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.
+ */
+
+#define LOG_TAG "GRALLOC-MOD"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+/*
+ * Initialize the DRM device object, optionally with KMS.
+ */
+static int drm_init(struct drm_module_t *dmod, int kms)
+{
+	int err = 0;
+
+	pthread_mutex_lock(&dmod->mutex);
+	if (!dmod->drm) {
+		dmod->drm = gralloc_drm_create();
+		if (!dmod->drm)
+			err = -EINVAL;
+	}
+	if (!err && kms)
+		err = gralloc_drm_init_kms(dmod->drm);
+	pthread_mutex_unlock(&dmod->mutex);
+
+	return err;
+}
+
+static int drm_mod_perform(const struct gralloc_module_t *mod, int op, ...)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) mod;
+	va_list args;
+	int err;
+
+	err = drm_init(dmod, 0);
+	if (err)
+		return err;
+
+	va_start(args, op);
+	switch (op) {
+	case GRALLOC_MODULE_PERFORM_GET_DRM_FD:
+		{
+			int *fd = va_arg(args, int *);
+			*fd = gralloc_drm_get_fd(dmod->drm);
+			err = 0;
+		}
+		break;
+	/* should we remove this and next ops, and make it transparent? */
+	case GRALLOC_MODULE_PERFORM_GET_DRM_MAGIC:
+		{
+			int32_t *magic = va_arg(args, int32_t *);
+			err = gralloc_drm_get_magic(dmod->drm, magic);
+		}
+		break;
+	case GRALLOC_MODULE_PERFORM_AUTH_DRM_MAGIC:
+		{
+			int32_t magic = va_arg(args, int32_t);
+			err = gralloc_drm_auth_magic(dmod->drm, magic);
+		}
+		break;
+	case GRALLOC_MODULE_PERFORM_ENTER_VT:
+		{
+			err = gralloc_drm_set_master(dmod->drm);
+		}
+		break;
+	case GRALLOC_MODULE_PERFORM_LEAVE_VT:
+		{
+			gralloc_drm_drop_master(dmod->drm);
+			err = 0;
+		}
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	va_end(args);
+
+	return err;
+}
+
+static int drm_mod_register_buffer(const gralloc_module_t *mod,
+		buffer_handle_t handle)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) mod;
+	int err;
+
+	err = drm_init(dmod, 0);
+	if (err)
+		return err;
+
+	return gralloc_drm_handle_register(handle, dmod->drm);
+}
+
+static int drm_mod_unregister_buffer(const gralloc_module_t *mod,
+		buffer_handle_t handle)
+{
+	return gralloc_drm_handle_unregister(handle);
+}
+
+static int drm_mod_lock(const gralloc_module_t *mod, buffer_handle_t handle,
+		int usage, int x, int y, int w, int h, void **ptr)
+{
+	struct gralloc_drm_bo_t *bo;
+	int err;
+
+	bo = gralloc_drm_bo_from_handle(handle);
+	if (!bo)
+		return -EINVAL;
+
+	return gralloc_drm_bo_lock(bo, usage, x, y, w, h, ptr);
+}
+
+static int drm_mod_unlock(const gralloc_module_t *mod, buffer_handle_t handle)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) mod;
+	struct gralloc_drm_bo_t *bo;
+
+	bo = gralloc_drm_bo_from_handle(handle);
+	if (!bo)
+		return -EINVAL;
+
+	gralloc_drm_bo_unlock(bo);
+
+	return 0;
+}
+
+static int drm_mod_close_gpu0(struct hw_device_t *dev)
+{
+	struct alloc_device_t *alloc = (struct alloc_device_t *) dev;
+
+	free(alloc);
+
+	return 0;
+}
+
+static int drm_mod_free_gpu0(alloc_device_t *dev, buffer_handle_t handle)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
+	struct gralloc_drm_bo_t *bo;
+
+	bo = gralloc_drm_bo_from_handle(handle);
+	if (!bo)
+		return -EINVAL;
+
+	gralloc_drm_bo_decref(bo);
+
+	return 0;
+}
+
+static int drm_mod_alloc_gpu0(alloc_device_t *dev,
+		int w, int h, int format, int usage,
+		buffer_handle_t *handle, int *stride)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) dev->common.module;
+	struct gralloc_drm_bo_t *bo;
+	int size, bpp, err;
+
+	bpp = gralloc_drm_get_bpp(format);
+	if (!bpp)
+		return -EINVAL;
+
+	bo = gralloc_drm_bo_create(dmod->drm, w, h, format, usage);
+	if (!bo)
+		return -ENOMEM;
+
+	if (gralloc_drm_bo_need_fb(bo)) {
+		err = gralloc_drm_bo_add_fb(bo);
+		if (err) {
+			ALOGE("failed to add fb");
+			gralloc_drm_bo_decref(bo);
+			return err;
+		}
+	}
+
+	*handle = gralloc_drm_bo_get_handle(bo, stride);
+	/* in pixels */
+	*stride /= bpp;
+
+	return 0;
+}
+
+static int drm_mod_open_gpu0(struct drm_module_t *dmod, hw_device_t **dev)
+{
+	struct alloc_device_t *alloc;
+	int err;
+
+	err = drm_init(dmod, 0);
+	if (err)
+		return err;
+
+	alloc = calloc(1, sizeof(*alloc));
+	if (!alloc)
+		return -EINVAL;
+
+	alloc->common.tag = HARDWARE_DEVICE_TAG;
+	alloc->common.version = 0;
+	alloc->common.module = &dmod->base.common;
+	alloc->common.close = drm_mod_close_gpu0;
+
+	alloc->alloc = drm_mod_alloc_gpu0;
+	alloc->free = drm_mod_free_gpu0;
+
+	*dev = &alloc->common;
+
+	return 0;
+}
+
+static int drm_mod_close_fb0(struct hw_device_t *dev)
+{
+	struct framebuffer_device_t *fb = (struct framebuffer_device_t *) dev;
+
+	free(fb);
+
+	return 0;
+}
+
+static int drm_mod_set_swap_interval_fb0(struct framebuffer_device_t *fb,
+		int interval)
+{
+	if (interval < fb->minSwapInterval || interval > fb->maxSwapInterval)
+		return -EINVAL;
+	return 0;
+}
+
+static int drm_mod_post_fb0(struct framebuffer_device_t *fb,
+		buffer_handle_t handle)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) fb->common.module;
+	struct gralloc_drm_bo_t *bo;
+
+	bo = gralloc_drm_bo_from_handle(handle);
+	if (!bo)
+		return -EINVAL;
+
+	return gralloc_drm_bo_post(bo);
+}
+
+#include <GLES/gl.h>
+static int drm_mod_composition_complete_fb0(struct framebuffer_device_t *fb)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) fb->common.module;
+
+	if (gralloc_drm_is_kms_pipelined(dmod->drm))
+		glFlush();
+	else
+		glFinish();
+
+	return 0;
+}
+
+static int drm_mod_open_fb0(struct drm_module_t *dmod, struct hw_device_t **dev)
+{
+	struct framebuffer_device_t *fb;
+	int err;
+
+	err = drm_init(dmod, 1);
+	if (err)
+		return err;
+
+	fb = calloc(1, sizeof(*fb));
+	if (!fb)
+		return -ENOMEM;
+
+	fb->common.tag = HARDWARE_DEVICE_TAG;
+	fb->common.version = 0;
+	fb->common.module = &dmod->base.common;
+	fb->common.close = drm_mod_close_fb0;
+
+	fb->setSwapInterval = drm_mod_set_swap_interval_fb0;
+	fb->post = drm_mod_post_fb0;
+	fb->compositionComplete = drm_mod_composition_complete_fb0;
+
+	gralloc_drm_get_kms_info(dmod->drm, fb);
+
+	*dev = &fb->common;
+
+	ALOGI("mode.hdisplay %d\n"
+	     "mode.vdisplay %d\n"
+	     "mode.vrefresh %f\n"
+	     "format 0x%x\n"
+	     "xdpi %f\n"
+	     "ydpi %f\n",
+	     fb->width,
+	     fb->height,
+	     fb->fps,
+	     fb->format,
+	     fb->xdpi, fb->ydpi);
+
+	return 0;
+}
+
+static int drm_mod_open(const struct hw_module_t *mod,
+		const char *name, struct hw_device_t **dev)
+{
+	struct drm_module_t *dmod = (struct drm_module_t *) mod;
+	int err;
+
+	if (strcmp(name, GRALLOC_HARDWARE_GPU0) == 0)
+		err = drm_mod_open_gpu0(dmod, dev);
+	else if (strcmp(name, GRALLOC_HARDWARE_FB0) == 0)
+		err = drm_mod_open_fb0(dmod, dev);
+	else
+		err = -EINVAL;
+
+	return err;
+}
+
+static struct hw_module_methods_t drm_mod_methods = {
+	.open = drm_mod_open
+};
+
+struct drm_module_t HAL_MODULE_INFO_SYM = {
+	.base = {
+		.common = {
+			.tag = HARDWARE_MODULE_TAG,
+			.version_major = 1,
+			.version_minor = 0,
+			.id = GRALLOC_HARDWARE_MODULE_ID,
+			.name = "DRM Memory Allocator",
+			.author = "Chia-I Wu",
+			.methods = &drm_mod_methods
+		},
+		.registerBuffer = drm_mod_register_buffer,
+		.unregisterBuffer = drm_mod_unregister_buffer,
+		.lock = drm_mod_lock,
+		.unlock = drm_mod_unlock,
+		.perform = drm_mod_perform
+	},
+	.hwc_reserve_plane = gralloc_drm_reserve_plane,
+	.hwc_disable_planes = gralloc_drm_disable_planes,
+	.hwc_set_plane_handle = gralloc_drm_set_plane_handle,
+
+	.mutex = PTHREAD_MUTEX_INITIALIZER,
+	.drm = NULL
+};
diff --git a/src/drm_gralloc/gralloc_drm.c b/src/drm_gralloc/gralloc_drm.c
new file mode 100644
index 0000000..bd38d57
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG 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 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.
+ */
+
+#define LOG_TAG "GRALLOC-DRM"
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define GRALLOC_DRM_DEVICE "/dev/dri/card0"
+
+static int32_t gralloc_drm_pid = 0;
+
+/*
+ * Return the pid of the process.
+ */
+static int gralloc_drm_get_pid(void)
+{
+	if (unlikely(!gralloc_drm_pid))
+		android_atomic_write((int32_t) getpid(), &gralloc_drm_pid);
+
+	return gralloc_drm_pid;
+}
+
+/*
+ * Create the driver for a DRM fd.
+ */
+static struct gralloc_drm_drv_t *
+init_drv_from_fd(int fd)
+{
+	struct gralloc_drm_drv_t *drv = NULL;
+	drmVersionPtr version;
+
+	/* get the kernel module name */
+	version = drmGetVersion(fd);
+	if (!version) {
+		ALOGE("invalid DRM fd");
+		return NULL;
+	}
+
+	if (version->name) {
+#ifdef ENABLE_PIPE
+		drv = gralloc_drm_drv_create_for_pipe(fd, version->name);
+#endif
+
+#ifdef ENABLE_INTEL
+		if (!drv && !strcmp(version->name, "i915"))
+			drv = gralloc_drm_drv_create_for_intel(fd);
+#endif
+#ifdef ENABLE_RADEON
+		if (!drv && !strcmp(version->name, "radeon"))
+			drv = gralloc_drm_drv_create_for_radeon(fd);
+#endif
+#ifdef ENABLE_NOUVEAU
+		if (!drv && !strcmp(version->name, "nouveau"))
+			drv = gralloc_drm_drv_create_for_nouveau(fd);
+#endif
+	}
+
+	if (!drv) {
+		ALOGE("unsupported driver: %s", (version->name) ?
+				version->name : "NULL");
+	}
+
+	drmFreeVersion(version);
+
+	return drv;
+}
+
+/*
+ * Create a DRM device object.
+ */
+struct gralloc_drm_t *gralloc_drm_create(void)
+{
+	struct gralloc_drm_t *drm;
+	int err;
+
+	drm = calloc(1, sizeof(*drm));
+	if (!drm)
+		return NULL;
+
+	drm->fd = open(GRALLOC_DRM_DEVICE, O_RDWR);
+	if (drm->fd < 0) {
+		ALOGE("failed to open %s", GRALLOC_DRM_DEVICE);
+		return NULL;
+	}
+
+	drm->drv = init_drv_from_fd(drm->fd);
+	if (!drm->drv) {
+		close(drm->fd);
+		free(drm);
+		return NULL;
+	}
+
+	return drm;
+}
+
+/*
+ * Destroy a DRM device object.
+ */
+void gralloc_drm_destroy(struct gralloc_drm_t *drm)
+{
+	if (drm->drv)
+		drm->drv->destroy(drm->drv);
+	close(drm->fd);
+	free(drm);
+}
+
+/*
+ * Get the file descriptor of a DRM device object.
+ */
+int gralloc_drm_get_fd(struct gralloc_drm_t *drm)
+{
+	return drm->fd;
+}
+
+/*
+ * Get the magic for authentication.
+ */
+int gralloc_drm_get_magic(struct gralloc_drm_t *drm, int32_t *magic)
+{
+	return drmGetMagic(drm->fd, (drm_magic_t *) magic);
+}
+
+/*
+ * Authenticate a magic.
+ */
+int gralloc_drm_auth_magic(struct gralloc_drm_t *drm, int32_t magic)
+{
+	return drmAuthMagic(drm->fd, (drm_magic_t) magic);
+}
+
+/*
+ * Set as the master of a DRM device.
+ */
+int gralloc_drm_set_master(struct gralloc_drm_t *drm)
+{
+	ALOGD("set master");
+	drmSetMaster(drm->fd);
+	drm->first_post = 1;
+
+	return 0;
+}
+
+/*
+ * Drop from the master of a DRM device.
+ */
+void gralloc_drm_drop_master(struct gralloc_drm_t *drm)
+{
+	drmDropMaster(drm->fd);
+}
+
+/*
+ * Validate a buffer handle and return the associated bo.
+ */
+static struct gralloc_drm_bo_t *validate_handle(buffer_handle_t _handle,
+		struct gralloc_drm_t *drm)
+{
+	struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+
+	if (!handle)
+		return NULL;
+
+	/* the buffer handle is passed to a new process */
+	if (unlikely(handle->data_owner != gralloc_drm_pid)) {
+		struct gralloc_drm_bo_t *bo;
+
+		/* check only */
+		if (!drm)
+			return NULL;
+
+		/* create the struct gralloc_drm_bo_t locally */
+		if (handle->name)
+			bo = drm->drv->alloc(drm->drv, handle);
+		else /* an invalid handle */
+			bo = NULL;
+		if (bo) {
+			bo->drm = drm;
+			bo->imported = 1;
+			bo->handle = handle;
+			bo->refcount = 1;
+		}
+
+		handle->data_owner = gralloc_drm_get_pid();
+		handle->data = (int) bo;
+	}
+
+	return (struct gralloc_drm_bo_t *) handle->data;
+}
+
+/*
+ * Register a buffer handle.
+ */
+int gralloc_drm_handle_register(buffer_handle_t handle, struct gralloc_drm_t *drm)
+{
+	return (validate_handle(handle, drm)) ? 0 : -EINVAL;
+}
+
+/*
+ * Unregister a buffer handle.  It is no-op for handles created locally.
+ */
+int gralloc_drm_handle_unregister(buffer_handle_t handle)
+{
+	struct gralloc_drm_bo_t *bo;
+
+	bo = validate_handle(handle, NULL);
+	if (!bo)
+		return -EINVAL;
+
+	if (bo->imported)
+		gralloc_drm_bo_decref(bo);
+
+	return 0;
+}
+
+/*
+ * Create a buffer handle.
+ */
+static struct gralloc_drm_handle_t *create_bo_handle(int width,
+		int height, int format, int usage)
+{
+	struct gralloc_drm_handle_t *handle;
+
+	handle = calloc(1, sizeof(*handle));
+	if (!handle)
+		return NULL;
+
+	handle->base.version = sizeof(handle->base);
+	handle->base.numInts = GRALLOC_DRM_HANDLE_NUM_INTS;
+	handle->base.numFds = GRALLOC_DRM_HANDLE_NUM_FDS;
+
+	handle->magic = GRALLOC_DRM_HANDLE_MAGIC;
+	handle->width = width;
+	handle->height = height;
+	handle->format = format;
+	handle->usage = usage;
+	handle->plane_mask = 0;
+
+	return handle;
+}
+
+/*
+ * Create a bo.
+ */
+struct gralloc_drm_bo_t *gralloc_drm_bo_create(struct gralloc_drm_t *drm,
+		int width, int height, int format, int usage)
+{
+	struct gralloc_drm_bo_t *bo;
+	struct gralloc_drm_handle_t *handle;
+
+	handle = create_bo_handle(width, height, format, usage);
+	if (!handle)
+		return NULL;
+
+	handle->plane_mask = planes_for_format(drm, format);
+
+	bo = drm->drv->alloc(drm->drv, handle);
+	if (!bo) {
+		free(handle);
+		return NULL;
+	}
+
+	bo->drm = drm;
+	bo->imported = 0;
+	bo->handle = handle;
+	bo->fb_id = 0;
+	bo->refcount = 1;
+
+	handle->data_owner = gralloc_drm_get_pid();
+	handle->data = (int) bo;
+
+	return bo;
+}
+
+/*
+ * Destroy a bo.
+ */
+static void gralloc_drm_bo_destroy(struct gralloc_drm_bo_t *bo)
+{
+	struct gralloc_drm_handle_t *handle = bo->handle;
+	int imported = bo->imported;
+
+	/* gralloc still has a reference */
+	if (bo->refcount)
+		return;
+
+	gralloc_drm_bo_rm_fb(bo);
+
+	bo->drm->drv->free(bo->drm->drv, bo);
+	if (imported) {
+		handle->data_owner = 0;
+		handle->data = 0;
+	}
+	else {
+		free(handle);
+	}
+}
+
+/*
+ * Decrease refcount, if no refs anymore then destroy.
+ */
+void gralloc_drm_bo_decref(struct gralloc_drm_bo_t *bo)
+{
+	if (!--bo->refcount)
+		gralloc_drm_bo_destroy(bo);
+}
+
+/*
+ * Return the bo of a registered handle.
+ */
+struct gralloc_drm_bo_t *gralloc_drm_bo_from_handle(buffer_handle_t handle)
+{
+	return validate_handle(handle, NULL);
+}
+
+/*
+ * Get the buffer handle and stride of a bo.
+ */
+buffer_handle_t gralloc_drm_bo_get_handle(struct gralloc_drm_bo_t *bo, int *stride)
+{
+	if (stride)
+		*stride = bo->handle->stride;
+	return &bo->handle->base;
+}
+
+int gralloc_drm_get_gem_handle(buffer_handle_t _handle)
+{
+	struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+	return (handle) ? handle->name : 0;
+}
+
+/*
+ * Query YUV component offsets for a buffer handle
+ */
+void gralloc_drm_resolve_format(buffer_handle_t _handle,
+	uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+	struct gralloc_drm_handle_t *handle = gralloc_drm_handle(_handle);
+	struct gralloc_drm_bo_t *bo = (struct gralloc_drm_bo_t *) handle->data;
+	struct gralloc_drm_t *drm = bo->drm;
+
+	/* if handle exists and driver implements resolve_format */
+	if (handle && drm->drv->resolve_format)
+		drm->drv->resolve_format(drm->drv, bo,
+			pitches, offsets, handles);
+}
+
+/*
+ * Lock a bo.  XXX thread-safety?
+ */
+int gralloc_drm_bo_lock(struct gralloc_drm_bo_t *bo,
+		int usage, int x, int y, int w, int h,
+		void **addr)
+{
+	if ((bo->handle->usage & usage) != usage) {
+		/* make FB special for testing software renderer with */
+
+		if (!(bo->handle->usage & GRALLOC_USAGE_HW_FB)
+		&&  !(bo->handle->usage & GRALLOC_USAGE_HW_TEXTURE)) {
+			ALOGE("bo.usage:x%X/usage:x%X is not GRALLOC_USAGE_HW_FB or GRALLOC_USAGE_HW_TEXTURE"
+				,bo->handle->usage,usage);
+			return -EINVAL;
+		}
+	}
+
+	/* allow multiple locks with compatible usages */
+	if (bo->lock_count && (bo->locked_for & usage) != usage)
+		return -EINVAL;
+
+	usage |= bo->locked_for;
+
+	if (usage & (GRALLOC_USAGE_SW_WRITE_MASK |
+		     GRALLOC_USAGE_SW_READ_MASK)) {
+		/* the driver is supposed to wait for the bo */
+		int write = !!(usage & GRALLOC_USAGE_SW_WRITE_MASK);
+		int err = bo->drm->drv->map(bo->drm->drv, bo,
+				x, y, w, h, write, addr);
+		if (err)
+			return err;
+	}
+	else {
+		/* kernel handles the synchronization here */
+	}
+
+	bo->lock_count++;
+	bo->locked_for |= usage;
+
+	return 0;
+}
+
+/*
+ * Unlock a bo.
+ */
+void gralloc_drm_bo_unlock(struct gralloc_drm_bo_t *bo)
+{
+	int mapped = bo->locked_for &
+		(GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_SW_READ_MASK);
+
+	if (!bo->lock_count)
+		return;
+
+	if (mapped)
+		bo->drm->drv->unmap(bo->drm->drv, bo);
+
+	bo->lock_count--;
+	if (!bo->lock_count)
+		bo->locked_for = 0;
+}
diff --git a/src/drm_gralloc/gralloc_drm.h b/src/drm_gralloc/gralloc_drm.h
new file mode 100644
index 0000000..c32aaf6
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG 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 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.
+ */
+
+#ifndef _GRALLOC_DRM_H_
+#define _GRALLOC_DRM_H_
+
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
+
+struct gralloc_drm_t;
+struct gralloc_drm_bo_t;
+
+struct gralloc_drm_t *gralloc_drm_create(void);
+void gralloc_drm_destroy(struct gralloc_drm_t *drm);
+
+int gralloc_drm_get_fd(struct gralloc_drm_t *drm);
+int gralloc_drm_get_magic(struct gralloc_drm_t *drm, int32_t *magic);
+int gralloc_drm_auth_magic(struct gralloc_drm_t *drm, int32_t magic);
+int gralloc_drm_set_master(struct gralloc_drm_t *drm);
+void gralloc_drm_drop_master(struct gralloc_drm_t *drm);
+
+int gralloc_drm_init_kms(struct gralloc_drm_t *drm);
+void gralloc_drm_fini_kms(struct gralloc_drm_t *drm);
+int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm);
+
+void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm, struct framebuffer_device_t *fb);
+int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm);
+
+static inline int gralloc_drm_get_bpp(int format)
+{
+	int bpp;
+
+	switch (format) {
+	case HAL_PIXEL_FORMAT_RGBA_8888:
+	case HAL_PIXEL_FORMAT_RGBX_8888:
+	case HAL_PIXEL_FORMAT_BGRA_8888:
+		bpp = 4;
+		break;
+	case HAL_PIXEL_FORMAT_RGB_888:
+		bpp = 3;
+		break;
+	case HAL_PIXEL_FORMAT_RGB_565:
+	case HAL_PIXEL_FORMAT_YCbCr_422_I:
+		bpp = 2;
+		break;
+	/* planar; only Y is considered */
+	case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_DRM_NV12:
+	case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+	case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+		bpp = 1;
+		break;
+	default:
+		bpp = 0;
+		break;
+	}
+
+	return bpp;
+}
+
+static inline void gralloc_drm_align_geometry(int format, int *width, int *height)
+{
+	int align_w = 1, align_h = 1, extra_height_div = 0;
+
+	switch (format) {
+	case HAL_PIXEL_FORMAT_DRM_NV12:
+	case HAL_PIXEL_FORMAT_YV12:
+		align_w = 32;
+		align_h = 2;
+		extra_height_div = 2;
+		break;
+	case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+		align_w = 2;
+		extra_height_div = 1;
+		break;
+	case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+		align_w = 2;
+		align_h = 2;
+		extra_height_div = 2;
+		break;
+	case HAL_PIXEL_FORMAT_YCbCr_422_I:
+		align_w = 2;
+		break;
+	}
+
+	*width = ALIGN(*width, align_w);
+	*height = ALIGN(*height, align_h);
+
+	if (extra_height_div)
+		*height += *height / extra_height_div;
+}
+
+int gralloc_drm_handle_register(buffer_handle_t handle, struct gralloc_drm_t *drm);
+int gralloc_drm_handle_unregister(buffer_handle_t handle);
+
+struct gralloc_drm_bo_t *gralloc_drm_bo_create(struct gralloc_drm_t *drm, int width, int height, int format, int usage);
+void gralloc_drm_bo_decref(struct gralloc_drm_bo_t *bo);
+
+struct gralloc_drm_bo_t *gralloc_drm_bo_from_handle(buffer_handle_t handle);
+buffer_handle_t gralloc_drm_bo_get_handle(struct gralloc_drm_bo_t *bo, int *stride);
+int gralloc_drm_get_gem_handle(buffer_handle_t handle);
+void gralloc_drm_resolve_format(buffer_handle_t _handle, uint32_t *pitches, uint32_t *offsets, uint32_t *handles);
+unsigned int planes_for_format(struct gralloc_drm_t *drm, int hal_format);
+
+int gralloc_drm_bo_lock(struct gralloc_drm_bo_t *bo, int x, int y, int w, int h, int enable_write, void **addr);
+void gralloc_drm_bo_unlock(struct gralloc_drm_bo_t *bo);
+
+int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo);
+int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo);
+void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo);
+int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo);
+
+int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
+	buffer_handle_t handle, uint32_t id,
+	uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h,
+	uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h);
+void gralloc_drm_disable_planes(struct gralloc_drm_t *mod);
+int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
+	uint32_t id, buffer_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _GRALLOC_DRM_H_ */
diff --git a/src/drm_gralloc/gralloc_drm_handle.h b/src/drm_gralloc/gralloc_drm_handle.h
new file mode 100644
index 0000000..f7b03b2
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_handle.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG 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 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.
+ */
+
+#ifndef _GRALLOC_DRM_HANDLE_H_
+#define _GRALLOC_DRM_HANDLE_H_
+
+#include <cutils/native_handle.h>
+#include <system/graphics.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gralloc_drm_handle_t {
+	native_handle_t base;
+
+#define GRALLOC_DRM_HANDLE_MAGIC 0x12345678
+#define GRALLOC_DRM_HANDLE_NUM_INTS 10
+#define GRALLOC_DRM_HANDLE_NUM_FDS 0
+	int magic;
+
+	int width;
+	int height;
+	int format;
+	int usage;
+
+	unsigned int plane_mask; /* planes that support handle */
+
+	int name;   /* the name of the bo */
+	int stride; /* the stride in bytes */
+
+	int data_owner; /* owner of data (for validation) */
+	int data;       /* pointer to struct gralloc_drm_bo_t */
+};
+
+static inline struct gralloc_drm_handle_t *gralloc_drm_handle(buffer_handle_t _handle)
+{
+	struct gralloc_drm_handle_t *handle =
+		(struct gralloc_drm_handle_t *) _handle;
+
+	if (handle && (handle->base.version != sizeof(handle->base) ||
+	               handle->base.numInts != GRALLOC_DRM_HANDLE_NUM_INTS ||
+	               handle->base.numFds != GRALLOC_DRM_HANDLE_NUM_FDS ||
+	               handle->magic != GRALLOC_DRM_HANDLE_MAGIC))
+		handle = NULL;
+
+	return handle;
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _GRALLOC_DRM_HANDLE_H_ */
diff --git a/src/drm_gralloc/gralloc_drm_intel.c b/src/drm_gralloc/gralloc_drm_intel.c
new file mode 100644
index 0000000..3a020b4
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_intel.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ *
+ * drm_gem_intel_copy is based on xorg-driver-intel, which has
+ *
+ * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
+ *
+ * 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 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.
+ */
+
+#define LOG_TAG "GRALLOC-I915"
+
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <drm.h>
+#include <intel_bufmgr.h>
+#include <i915_drm.h>
+
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+
+#define MI_NOOP                     (0)
+#define MI_BATCH_BUFFER_END         (0x0a << 23)
+#define MI_FLUSH                    (0x04 << 23)
+#define MI_FLUSH_DW                 (0x26 << 23)
+#define MI_WRITE_DIRTY_STATE        (1 << 4) 
+#define MI_INVALIDATE_MAP_CACHE     (1 << 0)
+#define XY_SRC_COPY_BLT_CMD         ((2 << 29) | (0x53 << 22) | 6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1 << 21)
+#define XY_SRC_COPY_BLT_WRITE_RGB   (1 << 20)
+#define XY_SRC_COPY_BLT_SRC_TILED   (1 << 15)
+#define XY_SRC_COPY_BLT_DST_TILED   (1 << 11)
+
+struct intel_info {
+	struct gralloc_drm_drv_t base;
+
+	int fd;
+	drm_intel_bufmgr *bufmgr;
+	int gen;
+
+	drm_intel_bo *batch_ibo;
+	uint32_t *batch, *cur;
+	int capacity, size;
+	int exec_blt;
+};
+
+struct intel_buffer {
+	struct gralloc_drm_bo_t base;
+	drm_intel_bo *ibo;
+	uint32_t tiling;
+};
+
+static int
+batch_next(struct intel_info *info)
+{
+	info->cur = info->batch;
+
+	if (info->batch_ibo)
+		drm_intel_bo_unreference(info->batch_ibo);
+
+	info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
+			"gralloc-batchbuffer", info->size, 4096);
+
+	return (info->batch_ibo) ? 0 : -ENOMEM;
+}
+
+static int
+batch_count(struct intel_info *info)
+{
+	return info->cur - info->batch;
+}
+
+static void
+batch_dword(struct intel_info *info, uint32_t dword)
+{
+	*info->cur++ = dword;
+}
+
+static int
+batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
+		uint32_t read_domains, uint32_t write_domain)
+{
+	struct intel_buffer *target = (struct intel_buffer *) bo;
+	uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
+	int ret;
+
+	ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
+			target->ibo, 0, read_domains, write_domain);
+	if (!ret)
+		batch_dword(info, target->ibo->offset);
+
+	return ret;
+}
+
+static int
+batch_flush(struct intel_info *info)
+{
+	int size, ret;
+
+	batch_dword(info, MI_BATCH_BUFFER_END);
+	size = batch_count(info);
+	if (size & 1) {
+		batch_dword(info, MI_NOOP);
+		size = batch_count(info);
+	}
+
+	size *= sizeof(info->batch[0]);
+	ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
+	if (ret) {
+		ALOGE("failed to subdata batch");
+		goto fail;
+	}
+	ret = drm_intel_bo_mrb_exec(info->batch_ibo, size,
+		NULL, 0, 0, info->exec_blt);
+	if (ret) {
+		ALOGE("failed to exec batch");
+		goto fail;
+	}
+
+	return batch_next(info);
+
+fail:
+	info->cur = info->batch;
+
+	return ret;
+}
+
+static int
+batch_reserve(struct intel_info *info, int count)
+{
+	int ret = 0;
+
+	if (batch_count(info) + count > info->capacity)
+		ret = batch_flush(info);
+
+	return ret;
+}
+
+static void
+batch_destroy(struct intel_info *info)
+{
+	if (info->batch_ibo) {
+		drm_intel_bo_unreference(info->batch_ibo);
+		info->batch_ibo = NULL;
+	}
+
+	if (info->batch) {
+		free(info->batch);
+		info->batch = NULL;
+	}
+}
+
+static int
+batch_init(struct intel_info *info)
+{
+	int ret;
+
+	info->capacity = 512;
+	info->size = (info->capacity + 16) * sizeof(info->batch[0]);
+
+	info->batch = malloc(info->size);
+	if (!info->batch)
+		return -ENOMEM;
+
+	ret = batch_next(info);
+	if (ret) {
+		free(info->batch);
+		info->batch = NULL;
+	}
+
+	return ret;
+}
+
+static void intel_resolve_format(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_bo_t *bo,
+		uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+	/*
+	 * TODO - should take account hw specific padding, alignment
+	 * for camera, video decoder etc.
+	 */
+
+	struct intel_buffer *ib = (struct intel_buffer *) bo;
+
+	memset(pitches, 0, 4 * sizeof(uint32_t));
+	memset(offsets, 0, 4 * sizeof(uint32_t));
+	memset(handles, 0, 4 * sizeof(uint32_t));
+
+	pitches[0] = ib->base.handle->stride;
+	handles[0] = ib->base.fb_handle;
+
+	switch(ib->base.handle->format) {
+		case HAL_PIXEL_FORMAT_YV12:
+
+			// U and V stride are half of Y plane
+			pitches[2] = pitches[0]/2;
+			pitches[1] = pitches[0]/2;
+
+			// like I420 but U and V are in reverse order
+			offsets[2] = offsets[0] +
+				pitches[0] * ib->base.handle->height;
+			offsets[1] = offsets[2] +
+				pitches[2] * ib->base.handle->height/2;
+
+			handles[1] = handles[2] = handles[0];
+			break;
+
+		case HAL_PIXEL_FORMAT_DRM_NV12:
+
+			// U and V are interleaved in 2nd plane
+			pitches[1] = pitches[0];
+			offsets[1] = offsets[0] +
+				pitches[0] * ib->base.handle->height;
+
+			handles[1] = handles[0];
+			break;
+	}
+}
+
+
+static void intel_blit(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_bo_t *dst,
+		struct gralloc_drm_bo_t *src,
+		uint16_t dst_x1, uint16_t dst_y1,
+		uint16_t dst_x2, uint16_t dst_y2,
+		uint16_t src_x1, uint16_t src_y1,
+		uint16_t src_x2, uint16_t src_y2)
+{
+	struct intel_info *info = (struct intel_info *) drv;
+	struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
+	struct intel_buffer *src_ib = (struct intel_buffer *) src;
+	drm_intel_bo *bo_table[3];
+	uint32_t cmd, br13, dst_pitch, src_pitch;
+
+	/*
+	 * XY_SRC_COPY_BLT_CMD does not support scaling,
+	 * rectangle dimensions much match
+	 */
+	if (src_x2 - src_x1 != dst_x2 - dst_x1 ||
+		src_y2 - src_y1 != dst_y2 - dst_y1) {
+		ALOGE("%s, src and dst rect must match", __func__);
+		return;
+	}
+
+	if (dst->handle->format != src->handle->format) {
+		ALOGE("%s, src and dst format must match", __func__);
+		return;
+	}
+
+	/* nothing to blit */
+	if (src_x2 <= src_x1 || src_y2 <= src_y1)
+		return;
+
+	/* clamp x2, y2 to surface size */
+	if (src_x2 > src->handle->width)
+		src_x2 = src->handle->width;
+	if (src_y2 > src->handle->height)
+		src_y2 = src->handle->height;
+
+	if (dst_x2 > dst->handle->width)
+		dst_x2 = dst->handle->width;
+	if (dst_y2 > dst->handle->height)
+		dst_y2 = dst->handle->height;
+
+	bo_table[0] = info->batch_ibo;
+	bo_table[1] = src_ib->ibo;
+	bo_table[2] = dst_ib->ibo;
+	if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
+		if (batch_flush(info))
+			return;
+		assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
+	}
+
+	cmd = XY_SRC_COPY_BLT_CMD;
+	br13 = 0xcc << 16; /* ROP_S/GXcopy */
+	dst_pitch = dst->handle->stride;
+	src_pitch = src->handle->stride;
+
+	/* Blit pitch must be dword-aligned.  Otherwise, the hardware appears to
+	 * drop the low bits.
+	 */
+	if (src_pitch % 4 != 0 || dst_pitch % 4 != 0) {
+		ALOGE("%s, src and dst pitch must be dword aligned", __func__);
+		return;
+	}
+
+	switch (gralloc_drm_get_bpp(dst->handle->format)) {
+	case 1:
+		break;
+	case 2:
+		br13 |= (1 << 24);
+		break;
+	case 4:
+		br13 |= (1 << 24) | (1 << 25);
+		cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
+		break;
+	default:
+		ALOGE("%s, copy with unsupported format", __func__);
+		return;
+	}
+
+	if (info->gen >= 40) {
+		if (dst_ib->tiling != I915_TILING_NONE) {
+			assert(dst_pitch % 512 == 0);
+			dst_pitch >>= 2;
+			cmd |= XY_SRC_COPY_BLT_DST_TILED;
+		}
+		if (src_ib->tiling != I915_TILING_NONE) {
+			assert(src_pitch % 512 == 0);
+			src_pitch >>= 2;
+			cmd |= XY_SRC_COPY_BLT_SRC_TILED;
+		}
+	}
+
+	if (batch_reserve(info, 8))
+		return;
+
+	batch_dword(info, cmd);
+	batch_dword(info, br13 | (uint16_t)dst_pitch);
+	batch_dword(info, (dst_y1 << 16) | dst_x1);
+	batch_dword(info, (dst_y2 << 16) | dst_x2);
+	batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+	batch_dword(info, (src_y1 << 16) | src_x1);
+	batch_dword(info, (uint16_t)src_pitch);
+	batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
+
+	if (info->gen >= 60) {
+		batch_reserve(info, 4);
+		batch_dword(info, MI_FLUSH_DW | 2);
+		batch_dword(info, 0);
+		batch_dword(info, 0);
+		batch_dword(info, 0);
+	}
+	else {
+		int flags = (info->gen >= 40) ? 0 :
+			MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
+
+		batch_reserve(info, 1);
+		batch_dword(info, MI_FLUSH | flags);
+	}
+
+	batch_flush(info);
+}
+
+static drm_intel_bo *alloc_ibo(struct intel_info *info,
+		const struct gralloc_drm_handle_t *handle,
+		uint32_t *tiling, unsigned long *stride)
+{
+	drm_intel_bo *ibo;
+	const char *name;
+	int aligned_width, aligned_height, bpp;
+	unsigned long flags;
+
+	flags = 0;
+	bpp = gralloc_drm_get_bpp(handle->format);
+	if (!bpp) {
+		ALOGE("unrecognized format 0x%x", handle->format);
+		return NULL;
+	}
+
+	aligned_width = handle->width;
+	aligned_height = handle->height;
+	gralloc_drm_align_geometry(handle->format,
+			&aligned_width, &aligned_height);
+
+	if (handle->usage & GRALLOC_USAGE_HW_FB) {
+		unsigned long max_stride;
+
+		max_stride = 32 * 1024;
+		if (info->gen < 50)
+			max_stride /= 2;
+		if (info->gen < 40)
+			max_stride /= 2;
+
+		name = "gralloc-fb";
+		aligned_width = ALIGN(aligned_width, 64);
+		flags = BO_ALLOC_FOR_RENDER;
+
+		*tiling = I915_TILING_X;
+		*stride = aligned_width * bpp;
+		if (*stride > max_stride) {
+			*tiling = I915_TILING_NONE;
+			max_stride = 32 * 1024;
+			if (*stride > max_stride)
+				return NULL;
+		}
+
+		while (1) {
+			ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
+					aligned_width, aligned_height,
+					bpp, tiling, stride, flags);
+			if (!ibo || *stride > max_stride) {
+				if (ibo) {
+					drm_intel_bo_unreference(ibo);
+					ibo = NULL;
+				}
+
+				if (*tiling != I915_TILING_NONE) {
+					/* retry */
+					*tiling = I915_TILING_NONE;
+					max_stride = 32 * 1024;
+					continue;
+				}
+			}
+			if (ibo)
+				drm_intel_bo_disable_reuse(ibo);
+			break;
+		}
+	}
+	else {
+		if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
+				     GRALLOC_USAGE_SW_WRITE_OFTEN))
+			*tiling = I915_TILING_NONE;
+		else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
+			 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
+			  handle->width >= 64))
+			*tiling = I915_TILING_X;
+		else
+			*tiling = I915_TILING_NONE;
+
+		if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
+			name = "gralloc-texture";
+			/* see 2D texture layout of DRI drivers */
+			aligned_width = ALIGN(aligned_width, 4);
+			aligned_height = ALIGN(aligned_height, 2);
+		}
+		else {
+			name = "gralloc-buffer";
+		}
+
+		if (handle->usage & GRALLOC_USAGE_HW_RENDER)
+			flags = BO_ALLOC_FOR_RENDER;
+
+		ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
+				aligned_width, aligned_height,
+				bpp, tiling, stride, flags);
+	}
+
+	return ibo;
+}
+
+static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_handle_t *handle)
+{
+	struct intel_info *info = (struct intel_info *) drv;
+	struct intel_buffer *ib;
+
+	ib = calloc(1, sizeof(*ib));
+	if (!ib)
+		return NULL;
+
+	if (handle->name) {
+		uint32_t dummy;
+
+		ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
+				"gralloc-r", handle->name);
+		if (!ib->ibo) {
+			ALOGE("failed to create ibo from name %u",
+					handle->name);
+			free(ib);
+			return NULL;
+		}
+
+		if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
+			ALOGE("failed to get ibo tiling");
+			drm_intel_bo_unreference(ib->ibo);
+			free(ib);
+			return NULL;
+		}
+	}
+	else {
+		unsigned long stride;
+
+		ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
+		if (!ib->ibo) {
+			ALOGE("failed to allocate ibo %dx%d (format %d)",
+					handle->width,
+					handle->height,
+					handle->format);
+			free(ib);
+			return NULL;
+		}
+
+		handle->stride = stride;
+
+		if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
+			ALOGE("failed to flink ibo");
+			drm_intel_bo_unreference(ib->ibo);
+			free(ib);
+			return NULL;
+		}
+	}
+
+	ib->base.fb_handle = ib->ibo->handle;
+
+	ib->base.handle = handle;
+
+	return &ib->base;
+}
+
+static void intel_free(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_bo_t *bo)
+{
+	struct intel_buffer *ib = (struct intel_buffer *) bo;
+
+	drm_intel_bo_unreference(ib->ibo);
+	free(ib);
+}
+
+static int intel_map(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_bo_t *bo,
+		int x, int y, int w, int h,
+		int enable_write, void **addr)
+{
+	struct intel_buffer *ib = (struct intel_buffer *) bo;
+	int err;
+
+	if (ib->tiling != I915_TILING_NONE ||
+	    (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
+		err = drm_intel_gem_bo_map_gtt(ib->ibo);
+	else
+		err = drm_intel_bo_map(ib->ibo, enable_write);
+	if (!err)
+		*addr = ib->ibo->virtual;
+
+	return err;
+}
+
+static void intel_unmap(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_bo_t *bo)
+{
+	struct intel_buffer *ib = (struct intel_buffer *) bo;
+
+	if (ib->tiling != I915_TILING_NONE ||
+	    (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
+		drm_intel_gem_bo_unmap_gtt(ib->ibo);
+	else
+		drm_intel_bo_unmap(ib->ibo);
+}
+
+#include "intel_chipset.h" /* for platform detection macros */
+static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
+		struct gralloc_drm_t *drm)
+{
+	struct intel_info *info = (struct intel_info *) drv;
+	struct drm_i915_getparam gp;
+	int pageflipping, id, has_blt;
+
+	switch (drm->primary.fb_format) {
+	case HAL_PIXEL_FORMAT_BGRA_8888:
+	case HAL_PIXEL_FORMAT_RGB_565:
+		break;
+	default:
+		drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
+		break;
+	}
+
+	drm->mode_quirk_vmwgfx = 0;
+	/* why? */
+	drm->mode_sync_flip = 1;
+
+	memset(&gp, 0, sizeof(gp));
+	gp.param = I915_PARAM_HAS_PAGEFLIPPING;
+	gp.value = &pageflipping;
+	if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+		pageflipping = 0;
+
+	memset(&gp, 0, sizeof(gp));
+	gp.param = I915_PARAM_CHIPSET_ID;
+	gp.value = &id;
+	if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+		id = 0;
+
+	memset(&gp, 0, sizeof(gp));
+	gp.param = I915_PARAM_HAS_BLT;
+	gp.value = &has_blt;
+	if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
+		has_blt = 0;
+	info->exec_blt = has_blt ? I915_EXEC_BLT : 0;
+
+	/* GEN4, G4X, GEN5, GEN6, GEN7 */
+	if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
+		if (IS_GEN7(id))
+			info->gen = 70;
+		else if (IS_GEN6(id))
+			info->gen = 60;
+		else if (IS_GEN5(id))
+			info->gen = 50;
+		else
+			info->gen = 40;
+	}
+	else {
+		info->gen = 30;
+	}
+
+	if (pageflipping && info->gen > 30)
+		drm->swap_mode = DRM_SWAP_FLIP;
+	else if (info->batch && info->gen == 30)
+		drm->swap_mode = DRM_SWAP_COPY;
+	else
+		drm->swap_mode = DRM_SWAP_SETCRTC;
+
+	if (drm->resources) {
+		int pipe;
+
+		pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
+				drm->primary.crtc_id);
+		drm->swap_interval = (pipe >= 0) ? 1 : 0;
+		drm->vblank_secondary = (pipe > 0);
+	}
+	else {
+		drm->swap_interval = 0;
+	}
+}
+
+static void intel_destroy(struct gralloc_drm_drv_t *drv)
+{
+	struct intel_info *info = (struct intel_info *) drv;
+
+	batch_destroy(info);
+	drm_intel_bufmgr_destroy(info->bufmgr);
+	free(info);
+}
+
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
+{
+	struct intel_info *info;
+
+	info = calloc(1, sizeof(*info));
+	if (!info) {
+		ALOGE("failed to allocate driver info");
+		return NULL;
+	}
+
+	info->fd = fd;
+	info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
+	if (!info->bufmgr) {
+		ALOGE("failed to create buffer manager");
+		free(info);
+		return NULL;
+	}
+
+	batch_init(info);
+
+	info->base.destroy = intel_destroy;
+	info->base.init_kms_features = intel_init_kms_features;
+	info->base.alloc = intel_alloc;
+	info->base.free = intel_free;
+	info->base.map = intel_map;
+	info->base.unmap = intel_unmap;
+	info->base.blit = intel_blit;
+	info->base.resolve_format = intel_resolve_format;
+
+	return &info->base;
+}
diff --git a/src/drm_gralloc/gralloc_drm_kms.c b/src/drm_gralloc/gralloc_drm_kms.c
new file mode 100644
index 0000000..0909361
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_kms.c
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG 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 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.
+ */
+
+#define LOG_TAG "GRALLOC-KMS"
+
+#include <cutils/properties.h>
+#include <cutils/log.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <poll.h>
+#include <math.h>
+#include "gralloc_drm.h"
+#include "gralloc_drm_priv.h"
+#include <hardware_legacy/uevent.h>
+
+#include <drm_fourcc.h>
+
+/*
+ * Return true if a bo needs fb.
+ */
+int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
+{
+	return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
+		bo->drm->swap_mode != DRM_SWAP_COPY);
+}
+
+static unsigned int drm_format_from_hal(int hal_format)
+{
+	switch(hal_format) {
+		case HAL_PIXEL_FORMAT_RGB_888:
+		case HAL_PIXEL_FORMAT_BGRA_8888:
+			return DRM_FORMAT_XRGB8888;
+		case HAL_PIXEL_FORMAT_RGBX_8888:
+			return DRM_FORMAT_XBGR8888;
+		case HAL_PIXEL_FORMAT_RGBA_8888:
+			return DRM_FORMAT_RGBA8888;
+		case HAL_PIXEL_FORMAT_RGB_565:
+			return DRM_FORMAT_RGB565;
+		case HAL_PIXEL_FORMAT_YV12:
+			return DRM_FORMAT_YUV420;
+		case HAL_PIXEL_FORMAT_DRM_NV12:
+			return DRM_FORMAT_NV12;
+		default:
+			return 0;
+	}
+}
+
+/*
+ * Modify pitches, offsets and handles according to
+ * the format and return corresponding drm format value
+ */
+static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
+	uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+	struct gralloc_drm_t *drm = bo->drm;
+
+	pitches[0] = bo->handle->stride;
+	handles[0] = bo->fb_handle;
+
+	/* driver takes care of HW specific padding, alignment etc. */
+	if (drm->drv->resolve_format)
+		drm->drv->resolve_format(drm->drv, bo,
+			pitches, offsets, handles);
+
+	return drm_format_from_hal(bo->handle->format);
+}
+
+/*
+ * Returns planes that are supported for a particular format
+ */
+unsigned int planes_for_format(struct gralloc_drm_t *drm,
+	int hal_format)
+{
+	unsigned int i, j, mask = 0;
+	unsigned int drm_format = drm_format_from_hal(hal_format);
+	struct gralloc_drm_plane_t *plane = drm->planes;
+
+	/* no planes available */
+	if (!plane)
+		return 0;
+
+	/* iterate through planes, mark those that match format */
+	for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
+		for (j=0; j<plane->drm_plane->count_formats; j++)
+			if (plane->drm_plane->formats[j] == drm_format)
+				mask |= (1U << plane->drm_plane->plane_id);
+
+	return mask;
+}
+
+/*
+ * Add a fb object for a bo.
+ */
+int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
+{
+	uint32_t pitches[4] = { 0, 0, 0, 0 };
+	uint32_t offsets[4] = { 0, 0, 0, 0 };
+	uint32_t handles[4] = { 0, 0, 0, 0 };
+
+	if (bo->fb_id)
+		return 0;
+
+	int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
+
+	if (drm_format == 0) {
+		ALOGE("error resolving drm format");
+		return -EINVAL;
+	}
+
+	return drmModeAddFB2(bo->drm->fd,
+		bo->handle->width, bo->handle->height,
+		drm_format, handles, pitches, offsets,
+		(uint32_t *) &bo->fb_id, 0);
+}
+
+/*
+ * Remove a fb object for a bo.
+ */
+void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
+{
+	if (bo->fb_id) {
+		drmModeRmFB(bo->drm->fd, bo->fb_id);
+		bo->fb_id = 0;
+	}
+}
+
+/*
+ * Program CRTC.
+ */
+static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
+	struct gralloc_drm_output *output, int fb_id)
+{
+	int ret;
+
+	ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
+			0, 0, &output->connector_id, 1, &output->mode);
+	if (ret) {
+		ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
+			strerror(errno), output->crtc_id, fb_id, output->connector_id,
+			output->mode.hdisplay, output->mode.vdisplay);
+		return ret;
+	}
+
+	if (drm->mode_quirk_vmwgfx)
+		ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
+
+	return ret;
+}
+
+/*
+ * Callback for a page flip event.
+ */
+static void page_flip_handler(int fd, unsigned int sequence,
+		unsigned int tv_sec, unsigned int tv_usec,
+		void *user_data)
+{
+	struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
+
+	/* ack the last scheduled flip */
+	drm->current_front = drm->next_front;
+	drm->next_front = NULL;
+}
+
+/*
+ * Set a plane.
+ */
+static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
+	struct gralloc_drm_plane_t *plane)
+{
+	struct gralloc_drm_bo_t *bo = NULL;
+	int err;
+
+	if (plane->handle)
+		bo = gralloc_drm_bo_from_handle(plane->handle);
+
+	// create a framebuffer if does not exist
+	if (bo && bo->fb_id == 0) {
+		err = gralloc_drm_bo_add_fb(bo);
+		if (err) {
+			ALOGE("%s: could not create drm fb, (%s)",
+				__func__, strerror(-err));
+			return err;
+		}
+	}
+
+	err = drmModeSetPlane(drm->fd,
+		plane->drm_plane->plane_id,
+		drm->primary.crtc_id,
+		bo ? bo->fb_id : 0,
+		0, // flags
+		plane->dst_x,
+		plane->dst_y,
+		plane->dst_w,
+		plane->dst_h,
+		plane->src_x << 16,
+		plane->src_y << 16,
+		plane->src_w << 16,
+		plane->src_h << 16);
+
+	if (err) {
+		/* clear plane_mask so that this buffer won't be tried again */
+		struct gralloc_drm_handle_t *drm_handle =
+			(struct gralloc_drm_handle_t *) plane->handle;
+		drm_handle->plane_mask = 0;
+
+		ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
+			strerror(-err),
+			plane->drm_plane->plane_id,
+			drm->primary.crtc_id,
+			bo ? bo->fb_id : 0);
+	}
+
+	if (plane->prev)
+		gralloc_drm_bo_decref(plane->prev);
+
+	if (bo)
+		bo->refcount++;
+
+	plane->prev = bo;
+
+	return err;
+}
+
+/*
+ * Returns if a particular plane is supported with the implementation
+ */
+static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
+	const struct gralloc_drm_plane_t *plane)
+{
+	/* Planes are only supported on primary pipe for now */
+	return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
+}
+
+/*
+ * Sets all the active planes to be displayed.
+ */
+static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
+{
+	struct gralloc_drm_plane_t *plane = drm->planes;
+	unsigned int i;
+	for (i = 0; i < drm->plane_resources->count_planes;
+		i++, plane++) {
+		/* plane is not in use at all */
+		if (!plane->active && !plane->handle)
+			continue;
+
+		/* plane is active, safety check if it is supported */
+		if (!is_plane_supported(drm, plane))
+			ALOGE("%s: plane %d is not supported",
+				 __func__, plane->drm_plane->plane_id);
+
+		/*
+		 * Disable overlay if it is not active
+		 * or if there is error during setplane
+		 */
+		if (!plane->active)
+			plane->handle = 0;
+
+		if (gralloc_drm_bo_setplane(drm, plane))
+			plane->active = 0;
+	}
+}
+
+/*
+ * Interface for HWC, used to reserve a plane for a layer.
+ */
+int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
+	buffer_handle_t handle,
+	uint32_t id,
+	uint32_t dst_x,
+	uint32_t dst_y,
+	uint32_t dst_w,
+	uint32_t dst_h,
+	uint32_t src_x,
+	uint32_t src_y,
+	uint32_t src_w,
+	uint32_t src_h)
+{
+	unsigned int i, j;
+	struct gralloc_drm_handle_t *drm_handle =
+		gralloc_drm_handle(handle);
+	int plane_count = drm->plane_resources->count_planes;
+	struct gralloc_drm_plane_t *plane = drm->planes;
+
+	/* no supported planes for this handle */
+	if (!drm_handle->plane_mask) {
+		ALOGE("%s: buffer %p cannot be shown on a plane\n",
+			__func__, drm_handle);
+		return -EINVAL;
+	}
+
+	for (j = 0; j < plane_count; j++, plane++) {
+
+		/*
+		 * handle may be suitable to be shown on a plane, in
+		 * addition we need to check that this particular plane
+		 * is supported by the current implementation
+		 */
+		if (!is_plane_supported(drm, plane))
+			continue;
+
+		/* if plane is available and can support this buffer */
+		if (!plane->active &&
+			drm_handle->plane_mask &
+			(1U << plane->drm_plane->plane_id)) {
+
+			plane->dst_x = dst_x;
+			plane->dst_y = dst_y;
+			plane->dst_w = dst_w;
+			plane->dst_h = dst_h;
+			plane->src_x = src_x;
+			plane->src_y = src_y;
+			plane->src_w = src_w;
+			plane->src_h = src_h;
+			plane->handle = handle;
+			plane->id = id;
+			plane->active = 1;
+
+			return 0;
+		}
+	}
+
+	/* no free planes available */
+	return -EBUSY;
+}
+
+/*
+ * Interface for HWC, used to disable all the overlays. Plane id
+ * is also set to 0 as it should be mappable to a particular layer only
+ * if it has been reserved with 'reserve_plane'.
+ */
+void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
+{
+	struct gralloc_drm_plane_t *plane = drm->planes;
+	unsigned int i;
+
+	for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
+		plane->active = 0;
+		plane->id = 0;
+	}
+}
+
+/*
+ * Interface for HWC, used to change handle of a reserved plane.
+ */
+int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
+	uint32_t id, buffer_handle_t handle)
+{
+	struct gralloc_drm_plane_t *plane = drm->planes;
+	unsigned i;
+
+	for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
+		if (plane->active && plane->id == id) {
+			plane->handle = handle;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+/*
+ * Schedule a page flip.
+ */
+static int drm_kms_page_flip(struct gralloc_drm_t *drm,
+		struct gralloc_drm_bo_t *bo)
+{
+	int ret;
+
+	/* there is another flip pending */
+	while (drm->next_front) {
+		drm->waiting_flip = 1;
+		drmHandleEvent(drm->fd, &drm->evctx);
+		drm->waiting_flip = 0;
+		if (drm->next_front) {
+			/* record an error and break */
+			ALOGE("drmHandleEvent returned without flipping");
+			drm->current_front = drm->next_front;
+			drm->next_front = NULL;
+		}
+	}
+
+	if (!bo)
+		return 0;
+
+	pthread_mutex_lock(&drm->hdmi_mutex);
+	if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
+
+		int dst_x1 = 0, dst_y1 = 0;
+
+		if (drm->hdmi.bo->handle->width > bo->handle->width)
+			dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
+		if (drm->hdmi.bo->handle->height > bo->handle->height)
+			dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
+
+		drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
+			dst_x1, dst_y1,
+			dst_x1 + bo->handle->width,
+			dst_y1 + bo->handle->height,
+			0, 0, bo->handle->width, bo->handle->height);
+
+		ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
+		if (ret && errno != EBUSY)
+			ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
+				strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
+	}
+	pthread_mutex_unlock(&drm->hdmi_mutex);
+
+	/* set planes to be displayed */
+	gralloc_drm_set_planes(drm);
+
+	ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
+			DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
+	if (ret) {
+		ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
+			strerror(errno), drm->primary.crtc_id, bo->fb_id);
+		/* try to set mode for next frame */
+		if (errno != EBUSY)
+			drm->first_post = 1;
+	}
+	else
+		drm->next_front = bo;
+
+	return ret;
+}
+
+/*
+ * Wait for the next post.
+ */
+static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
+{
+	unsigned int current, target;
+	drmVBlank vbl;
+	int ret;
+
+	if (drm->mode_quirk_vmwgfx)
+		return;
+
+	flip = !!flip;
+
+	memset(&vbl, 0, sizeof(vbl));
+	vbl.request.type = DRM_VBLANK_RELATIVE;
+	if (drm->vblank_secondary)
+		vbl.request.type |= DRM_VBLANK_SECONDARY;
+	vbl.request.sequence = 0;
+
+	/* get the current vblank */
+	ret = drmWaitVBlank(drm->fd, &vbl);
+	if (ret) {
+		ALOGW("failed to get vblank");
+		return;
+	}
+
+	current = vbl.reply.sequence;
+	if (drm->first_post)
+		target = current;
+	else
+		target = drm->last_swap + drm->swap_interval - flip;
+
+	/* wait for vblank */
+	if (current < target || !flip) {
+		memset(&vbl, 0, sizeof(vbl));
+		vbl.request.type = DRM_VBLANK_ABSOLUTE;
+		if (drm->vblank_secondary)
+			vbl.request.type |= DRM_VBLANK_SECONDARY;
+		if (!flip) {
+			vbl.request.type |= DRM_VBLANK_NEXTONMISS;
+			if (target < current)
+				target = current;
+		}
+
+		vbl.request.sequence = target;
+
+		ret = drmWaitVBlank(drm->fd, &vbl);
+		if (ret) {
+			ALOGW("failed to wait vblank");
+			return;
+		}
+	}
+
+	drm->last_swap = vbl.reply.sequence + flip;
+}
+
+/*
+ * Post a bo.  This is not thread-safe.
+ */
+int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
+{
+	struct gralloc_drm_t *drm = bo->drm;
+	int ret;
+
+	if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
+		ALOGE("unable to post bo %p without fb", bo);
+		return -EINVAL;
+	}
+
+	/* TODO spawn a thread to avoid waiting and race */
+
+	if (drm->first_post) {
+		if (drm->swap_mode == DRM_SWAP_COPY) {
+			struct gralloc_drm_bo_t *dst;
+
+			dst = (drm->next_front) ?
+				drm->next_front :
+				drm->current_front;
+			drm->drv->blit(drm->drv, dst, bo, 0, 0,
+					bo->handle->width,
+					bo->handle->height,
+					0, 0,
+					bo->handle->width,
+					bo->handle->height);
+			bo = dst;
+		}
+
+		ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
+		if (!ret) {
+			drm->first_post = 0;
+			drm->current_front = bo;
+			if (drm->next_front == bo)
+				drm->next_front = NULL;
+		}
+
+		pthread_mutex_lock(&drm->hdmi_mutex);
+		if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
+			drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
+		pthread_mutex_unlock(&drm->hdmi_mutex);
+
+		return ret;
+	}
+
+	switch (drm->swap_mode) {
+	case DRM_SWAP_FLIP:
+		if (drm->swap_interval > 1)
+			drm_kms_wait_for_post(drm, 1);
+		ret = drm_kms_page_flip(drm, bo);
+		if (drm->next_front) {
+			/*
+			 * wait if the driver says so or the current front
+			 * will be written by CPU
+			 */
+			if (drm->mode_sync_flip ||
+			    (drm->current_front->handle->usage &
+			     GRALLOC_USAGE_SW_WRITE_MASK))
+				drm_kms_page_flip(drm, NULL);
+		}
+		break;
+	case DRM_SWAP_COPY:
+		drm_kms_wait_for_post(drm, 0);
+		drm->drv->blit(drm->drv, drm->current_front,
+				bo, 0, 0,
+				bo->handle->width,
+				bo->handle->height,
+				0, 0,
+				bo->handle->width,
+				bo->handle->height);
+		if (drm->mode_quirk_vmwgfx)
+			ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
+		ret = 0;
+		break;
+	case DRM_SWAP_SETCRTC:
+		drm_kms_wait_for_post(drm, 0);
+		ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
+
+		pthread_mutex_lock(&drm->hdmi_mutex);
+		if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
+			drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
+		pthread_mutex_unlock(&drm->hdmi_mutex);
+
+		drm->current_front = bo;
+		break;
+	default:
+		/* no-op */
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static struct gralloc_drm_t *drm_singleton;
+
+static void on_signal(int sig)
+{
+	struct gralloc_drm_t *drm = drm_singleton;
+
+	/* wait the pending flip */
+	if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
+		/* there is race, but this function is hacky enough to ignore that */
+		if (drm_singleton->waiting_flip)
+			usleep(100 * 1000); /* 100ms */
+		else
+			drm_kms_page_flip(drm_singleton, NULL);
+	}
+
+	exit(-1);
+}
+
+static void drm_kms_init_features(struct gralloc_drm_t *drm)
+{
+	const char *swap_mode;
+
+	/* call to the driver here, after KMS has been initialized */
+	drm->drv->init_kms_features(drm->drv, drm);
+
+	if (drm->swap_mode == DRM_SWAP_FLIP) {
+		struct sigaction act;
+
+		memset(&drm->evctx, 0, sizeof(drm->evctx));
+		drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
+		drm->evctx.page_flip_handler = page_flip_handler;
+
+		/*
+		 * XXX GPU tends to freeze if the program is terminiated with a
+		 * flip pending.  What is the right way to handle the
+		 * situation?
+		 */
+		sigemptyset(&act.sa_mask);
+		act.sa_handler = on_signal;
+		act.sa_flags = 0;
+		sigaction(SIGINT, &act, NULL);
+		sigaction(SIGTERM, &act, NULL);
+
+		drm_singleton = drm;
+	}
+	else if (drm->swap_mode == DRM_SWAP_COPY) {
+		struct gralloc_drm_bo_t *front;
+		int stride;
+
+		/* create the real front buffer */
+		front = gralloc_drm_bo_create(drm,
+					      drm->primary.mode.hdisplay,
+					      drm->primary.mode.vdisplay,
+					      drm->primary.fb_format,
+					      GRALLOC_USAGE_HW_FB);
+		if (front && gralloc_drm_bo_add_fb(front)) {
+			gralloc_drm_bo_decref(front);
+			front = NULL;
+		}
+
+		/* abuse next_front */
+		if (front)
+			drm->next_front = front;
+		else
+			drm->swap_mode = DRM_SWAP_SETCRTC;
+	}
+
+	switch (drm->swap_mode) {
+	case DRM_SWAP_FLIP:
+		swap_mode = "flip";
+		break;
+	case DRM_SWAP_COPY:
+		swap_mode = "copy";
+		break;
+	case DRM_SWAP_SETCRTC:
+		swap_mode = "set-crtc";
+		break;
+	default:
+		swap_mode = "no-op";
+		break;
+	}
+
+	ALOGD("will use %s for fb posting", swap_mode);
+}
+
+#define MARGIN_PERCENT 1.8   /* % of active vertical image*/
+#define CELL_GRAN 8.0   /* assumed character cell granularity*/
+#define MIN_PORCH 1 /* minimum front porch   */
+#define V_SYNC_RQD 3 /* width of vsync in lines   */
+#define H_SYNC_PERCENT 8.0   /* width of hsync as % of total line */
+#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
+#define M 600.0 /* blanking formula gradient */
+#define C 40.0  /* blanking formula offset   */
+#define K 128.0 /* blanking formula scaling factor   */
+#define J 20.0  /* blanking formula scaling factor   */
+/* C' and M' are part of the Blanking Duty Cycle computation */
+#define C_PRIME   (((C - J) * K / 256.0) + J)
+#define M_PRIME   (K / 256.0 * M)
+
+static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
+{
+	float h_pixels_rnd;
+	float v_lines_rnd;
+	float v_field_rate_rqd;
+	float top_margin;
+	float bottom_margin;
+	float interlace;
+	float h_period_est;
+	float vsync_plus_bp;
+	float v_back_porch;
+	float total_v_lines;
+	float v_field_rate_est;
+	float h_period;
+	float v_field_rate;
+	float v_frame_rate;
+	float left_margin;
+	float right_margin;
+	float total_active_pixels;
+	float ideal_duty_cycle;
+	float h_blank;
+	float total_pixels;
+	float pixel_freq;
+	float h_freq;
+
+	float h_sync;
+	float h_front_porch;
+	float v_odd_front_porch_lines;
+	int interlaced = 0;
+	int margins = 0;
+
+	drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
+
+	h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
+	v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
+	v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
+	top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
+	bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
+	interlace = interlaced ? 0.5 : 0.0;
+	h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) * 1000000.0);
+	vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
+	v_back_porch = vsync_plus_bp - V_SYNC_RQD;
+	total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
+	v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
+	h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
+	v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
+	v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
+	left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
+	right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
+	total_active_pixels = h_pixels_rnd + left_margin + right_margin;
+	ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
+	h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
+	total_pixels = total_active_pixels + h_blank;
+	pixel_freq = total_pixels / h_period;
+	h_freq = 1000.0 / h_period;
+	h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
+	h_front_porch = (h_blank / 2.0) - h_sync;
+	v_odd_front_porch_lines = MIN_PORCH + interlace;
+
+	m->clock = ceil(pixel_freq) * 1000;
+	m->hdisplay = (int) (h_pixels_rnd);
+	m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
+	m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
+	m->htotal = (int) (total_pixels);
+	m->hskew = 0;
+	m->vdisplay = (int) (v_lines_rnd);
+	m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
+	m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
+	m->vtotal = (int) (total_v_lines);
+	m->vscan = 0;
+	m->vrefresh = freq;
+	m->flags = 10;
+	m->type = 64;
+
+	return (m);
+}
+
+static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
+{
+	char value[PROPERTY_VALUE_MAX];
+	drmModeModeInfoPtr mode;
+	int dist, i;
+	int xres = 0, yres = 0, rate = 0;
+	int forcemode = 0;
+
+	if (property_get("debug.drm.mode", value, NULL)) {
+		char *p = value, *end;
+
+		/* parse <xres>x<yres>[@<bpp>] */
+		if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
+			*bpp = 0;
+			if (sscanf(value, "%dx%d", &xres, &yres) != 2)
+				xres = yres = 0;
+		}
+
+		if ((xres && yres) || *bpp) {
+			ALOGI("will find the closest match for %dx%d@%d",
+					xres, yres, *bpp);
+		}
+	} else if (property_get("debug.drm.mode.force", value, NULL)) {
+		char *p = value, *end;
+		*bpp = 0;
+
+		/* parse <xres>x<yres>[@<refreshrate>] */
+		if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
+			rate = 60;
+			if (sscanf(value, "%dx%d", &xres, &yres) != 2)
+				xres = yres = 0;
+		}
+
+		if (xres && yres && rate) {
+			ALOGI("will use %dx%d@%dHz", xres, yres, rate);
+			forcemode = 1;
+		}
+	} else {
+		*bpp = 0;
+	}
+
+	dist = INT_MAX;
+
+	if (forcemode)
+		mode = generate_mode(xres, yres, rate);
+	else {
+		mode = NULL;
+		for (i = 0; i < connector->count_modes; i++) {
+			drmModeModeInfoPtr m = &connector->modes[i];
+			int tmp;
+
+			if (xres && yres) {
+				tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
+					(m->vdisplay - yres) * (m->vdisplay - yres);
+			}
+			else {
+				/* use the first preferred mode */
+				tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
+			}
+
+			if (tmp < dist) {
+				mode = m;
+				dist = tmp;
+				if (!dist)
+					break;
+			}
+		}
+	}
+
+	/* fallback to the first mode */
+	if (!mode)
+		mode = &connector->modes[0];
+
+	ALOGI("Established mode:");
+	ALOGI("clock: %d, hdisplay: %d, hsync_start: %d, hsync_end: %d, htotal: %d, hskew: %d", mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->hskew);
+	ALOGI("vdisplay: %d, vsync_start: %d, vsync_end: %d, vtotal: %d, vscan: %d, vrefresh: %d", mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->vscan, mode->vrefresh);
+	ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
+
+	*bpp /= 8;
+
+	return mode;
+}
+
+/*
+ * Initialize KMS with a connector.
+ */
+static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
+		struct gralloc_drm_output *output, drmModeConnectorPtr connector)
+{
+	drmModeEncoderPtr encoder;
+	drmModeModeInfoPtr mode;
+	static int used_crtcs = 0;
+	int bpp, i;
+
+	if (!connector->count_modes)
+		return -EINVAL;
+
+	encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
+	if (!encoder)
+		return -EINVAL;
+
+	/* find first possible crtc which is not used yet */
+	for (i = 0; i < drm->resources->count_crtcs; i++) {
+		if (encoder->possible_crtcs & (1 << i) &&
+			(used_crtcs & (1 << i)) != (1 << i))
+			break;
+	}
+
+	used_crtcs |= (1 << i);
+
+	drmModeFreeEncoder(encoder);
+	if (i == drm->resources->count_crtcs)
+		return -EINVAL;
+
+	output->bo = NULL;
+	output->crtc_id = drm->resources->crtcs[i];
+	output->connector_id = connector->connector_id;
+	output->pipe = i;
+
+	/* print connector info */
+	if (connector->count_modes > 1) {
+		ALOGI("there are %d modes on connector 0x%x, type %d",
+				connector->count_modes,
+				connector->connector_id,
+				connector->connector_type);
+		for (i = 0; i < connector->count_modes; i++)
+			ALOGI("  %s", connector->modes[i].name);
+	}
+	else {
+		ALOGI("there is one mode on connector 0x%d: %s",
+				connector->connector_id,
+				connector->modes[0].name);
+	}
+
+	mode = find_mode(connector, &bpp);
+
+	ALOGI("the best mode is %s", mode->name);
+
+	output->mode = *mode;
+	switch (bpp) {
+	case 2:
+		output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
+		break;
+	case 4:
+	default:
+		output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
+		break;
+	}
+
+	if (connector->mmWidth && connector->mmHeight) {
+		output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
+		output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
+	}
+	else {
+		output->xdpi = 75;
+		output->ydpi = 75;
+	}
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+	drm->clip.x1 = 0;
+	drm->clip.y1 = 0;
+	drm->clip.x2 = output->mode.hdisplay;
+	drm->clip.y2 = output->mode.vdisplay;
+#endif
+
+	return 0;
+}
+
+
+/*
+ * Fetch a connector of particular type
+ */
+static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
+	uint32_t type)
+{
+	int i;
+
+	if (!drm->resources)
+		return NULL;
+
+	for (i = 0; i < drm->resources->count_connectors; i++) {
+		drmModeConnectorPtr connector =
+			connector = drmModeGetConnector(drm->fd,
+				drm->resources->connectors[i]);
+		if (connector) {
+			if (connector->connector_type == type &&
+				connector->connection == DRM_MODE_CONNECTED)
+				return connector;
+			drmModeFreeConnector(connector);
+		}
+	}
+	return NULL;
+}
+
+
+/*
+ * Initializes hdmi output with a connector and allocates
+ * a private framebuffer for it. This is called on startup if
+ * hdmi cable is connected and also on hotplug events.
+ */
+static void init_hdmi_output(struct gralloc_drm_t *drm,
+	drmModeConnectorPtr connector)
+{
+	drm_kms_init_with_connector(drm, &drm->hdmi, connector);
+
+	ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
+		__func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
+
+	drm->hdmi.bo = gralloc_drm_bo_create(drm,
+		drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
+		drm->hdmi.fb_format,
+		GRALLOC_USAGE_SW_WRITE_OFTEN|GRALLOC_USAGE_HW_RENDER);
+
+	gralloc_drm_bo_add_fb(drm->hdmi.bo);
+
+	drm->hdmi_mode = HDMI_CLONED;
+	drm->hdmi.active = 1;
+}
+
+
+/*
+ * Thread that listens to uevents and checks if hdmi state changes
+ */
+static void *hdmi_observer(void *data)
+{
+	static char uevent_desc[4096];
+	drmModeConnectorPtr hdmi;
+	struct gralloc_drm_t *drm =
+		(struct gralloc_drm_t *) data;
+
+	uevent_init();
+
+	memset(uevent_desc, 0, sizeof(uevent_desc));
+
+	while(1) {
+
+		/* this polls */
+		int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
+
+		if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
+
+			/* check what changed */
+			const char *prop = uevent_desc + strlen(uevent_desc) + 1;
+
+			while (*prop) {
+
+				const char *state = strstr(prop, "SWITCH_STATE=");
+				if (state) {
+					unsigned int value = 0;
+					state += strlen("SWITCH_STATE=");
+					value = atoi(state);
+
+					pthread_mutex_lock(&drm->hdmi_mutex);
+
+					if (value) {
+						hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
+						if (hdmi) {
+
+							ALOGD("init hdmi on hotplug event");
+							init_hdmi_output(drm, hdmi);
+
+							/* will trigger modeset */
+							drm->first_post = 1;
+
+							drmModeFreeConnector(hdmi);
+
+							pthread_mutex_unlock(&drm->hdmi_mutex);
+						}
+						break;
+					} else {
+						drm->hdmi.active = 0;
+
+						ALOGD("destroy hdmi private buffer");
+						gralloc_drm_bo_decref(drm->hdmi.bo);
+						drm->hdmi.bo = NULL;
+
+						pthread_mutex_unlock(&drm->hdmi_mutex);
+						break;
+					}
+
+					pthread_mutex_unlock(&drm->hdmi_mutex);
+				}
+
+				/* next property/value pair */
+				prop += strlen(prop) + 1;
+				if (prop - uevent_desc >= len)
+					break;
+			}
+		}
+	}
+
+	pthread_exit(NULL);
+	return 0;
+}
+
+
+/*
+ * Initialize KMS.
+ */
+int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
+{
+	drmModeConnectorPtr lvds, hdmi;
+	int i, ret;
+
+	if (drm->resources)
+		return 0;
+
+	drm->resources = drmModeGetResources(drm->fd);
+	if (!drm->resources) {
+		ALOGE("failed to get modeset resources");
+		return -EINVAL;
+	}
+
+	drm->plane_resources = drmModeGetPlaneResources(drm->fd);
+	if (!drm->plane_resources) {
+		ALOGD("no planes found from drm resources");
+	} else {
+		ALOGD("supported drm planes and formats");
+		/* fill a helper structure for hwcomposer */
+		drm->planes = calloc(drm->plane_resources->count_planes,
+			sizeof(struct gralloc_drm_plane_t));
+
+		for (i = 0; i < drm->plane_resources->count_planes; i++) {
+
+			unsigned int j;
+
+			drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
+				drm->plane_resources->planes[i]);
+
+			ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
+			for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
+				ALOGD("    format %c%c%c%c",
+					(drm->planes[i].drm_plane->formats[j]),
+					(drm->planes[i].drm_plane->formats[j])>>8,
+					(drm->planes[i].drm_plane->formats[j])>>16,
+					(drm->planes[i].drm_plane->formats[j])>>24);
+		}
+	}
+
+	/* find the crtc/connector/mode to use */
+	lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
+	if (lvds) {
+		drm_kms_init_with_connector(drm, &drm->primary, lvds);
+		drmModeFreeConnector(lvds);
+		drm->primary.active = 1;
+	}
+
+	/* if still no connector, find first connected connector and try it */
+	if (!drm->primary.active) {
+
+		for (i = 0; i < drm->resources->count_connectors; i++) {
+			drmModeConnectorPtr connector;
+
+			connector = drmModeGetConnector(drm->fd,
+					drm->resources->connectors[i]);
+			if (connector) {
+				if (connector->connection == DRM_MODE_CONNECTED) {
+					if (!drm_kms_init_with_connector(drm,
+							&drm->primary, connector))
+						break;
+				}
+
+				drmModeFreeConnector(connector);
+			}
+		}
+		if (i == drm->resources->count_connectors) {
+			ALOGE("failed to find a valid crtc/connector/mode combination");
+			drmModeFreeResources(drm->resources);
+			drm->resources = NULL;
+
+			return -EINVAL;
+		}
+	}
+
+
+	/* check if hdmi is connected already */
+	hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
+	if (hdmi) {
+
+		if (hdmi->connector_id == drm->primary.connector_id) {
+			/* special case: our primary connector is hdmi */
+			ALOGD("hdmi is the primary connector");
+			goto skip_hdmi_modes;
+		}
+
+		ALOGD("init hdmi on startup");
+		init_hdmi_output(drm, hdmi);
+
+		drmModeFreeConnector(hdmi);
+	}
+
+goto skip_hdmi_modes;
+	/* launch hdmi observer thread */
+	pthread_mutex_init(&drm->hdmi_mutex, NULL);
+	pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
+
+skip_hdmi_modes:
+
+	drm_kms_init_features(drm);
+	drm->first_post = 1;
+
+	return 0;
+}
+
+void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
+{
+	switch (drm->swap_mode) {
+	case DRM_SWAP_FLIP:
+		drm_kms_page_flip(drm, NULL);
+		break;
+	case DRM_SWAP_COPY:
+		{
+			struct gralloc_drm_bo_t **bo = (drm->current_front) ?
+				&drm->current_front : &drm->next_front;
+
+			if (*bo)
+				gralloc_drm_bo_decref(*bo);
+			*bo = NULL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* restore crtc? */
+
+	if (drm->resources) {
+		drmModeFreeResources(drm->resources);
+		drm->resources = NULL;
+	}
+
+	if (drm->planes) {
+		unsigned int i;
+		for (i = 0; i < drm->plane_resources->count_planes; i++)
+			drmModeFreePlane(drm->planes[i].drm_plane);
+		free(drm->planes);
+		drm->planes = NULL;
+	}
+
+	if (drm->plane_resources) {
+		drmModeFreePlaneResources(drm->plane_resources);
+		drm->plane_resources = NULL;
+	}
+
+	/* destroy private buffer of hdmi output */
+	if (drm->hdmi.bo)
+		gralloc_drm_bo_decref(drm->hdmi.bo);
+
+	drm_singleton = NULL;
+}
+
+int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
+{
+	return (drm->resources != NULL);
+}
+
+/*
+ * Initialize a framebuffer device with KMS info.
+ */
+void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
+		struct framebuffer_device_t *fb)
+{
+	*((uint32_t *) &fb->flags) = 0x0;
+	*((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
+	*((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
+	*((int *)      &fb->stride) = drm->primary.mode.hdisplay;
+	*((float *)    &fb->fps) = drm->primary.mode.vrefresh;
+
+	*((int *)      &fb->format) = drm->primary.fb_format;
+	*((float *)    &fb->xdpi) = drm->primary.xdpi;
+	*((float *)    &fb->ydpi) = drm->primary.ydpi;
+	*((int *)      &fb->minSwapInterval) = drm->swap_interval;
+	*((int *)      &fb->maxSwapInterval) = drm->swap_interval;
+}
+
+/*
+ * Return true if fb posting is pipelined.
+ */
+int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
+{
+	return (drm->swap_mode != DRM_SWAP_SETCRTC);
+}
diff --git a/src/drm_gralloc/gralloc_drm_priv.h b/src/drm_gralloc/gralloc_drm_priv.h
new file mode 100644
index 0000000..1a36cc1
--- /dev/null
+++ b/src/drm_gralloc/gralloc_drm_priv.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG 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 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.
+ */
+
+#ifndef _GRALLOC_DRM_PRIV_H_
+#define _GRALLOC_DRM_PRIV_H_
+
+#include <pthread.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "gralloc_drm_handle.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* how a bo is posted */
+enum drm_swap_mode {
+	DRM_SWAP_NOOP,
+	DRM_SWAP_FLIP,
+	DRM_SWAP_COPY,
+	DRM_SWAP_SETCRTC,
+};
+
+enum hdmi_output_mode {
+	HDMI_CLONED,
+	HDMI_EXTENDED,
+};
+
+struct gralloc_drm_plane_t {
+	drmModePlane *drm_plane;
+
+	/* plane has been set to display a layer */
+	uint32_t active;
+
+	/* handle to display */
+	buffer_handle_t handle;
+
+	/* identifier set by hwc */
+	uint32_t id;
+
+	/* position, crop and scale */
+	uint32_t src_x;
+	uint32_t src_y;
+	uint32_t src_w;
+	uint32_t src_h;
+	uint32_t dst_x;
+	uint32_t dst_y;
+	uint32_t dst_w;
+	uint32_t dst_h;
+
+	/* previous buffer, for refcounting */
+	struct gralloc_drm_bo_t *prev;
+};
+
+struct gralloc_drm_output
+{
+	uint32_t crtc_id;
+	uint32_t connector_id;
+	uint32_t pipe;
+	drmModeModeInfo mode;
+	int xdpi, ydpi;
+	int fb_format;
+	int bpp;
+	uint32_t active;
+
+	/* 'private fb' for this output */
+	struct gralloc_drm_bo_t *bo;
+};
+
+struct gralloc_drm_t {
+	/* initialized by gralloc_drm_create */
+	int fd;
+	struct gralloc_drm_drv_t *drv;
+
+	/* initialized by gralloc_drm_init_kms */
+	drmModeResPtr resources;
+	struct gralloc_drm_output primary;
+	struct gralloc_drm_output hdmi;
+	enum hdmi_output_mode hdmi_mode;
+
+	/* hdmi hotplug */
+	pthread_mutex_t hdmi_mutex;
+	pthread_t hdmi_hotplug_thread;
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+	drmModeClip clip;
+#endif
+
+	/* initialized by drv->init_kms_features */
+	enum drm_swap_mode swap_mode;
+	int swap_interval;
+	int mode_quirk_vmwgfx;
+	int mode_sync_flip; /* page flip should block */
+	int vblank_secondary;
+
+	drmEventContext evctx;
+
+	int first_post;
+	struct gralloc_drm_bo_t *current_front, *next_front;
+	int waiting_flip;
+	unsigned int last_swap;
+
+	/* plane support */
+	drmModePlaneResPtr plane_resources;
+	struct gralloc_drm_plane_t *planes;
+};
+
+struct drm_module_t {
+	gralloc_module_t base;
+
+	/* HWC plane API */
+	int (*hwc_reserve_plane) (struct gralloc_drm_t *mod,
+		buffer_handle_t handle, uint32_t id,
+		uint32_t dst_x, uint32_t dst_y, uint32_t dst_w, uint32_t dst_h,
+		uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h);
+	void (*hwc_disable_planes) (struct gralloc_drm_t *mod);
+	int (*hwc_set_plane_handle) (struct gralloc_drm_t *mod,
+		uint32_t id, buffer_handle_t handle);
+
+	pthread_mutex_t mutex;
+	struct gralloc_drm_t *drm;
+};
+
+struct gralloc_drm_drv_t {
+	/* destroy the driver */
+	void (*destroy)(struct gralloc_drm_drv_t *drv);
+
+	/* initialize KMS features */
+	void (*init_kms_features)(struct gralloc_drm_drv_t *drv,
+				  struct gralloc_drm_t *drm);
+
+	/* allocate or import a bo */
+	struct gralloc_drm_bo_t *(*alloc)(struct gralloc_drm_drv_t *drv,
+			                  struct gralloc_drm_handle_t *handle);
+
+	/* free a bo */
+	void (*free)(struct gralloc_drm_drv_t *drv,
+		     struct gralloc_drm_bo_t *bo);
+
+	/* map a bo for CPU access */
+	int (*map)(struct gralloc_drm_drv_t *drv,
+		   struct gralloc_drm_bo_t *bo,
+		   int x, int y, int w, int h, int enable_write, void **addr);
+
+	/* unmap a bo */
+	void (*unmap)(struct gralloc_drm_drv_t *drv,
+		      struct gralloc_drm_bo_t *bo);
+
+	/* blit between two bo's, used for DRM_SWAP_COPY and general blitting */
+	void (*blit)(struct gralloc_drm_drv_t *drv,
+		     struct gralloc_drm_bo_t *dst,
+		     struct gralloc_drm_bo_t *src,
+		     uint16_t dst_x1, uint16_t dst_y1,
+		     uint16_t dst_x2, uint16_t dst_y2,
+		     uint16_t src_x1, uint16_t src_y1,
+		     uint16_t src_x2, uint16_t src_y2);
+
+	/* query component offsets, strides and handles for a format */
+	void (*resolve_format)(struct gralloc_drm_drv_t *drv,
+		     struct gralloc_drm_bo_t *bo,
+		     uint32_t *pitches, uint32_t *offsets, uint32_t *handles);
+};
+
+struct gralloc_drm_bo_t {
+	struct gralloc_drm_t *drm;
+	struct gralloc_drm_handle_t *handle;
+
+	int imported;  /* the handle is from a remote proces when true */
+	int fb_handle; /* the GEM handle of the bo */
+	int fb_id;     /* the fb id */
+
+	int lock_count;
+	int locked_for;
+
+	unsigned int refcount;
+};
+
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name);
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd);
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_radeon(int fd);
+struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_nouveau(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _GRALLOC_DRM_PRIV_H_ */