Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70f5abda authored by Hariram Purushothaman's avatar Hariram Purushothaman
Browse files

msm: camera: Return HAL buffer to fix drain issues



Return the HAL buffer to avoid drain issue
and provide the get buf by index interface so clients
can get buffer based on index.

CRs-Fixed: 1018651
Change-Id: I20329a6834f5f1498388c39b1dd95db2896b3239
Signed-off-by: default avatarHariram Purushothaman <hariramp@codeaurora.org>
parent 50239ba4
Loading
Loading
Loading
Loading
+86 −1
Original line number Diff line number Diff line
@@ -453,6 +453,38 @@ static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh,
	return rc;
}

static long camera_v4l2_vidioc_private_ioctl(struct file *filep, void *fh,
	bool valid_prio, unsigned int cmd, void *arg)
{
	struct camera_v4l2_private *sp = fh_to_private(fh);
	struct msm_video_device *pvdev = video_drvdata(filep);
	struct msm_camera_private_ioctl_arg *k_ioctl = arg;
	long rc = -EINVAL;

	if (WARN_ON(!k_ioctl || !pvdev))
		return -EIO;

	switch (k_ioctl->id) {
	case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
		struct msm_camera_return_buf ptr, *tmp = NULL;

		MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr,
			sizeof(tmp));
		if (copy_from_user(&ptr, tmp,
			sizeof(struct msm_camera_return_buf))) {
			return -EFAULT;
		}
		rc = msm_vb2_return_buf_by_idx(pvdev->vdev->num, sp->stream_id,
			ptr.index);
		}
		break;
	default:
		pr_debug("unimplemented id %d", k_ioctl->id);
		return -EINVAL;
	}
	return rc;
}

static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = {
	.vidioc_querycap = camera_v4l2_querycap,
	.vidioc_s_crop = camera_v4l2_s_crop,
@@ -477,6 +509,7 @@ static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = {
	/* event subscribe/unsubscribe */
	.vidioc_subscribe_event = camera_v4l2_subscribe_event,
	.vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event,
	.vidioc_default = camera_v4l2_vidioc_private_ioctl,
};

static int camera_v4l2_fh_open(struct file *filep)
@@ -724,10 +757,62 @@ static int camera_v4l2_close(struct file *filep)
}

#ifdef CONFIG_COMPAT
static long camera_handle_internal_compat_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
	long rc = 0;
	struct msm_camera_private_ioctl_arg k_ioctl;
	void __user *tmp_compat_ioctl_ptr = NULL;

	rc = msm_copy_camera_private_ioctl_args(arg,
		&k_ioctl, &tmp_compat_ioctl_ptr);
	if (rc < 0) {
		pr_err("Subdev cmd %d failed\n", cmd);
		return rc;
	}
	switch (k_ioctl.id) {
	case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
		if (k_ioctl.size != sizeof(struct msm_camera_return_buf)) {
			pr_debug("Invalid size for id %d with size %d",
				k_ioctl.id, k_ioctl.size);
			return -EINVAL;
		}
		k_ioctl.ioctl_ptr = (__u64)tmp_compat_ioctl_ptr;
		if (!k_ioctl.ioctl_ptr) {
			pr_debug("Invalid ptr for id %d", k_ioctl.id);
			return -EINVAL;
		}
		rc = camera_v4l2_vidioc_private_ioctl(file, file->private_data,
			0, cmd, (void *)&k_ioctl);
		}
		break;
	default:
		pr_debug("unimplemented id %d", k_ioctl.id);
		return -EINVAL;
	}
	return rc;
}

long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd,
	unsigned long arg)
{
	return -ENOIOCTLCMD;
	long ret = 0;

	switch (cmd) {
	case VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD: {
		ret = camera_handle_internal_compat_ioctl(file, cmd, arg);
		if (ret < 0) {
			pr_debug("Subdev cmd %d fail\n", cmd);
			return ret;
		}
		}
		break;
	default:
		ret = -ENOIOCTLCMD;
		break;

	}
	return ret;
}
#endif
static struct v4l2_file_operations camera_v4l2_fops = {
+1 −0
Original line number Diff line number Diff line
@@ -3,5 +3,6 @@ ccflags-y += -Idrivers/media/video/msm
ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc/cpp
ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_buf_mgr/

obj-$(CONFIG_MSM_FD) += msm_fd_dev.o msm_fd_hw.o
+22 −0
Original line number Diff line number Diff line
@@ -1088,6 +1088,28 @@ struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q)
}
EXPORT_SYMBOL(msm_get_stream_from_vb2q);

#ifdef CONFIG_COMPAT
long msm_copy_camera_private_ioctl_args(unsigned long arg,
	struct msm_camera_private_ioctl_arg *k_ioctl,
	void __user **tmp_compat_ioctl_ptr)
{
	struct msm_camera_private_ioctl_arg *up_ioctl_ptr =
		(struct msm_camera_private_ioctl_arg *)arg;

	if (WARN_ON(!arg || !k_ioctl || !tmp_compat_ioctl_ptr))
		return -EIO;

	k_ioctl->id = up_ioctl_ptr->id;
	k_ioctl->size = up_ioctl_ptr->size;
	k_ioctl->result = up_ioctl_ptr->result;
	k_ioctl->reserved = up_ioctl_ptr->reserved;
	*tmp_compat_ioctl_ptr = compat_ptr(up_ioctl_ptr->ioctl_ptr);

	return 0;
}
EXPORT_SYMBOL(msm_copy_camera_private_ioctl_args);
#endif

static void msm_sd_notify(struct v4l2_subdev *sd,
	unsigned int notification, void *arg)
{
+6 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, The Linux Foundation. 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
@@ -127,4 +127,9 @@ struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id,
	unsigned int stream_id);
struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q);
struct msm_session *msm_session_find(unsigned int session_id);
#ifdef CONFIG_COMPAT
long msm_copy_camera_private_ioctl_args(unsigned long arg,
	struct msm_camera_private_ioctl_arg *k_ioctl,
	void __user **tmp_compat_ioctl_ptr);
#endif
#endif /*_MSM_H */
+268 −48
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ static int32_t msm_buf_mngr_hdl_cont_get_buf(struct msm_buf_mngr_device *dev,
	}
	return 0;
}

static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev,
	void __user *argp)
{
@@ -91,6 +92,51 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev,
	return rc;
}

static int32_t msm_buf_mngr_get_buf_by_idx(struct msm_buf_mngr_device *dev,
	void *argp)
{
	unsigned long flags;
	int32_t rc = 0;
	struct msm_buf_mngr_info *buf_info =
		(struct msm_buf_mngr_info *)argp;
	struct msm_get_bufs *new_entry =
		kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL);

	if (!new_entry) {
		pr_err("%s:No mem\n", __func__);
		return -ENOMEM;
	}
	if (WARN_ON(!buf_info))
		return -EIO;

	INIT_LIST_HEAD(&new_entry->entry);
	new_entry->vb2_buf = dev->vb2_ops.get_buf_by_idx(buf_info->session_id,
		buf_info->stream_id, buf_info->index);
	if (!new_entry->vb2_buf) {
		pr_debug("%s:Get buf is null\n", __func__);
		kfree(new_entry);
		return -EINVAL;
	}
	new_entry->session_id = buf_info->session_id;
	new_entry->stream_id = buf_info->stream_id;
	new_entry->index = new_entry->vb2_buf->v4l2_buf.index;
	spin_lock_irqsave(&dev->buf_q_spinlock, flags);
	list_add_tail(&new_entry->entry, &dev->buf_qhead);
	spin_unlock_irqrestore(&dev->buf_q_spinlock, flags);
	if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
		mutex_lock(&dev->cont_mutex);
		if (!list_empty(&dev->cont_qhead)) {
			rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info);
		} else {
			pr_err("Nothing mapped in user buf for %d,%d\n",
				buf_info->session_id, buf_info->stream_id);
			rc = -EINVAL;
		}
		mutex_unlock(&dev->cont_mutex);
	}
	return rc;
}

static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev,
	struct msm_buf_mngr_info *buf_info)
{
@@ -410,6 +456,67 @@ static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd,
	return rc;
}

int msm_cam_buf_mgr_ops(unsigned int cmd, void *argp)
{
	int rc = 0;

	if (!msm_buf_mngr_dev)
		return -ENODEV;
	if (!argp)
		return -EINVAL;

	switch (cmd) {
	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
		rc = msm_buf_mngr_get_buf(msm_buf_mngr_dev, argp);
		break;
	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
		rc = msm_buf_mngr_buf_done(msm_buf_mngr_dev, argp);
		break;
	case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
		rc = msm_buf_mngr_put_buf(msm_buf_mngr_dev, argp);
		break;
	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
		struct msm_camera_private_ioctl_arg *k_ioctl = argp;

		switch (k_ioctl->id) {
		case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
			struct msm_buf_mngr_info *tmp = NULL;

			if (!k_ioctl->ioctl_ptr)
				return -EINVAL;
			if (k_ioctl->size != sizeof(struct msm_buf_mngr_info))
				return -EINVAL;

			MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr,
				sizeof(tmp));
			rc = msm_buf_mngr_get_buf_by_idx(msm_buf_mngr_dev,
				tmp);
			}
			break;
		default:
			pr_debug("unimplemented id %d", k_ioctl->id);
			return -EINVAL;
		}
	break;
	}
	default:
		return -ENOIOCTLCMD;
	}

	return rc;
}

int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct)
{
	if (!msm_buf_mngr_dev)
		return -ENODEV;
	if (!cb_struct)
		return -EINVAL;

	cb_struct->msm_cam_buf_mgr_ops = msm_cam_buf_mgr_ops;
	return 0;
}

static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
	unsigned int cmd, void *arg)
{
@@ -422,16 +529,45 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
		rc = -ENOMEM;
		return rc;
	}

	switch (cmd) {
	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
		rc = msm_buf_mngr_get_buf(buf_mngr_dev, argp);
	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
		struct msm_camera_private_ioctl_arg k_ioctl, *ptr;

		if (!arg)
			return -EINVAL;
		ptr = arg;
		k_ioctl = *ptr;
		switch (k_ioctl.id) {
		case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
			struct msm_buf_mngr_info buf_info, *tmp = NULL;

			if (k_ioctl.size != sizeof(struct msm_buf_mngr_info))
				return -EINVAL;
			if (!k_ioctl.ioctl_ptr)
				return -EINVAL;

			MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr,
				sizeof(tmp));
			if (copy_from_user(&buf_info, tmp,
				sizeof(struct msm_buf_mngr_info))) {
				return -EFAULT;
			}
			MSM_CAM_GET_IOCTL_ARG_PTR(&k_ioctl.ioctl_ptr,
				&buf_info, sizeof(void *));
			argp = &k_ioctl;
			rc = msm_cam_buf_mgr_ops(cmd, argp);
			}
			break;
	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
		rc = msm_buf_mngr_buf_done(buf_mngr_dev, argp);
		default:
			pr_debug("unimplemented id %d", k_ioctl.id);
			return -EINVAL;
		}
		}
		break;
	case VIDIOC_MSM_BUF_MNGR_GET_BUF:
	case VIDIOC_MSM_BUF_MNGR_BUF_DONE:
	case VIDIOC_MSM_BUF_MNGR_PUT_BUF:
		rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp);
		rc = msm_cam_buf_mgr_ops(cmd, argp);
		break;
	case VIDIOC_MSM_BUF_MNGR_INIT:
		rc = msm_generic_buf_mngr_open(sd, NULL);
@@ -459,6 +595,105 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
}

#ifdef CONFIG_COMPAT
static long msm_camera_buf_mgr_fetch_buf_info(
		struct msm_buf_mngr_info32_t *buf_info32,
		struct msm_buf_mngr_info *buf_info, unsigned long arg)
{
	WARN_ON(!arg || !buf_info32 || !buf_info);

	if (copy_from_user(buf_info32, (void __user *)arg,
				sizeof(struct msm_buf_mngr_info32_t)))
		return -EFAULT;

	buf_info->session_id = buf_info32->session_id;
	buf_info->stream_id = buf_info32->stream_id;
	buf_info->frame_id = buf_info32->frame_id;
	buf_info->index = buf_info32->index;
	buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec;
	buf_info->timestamp.tv_usec = (long) buf_info32->
					timestamp.tv_usec;
	buf_info->reserved = buf_info32->reserved;
	buf_info->type = buf_info32->type;
	return 0;
}

static long msm_camera_buf_mgr_update_buf_info(
		struct msm_buf_mngr_info32_t *buf_info32,
		struct msm_buf_mngr_info *buf_info, unsigned long arg)
{
	WARN_ON(!arg || !buf_info32 || !buf_info);

	buf_info32->session_id = buf_info->session_id;
	buf_info32->stream_id = buf_info->stream_id;
	buf_info32->index = buf_info->index;
	buf_info32->timestamp.tv_sec = (int32_t) buf_info->
						timestamp.tv_sec;
	buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp.
						tv_usec;
	buf_info32->reserved = buf_info->reserved;
	buf_info32->type = buf_info->type;
	buf_info32->user_buf.buf_cnt = buf_info->user_buf.buf_cnt;
	memcpy(&buf_info32->user_buf.buf_idx,
		&buf_info->user_buf.buf_idx,
		sizeof(buf_info->user_buf.buf_idx));
	if (copy_to_user((void __user *)arg, buf_info32,
			sizeof(struct msm_buf_mngr_info32_t)))
		return -EFAULT;
	return 0;
}
static long msm_camera_buf_mgr_internal_compat_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
	struct video_device *vdev = video_devdata(file);
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
	long rc = 0;
	struct msm_camera_private_ioctl_arg k_ioctl;
	void __user *tmp_compat_ioctl_ptr = NULL;

	rc = msm_copy_camera_private_ioctl_args(arg,
		&k_ioctl, &tmp_compat_ioctl_ptr);
	if (rc < 0) {
		pr_err("Subdev cmd %d failed\n", cmd);
		return rc;
	}

	switch (k_ioctl.id) {
	case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: {
		struct msm_buf_mngr_info32_t buf_info32;
		struct msm_buf_mngr_info buf_info;

		if (k_ioctl.size != sizeof(struct msm_buf_mngr_info32_t)) {
			pr_err("Invalid size for id %d with size %d",
				k_ioctl.id, k_ioctl.size);
			return -EINVAL;
		}
		if (!tmp_compat_ioctl_ptr) {
			pr_err("Invalid ptr for id %d", k_ioctl.id);
			return -EINVAL;
		}
		k_ioctl.ioctl_ptr = (__u64)&buf_info;
		rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info,
			(unsigned long)tmp_compat_ioctl_ptr);
		if (rc < 0) {
			pr_err("Fetch buf info failed for cmd=%d", cmd);
			return rc;
		}
		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &k_ioctl);
		if (rc < 0) {
			pr_err("Subdev cmd %d failed for id %d", cmd,
				k_ioctl.id);
			return rc;
		}
		}
		break;
	default:
		pr_debug("unimplemented id %d", k_ioctl.id);
		return -EINVAL;
	}

	return 0;
}

static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
@@ -466,8 +701,6 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file,
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
	int32_t rc = 0;

	void __user *up = (void __user *)arg;

	/* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's
	 * except VIDIOC_MSM_CPP_CFG32, which needs special
	 * processing
@@ -483,13 +716,14 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file,
		cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF;
		break;
	case VIDIOC_MSM_BUF_MNGR_CONT_CMD:
		cmd = VIDIOC_MSM_BUF_MNGR_CONT_CMD;
		break;
	case VIDIOC_MSM_BUF_MNGR_FLUSH32:
		cmd = VIDIOC_MSM_BUF_MNGR_FLUSH;
		break;
	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD:
		break;
	default:
		pr_debug("%s : unsupported compat type", __func__);
		pr_debug("unsupported compat type\n");
		return -ENOIOCTLCMD;
	}

@@ -501,65 +735,51 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file,
		struct msm_buf_mngr_info32_t buf_info32;
		struct msm_buf_mngr_info buf_info;

		if (copy_from_user(&buf_info32, (void __user *)up,
					sizeof(struct msm_buf_mngr_info32_t)))
			return -EFAULT;

		buf_info.session_id = buf_info32.session_id;
		buf_info.stream_id = buf_info32.stream_id;
		buf_info.frame_id = buf_info32.frame_id;
		buf_info.index = buf_info32.index;
		buf_info.timestamp.tv_sec = (long) buf_info32.timestamp.tv_sec;
		buf_info.timestamp.tv_usec = (long) buf_info32.
						timestamp.tv_usec;
		buf_info.reserved = buf_info32.reserved;
		buf_info.type = buf_info32.type;

		rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info,
			arg);
		if (rc < 0) {
			pr_err("Fetch buf info failed for cmd=%d\n", cmd);
			return rc;
		}
		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info);
		if (rc < 0) {
			pr_debug("%s : Subdev cmd %d fail", __func__, cmd);
			pr_debug("Subdev cmd %d fail\n", cmd);
			return rc;
		}
		rc = msm_camera_buf_mgr_update_buf_info(&buf_info32, &buf_info,
			arg);
		if (rc < 0) {
			pr_err("Update buf info failed for cmd=%d\n", cmd);
			return rc;
		}
		}
		break;
	case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: {
		rc = msm_camera_buf_mgr_internal_compat_ioctl(file, cmd, arg);
		if (rc < 0) {
			pr_debug("Subdev cmd %d fail\n", cmd);
			return rc;
		}

		buf_info32.session_id = buf_info.session_id;
		buf_info32.stream_id = buf_info.stream_id;
		buf_info32.index = buf_info.index;
		buf_info32.timestamp.tv_sec = (int32_t) buf_info.
							timestamp.tv_sec;
		buf_info32.timestamp.tv_usec = (int32_t) buf_info.timestamp.
							tv_usec;
		buf_info32.reserved = buf_info.reserved;
		buf_info32.type = buf_info.type;
		buf_info32.user_buf.buf_cnt = buf_info.user_buf.buf_cnt;
		memcpy(&buf_info32.user_buf.buf_idx,
			&buf_info.user_buf.buf_idx,
			sizeof(buf_info.user_buf.buf_idx));
		if (copy_to_user((void __user *)up, &buf_info32,
				sizeof(struct msm_buf_mngr_info32_t)))
			return -EFAULT;
		}
		break;
	case VIDIOC_MSM_BUF_MNGR_CONT_CMD: {
		struct msm_buf_mngr_main_cont_info cont_cmd;

		if (copy_from_user(&cont_cmd, (void __user *)up,
		if (copy_from_user(&cont_cmd, (void __user *)arg,
			sizeof(struct msm_buf_mngr_main_cont_info)))
			return -EFAULT;
		rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd);
		if (rc < 0) {
			pr_debug("%s : Subdev cmd %d fail", __func__, cmd);
			pr_debug("Subdev cmd %d fail\n", cmd);
			return rc;
		}
		}
		break;
	default:
		pr_debug("%s : unsupported compat type", __func__);
		pr_debug("unsupported compat type\n");
		return -ENOIOCTLCMD;
		break;
	}



	return 0;
}
#endif
Loading