Exemple #1
0
static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
			unsigned int subdev_cmd, void *arg)
{
	struct msm_mctl_pp_params *vpe_params;
	struct msm_mctl_pp_cmd *cmd;
	int rc = 0;

	if (subdev_cmd == VIDIOC_MSM_VPE_INIT) {
		struct msm_cam_media_controller *mctl =
			(struct msm_cam_media_controller *)arg;
		msm_vpe_subdev_init(sd, mctl);
	} else if (subdev_cmd == VIDIOC_MSM_VPE_RELEASE) {
		msm_vpe_subdev_release();
	} else if (subdev_cmd == VIDIOC_MSM_VPE_CFG) {
		vpe_params = (struct msm_mctl_pp_params *)arg;
		cmd = vpe_params->cmd;
		switch (cmd->id) {
		case VPE_CMD_INIT:
		case VPE_CMD_DEINIT:
			break;
		case VPE_CMD_RESET:
			rc = vpe_reset();
			break;
		case VPE_CMD_OPERATION_MODE_CFG:
			rc = vpe_operation_config(cmd->value);
			break;
		case VPE_CMD_INPUT_PLANE_CFG:
			vpe_input_plane_config(cmd->value);
			break;
		case VPE_CMD_OUTPUT_PLANE_CFG:
			vpe_output_plane_config(cmd->value);
			break;
		case VPE_CMD_SCALE_CFG_TYPE:
			vpe_update_scale_coef(cmd->value);
			break;
		case VPE_CMD_ZOOM: {
			rc = msm_vpe_do_pp(cmd,
			(struct msm_mctl_pp_frame_info *)vpe_params->data);
			break;
		}
		case VPE_CMD_ENABLE: {
			struct msm_vpe_clock_rate *clk_rate = cmd->value;
			int turbo_mode = (int)clk_rate->rate;
			rc = turbo_mode ?
				vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
				vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
			break;
		}
		case VPE_CMD_DISABLE:
			rc = vpe_disable();
			break;
		case VPE_CMD_INPUT_PLANE_UPDATE:
		case VPE_CMD_FLUSH:
		default:
			break;
		}
		CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
	}
	return rc;
}
static int vpe_proc_general(struct msm_vpe_cmd *cmd)
{
	int rc = 0;
	uint32_t *cmdp = NULL;
	struct msm_queue_cmd *qcmd = NULL;
	struct msm_vpe_buf_info *vpe_buf;
	int turbo_mode = 0;
	struct msm_sync *sync = (struct msm_sync *)vpe_ctrl->syncdata;
	CDBG("vpe_proc_general: cmdID = %s, length = %d\n",
		vpe_general_cmd[cmd->id], cmd->length);
	switch (cmd->id) {
	case VPE_ENABLE:
		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
		if (!cmdp) {
			rc = -ENOMEM;
			goto vpe_proc_general_done;
		}
		if (copy_from_user(cmdp,
			(void __user *)(cmd->value),
			cmd->length)) {
			rc = -EFAULT;
			goto vpe_proc_general_done;
		}
		turbo_mode = *((int *)(cmd->value));
		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE)
			: vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
		break;
	case VPE_DISABLE:
		rc = vpe_disable();
		break;
	case VPE_RESET:
	case VPE_ABORT:
		rc = vpe_reset();
		break;
	case VPE_START:
		rc = vpe_start();
		break;

	case VPE_INPUT_PLANE_CFG:
		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
		if (!cmdp) {
			rc = -ENOMEM;
			goto vpe_proc_general_done;
		}
		if (copy_from_user(cmdp,
			(void __user *)(cmd->value),
			cmd->length)) {
			rc = -EFAULT;
			goto vpe_proc_general_done;
		}
		vpe_input_plane_config(cmdp);
		break;

	case VPE_OPERATION_MODE_CFG:
		CDBG("cmd->length = %d\n", cmd->length);
		if (cmd->length != VPE_OPERATION_MODE_CFG_LEN_ZSL) {
			rc = -EINVAL;
			goto vpe_proc_general_done;
		}
		cmdp = kmalloc(VPE_OPERATION_MODE_CFG_LEN_ZSL,
					GFP_ATOMIC);
		if (copy_from_user(cmdp,
			(void __user *)(cmd->value),
			VPE_OPERATION_MODE_CFG_LEN_ZSL)) {
			rc = -EFAULT;
			goto vpe_proc_general_done;
		}
		rc = vpe_operation_config(cmdp);
		CDBG("rc = %d \n", rc);
		break;

	case VPE_OUTPUT_PLANE_CFG:
		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
		if (!cmdp) {
			rc = -ENOMEM;
			goto vpe_proc_general_done;
		}
		if (copy_from_user(cmdp,
			(void __user *)(cmd->value),
			cmd->length)) {
			rc = -EFAULT;
			goto vpe_proc_general_done;
		}
		vpe_output_plane_config(cmdp);
		break;

	case VPE_SCALE_CFG_TYPE:
		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
		if (!cmdp) {
			rc = -ENOMEM;
			goto vpe_proc_general_done;
		}
		if (copy_from_user(cmdp,
			(void __user *)(cmd->value),
			cmd->length)) {
			rc = -EFAULT;
			goto vpe_proc_general_done;
		}
		vpe_update_scale_coef(cmdp);
		break;

	case VPE_CMD_DIS_OFFSET_CFG: {
		struct msm_vfe_resp *vdata;
		/* first get the dis offset and frame id. */
		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
		if (!cmdp) {
			rc = -ENOMEM;
			goto vpe_proc_general_done;
		}
		if (copy_from_user(cmdp,
			(void __user *)(cmd->value),
			cmd->length)) {
			rc = -EFAULT;
			goto vpe_proc_general_done;
		}
		/* get the offset. */
		vpe_ctrl->dis_offset = *(struct dis_offset_type *)cmdp;
		qcmd = msm_dequeue_vpe(&sync->vpe_q, list_vpe_frame);
		if (!qcmd) {
			pr_err("%s: no video frame.\n", __func__);
			kfree(cmdp);
			return -EAGAIN;
		}
		vdata = (struct msm_vfe_resp *)(qcmd->command);
		vpe_buf = &vdata->vpe_bf;
		vpe_update_scaler_with_dis(&(vpe_buf->vpe_crop),
					&(vpe_ctrl->dis_offset));

		msm_send_frame_to_vpe(vpe_buf->y_phy, vpe_buf->cbcr_phy,
						&(vpe_buf->ts), OUTPUT_TYPE_V);

		if (!qcmd || !atomic_read(&qcmd->on_heap)) {
			kfree(cmdp);
			return -EAGAIN;
		}
		if (!atomic_sub_return(1, &qcmd->on_heap))
			kfree(qcmd);
		break;
	}

	default:
		break;
	}
vpe_proc_general_done:
	kfree(cmdp);
	return rc;
}
static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd,
				struct msm_cam_media_controller *mctl)
{
	int rc = 0;

	switch (vpe_cmd->cmd_type) {
	case VPE_CMD_RESET:
		rc = vpe_reset();
		break;

	case VPE_CMD_OPERATION_MODE_CFG: {
		struct msm_vpe_op_mode_cfg op_mode_cfg;
		if (sizeof(struct msm_vpe_op_mode_cfg) != vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_op_mode_cfg));
			rc = -EINVAL;
			break;
		}
		COPY_FROM_USER(rc, &op_mode_cfg, (void __user *)vpe_cmd->value,
			sizeof(op_mode_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&op_mode_cfg;
		rc = vpe_operation_config(vpe_cmd->value);
		break;
		}

	case VPE_CMD_INPUT_PLANE_CFG: {
		struct msm_vpe_input_plane_cfg input_cfg;
		if (sizeof(struct msm_vpe_input_plane_cfg) != vpe_cmd->length) {
			pr_err("%s: mismatch cmd = %d, len = %d, expected = %d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_input_plane_cfg));
			rc = -EINVAL;
			break;
		}
		COPY_FROM_USER(rc, &input_cfg, (void __user *)vpe_cmd->value,
			sizeof(input_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&input_cfg;
		vpe_input_plane_config(vpe_cmd->value);
		break;
		}

	case VPE_CMD_OUTPUT_PLANE_CFG: {
		struct msm_vpe_output_plane_cfg output_cfg;
		if (sizeof(struct msm_vpe_output_plane_cfg) !=
			vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_output_plane_cfg));
				rc = -EINVAL;
				break;
		}
		COPY_FROM_USER(rc, &output_cfg, (void __user *)vpe_cmd->value,
			sizeof(output_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&output_cfg;
		vpe_output_plane_config(vpe_cmd->value);
		break;
		}

	case VPE_CMD_SCALE_CFG_TYPE:{
		struct msm_vpe_scaler_cfg scaler_cfg;
		if (sizeof(struct msm_vpe_scaler_cfg) != vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_scaler_cfg));
			rc = -EINVAL;
			break;
		}
		COPY_FROM_USER(rc, &scaler_cfg, (void __user *)vpe_cmd->value,
			sizeof(scaler_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&scaler_cfg;
		vpe_update_scale_coef(vpe_cmd->value);
		break;
		}

	case VPE_CMD_ZOOM: {
		struct msm_mctl_pp_frame_info *zoom;
		zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info),
				GFP_ATOMIC);
		if (!zoom) {
			pr_err("%s Not enough memory ", __func__);
			rc = -ENOMEM;
			break;
		}

		if (sizeof(zoom->pp_frame_cmd) != vpe_cmd->length) {
			pr_err("%s: size mismatch id=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(zoom->pp_frame_cmd));
			rc = -EINVAL;
			kfree(zoom);
			break;
		}
		COPY_FROM_USER(rc, &zoom->pp_frame_cmd,
			(void __user *)vpe_cmd->value,
			sizeof(zoom->pp_frame_cmd));
		if (rc) {
			ERR_COPY_FROM_USER();
			kfree(zoom);
			break;
		}

		zoom->user_cmd = vpe_cmd->cmd_type;
		zoom->p_mctl = v4l2_get_subdev_hostdata(&vpe_ctrl->subdev);
		D("%s: cookie=0x%x,action=0x%x,path=0x%x",
			__func__, zoom->pp_frame_cmd.cookie,
			zoom->pp_frame_cmd.vpe_output_action,
			zoom->pp_frame_cmd.path);

		D("%s Mapping Source frame ", __func__);
		zoom->src_frame.frame = zoom->pp_frame_cmd.src_frame;
		rc = msm_mctl_map_user_frame(&zoom->src_frame,
			zoom->p_mctl->client, mctl->domain_num);
		if (rc < 0) {
			pr_err("%s Error mapping source buffer rc = %d",
				__func__, rc);
			kfree(zoom);
			break;
		}

		D("%s Mapping Destination frame ", __func__);
		zoom->dest_frame.frame = zoom->pp_frame_cmd.dest_frame;
		rc = msm_mctl_map_user_frame(&zoom->dest_frame,
			zoom->p_mctl->client, mctl->domain_num);
		if (rc < 0) {
			pr_err("%s Error mapping dest buffer rc = %d",
				__func__, rc);
			msm_mctl_unmap_user_frame(&zoom->src_frame,
				zoom->p_mctl->client, mctl->domain_num);
			kfree(zoom);
			break;
		}

		rc = msm_vpe_do_pp(zoom);
		break;
		}

	case VPE_CMD_ENABLE: {
		struct msm_vpe_clock_rate clk_rate;
		int turbo_mode;
		if (sizeof(struct msm_vpe_clock_rate) != vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_clock_rate));
			rc = -EINVAL;
			break;
		}
		if (copy_from_user(&clk_rate, (void __user *)vpe_cmd->value,
			sizeof(struct msm_vpe_clock_rate))) {
			pr_err("%s:clk_rate copy failed", __func__);
			return -EFAULT;
		}
		turbo_mode = (int)clk_rate.rate;
		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE, mctl) :
				vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE, mctl);
		break;
		}

	case VPE_CMD_DISABLE:
#ifdef CONFIG_PANTECH_CAMERA
		if (vpe_ctrl->pp_frame_info) {
			pr_err("%s : vpe_ctrl->pp_frame_info = %p ", __func__, vpe_ctrl->pp_frame_info);
			msm_mctl_unmap_user_frame(&vpe_ctrl->pp_frame_info->src_frame,
				vpe_ctrl->pp_frame_info->p_mctl->client, mctl->domain_num);
			msm_mctl_unmap_user_frame(&vpe_ctrl->pp_frame_info->dest_frame,
				vpe_ctrl->pp_frame_info->p_mctl->client, mctl->domain_num);
			kfree(vpe_ctrl->pp_frame_info);
			vpe_ctrl->pp_frame_info = NULL;			
		}
#endif
		rc = vpe_disable(mctl);
		break;

	default:
		break;
	}

	return rc;
}
static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd)
{
	int rc = 0;

	switch (vpe_cmd->cmd_type) {
	case VPE_CMD_RESET:
		rc = vpe_reset();
		break;

	case VPE_CMD_OPERATION_MODE_CFG: {
		struct msm_vpe_op_mode_cfg op_mode_cfg;
		if (sizeof(struct msm_vpe_op_mode_cfg) != vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_op_mode_cfg));
			rc = -EINVAL;
			break;
		}
		COPY_FROM_USER(rc, &op_mode_cfg, (void __user *)vpe_cmd->value,
			sizeof(op_mode_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&op_mode_cfg;
		rc = vpe_operation_config(vpe_cmd->value);
		break;
		}

	case VPE_CMD_INPUT_PLANE_CFG: {
		struct msm_vpe_input_plane_cfg input_cfg;
		if (sizeof(struct msm_vpe_input_plane_cfg) != vpe_cmd->length) {
			pr_err("%s: mismatch cmd = %d, len = %d, expected = %d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_input_plane_cfg));
			rc = -EINVAL;
			break;
		}
		COPY_FROM_USER(rc, &input_cfg, (void __user *)vpe_cmd->value,
			sizeof(input_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&input_cfg;
		vpe_input_plane_config(vpe_cmd->value);
		break;
		}

	case VPE_CMD_OUTPUT_PLANE_CFG: {
		struct msm_vpe_output_plane_cfg output_cfg;
		if (sizeof(struct msm_vpe_output_plane_cfg) !=
			vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_output_plane_cfg));
				rc = -EINVAL;
				break;
		}
		COPY_FROM_USER(rc, &output_cfg, (void __user *)vpe_cmd->value,
			sizeof(output_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&output_cfg;
		vpe_output_plane_config(vpe_cmd->value);
		break;
		}

	case VPE_CMD_SCALE_CFG_TYPE:{
		struct msm_vpe_scaler_cfg scaler_cfg;
		if (sizeof(struct msm_vpe_scaler_cfg) != vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_scaler_cfg));
			rc = -EINVAL;
			break;
		}
		COPY_FROM_USER(rc, &scaler_cfg, (void __user *)vpe_cmd->value,
			sizeof(scaler_cfg));
		if (rc) {
			ERR_COPY_FROM_USER();
			break;
		}

		vpe_cmd->value = (void *)&scaler_cfg;
		vpe_update_scale_coef(vpe_cmd->value);
		break;
		}

	case VPE_CMD_ZOOM: {
		struct msm_mctl_pp_frame_info *zoom;
		zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info),
				GFP_ATOMIC);
		if (!zoom) {
			pr_err("%s Not enough memory ", __func__);
			rc = -ENOMEM;
			break;
		}

		if (sizeof(zoom->pp_frame_cmd) != vpe_cmd->length) {
			pr_err("%s: size mismatch id=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(zoom->pp_frame_cmd));
			rc = -EINVAL;
			kfree(zoom);
			break;
		}
		COPY_FROM_USER(rc, &zoom->pp_frame_cmd,
			(void __user *)vpe_cmd->value,
			sizeof(zoom->pp_frame_cmd));
		if (rc) {
			ERR_COPY_FROM_USER();
			kfree(zoom);
			break;
		}

		zoom->user_cmd = vpe_cmd->cmd_type;
		zoom->p_mctl = v4l2_get_subdev_hostdata(&vpe_ctrl->subdev);
		D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
			__func__, zoom->pp_frame_cmd.src_buf_handle,
			zoom->pp_frame_cmd.dest_buf_handle,
			zoom->pp_frame_cmd.cookie,
			zoom->pp_frame_cmd.vpe_output_action,
			zoom->pp_frame_cmd.path);
		rc = msm_mctl_pp_get_vpe_buf_info(zoom);
		if (rc < 0) {
			pr_err("%s Error getting buffer info from mctl rc = %d",
				__func__, rc);
			kfree(zoom);
			break;
		}
		rc = msm_vpe_do_pp(zoom);
		kfree(zoom);
		break;
		}

	case VPE_CMD_ENABLE: {
		struct msm_vpe_clock_rate clk_rate;
		int turbo_mode;
		if (sizeof(struct msm_vpe_clock_rate) != vpe_cmd->length) {
			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
				__func__, vpe_cmd->cmd_type, vpe_cmd->length,
				sizeof(struct msm_vpe_clock_rate));
			rc = -EINVAL;
			break;
		}
		if (copy_from_user(&clk_rate, (void __user *)vpe_cmd->value,
			sizeof(struct msm_vpe_clock_rate))) {
			pr_err("%s:clk_rate copy failed", __func__);
			return -EFAULT;
		}
		turbo_mode = (int)clk_rate.rate;
		rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
				vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
		break;
		}

	case VPE_CMD_DISABLE:
		rc = vpe_disable();
		break;

	default:
		break;
	}

	return rc;
}