static int
__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
{
    struct v4l2_subdev_format fmt;
    struct v4l2_subdev *subdev;
    u32 pad;
    int ret;

    subdev = isp_video_remote_subdev(video, &pad);
    if (subdev == NULL)
        return -EINVAL;

    mutex_lock(&video->mutex);

    fmt.pad = pad;
    fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
    ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
    if (ret == -ENOIOCTLCMD)
        ret = -EINVAL;

    mutex_unlock(&video->mutex);

    if (ret)
        return ret;

    format->type = video->type;
    return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
}
Esempio n. 2
0
static int
isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
	struct isp_video *video = video_drvdata(file);
	struct v4l2_subdev *subdev;
	struct v4l2_mbus_framefmt format;
	u32 pad;
	int ret;

	subdev = isp_video_remote_subdev(video, &pad);
	if (subdev == NULL)
		return -EINVAL;

	/* Try the get crop operation first and fallback to get format if not
	 * implemented.
	 */
	ret = v4l2_subdev_call(subdev, video, g_crop, crop);
	if (ret != -ENOIOCTLCMD)
		return ret;

	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, pad, &format,
			       V4L2_SUBDEV_FORMAT_ACTIVE);
	if (ret < 0)
		return ret == -ENOIOCTLCMD ? -EINVAL : ret;

	crop->c.left = 0;
	crop->c.top = 0;
	crop->c.width = format.width;
	crop->c.height = format.height;

	return 0;
}
Esempio n. 3
0
static int
isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
{
	struct isp_video *video = video_drvdata(file);
	struct v4l2_mbus_framefmt fmt;
	struct v4l2_subdev *subdev;
	u32 pad;
	int ret;

	if (format->type != video->type)
		return -EINVAL;

	subdev = isp_video_remote_subdev(video, &pad);
	if (subdev == NULL)
		return -EINVAL;

	isp_video_pix_to_mbus(&format->fmt.pix, &fmt);

	ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, pad, &fmt,
			       V4L2_SUBDEV_FORMAT_ACTIVE);
	if (ret)
		return ret == -ENOIOCTLCMD ? -EINVAL : ret;

	isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
	return 0;
}
Esempio n. 4
0
/*
 * Validate a pipeline by checking both ends of all links for format
 * discrepancies.
 *
 * Return 0 if all formats match, or -EPIPE if at least one link is found with
 * different formats on its two ends.
 */
static int
isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
	struct v4l2_mbus_framefmt fmt_source;
	struct v4l2_mbus_framefmt fmt_sink;
	struct media_entity_pad *pad;
	struct v4l2_subdev *subdev;
	int ret;

	subdev = isp_video_remote_subdev(pipe->output, NULL);
	if (subdev == NULL)
		return -EPIPE;

	while (1) {
		/* Retrieve the sink format */
		pad = &subdev->entity.pads[0];
		if (pad->type != MEDIA_PAD_TYPE_INPUT)
			break;

		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, pad->index,
				       &fmt_sink, V4L2_SUBDEV_FORMAT_ACTIVE);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		/* Retrieve the source format */
		pad = media_entity_remote_pad(pad);
		if (pad == NULL ||
		    pad->entity->type != MEDIA_ENTITY_TYPE_SUBDEV)
			break;

		subdev = media_entity_to_v4l2_subdev(pad->entity);

		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, pad->index,
				       &fmt_source, V4L2_SUBDEV_FORMAT_ACTIVE);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		/* Check if the two ends match */
		if (fmt_source.code != fmt_sink.code ||
		    fmt_source.width != fmt_sink.width ||
		    fmt_source.height != fmt_sink.height) {
			printk(KERN_ERR "%s format mismatch\n", __func__);
			printk(KERN_ERR "  code   source=%d sink=%d\n", fmt_source.code, fmt_sink.code);
			printk(KERN_ERR "  width  source=%d sink=%d\n", fmt_source.width, fmt_sink.width);
			printk(KERN_ERR "  height source=%d sink=%d\n", fmt_source.height, fmt_sink.height);

			return -EPIPE;
		}
	}

	return 0;
}
Esempio n. 5
0
static int
isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
	struct isp_video *video = video_drvdata(file);
	struct v4l2_subdev *subdev;
	int ret;

	subdev = isp_video_remote_subdev(video, NULL);
	if (subdev == NULL)
		return -EINVAL;

	mutex_lock(&video->mutex);
	ret = v4l2_subdev_call(subdev, video, s_crop, crop);
	mutex_unlock(&video->mutex);

	return ret == -ENOIOCTLCMD ? -EINVAL : ret;
}
/*
 * Validate a pipeline by checking both ends of all links for format
 * discrepancies.
 *
 * Compute the minimum time per frame value as the maximum of time per frame
 * limits reported by every block in the pipeline.
 *
 * Return 0 if all formats match, or -EPIPE if at least one link is found with
 * different formats on its two ends or if the pipeline doesn't start with a
 * video source (either a subdev with no input pad, or a non-subdev entity).
 */
static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
	struct isp_device *isp = pipe->output->isp;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;

	subdev = isp_video_remote_subdev(pipe->output, NULL);
	if (subdev == NULL)
		return -EPIPE;

	while (1) {
		/* Retrieve the sink format */
		pad = &subdev->entity.pads[0];
		if (!(pad->flags & MEDIA_PAD_FL_SINK))
			break;

		/* Update the maximum frame rate */
		if (subdev == &isp->isp_res.subdev)
			omap3isp_resizer_max_rate(&isp->isp_res,
						  &pipe->max_rate);

		/* Retrieve the source format. Return an error if no source
		 * entity can be found, and stop checking the pipeline if the
		 * source entity isn't a subdev.
		 */
		pad = media_entity_remote_source(pad);
		if (pad == NULL)
			return -EPIPE;

		if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
			break;

		subdev = media_entity_to_v4l2_subdev(pad->entity);
	}

	return 0;
}
/*
 * Validate a pipeline by checking both ends of all links for format
 * discrepancies.
 *
 * Compute the minimum time per frame value as the maximum of time per frame
 * limits reported by every block in the pipeline.
 *
 * Return 0 if all formats match, or -EPIPE if at least one link is found with
 * different formats on its two ends or if the pipeline doesn't start with a
 * video source (either a subdev with no input pad, or a non-subdev entity).
 */
static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
    struct isp_device *isp = pipe->output->isp;
    struct v4l2_subdev_format fmt_source;
    struct v4l2_subdev_format fmt_sink;
    struct media_pad *pad;
    struct v4l2_subdev *subdev;
    int ret;

    pipe->max_rate = pipe->l3_ick;

    subdev = isp_video_remote_subdev(pipe->output, NULL);
    if (subdev == NULL)
        return -EPIPE;

    while (1) {
        unsigned int shifter_link;
        /* Retrieve the sink format */
        pad = &subdev->entity.pads[0];
        if (!(pad->flags & MEDIA_PAD_FL_SINK))
            break;

        fmt_sink.pad = pad->index;
        fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
        if (ret < 0 && ret != -ENOIOCTLCMD)
            return -EPIPE;

        /* Update the maximum frame rate */
        if (subdev == &isp->isp_res.subdev)
            omap3isp_resizer_max_rate(&isp->isp_res,
                                      &pipe->max_rate);

        /* Check ccdc maximum data rate when data comes from sensor
         * TODO: Include ccdc rate in pipe->max_rate and compare the
         *       total pipe rate with the input data rate from sensor.
         */
        if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
            unsigned int rate = UINT_MAX;

            omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
            if (isp->isp_ccdc.vpcfg.pixelclk > rate)
                return -ENOSPC;
        }

        /* If sink pad is on CCDC, the link has the lane shifter
         * in the middle of it. */
        shifter_link = subdev == &isp->isp_ccdc.subdev;

        /* Retrieve the source format. Return an error if no source
         * entity can be found, and stop checking the pipeline if the
         * source entity isn't a subdev.
         */
        pad = media_entity_remote_source(pad);
        if (pad == NULL)
            return -EPIPE;

        if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
            break;

        subdev = media_entity_to_v4l2_subdev(pad->entity);

        fmt_source.pad = pad->index;
        fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
        if (ret < 0 && ret != -ENOIOCTLCMD)
            return -EPIPE;

        /* Check if the two ends match */
        if (fmt_source.format.width != fmt_sink.format.width ||
                fmt_source.format.height != fmt_sink.format.height)
            return -EPIPE;

        if (shifter_link) {
            unsigned int parallel_shift = 0;
            if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
                struct isp_parallel_platform_data *pdata =
                    &((struct isp_v4l2_subdevs_group *)
                      subdev->host_priv)->bus.parallel;
                parallel_shift = pdata->data_lane_shift * 2;
            }
            if (!isp_video_is_shiftable(fmt_source.format.code,
                                        fmt_sink.format.code,
                                        parallel_shift))
                return -EPIPE;
        } else if (fmt_source.format.code != fmt_sink.format.code)
            return -EPIPE;
    }

    return 0;
}
Esempio n. 8
0
/*
 * Validate a pipeline by checking both ends of all links for format
 * discrepancies.
 *
 * Compute the minimum time per frame value as the maximum of time per frame
 * limits reported by every block in the pipeline.
 *
 * Return 0 if all formats match, or -EPIPE if at least one link is found with
 * different formats on its two ends.
 */
static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
	struct isp_device *isp = pipe->output->isp;
	struct v4l2_subdev_format fmt_source;
	struct v4l2_subdev_format fmt_sink;
	struct media_pad *pad;
	struct v4l2_subdev *subdev;
	int ret;

	pipe->max_rate = pipe->l3_ick;

	subdev = isp_video_remote_subdev(pipe->output, NULL);
	if (subdev == NULL)
		return -EPIPE;

	while (1) {
		/* Retrieve the sink format */
		pad = &subdev->entity.pads[0];
		if (!(pad->flags & MEDIA_PAD_FLAG_INPUT))
			break;

		fmt_sink.pad = pad->index;
		fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		/* Update the maximum frame rate */
		if (subdev == &isp->isp_res.subdev)
			ispresizer_max_rate(&isp->isp_res, &pipe->max_rate);

		/* Check ccdc maximum data rate when data comes from sensor
		 * TODO: Include ccdc rate in pipe->max_rate and compare the
		 *       total pipe rate with the input data rate from sensor.
		 */
		if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
			unsigned int rate = UINT_MAX;

			ispccdc_max_rate(&isp->isp_ccdc, &rate);
			if (isp->isp_ccdc.vpcfg.pixelclk > rate)
				return -ENOSPC;
		}

		/* Retrieve the source format */
		pad = media_entity_remote_source(pad);
		if (pad == NULL ||
		    media_entity_type(pad->entity) !=
				MEDIA_ENTITY_TYPE_V4L2_SUBDEV)
			break;

		subdev = media_entity_to_v4l2_subdev(pad->entity);

		fmt_source.pad = pad->index;
		fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
		ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
		if (ret < 0 && ret != -ENOIOCTLCMD)
			return -EPIPE;

		/* Check if the two ends match */
		if (fmt_source.format.code != fmt_sink.format.code ||
		    fmt_source.format.width != fmt_sink.format.width ||
		    fmt_source.format.height != fmt_sink.format.height)
			return -EPIPE;
	}

	return 0;
}