msm: camera: Add support for gesture driver

Added gesture driver code. Gesture node is a subdevice to
server node.

Change-Id: I488da3dbdb502a2f78b0cd5269dd113c472ee377
Signed-off-by: Sunid Wilson <sunidw@codeaurora.org>
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index ebfed6c..b60f99f 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -13,6 +13,7 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
   obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
+  obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 1220b6e..034cbc5 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -45,6 +45,10 @@
 module_param(msm_camera_v4l2_nr, uint, 0644);
 MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect");
 
+static long msm_server_send_v4l2_evt(void *evt);
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+	unsigned int notification, void *arg);
+
 static void msm_queue_init(struct msm_device_queue *queue, const char *name)
 {
 	D("%s\n", __func__);
@@ -178,10 +182,16 @@
 		return -EINVAL;
 	}
 
+	D("%s qid %d evtid %d %d\n", __func__, command->queue_idx,
+		command->evt_id,
+		g_server_dev.server_queue[command->queue_idx].evt_id);
 	g_server_dev.server_queue[command->queue_idx].ctrl = command;
 	if (command->evt_id !=
 		g_server_dev.server_queue[command->queue_idx].evt_id) {
-		pr_err("Invalid event id from userspace\n");
+		pr_err("%s Invalid event id from userspace cmd id %d %d qid %d\n",
+			__func__, command->evt_id,
+			g_server_dev.server_queue[command->queue_idx].evt_id,
+			command->queue_idx);
 		return -EINVAL;
 	}
 
@@ -241,6 +251,8 @@
 	mutex_lock(&server_dev->server_queue_lock);
 	if (++server_dev->server_evt_id == 0)
 		server_dev->server_evt_id++;
+	D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+		server_dev->server_evt_id);
 
 	server_dev->server_queue[out->queue_idx].evt_id =
 		server_dev->server_evt_id;
@@ -317,7 +329,7 @@
 {
 	int rc = 0;
 	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
+	D("%s qid %d\n", __func__, pcam->server_queue_idx);
 	ctrlcmd.type	   = MSM_V4L2_OPEN;
 	ctrlcmd.timeout_ms = 10000;
 	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -337,7 +349,7 @@
 {
 	int rc = 0;
 	struct msm_ctrl_cmd ctrlcmd;
-	D("%s\n", __func__);
+	D("%s qid %d\n", __func__, pcam->server_queue_idx);
 	ctrlcmd.type	   = MSM_V4L2_CLOSE;
 	ctrlcmd.timeout_ms = 10000;
 	ctrlcmd.length	 = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -1432,7 +1444,7 @@
 			sub->type++;
 			D("sub->type while = 0x%x\n", sub->type);
 		} while (sub->type !=
-			V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX);
+			V4L2_EVENT_PRIVATE_START + MSM_SVR_RESP_MAX);
 	} else {
 		D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
 		rc = v4l2_event_subscribe(fh, sub);
@@ -1555,6 +1567,150 @@
 	msm_mctl_free(pcam);
 	return rc;
 }
+
+int msm_server_open_client(int *p_qidx)
+{
+	int rc = 0;
+	int server_q_idx = 0;
+	struct msm_cam_server_queue *queue = NULL;
+
+	mutex_lock(&g_server_dev.server_lock);
+	server_q_idx = msm_find_free_queue();
+	if (server_q_idx < 0) {
+		mutex_unlock(&g_server_dev.server_lock);
+		return server_q_idx;
+	}
+
+	*p_qidx = server_q_idx;
+	queue = &g_server_dev.server_queue[server_q_idx];
+	queue->ctrl = NULL;
+	queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+		max_control_command_size, GFP_KERNEL);
+	msm_queue_init(&queue->ctrl_q, "control");
+	msm_queue_init(&queue->eventData_q, "eventdata");
+	queue->queue_active = 1;
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
+
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out,
+	int ctrl_id)
+{
+	int rc = 0;
+	void *value;
+	struct msm_queue_cmd *rcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_ctrl_cmd *ctrlcmd;
+	struct msm_cam_server_dev *server_dev = &g_server_dev;
+	struct msm_device_queue *queue =
+		&server_dev->server_queue[out->queue_idx].ctrl_q;
+
+	struct v4l2_event v4l2_evt;
+	struct msm_isp_event_ctrl *isp_event;
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		return -ENOMEM;
+	}
+	event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!event_qcmd) {
+		pr_err("%s Insufficient memory. return", __func__);
+		kfree(isp_event);
+		return -ENOMEM;
+	}
+
+	D("%s\n", __func__);
+	mutex_lock(&server_dev->server_queue_lock);
+	if (++server_dev->server_evt_id == 0)
+		server_dev->server_evt_id++;
+
+	D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+		server_dev->server_evt_id);
+	server_dev->server_queue[out->queue_idx].evt_id =
+		server_dev->server_evt_id;
+	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+	v4l2_evt.u.data[0] = out->queue_idx;
+	/* setup event object to transfer the command; */
+	isp_event->resptype = MSM_CAM_RESP_V4L2;
+	isp_event->isp_data.ctrl = *out;
+	isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+	atomic_set(&event_qcmd->on_heap, 1);
+	event_qcmd->command = isp_event;
+
+	msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+				&event_qcmd->list_eventdata);
+
+	/* now send command to config thread in userspace,
+	 * and wait for results */
+	v4l2_event_queue(server_dev->server_command_queue.pvdev,
+					  &v4l2_evt);
+	D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+	mutex_unlock(&server_dev->server_queue_lock);
+
+	/* wait for config return status */
+	D("Waiting for config status\n");
+	rc = wait_event_interruptible_timeout(queue->wait,
+		!list_empty_careful(&queue->list),
+		msecs_to_jiffies(out->timeout_ms));
+	D("Waiting is over for config status\n");
+	if (list_empty_careful(&queue->list)) {
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			kfree(isp_event);
+			pr_err("%s: wait_event error %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	rcmd = msm_dequeue(queue, list_control);
+	BUG_ON(!rcmd);
+	D("%s Finished servicing ioctl\n", __func__);
+
+	ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+	value = out->value;
+	if (ctrlcmd->length > 0)
+		memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+	memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+	out->value = value;
+
+	kfree(ctrlcmd);
+	server_dev->server_queue[out->queue_idx].ctrl = NULL;
+
+	free_qcmd(rcmd);
+	kfree(isp_event);
+	D("%s: rc %d\n", __func__, rc);
+	/* rc is the time elapsed. */
+	if (rc >= 0) {
+		/* TODO: Refactor msm_ctrl_cmd::status field */
+		if (out->status == 0)
+			rc = -1;
+		else if (out->status == 1 || out->status == 4)
+			rc = 0;
+		else
+			rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_server_close_client(int idx)
+{
+	int rc = 0;
+	struct msm_cam_server_queue *queue = NULL;
+	mutex_lock(&g_server_dev.server_lock);
+	queue = &g_server_dev.server_queue[idx];
+	queue->queue_active = 0;
+	kfree(queue->ctrl);
+	queue->ctrl = NULL;
+	kfree(queue->ctrl_data);
+	queue->ctrl_data = NULL;
+	msm_queue_drain(&queue->ctrl_q, list_control);
+	msm_drain_eventq(&queue->eventData_q);
+	mutex_unlock(&g_server_dev.server_lock);
+	return rc;
+}
 /* v4l2_file_operations */
 static int msm_open(struct file *f)
 {
@@ -1610,7 +1766,10 @@
 			pcam_inst->my_index,
 			pcam->vnode_id, pcam->use_count);
 	pcam->use_count++;
+	D("%s use_count %d\n", __func__, pcam->use_count);
 	if (pcam->use_count == 1) {
+		struct msm_cam_server_queue *queue;
+		int ges_evt = MSM_V4L2_GES_CAM_OPEN;
 		pcam->server_queue_idx = server_q_idx;
 		queue = &g_server_dev.server_queue[server_q_idx];
 		queue->ctrl = NULL;
@@ -1620,6 +1779,10 @@
 		msm_queue_init(&queue->eventData_q, "eventdata");
 		queue->queue_active = 1;
 
+		pr_err("%s send gesture evt\n", __func__);
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
 		rc = msm_cam_server_open_session(&g_server_dev, pcam);
 		if (rc < 0) {
 			pr_err("%s: cam_server_open_session failed %d\n",
@@ -1713,6 +1876,74 @@
 	}
 	mutex_unlock(&pcam->vid_lock);
 	kfree(pcam_inst);
+	pr_err("%s: error end", __func__);
+	return rc;
+}
+
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		D("%s: invalid handle\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pmctl->mctl_release) {
+		rc = pmctl->mctl_release(pmctl);
+		if (rc < 0)
+			pr_err("mctl_release fails %d\n", rc);
+	}
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	kref_put(&pmctl->refcount, msm_release_ion_client);
+#endif
+
+	rc = msm_cam_server_close_session(&g_server_dev, pcam);
+	if (rc < 0)
+		pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+	return rc;
+}
+
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+	int *p_active)
+{
+	int rc = 0;
+	struct msm_cam_media_controller *pmctl = NULL;
+	D("%s: %p", __func__, g_server_dev.pcam_active);
+	*p_active = 0;
+	if (g_server_dev.pcam_active) {
+		D("%s: Active camera present return", __func__);
+		return 0;
+	}
+	rc = msm_cam_server_open_session(&g_server_dev, pcam);
+	if (rc < 0) {
+		pr_err("%s: cam_server_open_session failed %d\n",
+		__func__, rc);
+		return rc;
+	}
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	/* Should be set to sensor ops if any but right now its OK!! */
+	if (!pmctl->mctl_open) {
+		D("%s: media contoller is not inited\n",
+			 __func__);
+		rc = -ENODEV;
+		return rc;
+	}
+
+	D("%s: call mctl_open\n", __func__);
+	rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
+
+	if (rc < 0) {
+		pr_err("%s: HW open failed rc = 0x%x\n",  __func__, rc);
+		return rc;
+	}
+	pmctl->pcam_ptr = pcam;
+	*p_active = 1;
 	return rc;
 }
 
@@ -1839,6 +2070,7 @@
 	f->private_data = NULL;
 
 	if (pcam->use_count == 0) {
+		int ges_evt = MSM_V4L2_GES_CAM_CLOSE;
 		if (g_server_dev.use_count > 0) {
 			rc = msm_send_close_server(pcam);
 			if (rc < 0)
@@ -1866,6 +2098,9 @@
 
 		if (g_server_dev.use_count == 0)
 			mutex_unlock(&g_server_dev.server_lock);
+
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_CAM_EVT, &ges_evt);
 	}
 	mutex_unlock(&pcam->vid_lock);
 	return rc;
@@ -2080,6 +2315,11 @@
 		rc = 0;
 		break;
 	}
+
+	case MSM_CAM_IOCTL_SEND_EVENT:
+		rc = msm_server_send_v4l2_evt(arg);
+		break;
+
 	default:
 		pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
 		break;
@@ -2143,6 +2383,29 @@
 	return 0;
 }
 
+static long msm_server_send_v4l2_evt(void *evt)
+{
+	struct v4l2_event *v4l2_ev = (struct v4l2_event *)evt;
+	int rc = 0;
+
+	if (NULL == evt) {
+		pr_err("%s: evt is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s: evt type 0x%x\n", __func__, v4l2_ev->type);
+	if ((v4l2_ev->type >= MSM_GES_APP_EVT_MIN) &&
+		(v4l2_ev->type < MSM_GES_APP_EVT_MAX)) {
+		msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+			NOTIFY_GESTURE_EVT, v4l2_ev);
+	} else {
+		pr_err("%s: Invalid evt %d\n", __func__, v4l2_ev->type);
+		rc = -EINVAL;
+	}
+	D("%s: end\n", __func__);
+
+	return rc;
+}
 
 static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
 		unsigned int cmd, unsigned long evt)
@@ -2635,6 +2898,14 @@
 		rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
 			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
 		break;
+	case NOTIFY_GESTURE_EVT:
+		rc = v4l2_subdev_call(g_server_dev.gesture_device,
+			core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
+		break;
+	case NOTIFY_GESTURE_CAM_EVT:
+		rc = v4l2_subdev_call(g_server_dev.gesture_device,
+			core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
+		break;
 	default:
 		break;
 	}
@@ -2674,6 +2945,8 @@
 		if (index >= MAX_NUM_AXI_DEV)
 			return -EINVAL;
 		g_server_dev.axi_device[index] = sd;
+	} else if (sdev_type == GESTURE_DEV) {
+		g_server_dev.gesture_device = sd;
 	}
 
 	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 04e224c..6798cbb 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -32,6 +32,7 @@
 #include <mach/camera.h>
 #include <media/msm_isp.h>
 #include <linux/ion.h>
+#include <media/msm_gestures.h>
 
 #define MSM_V4L2_DIMENSION_SIZE 96
 #define MAX_DEV_NAME_LEN 50
@@ -69,6 +70,7 @@
 	SENSOR_DEV,
 	ACTUATOR_DEV,
 	EEPROM_DEV,
+	GESTURE_DEV,
 };
 
 /* msm queue management APIs*/
@@ -150,6 +152,8 @@
 	NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
 	NOTIFY_VFE_IRQ,
 	NOTIFY_AXI_IRQ,
+	NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
+	NOTIFY_GESTURE_CAM_EVT, /* arg = int */
 	NOTIFY_INVALID
 };
 
@@ -330,6 +334,8 @@
 	struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
 	struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
 	struct mutex dev_lock;
+	int active;
+	int use_count;
 };
 
 /* abstract camera device for each sensor successfully probed*/
@@ -384,7 +390,8 @@
 	struct msm_mem_map_info mem_map;
 };
 
-#define MAX_NUM_ACTIVE_CAMERA 2
+/* 2 for camera, 1 for gesture */
+#define MAX_NUM_ACTIVE_CAMERA 3
 
 struct msm_cam_server_queue {
 	uint32_t queue_active;
@@ -444,6 +451,7 @@
 	struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
 	struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
 	struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
+	struct v4l2_subdev *gesture_device;
 };
 
 /* camera server related functions */
@@ -566,6 +574,12 @@
 uint32_t msm_camera_get_mctl_handle(void);
 struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle);
 void msm_camera_free_mctl(uint32_t handle);
+int msm_server_open_client(int *p_qidx);
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
+int msm_server_close_client(int idx);
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+	int *p_active);
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
 #endif /* __KERNEL__ */
 
 #endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
new file mode 100644
index 0000000..654594d
--- /dev/null
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -0,0 +1,497 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include <media/msm_camera.h>
+#include <media/msm_gestures.h>
+#include <media/v4l2-ctrls.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_gesture: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+struct msm_gesture_ctrl {
+	int queue_id;
+	atomic_t active;
+	struct v4l2_ctrl_handler ctrl_handler;
+	int num_ctrls;
+	struct v4l2_fh *p_eventHandle;
+	struct v4l2_subdev *sd;
+	struct msm_ges_evt event;
+	int camera_opened;
+};
+
+static struct msm_gesture_ctrl g_gesture_ctrl;
+
+int msm_gesture_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+	struct v4l2_event_subscription *sub)
+{
+	D("%s\n", __func__);
+	if (sub->type == V4L2_EVENT_ALL)
+		sub->type = MSM_GES_APP_NOTIFY_EVENT;
+	return v4l2_event_subscribe(fh, sub);
+}
+
+static int msm_gesture_send_ctrl(struct msm_gesture_ctrl *p_gesture_ctrl,
+	int type, void *value, int length, uint32_t timeout)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd ctrlcmd;
+	D("%s qid %d\n", __func__, p_gesture_ctrl->queue_id);
+	ctrlcmd.type = type;
+	ctrlcmd.timeout_ms = timeout;
+	ctrlcmd.length = length;
+	ctrlcmd.value = value;
+	ctrlcmd.vnode_id = 0;
+	ctrlcmd.queue_idx = p_gesture_ctrl->queue_id;
+	ctrlcmd.config_ident = 0;
+
+	rc = msm_server_send_ctrl(&ctrlcmd, MSM_GES_RESP_V4L2);
+	return rc;
+}
+
+static int msm_gesture_proc_ctrl_cmd(struct msm_gesture_ctrl *p_gesture_ctrl,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_ctrl_cmd *tmp_cmd = NULL;
+	uint8_t *ctrl_data = NULL;
+	void __user *uptr_cmd;
+	void __user *uptr_value;
+	uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+	uint32_t value_len;
+
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+	uptr_cmd = (void __user *)ctrl->value;
+	uptr_value = (void __user *)tmp_cmd->value;
+	value_len = tmp_cmd->length;
+
+	D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+		__func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+		(uint32_t)uptr_value, tmp_cmd->length);
+
+	ctrl_data = kzalloc(value_len + cmd_len, GFP_KERNEL);
+	if (ctrl_data == 0) {
+		pr_err("%s could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto end;
+	}
+	tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+	if (copy_from_user((void *)ctrl_data, uptr_cmd,
+			cmd_len)) {
+		pr_err("%s: copy_from_user failed.\n", __func__);
+		rc = -EINVAL;
+		goto end;
+	}
+	tmp_cmd->value = (void *)(ctrl_data + cmd_len);
+	if (uptr_value && tmp_cmd->length > 0) {
+		if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+			value_len)) {
+			pr_err("%s: copy_from_user failed, size=%d\n",
+				__func__, value_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	} else
+		tmp_cmd->value = NULL;
+
+	/* send command to config thread in usersspace, and get return value */
+	rc = msm_server_send_ctrl((struct msm_ctrl_cmd *)ctrl_data,
+			MSM_GES_RESP_V4L2);
+	D("%s: msm_server_control rc=%d\n", __func__, rc);
+	if (rc == 0) {
+		if (uptr_value && tmp_cmd->length > 0 &&
+			copy_to_user((void __user *)uptr_value,
+				(void *)(ctrl_data + cmd_len),
+				tmp_cmd->length)) {
+			pr_err("%s: copy_to_user failed, size=%d\n",
+				__func__, tmp_cmd->length);
+			rc = -EINVAL;
+			goto end;
+		}
+		tmp_cmd->value = uptr_value;
+		if (copy_to_user((void __user *)uptr_cmd,
+			(void *)tmp_cmd, cmd_len)) {
+			pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+				__func__, cmd_len);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+end:
+	D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+		__func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+		tmp_cmd->length, tmp_cmd->status, rc);
+	kfree(ctrl_data);
+	return rc;
+}
+
+static int msm_gesture_s_ctrl(struct v4l2_subdev *sd,
+	struct v4l2_control *ctrl)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s ctrl->id %d\n", __func__, ctrl->id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, ctrl);
+	if (rc != 0) {
+		pr_err("%s set ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_s_ctrl_ops(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct v4l2_control control;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	control.id = ctrl->id;
+	control.value = ctrl->val;
+	D("%s ctrl->id 0x%x\n", __func__, ctrl->id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+	if (rc != 0) {
+		pr_err("%s proc ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_s_ctrl_ext(struct v4l2_subdev *sd,
+	struct v4l2_ext_controls *ctrls)
+{
+	int rc = 0;
+	struct v4l2_control control;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	if ((ctrls->count < 1) || (NULL == ctrls->controls)) {
+		pr_err("%s invalid ctrl failed\n", __func__);
+		return -EINVAL;
+	}
+	control.id = ctrls->controls->id;
+	control.value = ctrls->controls->value;
+	D("%s ctrl->id %d\n", __func__, control.id);
+	rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+	if (rc != 0) {
+		pr_err("%s proc ctrl failed %d\n", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_gesture_handle_event(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+	int rc = 0;
+	struct v4l2_event *evt = (struct v4l2_event *)arg;
+	struct msm_ges_evt *p_ges_evt = NULL;
+	D("%s: Received gesture evt 0x%x ", __func__, evt->type);
+	p_gesture_ctrl->event.evt_len = 0;
+	p_gesture_ctrl->event.evt_data = NULL;
+	if (0 != evt->u.data[0]) {
+		p_ges_evt = (struct msm_ges_evt *)evt->u.data;
+		D("%s: event data %p len %d", __func__,
+			p_ges_evt->evt_data,
+			p_ges_evt->evt_len);
+
+		if (p_ges_evt->evt_len > 0) {
+			p_gesture_ctrl->event.evt_data =
+				kzalloc(p_ges_evt->evt_len, GFP_KERNEL);
+
+			if (NULL == p_gesture_ctrl->event.evt_data) {
+				pr_err("%s: cannot allocate event", __func__);
+				rc = -ENOMEM;
+			} else {
+				if (copy_from_user(
+					(void *)p_gesture_ctrl->event.evt_data,
+					(void __user *)p_ges_evt->evt_data,
+					p_ges_evt->evt_len)) {
+					pr_err("%s: copy_from_user failed",
+							__func__);
+					rc = -EFAULT;
+				} else {
+					D("%s: copied the event", __func__);
+					p_gesture_ctrl->event.evt_len =
+						p_ges_evt->evt_len;
+				}
+			}
+		}
+	}
+
+	if (rc == 0) {
+		ktime_get_ts(&evt->timestamp);
+		v4l2_event_queue(&sd->devnode, evt);
+	}
+	D("%s: exit rc %d ", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_get_evt_payload(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+	int rc = 0;
+	struct msm_ges_evt *p_ges_evt = (struct msm_ges_evt *)arg;
+	D("%s: enter ", __func__);
+	if (NULL != p_gesture_ctrl->event.evt_data) {
+		D("%s: event data %p len %d", __func__,
+			p_gesture_ctrl->event.evt_data,
+			p_gesture_ctrl->event.evt_len);
+
+		if (copy_to_user((void __user *)p_ges_evt->evt_data,
+			p_gesture_ctrl->event.evt_data,
+			p_gesture_ctrl->event.evt_len)) {
+			pr_err("%s: copy_to_user failed.\n", __func__);
+			rc = -EFAULT;
+		} else {
+			D("%s: copied the event", __func__);
+			p_ges_evt->evt_len = p_gesture_ctrl->event.evt_len;
+		}
+	}
+	D("%s: exit rc %d ", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_handle_cam_event(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl, int cam_evt)
+{
+	int rc = 0;
+	D("%s: cam_evt %d ", __func__, cam_evt);
+
+	if ((cam_evt != MSM_V4L2_GES_CAM_OPEN)
+		&& (cam_evt != MSM_V4L2_GES_CAM_CLOSE)) {
+		pr_err("%s: error invalid event %d ", __func__, cam_evt);
+		return -EINVAL;
+	}
+
+	p_gesture_ctrl->camera_opened =
+		(cam_evt == MSM_V4L2_GES_CAM_OPEN);
+
+	if (atomic_read(&p_gesture_ctrl->active) == 0) {
+		D("%s gesture not active\n", __func__);
+		return 0;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, cam_evt, NULL,
+		0, 2000);
+	if (rc != 0) {
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+	}
+	D("%s exit rc %d\n", __func__, rc);
+	return rc;
+}
+
+long msm_gesture_ioctl(struct v4l2_subdev *sd,
+	 unsigned int cmd, void *arg)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	switch (cmd) {
+	case MSM_GES_IOCTL_CTRL_COMMAND: {
+		struct v4l2_control *ctrl = (struct v4l2_control *)arg;
+		D("%s MSM_GES_IOCTL_CTRL_COMMAND arg %p size %d\n", __func__,
+			arg, sizeof(ctrl));
+		rc = msm_gesture_s_ctrl(sd, ctrl);
+		break;
+	}
+	case VIDIOC_MSM_GESTURE_EVT: {
+		rc = msm_gesture_handle_event(sd, p_gesture_ctrl, arg);
+		break;
+	}
+	case VIDIOC_MSM_GESTURE_CAM_EVT: {
+		int cam_evt = *((int *)arg);
+		rc = msm_gesture_handle_cam_event(sd, p_gesture_ctrl, cam_evt);
+		break;
+	}
+	case MSM_GES_GET_EVT_PAYLOAD: {
+		rc = msm_gesture_get_evt_payload(sd, p_gesture_ctrl, arg);
+		break;
+	}
+	default:
+		pr_err("%s: Invalid ioctl %d", __func__, cmd);
+		break;
+	}
+	D("%s exit rc %d\n", __func__, rc);
+	return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_gesture_ctrl_ops = {
+	.s_ctrl = msm_gesture_s_ctrl_ops,
+};
+
+static const struct v4l2_ctrl_config msm_gesture_ctrl_filter = {
+	.ops = &msm_gesture_ctrl_ops,
+	.id = MSM_GESTURE_CID_CTRL_CMD,
+	.name = "Gesture ctrl",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.flags = V4L2_CTRL_FLAG_SLIDER,
+	.max = 0x7fffffff,
+	.step = 1,
+	.min = 0x80000000,
+};
+
+static int msm_gesture_init_ctrl(struct v4l2_subdev *sd,
+	struct msm_gesture_ctrl *p_gesture_ctrl)
+{
+	int rc = 0;
+	p_gesture_ctrl->num_ctrls = 1;
+	p_gesture_ctrl->ctrl_handler.error = 0;
+	v4l2_ctrl_handler_init(&p_gesture_ctrl->ctrl_handler,
+		p_gesture_ctrl->num_ctrls);
+	v4l2_ctrl_new_custom(&p_gesture_ctrl->ctrl_handler,
+		&msm_gesture_ctrl_filter, p_gesture_ctrl);
+	if (p_gesture_ctrl->ctrl_handler.error) {
+		int err = p_gesture_ctrl->ctrl_handler.error;
+		D("%s: error adding control %d", __func__, err);
+		p_gesture_ctrl->ctrl_handler.error = 0;
+	}
+	sd->ctrl_handler = &p_gesture_ctrl->ctrl_handler;
+	return rc;
+}
+
+static int msm_gesture_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0, rc_err = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	if (atomic_read(&p_gesture_ctrl->active) != 0) {
+		pr_err("%s already opened\n", __func__);
+		return -EINVAL;
+	}
+	memset(&p_gesture_ctrl->event, 0x0, sizeof(struct msm_ges_evt));
+	rc = msm_server_open_client(&p_gesture_ctrl->queue_id);
+	if (rc != 0) {
+		pr_err("%s open failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = msm_gesture_init_ctrl(sd, p_gesture_ctrl);
+	if (rc != 0) {
+		pr_err("%s init ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_OPEN, NULL,
+		0, 10000);
+	if (rc != 0) {
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	atomic_inc(&p_gesture_ctrl->active);
+
+	return rc;
+
+err:
+	rc_err = msm_server_close_client(p_gesture_ctrl->queue_id);
+	if (rc_err != 0)
+		pr_err("%s failed %d\n", __func__, rc);
+	return rc;
+}
+
+static int msm_gesture_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	D("%s\n", __func__);
+	if (atomic_read(&p_gesture_ctrl->active) == 0) {
+		pr_err("%s already closed\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_CLOSE, NULL,
+		0, 10000);
+	if (rc != 0)
+		pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+
+	rc = msm_server_close_client(p_gesture_ctrl->queue_id);
+	if (rc != 0)
+		pr_err("%s failed %d\n", __func__, rc);
+
+	v4l2_ctrl_handler_free(&p_gesture_ctrl->ctrl_handler);
+	kfree(p_gesture_ctrl->event.evt_data);
+
+	atomic_dec(&p_gesture_ctrl->active);
+	g_gesture_ctrl.queue_id = -1;
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_gesture_core_ops = {
+	.s_ctrl = msm_gesture_s_ctrl,
+	.s_ext_ctrls = msm_gesture_s_ctrl_ext,
+	.ioctl = msm_gesture_ioctl,
+	.subscribe_event = msm_gesture_subscribe_event,
+};
+
+static struct v4l2_subdev_video_ops msm_gesture_video_ops;
+
+static struct v4l2_subdev_ops msm_gesture_subdev_ops = {
+	.core = &msm_gesture_core_ops,
+	.video  = &msm_gesture_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_gesture_internal_ops = {
+	.open = msm_gesture_open,
+	.close = msm_gesture_close,
+};
+
+static int msm_gesture_node_register(void)
+{
+	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+	struct v4l2_subdev *gesture_subdev =
+		kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	D("%s\n", __func__);
+	if (!gesture_subdev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	};
+
+	v4l2_subdev_init(gesture_subdev, &msm_gesture_subdev_ops);
+	gesture_subdev->internal_ops = &msm_gesture_internal_ops;
+	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(gesture_subdev->name,
+			 sizeof(gesture_subdev->name), "gesture");
+
+	media_entity_init(&gesture_subdev->entity, 0, NULL, 0);
+	gesture_subdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	gesture_subdev->entity.group_id = GESTURE_DEV;
+	gesture_subdev->entity.name = gesture_subdev->name;
+
+	/* events */
+	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	gesture_subdev->nevents = MAX_GES_EVENTS;
+
+	msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+
+	gesture_subdev->entity.revision = gesture_subdev->devnode.num;
+
+	atomic_set(&p_gesture_ctrl->active, 0);
+	p_gesture_ctrl->queue_id = -1;
+	p_gesture_ctrl->event.evt_data = NULL;
+	p_gesture_ctrl->event.evt_len = 0;
+	return 0;
+}
+
+static int __init msm_gesture_init_module(void)
+{
+	return msm_gesture_node_register();
+}
+
+module_init(msm_gesture_init_module);
+MODULE_DESCRIPTION("MSM Gesture driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e878063..e9eb68f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -923,7 +923,6 @@
 	struct msm_cam_v4l2_device *pcam  = NULL;
 	struct msm_cam_v4l2_dev_inst *pcam_inst;
 	struct msm_cam_media_controller *pmctl;
-	D("%s : E ", __func__);
 
 	if (f == NULL) {
 		pr_err("%s :: cannot open video driver data", __func__);
@@ -935,8 +934,8 @@
 		pr_err("%s NULL pointer passed in!\n", __func__);
 		return rc;
 	}
-	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 
+	D("%s : E use_count %d", __func__, pcam->mctl_node.use_count);
 	mutex_lock(&pcam->mctl_node.dev_lock);
 	for (i = 0; i < MSM_DEV_INST_MAX; i++) {
 		if (pcam->mctl_node.dev_inst[i] == NULL)
@@ -960,6 +959,21 @@
 
 	D("%s pcam_inst %p my_index = %d\n", __func__,
 		pcam_inst, pcam_inst->my_index);
+	rc = msm_cam_server_open_mctl_session(pcam,
+		&pcam->mctl_node.active);
+	if (rc < 0) {
+		pr_err("%s: mctl session open failed %d", __func__, rc);
+		mutex_unlock(&pcam->mctl_node.dev_lock);
+		return rc;
+	}
+
+	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+	if (!pmctl) {
+		pr_err("%s mctl NULL!\n", __func__);
+		return rc;
+	}
+
+	D("%s active %d\n", __func__, pcam->mctl_node.active);
 	rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 					pcam->mctl_node.pvdev);
 	if (rc < 0) {
@@ -973,6 +987,7 @@
 	D("f->private_data = 0x%x, pcam = 0x%x\n",
 		(u32)f->private_data, (u32)pcam_inst);
 
+	pcam->mctl_node.use_count++;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
 	D("%s : X ", __func__);
 	return rc;
@@ -1030,6 +1045,17 @@
 
 	pmctl = msm_camera_get_mctl(pcam->mctl_handle);
 	mutex_lock(&pcam->mctl_node.dev_lock);
+	D("%s : active %d ", __func__, pcam->mctl_node.active);
+	if (pcam->mctl_node.active == 1) {
+		rc = msm_cam_server_close_mctl_session(pcam);
+		if (rc < 0) {
+			pr_err("%s: mctl session close failed %d",
+				__func__, rc);
+			mutex_unlock(&pcam->mctl_node.dev_lock);
+			return rc;
+		}
+		pmctl = NULL;
+	}
 	pcam_inst->streamon = 0;
 	pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
 	if (pcam_inst->vbqueue_initialized)
@@ -1040,10 +1066,14 @@
 	v4l2_fh_exit(&pcam_inst->eventHandle);
 
 	kfree(pcam_inst);
-	kref_put(&pmctl->refcount, msm_release_ion_client);
+	if (NULL != pmctl) {
+		D("%s : release ion client", __func__);
+		kref_put(&pmctl->refcount, msm_release_ion_client);
+	}
 	f->private_data = NULL;
 	mutex_unlock(&pcam->mctl_node.dev_lock);
-	D("%s : X ", __func__);
+	pcam->mctl_node.use_count--;
+	D("%s : use_count %d X ", __func__, pcam->mctl_node.use_count);
 	return rc;
 }
 
@@ -1246,6 +1276,11 @@
 				pb->m.planes[i].data_offset;
 			pcam_inst->buf_offset[pb->index][i].addr_offset =
 				pb->m.planes[i].reserved[0];
+			pcam_inst->plane_info.plane[i].offset = 0;
+			D("%s, len %d user[%d] %p buf_len %d\n",
+				__func__, pb->length, i,
+				(void *)pb->m.planes[i].m.userptr,
+				pb->m.planes[i].length);
 		}
 	} else {
 		D("%s stored reserved info %d", __func__, pb->reserved);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 5bc81a7..42d13a1 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -431,8 +431,8 @@
 	int pp_divert_type = 0, pp_type = 0;
 
 	msm_mctl_check_pp(p_mctl, image_mode, &pp_divert_type, &pp_type);
-	D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x",
-		__func__, pp_type, pp_divert_type, frame_id);
+	D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x image_mode %d",
+		__func__, pp_type, pp_divert_type, frame_id, image_mode);
 	if (pp_type || pp_divert_type)
 		rc = msm_mctl_do_pp_divert(p_mctl,
 		image_mode, fbuf, frame_id, pp_type);
@@ -440,9 +440,26 @@
 		idx = msm_mctl_img_mode_to_inst_index(
 				p_mctl, image_mode, 0);
 		if (idx < 0) {
-			pr_err("%s Invalid instance, dropping buffer\n",
-				__func__);
-			return idx;
+			/* check mctl node */
+			if ((image_mode >= 0) &&
+				p_mctl->pcam_ptr->mctl_node.
+					dev_inst_map[image_mode]) {
+				int index = p_mctl->pcam_ptr->mctl_node.
+					   dev_inst_map[image_mode]->my_index;
+				pcam_inst = p_mctl->pcam_ptr->mctl_node.
+					dev_inst[index];
+				D("%s: Mctl node index %d inst %p",
+					__func__, index, pcam_inst);
+				rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+					image_mode, fbuf,
+					&frame_id, 1);
+				D("%s mctl node buf done %d\n", __func__, 0);
+				return -EINVAL;
+			} else {
+			  pr_err("%s Invalid instance, dropping buffer\n",
+				  __func__);
+			  return idx;
+			}
 		}
 		pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
 		rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
@@ -573,6 +590,10 @@
 					plane_offset =
 					mem->offset.sp_off.cbcr_off;
 
+				D("%s: data off %d plane off %d",
+					__func__,
+					pcam_inst->buf_offset[buf_idx][i].
+					data_offset, plane_offset);
 				free_buf->ch_paddr[i] =	(uint32_t)
 				videobuf2_to_pmem_contig(&buf->vidbuf, i) +
 				pcam_inst->buf_offset[buf_idx][i].data_offset +
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index becdd95..3e8d3be 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -3056,7 +3056,7 @@
 		ch2_paddr = vfe32_get_ch_addr(ping_pong,
 			vfe32_ctrl->outpath.out1.ch2);
 
-		pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+		CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
 			__func__, ch0_paddr, ch1_paddr, ch2_paddr);
 		if (free_buf) {
 			/* Y channel */
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 8dfb0fc..03951ce 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -4,4 +4,4 @@
 header-y += vcap_fmt.h
 header-y += msm_isp.h
 header-y += msm_gemini.h
-header-y += msm_v4l2_overlay.h
+header-y += msm_gestures.h
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3f647dc..d4cf1d2 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1433,6 +1433,9 @@
 #define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
 
+#define MSM_CAM_IOCTL_SEND_EVENT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+
 struct msm_camera_v4l2_ioctl_t {
 	void __user *ioctl_ptr;
 };
diff --git a/include/media/msm_gestures.h b/include/media/msm_gestures.h
new file mode 100644
index 0000000..c9af034
--- /dev/null
+++ b/include/media/msm_gestures.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_MSM_GESTURES_H
+#define __LINUX_MSM_GESTURES_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <media/msm_camera.h>
+
+#define MSM_GES_IOCTL_CTRL_COMMAND \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 20, struct v4l2_control)
+
+#define VIDIOC_MSM_GESTURE_EVT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 21, struct v4l2_event)
+
+#define MSM_GES_GET_EVT_PAYLOAD \
+	_IOW('V', BASE_VIDIOC_PRIVATE + 22, struct msm_ges_evt)
+
+#define VIDIOC_MSM_GESTURE_CAM_EVT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 23, int)
+
+#define MSM_GES_RESP_V4L2  MSM_CAM_RESP_MAX
+#define MSM_GES_RESP_MAX  (MSM_GES_RESP_V4L2 + 1)
+
+#define MSM_SVR_RESP_MAX  MSM_GES_RESP_MAX
+
+
+#define MSM_V4L2_GES_BASE                             100
+#define MSM_V4L2_GES_OPEN         (MSM_V4L2_GES_BASE + 0)
+#define MSM_V4L2_GES_CLOSE        (MSM_V4L2_GES_BASE + 1)
+#define MSM_V4L2_GES_CAM_OPEN     (MSM_V4L2_GES_BASE + 2)
+#define MSM_V4L2_GES_CAM_CLOSE    (MSM_V4L2_GES_BASE + 3)
+
+#define MSM_GES_APP_EVT_MIN     (V4L2_EVENT_PRIVATE_START + 0x14)
+#define MSM_GES_APP_NOTIFY_EVENT        (MSM_GES_APP_EVT_MIN + 0)
+#define MSM_GES_APP_NOTIFY_ERROR_EVENT  (MSM_GES_APP_EVT_MIN + 1)
+#define MSM_GES_APP_EVT_MAX             (MSM_GES_APP_EVT_MIN + 2)
+
+#define MSM_GESTURE_CID_CTRL_CMD V4L2_CID_BRIGHTNESS
+
+#define MAX_GES_EVENTS 25
+
+struct msm_ges_ctrl_cmd {
+	int type;
+	void *value;
+	int len;
+	int fd;
+	uint32_t cookie;
+};
+
+struct msm_ges_evt {
+	void *evt_data;
+	int evt_len;
+};
+
+#endif /*__LINUX_MSM_GESTURES_H*/