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

Commit 22a14e1d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: Return HAL buffer to fix drain issues"

parents ae8c5b1b 70f5abda
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