Пример #1
0
/**
 * prev_get_status - Get status of ISP preview module
 * @status: Structure containing the busy state.
 *
 * Checks if the ISP preview module is busy.
 *
 * Returns 0 if successful, or -EINVAL if the status parameter is invalid.
 **/
static int prev_get_status(struct prev_status *status)
{
    if (!status) {
        dev_err(prev_dev, "get_status: invalid parameter\n");
        return -EINVAL;
    }
    status->hw_busy = (char)isppreview_busy();
    return 0;
}
Пример #2
0
/**
 * prev2resz_ioctl - I/O control function for device
 */
static int prev2resz_ioctl(struct inode *inode, struct file *file,
			   unsigned int cmd, unsigned long arg)
{
	struct prev2resz_fhdl *fh = file->private_data;
	long rval = 0;

	if ((_IOC_TYPE(cmd) != PREV2RESZ_IOC_BASE) && (_IOC_TYPE(cmd) != 'M') &&
	    (cmd < BASE_VIDIOC_PRIVATE)) {
		dev_err(p2r_device, "Bad command value.\n");
		return -EFAULT;
	}

	if (_IOC_DIR(cmd) & _IOC_READ)
		rval = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
	else if (_IOC_DIR(cmd) & _IOC_WRITE)
		rval = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));

	if (rval) {
		dev_err(p2r_device, "Access denied\n");
		return -EFAULT;
	}

	switch (cmd) {
	case PREV2RESZ_REQBUF:
	{
		struct v4l2_requestbuffers v4l2_req;
		if (copy_from_user(&v4l2_req, (void *)arg,
				   sizeof(struct v4l2_requestbuffers)))
			return -EIO;
		if (v4l2_req.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
			if (videobuf_reqbufs(&fh->src_vbq, &v4l2_req) < 0)
				return -EINVAL;
		} else if (v4l2_req.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
			if (videobuf_reqbufs(&fh->dst_vbq, &v4l2_req) < 0)
				return -EINVAL;
		}
		if (copy_to_user((void *)arg, &v4l2_req,
				 sizeof(struct v4l2_requestbuffers)))
			return -EIO;
		break;
	}
	case PREV2RESZ_QUERYBUF:
	{
		struct v4l2_buffer v4l2_buf;
		if (copy_from_user(&v4l2_buf, (void *)arg,
				   sizeof(struct v4l2_buffer)))
			return -EIO;
		if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
			if (videobuf_querybuf(&fh->src_vbq, &v4l2_buf) < 0)
				return -EINVAL;
		} else if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
			if (videobuf_querybuf(&fh->dst_vbq, &v4l2_buf) < 0)
				return -EINVAL;
		}
		if (copy_to_user((void *)arg, &v4l2_buf,
				 sizeof(struct v4l2_buffer)))
			return -EIO;
		break;
	}
	case PREV2RESZ_QUEUEBUF:
	{
		struct v4l2_buffer v4l2_buf;
		if (copy_from_user(&v4l2_buf, (void *)arg,
				   sizeof(struct v4l2_buffer)))
			return -EIO;
		if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
			if (videobuf_qbuf(&fh->src_vbq, &v4l2_buf) < 0)
				return -EINVAL;
		} else if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
			if (videobuf_qbuf(&fh->dst_vbq, &v4l2_buf) < 0)
				return -EINVAL;
		}
		if (copy_to_user((void *)arg, &v4l2_buf,
				 sizeof(struct v4l2_buffer)))
			return -EIO;
		break;
	}
	case PREV2RESZ_SET_CONFIG:
		if (copy_from_user(&fh->pipe, (void *)arg,
				   sizeof(fh->pipe)))
			return -EIO;
		if (prev2resz_ioc_set_config(fh) < 0)
			return -EINVAL;
		if (copy_to_user((void *)arg, &fh->pipe,
				 sizeof(fh->pipe)))
			return -EIO;
		break;

	case PREV2RESZ_GET_CONFIG:
		if (copy_to_user((void *)arg, &fh->pipe,
				 sizeof(fh->pipe)))
			return -EIO;
		break;

	case PREV2RESZ_RUN_ENGINE:
		if (file->f_flags & O_NONBLOCK) {
			if (isppreview_busy(fh->isp_prev))
				return -EBUSY;
			if (ispresizer_busy(fh->isp_resz))
				return -EBUSY;
		}
		if (prev2resz_ioc_run_engine(fh) < 0)
			return -EINVAL;
		break;

	case PREV2RESZ_GET_STATUS:
	{
		struct prev2resz_status *status =
			(struct prev2resz_status *)arg;
		status->prv_busy = isppreview_busy(fh->isp_prev);
		status->rsz_busy = ispresizer_busy(fh->isp_resz);
		break;
	}
	case VIDIOC_QUERYCAP:
	{
		struct v4l2_capability v4l2_cap;
		if (copy_from_user(&v4l2_cap, (void *)arg,
				   sizeof(struct v4l2_capability)))
			return -EIO;

		strcpy(v4l2_cap.driver, "omap3wrapper");
		strcpy(v4l2_cap.card, "omap3wrapper/prev-resz");
		v4l2_cap.version	= 1.0;;
		v4l2_cap.capabilities	= V4L2_CAP_VIDEO_CAPTURE |
					  V4L2_CAP_READWRITE;

		if (copy_to_user((void *)arg, &v4l2_cap,
				 sizeof(struct v4l2_capability)))
			return -EIO;
		break;
	}
	case VIDIOC_PRIVATE_ISP_PRV_CFG:
		if (isppreview_config(fh->isp_prev, (void *)arg))
			return -EIO;
		break;

	default:
		dev_err(p2r_device, "IOC: Invalid Command Value!\n");
		return -EINVAL;
	}

	return 0;
}
Пример #3
0
int isp_process_mem_data(struct isp_mem_data *data)
{
	int i;
	int ret = -1;
	struct isp_mem_data *ppreview_user = \
		(struct isp_mem_data *)data;
	struct isp_mem_data preview_param;
	u32 input_buffer_size, output_buffer_size;
	u32 input_nr_pages, output_nr_pages;
	struct page **input_pages = NULL;
	struct page **output_pages = NULL;
	unsigned long isp_addr_in = 0;
	unsigned long  isp_addr_out = 0;
	unsigned long  isp_addr_tmp = 0;
	unsigned long timeout;
	struct isp_mem_resize_data resizer_param;
	u16 cropadjust = 0;

	if (ppreview_user == NULL) {
		printk(KERN_ERR "ISP_PROC_ERR: Invalid user data!\n");
		return -EINVAL;
	}

	memcpy(&preview_param, ppreview_user, \
		sizeof(struct isp_mem_data));

	DPRINTK_ISPPROC("input(%d-%d) - output(%d-%d)\n",
		preview_param.input_width,
		preview_param.input_height,
		preview_param.output_width,
		preview_param.output_height);

	DPRINTK_ISPPROC("start(%d-%d) - end(%d-%d)\n",
		preview_param.left,
		preview_param.top,
		preview_param.crop_width,
		preview_param.crop_height);

	if (ppreview_user->datain == 0 || ppreview_user->dataout == 0)
		return -EINVAL;

	isppreview_enable(0);
	ispresizer_enable(0);
	timeout = jiffies + msecs_to_jiffies(200);
	while (isppreview_busy() ||
			ispresizer_busy()) {
		if (time_after(jiffies, timeout))
			return -EINVAL;
		msleep(1);
	}

	isppreview_save_context();
	ispresizer_save_context();
	isppreview_free();
	ispresizer_free();
	isppreview_request();
	ispresizer_request();

	/* set data path before configuring modules. */
	isppreview_update_datapath(PRV_RAW_MEM, PREVIEW_MEM);
	ispresizer_config_datapath(RSZ_MEM_YUV, 0);

	ret = isppreview_try_size(preview_param.input_width,
		preview_param.input_height,
		&preview_param.output_width,
		&preview_param.output_height);
	if (ret < 0)
		goto exit_cleanup;
	ret = isppreview_config_size(preview_param.input_width,
		preview_param.input_height,
		preview_param.output_width,
		preview_param.output_height);
	if (ret < 0)
		goto exit_cleanup;

	input_buffer_size = ALIGN_TO(ppreview_user->input_width* \
		ppreview_user->input_height*2 , 0x100);
	input_pages = map_user_memory_to_kernel(preview_param.datain,
		input_buffer_size, &input_nr_pages);
	if (input_pages == NULL) {
		ret = -EINVAL;
		printk(KERN_ERR "ISP_PROC_ERR: memory allocation failed\n");
		goto exit_cleanup;
	}

	output_buffer_size = ALIGN_TO(ppreview_user->output_width* \
		ppreview_user->output_height*2, 0x1000);
	output_pages = map_user_memory_to_kernel(preview_param.dataout,
		output_buffer_size, &output_nr_pages);
	if (output_pages == NULL) {
		ret = -EINVAL;
		printk(KERN_ERR "ISP_PROC_ERR: memory allocation failed\n");
		goto exit_cleanup;
	}
	for (i = 0; i < output_nr_pages; ++i)
		flush_dcache_page(output_pages[i]);

	isp_addr_in = ispmmu_vmap_pages(input_pages, input_nr_pages);
	if (IS_ERR((void *)isp_addr_in)) {
		isp_addr_in = 0;
		ret = -EINVAL;
		printk(KERN_ERR "ISP_PROC_ERR: isp mmu map failed\n");
		goto exit_cleanup;
	}
	isp_addr_out = ispmmu_vmap_pages(output_pages, output_nr_pages);
	if (IS_ERR((void *)isp_addr_out)) {
		isp_addr_out = 0;
		ret = -EINVAL;
		printk(KERN_ERR "ISP_PROC_ERR: isp mmu map failed\n");
		goto exit_cleanup;
	}

	/* This buffer must be allocated and mapped to
		the ISP MMU previously. */
	isp_addr_tmp = isp_tmp_buf_addr();
	if (isp_addr_tmp == 0) {
		printk(KERN_ERR "ISP_PROC_ERR: Invalid isp tmp buffer address!\n");
		goto exit_cleanup;
	}

	isppreview_config_inlineoffset(ppreview_user->input_width * 2);
	isppreview_set_inaddr(isp_addr_in);
	isppreview_set_outaddr(isp_addr_tmp);

	resizer_param.input_width = preview_param.output_width;
	resizer_param.input_height = preview_param.output_height;
	resizer_param.output_width = ppreview_user->output_width;
	resizer_param.output_height = ppreview_user->output_height;

	if ((preview_param.left == 0) && (preview_param.top == 0)) {
		ret = ispresizer_try_size(&resizer_param.input_width,
				&resizer_param.input_height,
				&resizer_param.output_width,
				&resizer_param.output_height);
		if (ret < 0)
			goto exit_cleanup;
		ret = ispresizer_config_size(resizer_param.input_width,
				resizer_param.input_height,
				resizer_param.output_width,
				resizer_param.output_height);
		if (ret < 0)
			goto exit_cleanup;
		ispresizer_set_inaddr(isp_addr_tmp);
	} else {
		ispresizer_trycrop(preview_param.left,
				preview_param.top,
				preview_param.crop_width,
				preview_param.crop_height,
				resizer_param.output_width,
				resizer_param.output_height);

		ispresizer_applycrop();

		/* account for pixel loss when using crop*/
		if ((preview_param.input_height > preview_param.output_height)
				&& (preview_param.top > 16))
			cropadjust = 8;
		else
			cropadjust = 0;

		/* pixel alignment in 32bit space, vertical must be 0 per TRM */
		isp_reg_writel(((preview_param.left%16) <<
					ISPRSZ_IN_START_HORZ_ST_SHIFT) |
					(0 <<
					ISPRSZ_IN_START_VERT_ST_SHIFT),
					OMAP3_ISP_IOMEM_RESZ,
					ISPRSZ_IN_START);

		/* Align input address for cropping, per TRM  */
		ispresizer_set_inaddr(isp_addr_tmp -
				(resizer_param.input_width*2*cropadjust) +
				(preview_param.top*resizer_param.input_width*2)
				+ ((preview_param.left/16)*32));
	}

	ispresizer_set_outaddr(isp_addr_out);
	ispresizer_config_inlineoffset(
		ALIGN_TO(resizer_param.input_width*2, 32));

	if (isp_set_callback(CBK_PREV_DONE, prv_isr,
			(void *) NULL, (void *)NULL) != 0) {
		printk(KERN_ERR "ISP_PROC_ERR: Error setting PRV callback.\n");
		goto exit_cleanup;
	}

	if (isp_set_callback(CBK_RESZ_DONE, rsz_isr,
			(void *) NULL, (void *)NULL) != 0) {
		printk(KERN_ERR "ISP_PROC_ERR: Error setting RSZ callback.\n");
		goto exit_cleanup;
	}

	isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
	isp_wfc.done = 0;

	/* start preview engine. */
	isppreview_enable(1);

	ret = wait_for_completion_timeout(&isp_wfc, msecs_to_jiffies(1000));
	if (!ret) {
		isppreview_enable(0);
		ispresizer_enable(0);
	}

	timeout = jiffies + msecs_to_jiffies(50);
	while (ispresizer_busy()) {
		msleep(5);
		if (time_after(jiffies, timeout)) {
			printk(KERN_ERR "ISP_RESZ_ERR: Resizer still busy");
			break;
		}
	}

	isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
	isp_unset_callback(CBK_PREV_DONE);
	isp_unset_callback(CBK_RESZ_DONE);

exit_cleanup:
	isppreview_restore_context();
	ispresizer_restore_context();

	if (isp_addr_in != 0)
		ispmmu_vunmap(isp_addr_in);
	if (isp_addr_out != 0)
		ispmmu_vunmap(isp_addr_out);
	if (input_pages != NULL) {
		unmap_user_memory_from_kernel(input_pages, input_nr_pages);
		kfree(input_pages);
	}
	if (output_pages != NULL) {
		unmap_user_memory_from_kernel(output_pages, output_nr_pages);
		kfree(output_pages);
	}

	DPRINTK_ISPPROC("exit.\n");

	return ret;
}