示例#1
0
文件: pwc-v4l.c 项目: 03199618/linux
static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
	struct pwc_device *pdev = video_drvdata(file);
	int ret, pixelformat, compression = 0;

	ret = pwc_vidioc_try_fmt(pdev, f);
	if (ret < 0)
		return ret;

	if (vb2_is_busy(&pdev->vb_queue))
		return -EBUSY;

	pixelformat = f->fmt.pix.pixelformat;

	PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
			"format=%c%c%c%c\n",
			f->fmt.pix.width, f->fmt.pix.height, pdev->vframes,
			(pixelformat)&255,
			(pixelformat>>8)&255,
			(pixelformat>>16)&255,
			(pixelformat>>24)&255);

	ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height,
				 pixelformat, 30, &compression, 0);

	PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);

	pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
	return ret;
}
示例#2
0
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
	struct stk1160 *dev = video_drvdata(file);
	struct vb2_queue *q = &dev->vb_vidq;

	if (vb2_is_busy(q))
		return -EBUSY;

	/* Check device presence */
	if (!dev->udev)
		return -ENODEV;

	/* We need to set this now, before we call stk1160_set_std */
	dev->norm = norm;

	/* This is taken from saa7115 video decoder */
	if (dev->norm & V4L2_STD_525_60) {
		dev->width = 720;
		dev->height = 480;
	} else if (dev->norm & V4L2_STD_625_50) {
		dev->width = 720;
		dev->height = 576;
	} else {
		stk1160_err("invalid standard\n");
		return -EINVAL;
	}

	stk1160_set_std(dev);

	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
			dev->norm);

	return 0;
}
示例#3
0
文件: fimc-lite.c 项目: 19Dan01/linux
static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
				    struct v4l2_subdev_pad_config *cfg,
				    struct v4l2_subdev_format *fmt)
{
	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
	struct v4l2_mbus_framefmt *mf = &fmt->format;
	struct flite_frame *sink = &fimc->inp_frame;
	struct flite_frame *source = &fimc->out_frame;
	const struct fimc_fmt *ffmt;

	v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n",
		 fmt->pad, mf->code, mf->width, mf->height);

	mutex_lock(&fimc->lock);

	if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP &&
	    sd->entity.stream_count > 0) ||
	    (atomic_read(&fimc->out_path) == FIMC_IO_DMA &&
	    vb2_is_busy(&fimc->vb_queue))) {
		mutex_unlock(&fimc->lock);
		return -EBUSY;
	}

	ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt);

	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
		struct v4l2_mbus_framefmt *src_fmt;

		mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad);
		*mf = fmt->format;

		if (fmt->pad == FLITE_SD_PAD_SINK) {
			unsigned int pad = FLITE_SD_PAD_SOURCE_DMA;
			src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad);
			*src_fmt = *mf;
		}

		mutex_unlock(&fimc->lock);
		return 0;
	}

	if (fmt->pad == FLITE_SD_PAD_SINK) {
		sink->f_width = mf->width;
		sink->f_height = mf->height;
		sink->fmt = ffmt;
		/* Set sink crop rectangle */
		sink->rect.width = mf->width;
		sink->rect.height = mf->height;
		sink->rect.left = 0;
		sink->rect.top = 0;
		/* Reset source format and crop rectangle */
		source->rect = sink->rect;
		source->f_width = mf->width;
		source->f_height = mf->height;
	}

	mutex_unlock(&fimc->lock);
	return 0;
}
static int jpeg_enc_vidioc_s_fmt_out(struct file *file, void *priv,
			struct v4l2_format *f)
{
	struct jpeg_ctx *ctx = priv;
	struct vb2_queue *vq;
	struct v4l2_pix_format_mplane *pix;
	struct jpeg_fmt *fmt;
	struct jpeg_frame *frame;
	int ret;
	int i;

	ret = jpeg_enc_vidioc_try_fmt(file, priv, f);
	if (ret)
		return ret;

	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
	if (!vq)
		return -EINVAL;

	if (vb2_is_busy(vq)) {
		v4l2_err(&ctx->jpeg_dev->v4l2_dev, "queue (%d) busy\n", f->type);
		return -EBUSY;
	}

	/* TODO: width & height has to be multiple of two */
	pix = &f->fmt.pix_mp;
	fmt = find_format(f);

	frame = ctx_get_frame(ctx, f->type);
	if (IS_ERR(frame))
		return PTR_ERR(frame);

	frame->jpeg_fmt = fmt;
	if (!frame->jpeg_fmt) {
		v4l2_err(&ctx->jpeg_dev->v4l2_dev,
				"not supported format values\n");
		return -EINVAL;
	}

	for (i = 0; i < fmt->memplanes; i++) {
		ctx->payload[i] =
			pix->plane_fmt[i].bytesperline * pix->height;
		ctx->param.enc_param.in_depth[i] = fmt->depth[i];
	}

	frame->width = pix->width;
	frame->height = pix->height;
	frame->pixelformat = pix->pixelformat;

	ctx->param.enc_param.in_width = pix->width;
	ctx->param.enc_param.in_height = pix->height;
	ctx->param.enc_param.in_plane = fmt->memplanes;
	ctx->param.enc_param.in_fmt = fmt->color;

	return 0;
}
示例#5
0
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
		__func__,
		(unsigned int)norm,
		v4l2_norm_to_name(norm));

	if (dev->tvnorm != norm) {
		if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
		    vb2_is_busy(&dev->vb2_mpegq))
			return -EBUSY;
	}

	dev->tvnorm = norm;

	call_all(dev, video, s_std, norm);

	return 0;
}
示例#6
0
/*
 * Check if buffers have been allocated.
 */
int uvc_queue_allocated(struct uvc_video_queue *queue)
{
	int allocated;

	mutex_lock(&queue->mutex);
	allocated = vb2_is_busy(&queue->queue);
	mutex_unlock(&queue->mutex);

	return allocated;
}
示例#7
0
static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
				    struct v4l2_subdev_fh *fh,
				    struct v4l2_subdev_format *fmt)
{
	struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
	struct v4l2_mbus_framefmt *mf = &fmt->format;
	struct flite_frame *sink = &fimc->inp_frame;
	struct flite_frame *source = &fimc->out_frame;
	const struct fimc_fmt *ffmt;

	v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d",
		 fmt->pad, mf->code, mf->width, mf->height);

	mf->colorspace = V4L2_COLORSPACE_JPEG;
	mutex_lock(&fimc->lock);

	if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) ||
	    (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) {
		mutex_unlock(&fimc->lock);
		return -EBUSY;
	}

	ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
				    &mf->code, NULL, fmt->pad);

	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
		*mf = fmt->format;
		mutex_unlock(&fimc->lock);
		return 0;
	}

	if (fmt->pad == FLITE_SD_PAD_SINK) {
		sink->f_width = mf->width;
		sink->f_height = mf->height;
		fimc->fmt = ffmt;
		/* Set sink crop rectangle */
		sink->rect.width = mf->width;
		sink->rect.height = mf->height;
		sink->rect.left = 0;
		sink->rect.top = 0;
		/* Reset source format and crop rectangle */
		source->rect = sink->rect;
		source->f_width = mf->width;
		source->f_height = mf->height;
	} else {
		/* Allow changing format only on sink pad */
		mf->code = fimc->fmt->mbus_code;
		mf->width = sink->rect.width;
		mf->height = sink->rect.height;
	}

	mutex_unlock(&fimc->lock);
	return 0;
}
示例#8
0
int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz)
{
	int i;

	/* Make sure all video nodes are idle */
	if (vb2_is_busy(&solo_dev->vidq))
		return -EBUSY;
	for (i = 0; i < solo_dev->nr_chans; i++)
		if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq))
			return -EBUSY;
	solo_dev->video_type = is_50hz ? SOLO_VO_FMT_TYPE_PAL :
					 SOLO_VO_FMT_TYPE_NTSC;
	/* Reconfigure for the new standard */
	solo_disp_init(solo_dev);
	solo_enc_init(solo_dev);
	solo_tw28_init(solo_dev);
	for (i = 0; i < solo_dev->nr_chans; i++)
		solo_update_mode(solo_dev->v4l2_enc[i]);
	return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch);
}
示例#9
0
static int solo_set_fmt_cap(struct file *file, void *priv,
			    struct v4l2_format *f)
{
	struct solo_dev *solo_dev = video_drvdata(file);

	if (vb2_is_busy(&solo_dev->vidq))
		return -EBUSY;

	/* For right now, if it doesn't match our running config,
	 * then fail */
	return solo_try_fmt_cap(file, priv, f);
}
示例#10
0
static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
				 struct v4l2_format *f)
{
	struct fimc_ctx *ctx = fh_to_ctx(fh);
	struct fimc_dev *fimc = ctx->fimc_dev;
	struct vb2_queue *vq;
	struct fimc_frame *frame;
	struct v4l2_pix_format_mplane *pix;
	int i, ret = 0;

	ret = fimc_try_fmt_mplane(ctx, f);
	if (ret)
		return ret;

	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);

	if (vb2_is_busy(vq)) {
		v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
		return -EBUSY;
	}

	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
		frame = &ctx->s_frame;
	else
		frame = &ctx->d_frame;

	pix = &f->fmt.pix_mp;
	frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
				      get_m2m_fmt_flags(f->type), 0);
	if (!frame->fmt)
		return -EINVAL;

	/* Update RGB Alpha control state and value range */
	fimc_alpha_ctrl_update(ctx);

	for (i = 0; i < frame->fmt->colplanes; i++) {
		frame->payload[i] =
			(pix->width * pix->height * frame->fmt->depth[i]) / 8;
	}

	fimc_fill_frame(frame, f);

	ctx->scaler.enabled = 1;

	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
		fimc_ctx_state_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
	else
		fimc_ctx_state_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);

	dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);

	return 0;
}
示例#11
0
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
	struct v4l2_subdev_format format = {
		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
		.format.code = MEDIA_BUS_FMT_FIXED,
	};

	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
		__func__,
		(unsigned int)norm,
		v4l2_norm_to_name(norm));

	if (dev->tvnorm == norm)
		return 0;

	if (dev->tvnorm != norm) {
		if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
		    vb2_is_busy(&dev->vb2_mpegq))
			return -EBUSY;
	}

	dev->tvnorm = norm;
	dev->width = 720;
	dev->height = norm_maxh(norm);
	dev->field = V4L2_FIELD_INTERLACED;

	call_all(dev, video, s_std, norm);

	format.format.width = dev->width;
	format.format.height = dev->height;
	format.format.field = dev->field;
	call_all(dev, pad, set_fmt, NULL, &format);

	return 0;
}

static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
				    struct pci_dev *pci,
				    struct video_device *template,
示例#12
0
static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,
                                 struct v4l2_format *f)
{
    struct fimc_ctx *ctx = priv;
    struct fimc_dev *fimc = ctx->fimc_dev;
    struct fimc_frame *frame;
    struct v4l2_pix_format_mplane *pix;
    int ret;
    int i;

    if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
        return -EINVAL;

    ret = fimc_vidioc_try_fmt_mplane(file, priv, f);
    if (ret)
        return ret;

    if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc))
        return -EBUSY;

    frame = &ctx->d_frame;

    pix = &f->fmt.pix_mp;
    frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
    if (!frame->fmt) {
        err("fimc target format not found\n");
        return -EINVAL;
    }

    for (i = 0; i < frame->fmt->colplanes; i++) {
        frame->payload[i] =
            (pix->width * pix->height * frame->fmt->depth[i]) >> 3;
    }

    /* Output DMA frame pixel size and offsets. */
    frame->f_width = pix->plane_fmt[0].bytesperline * 8
                     / frame->fmt->depth[0];
    frame->f_height = pix->height;
    frame->width	= pix->width;
    frame->height	= pix->height;
    frame->o_width	= pix->width;
    frame->o_height = pix->height;
    frame->offs_h	= 0;
    frame->offs_v	= 0;

    ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);

    ret = sync_capture_fmt(ctx);
    return ret;
}
示例#13
0
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
					struct v4l2_format *f)
{
	struct stk1160 *dev = video_drvdata(file);
	struct vb2_queue *q = &dev->vb_vidq;

	if (vb2_is_busy(q))
		return -EBUSY;

	vidioc_try_fmt_vid_cap(file, priv, f);

	/* We don't support any format changes */

	return 0;
}
示例#14
0
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
	struct stk1160 *dev = video_drvdata(file);

	if (vb2_is_busy(&dev->vb_vidq))
		return -EBUSY;

	if (i > STK1160_MAX_INPUT)
		return -EINVAL;

	dev->ctl_input = i;

	stk1160_select_input(dev);

	return 0;
}
示例#15
0
static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
	struct camss_video *video = video_drvdata(file);
	int ret;

	if (vb2_is_busy(&video->vb2_q))
		return -EBUSY;

	ret = __video_try_fmt(video, f);
	if (ret < 0)
		return ret;

	video->active_fmt = *f;

	return 0;
}
示例#16
0
static int jpeg_dec_vidioc_s_fmt_out(struct file *file, void *priv,
			struct v4l2_format *f)
{
	struct jpeg_ctx *ctx = priv;
	struct vb2_queue *vq;
	struct v4l2_pix_format_mplane *pix;
	struct jpeg_fmt *fmt;
	int ret;
	int i;

	ret = jpeg_dec_vidioc_try_fmt(file, priv, f);
	if (ret)
		return ret;

	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
	if (!vq)
		return -EINVAL;

	if (vb2_is_busy(vq)) {
		v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
		return -EBUSY;
	}

	/* TODO: width & height has to be multiple of two */
	pix = &f->fmt.pix_mp;
	fmt = find_format(f);

	for (i = 0; i < fmt->memplanes; i++)
		ctx->payload[i] =
			pix->plane_fmt[i].bytesperline * pix->height;

	ctx->param.dec_param.in_width = pix->width;
	ctx->param.dec_param.in_height = pix->height;
	ctx->param.dec_param.in_plane = fmt->memplanes;
	ctx->param.dec_param.in_depth = fmt->depth[0];
	ctx->param.dec_param.in_fmt = fmt->color;
	if((pix->plane_fmt[0].sizeimage % 32) == 0)
		ctx->param.dec_param.size = (pix->plane_fmt[0].sizeimage / 32);
	else
		ctx->param.dec_param.size = (pix->plane_fmt[0].sizeimage / 32) + 1;
	ctx->param.dec_param.mem_size = pix->plane_fmt[0].sizeimage;

	return 0;
}
示例#17
0
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
	struct smi2021 *smi2021 = video_drvdata(file);

	if (vb2_is_busy(&smi2021->vb2q))
		return -EBUSY;

	smi2021->cur_norm = norm;
	if (norm & V4L2_STD_525_60)
		smi2021->cur_height = SMI2021_NTSC_LINES;
	else if (norm & V4L2_STD_625_50)
		smi2021->cur_height = SMI2021_PAL_LINES;
	else
		return -EINVAL;

	v4l2_device_call_all(&smi2021->v4l2_dev, 0, core, s_std,
			     smi2021->cur_norm);
	return 0;
}
示例#18
0
文件: dt3155.c 项目: Lyude/linux
static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm)
{
	struct dt3155_priv *pd = video_drvdata(filp);

	if (pd->std == norm)
		return 0;
	if (vb2_is_busy(&pd->vidq))
		return -EBUSY;
	pd->std = norm;
	if (pd->std & V4L2_STD_525_60) {
		pd->csr2 = VT_60HZ;
		pd->width = 640;
		pd->height = 480;
	} else {
		pd->csr2 = VT_50HZ;
		pd->width = 768;
		pd->height = 576;
	}
	return 0;
}
示例#19
0
static int jpeg_enc_vidioc_s_fmt_cap(struct file *file, void *priv,
				struct v4l2_format *f)
{
	struct jpeg_ctx *ctx = priv;
	struct vb2_queue *vq;
	struct v4l2_pix_format_mplane *pix;
	struct jpeg_fmt *fmt;
	int ret;
	int i;

	ret = jpeg_enc_vidioc_try_fmt(file, priv, f);
	if (ret)
		return ret;

	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
	if (!vq)
		return -EINVAL;

	if (vb2_is_busy(vq)) {
		v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
		return -EBUSY;
	}

	pix = &f->fmt.pix_mp;
	fmt = find_format(f);
	if (!fmt)
		return -EINVAL;

	for (i = 0; i < fmt->memplanes; i++)
		ctx->payload[i] =
			pix->plane_fmt[i].bytesperline * pix->height;

	ctx->param.enc_param.out_width = pix->height;
	ctx->param.enc_param.out_height = pix->width;
	ctx->param.enc_param.out_plane = fmt->memplanes;
	ctx->param.enc_param.out_depth = fmt->depth[0];
	ctx->param.enc_param.out_fmt = fmt->color;

	return 0;
}
示例#20
0
文件: g2d.c 项目: 7799/linux
static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
	struct g2d_ctx *ctx = prv;
	struct g2d_dev *dev = ctx->dev;
	struct vb2_queue *vq;
	struct g2d_frame *frm;
	struct g2d_fmt *fmt;
	int ret = 0;

	/* Adjust all values accordingly to the hardware capabilities
	 * and chosen format. */
	ret = vidioc_try_fmt(file, prv, f);
	if (ret)
		return ret;
	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
	if (vb2_is_busy(vq)) {
		v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
		return -EBUSY;
	}
	frm = get_frame(ctx, f->type);
	if (IS_ERR(frm))
		return PTR_ERR(frm);
	fmt = find_fmt(f);
	if (!fmt)
		return -EINVAL;
	frm->width	= f->fmt.pix.width;
	frm->height	= f->fmt.pix.height;
	frm->size	= f->fmt.pix.sizeimage;
	/* Reset crop settings */
	frm->o_width	= 0;
	frm->o_height	= 0;
	frm->c_width	= frm->width;
	frm->c_height	= frm->height;
	frm->right	= frm->width;
	frm->bottom	= frm->height;
	frm->fmt	= fmt;
	frm->stride	= f->fmt.pix.bytesperline;
	return 0;
}
示例#21
0
/*
 * This function should not be used for anything else but the videobuf2-dvb
 * support. If you think you have another good use-case for this, then please
 * contact the linux-media mailinglist first.
 */
int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
		     const char *thread_name)
{
	struct vb2_threadio_data *threadio;
	int ret = 0;

	if (q->threadio)
		return -EBUSY;
	if (vb2_is_busy(q))
		return -EBUSY;
	if (WARN_ON(q->fileio))
		return -EBUSY;

	threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
	if (threadio == NULL)
		return -ENOMEM;
	threadio->fnc = fnc;
	threadio->priv = priv;

	ret = __vb2_init_fileio(q, !q->is_output);
	dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
	if (ret)
		goto nomem;
	q->threadio = threadio;
	threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
	if (IS_ERR(threadio->thread)) {
		ret = PTR_ERR(threadio->thread);
		threadio->thread = NULL;
		goto nothread;
	}
	return 0;

nothread:
	__vb2_cleanup_fileio(q);
nomem:
	kfree(threadio);
	return ret;
}
示例#22
0
static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
                                 struct v4l2_format *f)
{
    struct fimc_ctx *ctx = fh_to_ctx(fh);
    struct fimc_dev *fimc = ctx->fimc_dev;
    struct fimc_fmt *fmt;
    struct vb2_queue *vq;
    struct fimc_frame *frame;
    int ret;

    ret = fimc_try_fmt_mplane(ctx, f);
    if (ret)
        return ret;

    vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);

    if (vb2_is_busy(vq)) {
        v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
        return -EBUSY;
    }

    if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
        frame = &ctx->s_frame;
    else
        frame = &ctx->d_frame;

    fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL,
                           get_m2m_fmt_flags(f->type), 0);
    if (!fmt)
        return -EINVAL;

    __set_frame_format(frame, fmt, &f->fmt.pix_mp);

    /* Update RGB Alpha control state and value range */
    fimc_alpha_ctrl_update(ctx);

    return 0;
}
示例#23
0
static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
				  struct v4l2_format *f)
{
	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
	struct fimc_lite *fimc = video_drvdata(file);
	struct flite_frame *frame = &fimc->out_frame;
	const struct fimc_fmt *fmt = NULL;
	int ret;

	if (vb2_is_busy(&fimc->vb_queue))
		return -EBUSY;

	ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt);
	if (ret < 0)
		return ret;

	fimc->fmt = fmt;
	fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8,
			       pixm->plane_fmt[0].sizeimage);
	frame->f_width = pixm->width;
	frame->f_height = pixm->height;

	return 0;
}
示例#24
0
static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
			      struct v4l2_format *f)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct rvin_source_fmt source;
	int ret;

	if (vb2_is_busy(&vin->queue))
		return -EBUSY;

	ret = __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
				&source);
	if (ret)
		return ret;

	vin->source.width = source.width;
	vin->source.height = source.height;

	vin->format = f->fmt.pix;

	rvin_reset_crop_compose(vin);

	return 0;
}
示例#25
0
static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
			     struct v4l2_format *f)
{
	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
	struct vb2_queue *vq;
	struct mtk_q_data *q_data;
	int ret, i;
	struct mtk_video_fmt *fmt;
	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;

	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
	if (!vq) {
		mtk_v4l2_err("fail to get vq");
		return -EINVAL;
	}

	if (vb2_is_busy(vq)) {
		mtk_v4l2_err("queue busy");
		return -EBUSY;
	}

	q_data = mtk_venc_get_q_data(ctx, f->type);
	if (!q_data) {
		mtk_v4l2_err("fail to get q data");
		return -EINVAL;
	}

	fmt = mtk_venc_find_format(f);
	if (!fmt) {
		f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
		fmt = mtk_venc_find_format(f);
	}

	pix_fmt_mp->height = clamp(pix_fmt_mp->height,
				MTK_VENC_MIN_H,
				MTK_VENC_MAX_H);
	pix_fmt_mp->width = clamp(pix_fmt_mp->width,
				MTK_VENC_MIN_W,
				MTK_VENC_MAX_W);

	q_data->visible_width = f->fmt.pix_mp.width;
	q_data->visible_height = f->fmt.pix_mp.height;
	q_data->fmt = fmt;
	ret = vidioc_try_fmt(f, q_data->fmt);
	if (ret)
		return ret;

	q_data->coded_width = f->fmt.pix_mp.width;
	q_data->coded_height = f->fmt.pix_mp.height;

	q_data->field = f->fmt.pix_mp.field;
	ctx->colorspace = f->fmt.pix_mp.colorspace;
	ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
	ctx->quantization = f->fmt.pix_mp.quantization;
	ctx->xfer_func = f->fmt.pix_mp.xfer_func;

	for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
		struct v4l2_plane_pix_format *plane_fmt;

		plane_fmt = &f->fmt.pix_mp.plane_fmt[i];
		q_data->bytesperline[i] = plane_fmt->bytesperline;
		q_data->sizeimage[i] = plane_fmt->sizeimage;
	}

	return 0;
}
示例#26
0
static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
			     struct v4l2_format *f)
{
	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
	struct vb2_queue *vq;
	struct mtk_q_data *q_data;
	int i, ret;
	struct mtk_video_fmt *fmt;

	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
	if (!vq) {
		mtk_v4l2_err("fail to get vq");
		return -EINVAL;
	}

	if (vb2_is_busy(vq)) {
		mtk_v4l2_err("queue busy");
		return -EBUSY;
	}

	q_data = mtk_venc_get_q_data(ctx, f->type);
	if (!q_data) {
		mtk_v4l2_err("fail to get q data");
		return -EINVAL;
	}

	fmt = mtk_venc_find_format(f);
	if (!fmt) {
		f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
		fmt = mtk_venc_find_format(f);
	}

	q_data->fmt = fmt;
	ret = vidioc_try_fmt(f, q_data->fmt);
	if (ret)
		return ret;

	q_data->coded_width = f->fmt.pix_mp.width;
	q_data->coded_height = f->fmt.pix_mp.height;
	q_data->field = f->fmt.pix_mp.field;

	for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
		struct v4l2_plane_pix_format	*plane_fmt;

		plane_fmt = &f->fmt.pix_mp.plane_fmt[i];
		q_data->bytesperline[i]	= plane_fmt->bytesperline;
		q_data->sizeimage[i] = plane_fmt->sizeimage;
	}

	if (ctx->state == MTK_STATE_FREE) {
		ret = venc_if_init(ctx, q_data->fmt->fourcc);
		if (ret) {
			mtk_v4l2_err("venc_if_init failed=%d, codec type=%x",
					ret, q_data->fmt->fourcc);
			return -EBUSY;
		}
		ctx->state = MTK_STATE_INIT;
	}

	return 0;
}
示例#27
0
static int vidioc_vdec_s_fmt(struct file *file, void *priv,
			     struct v4l2_format *f)
{
	struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
	struct v4l2_pix_format_mplane *pix_mp;
	struct mtk_q_data *q_data;
	int ret = 0;
	struct mtk_video_fmt *fmt;

	mtk_v4l2_debug(3, "[%d]", ctx->id);

	q_data = mtk_vdec_get_q_data(ctx, f->type);
	if (!q_data)
		return -EINVAL;

	pix_mp = &f->fmt.pix_mp;
	if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
	    vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
		mtk_v4l2_err("out_q_ctx buffers already requested");
		ret = -EBUSY;
	}

	if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
	    vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) {
		mtk_v4l2_err("cap_q_ctx buffers already requested");
		ret = -EBUSY;
	}

	fmt = mtk_vdec_find_format(f);
	if (fmt == NULL) {
		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
			f->fmt.pix.pixelformat =
				mtk_video_formats[OUT_FMT_IDX].fourcc;
			fmt = mtk_vdec_find_format(f);
		} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
			f->fmt.pix.pixelformat =
				mtk_video_formats[CAP_FMT_IDX].fourcc;
			fmt = mtk_vdec_find_format(f);
		}
	}

	q_data->fmt = fmt;
	vidioc_try_fmt(f, q_data->fmt);
	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
		q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
		q_data->coded_width = pix_mp->width;
		q_data->coded_height = pix_mp->height;

		ctx->colorspace = f->fmt.pix_mp.colorspace;
		ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
		ctx->quantization = f->fmt.pix_mp.quantization;
		ctx->xfer_func = f->fmt.pix_mp.xfer_func;

		if (ctx->state == MTK_STATE_FREE) {
			ret = vdec_if_init(ctx, q_data->fmt->fourcc);
			if (ret) {
				mtk_v4l2_err("[%d]: vdec_if_init() fail ret=%d",
					ctx->id, ret);
				return -EINVAL;
			}
			ctx->state = MTK_STATE_INIT;
		}
	}

	return 0;
}
示例#28
0
static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
{
	struct fimc_ctx *ctx = fimc->vid_cap.ctx;
	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
	struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
	struct fimc_frame *ff = &ctx->d_frame;
	struct fimc_fmt *s_fmt = NULL;
	int ret, i;

	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
		return -EINVAL;
	if (vb2_is_busy(&fimc->vid_cap.vbq))
		return -EBUSY;

	/* Pre-configure format at camera interface input, for JPEG only */
	if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
		fimc_capture_try_format(ctx, &pix->width, &pix->height,
					NULL, &pix->pixelformat,
					FIMC_SD_PAD_SINK);
		ctx->s_frame.f_width  = pix->width;
		ctx->s_frame.f_height = pix->height;
	}
	/* Try the format at the scaler and the DMA output */
	ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
					  NULL, &pix->pixelformat,
					  FIMC_SD_PAD_SOURCE);
	if (!ff->fmt)
		return -EINVAL;

	/* Update RGB Alpha control state and value range */
	fimc_alpha_ctrl_update(ctx);

	/* Try to match format at the host and the sensor */
	if (!fimc->vid_cap.user_subdev_api) {
		mf->code   = ff->fmt->mbus_code;
		mf->width  = pix->width;
		mf->height = pix->height;

		fimc_md_graph_lock(fimc);
		ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true);
		fimc_md_graph_unlock(fimc);
		if (ret)
			return ret;
		pix->width  = mf->width;
		pix->height = mf->height;
	}
	fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
	for (i = 0; i < ff->fmt->colplanes; i++)
		ff->payload[i] =
			(pix->width * pix->height * ff->fmt->depth[i]) / 8;

	set_frame_bounds(ff, pix->width, pix->height);
	/* Reset the composition rectangle if not yet configured */
	if (!(ctx->state & FIMC_DST_CROP))
		set_frame_crop(ff, 0, 0, pix->width, pix->height);

	fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color));

	/* Reset cropping and set format at the camera interface input */
	if (!fimc->vid_cap.user_subdev_api) {
		ctx->s_frame.fmt = s_fmt;
		set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
		set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
	}

	return ret;
}
示例#29
0
static int rvin_reset_format(struct rvin_dev *vin)
{
	struct v4l2_subdev_format fmt = {
		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
		.pad = vin->parallel->source_pad,
	};
	int ret;

	ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
	if (ret)
		return ret;

	v4l2_fill_pix_format(&vin->format, &fmt.format);

	rvin_format_align(vin, &vin->format);

	vin->source.top = 0;
	vin->source.left = 0;
	vin->source.width = vin->format.width;
	vin->source.height = vin->format.height;

	vin->crop = vin->source;
	vin->compose = vin->source;

	return 0;
}

static int rvin_try_format(struct rvin_dev *vin, u32 which,
			   struct v4l2_pix_format *pix,
			   struct v4l2_rect *crop, struct v4l2_rect *compose)
{
	struct v4l2_subdev *sd = vin_to_source(vin);
	struct v4l2_subdev_pad_config *pad_cfg;
	struct v4l2_subdev_format format = {
		.which = which,
		.pad = vin->parallel->source_pad,
	};
	enum v4l2_field field;
	u32 width, height;
	int ret;

	pad_cfg = v4l2_subdev_alloc_pad_config(sd);
	if (pad_cfg == NULL)
		return -ENOMEM;

	if (!rvin_format_from_pixel(pix->pixelformat) ||
	    (vin->info->model == RCAR_M1 &&
	     pix->pixelformat == V4L2_PIX_FMT_XBGR32))
		pix->pixelformat = RVIN_DEFAULT_FORMAT;

	v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);

	/* Allow the video device to override field and to scale */
	field = pix->field;
	width = pix->width;
	height = pix->height;

	ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
	if (ret < 0 && ret != -ENOIOCTLCMD)
		goto done;

	v4l2_fill_pix_format(pix, &format.format);

	if (crop) {
		crop->top = 0;
		crop->left = 0;
		crop->width = pix->width;
		crop->height = pix->height;

		/*
		 * If source is ALTERNATE the driver will use the VIN hardware
		 * to INTERLACE it. The crop height then needs to be doubled.
		 */
		if (pix->field == V4L2_FIELD_ALTERNATE)
			crop->height *= 2;
	}

	if (field != V4L2_FIELD_ANY)
		pix->field = field;

	pix->width = width;
	pix->height = height;

	rvin_format_align(vin, pix);

	if (compose) {
		compose->top = 0;
		compose->left = 0;
		compose->width = pix->width;
		compose->height = pix->height;
	}
done:
	v4l2_subdev_free_pad_config(pad_cfg);

	return 0;
}

static int rvin_querycap(struct file *file, void *priv,
			 struct v4l2_capability *cap)
{
	struct rvin_dev *vin = video_drvdata(file);

	strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
	strscpy(cap->card, "R_Car_VIN", sizeof(cap->card));
	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
		 dev_name(vin->dev));
	return 0;
}

static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
				struct v4l2_format *f)
{
	struct rvin_dev *vin = video_drvdata(file);

	return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
			       NULL);
}

static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
			      struct v4l2_format *f)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_rect crop, compose;
	int ret;

	if (vb2_is_busy(&vin->queue))
		return -EBUSY;

	ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
			      &crop, &compose);
	if (ret)
		return ret;

	vin->format = f->fmt.pix;
	vin->crop = crop;
	vin->compose = compose;
	vin->source = crop;

	return 0;
}

static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
			      struct v4l2_format *f)
{
	struct rvin_dev *vin = video_drvdata(file);

	f->fmt.pix = vin->format;

	return 0;
}

static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
				 struct v4l2_fmtdesc *f)
{
	if (f->index >= ARRAY_SIZE(rvin_formats))
		return -EINVAL;

	f->pixelformat = rvin_formats[f->index].fourcc;

	return 0;
}

static int rvin_g_selection(struct file *file, void *fh,
			    struct v4l2_selection *s)
{
	struct rvin_dev *vin = video_drvdata(file);

	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	switch (s->target) {
	case V4L2_SEL_TGT_CROP_BOUNDS:
	case V4L2_SEL_TGT_CROP_DEFAULT:
		s->r.left = s->r.top = 0;
		s->r.width = vin->source.width;
		s->r.height = vin->source.height;
		break;
	case V4L2_SEL_TGT_CROP:
		s->r = vin->crop;
		break;
	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
		s->r.left = s->r.top = 0;
		s->r.width = vin->format.width;
		s->r.height = vin->format.height;
		break;
	case V4L2_SEL_TGT_COMPOSE:
		s->r = vin->compose;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int rvin_s_selection(struct file *file, void *fh,
			    struct v4l2_selection *s)
{
	struct rvin_dev *vin = video_drvdata(file);
	const struct rvin_video_format *fmt;
	struct v4l2_rect r = s->r;
	struct v4l2_rect max_rect;
	struct v4l2_rect min_rect = {
		.width = 6,
		.height = 2,
	};

	if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	v4l2_rect_set_min_size(&r, &min_rect);

	switch (s->target) {
	case V4L2_SEL_TGT_CROP:
		/* Can't crop outside of source input */
		max_rect.top = max_rect.left = 0;
		max_rect.width = vin->source.width;
		max_rect.height = vin->source.height;
		v4l2_rect_map_inside(&r, &max_rect);

		v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
				      &r.height, 2, vin->source.height, 0, 0);

		r.top  = clamp_t(s32, r.top, 0, vin->source.height - r.height);
		r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);

		vin->crop = s->r = r;

		vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
			r.width, r.height, r.left, r.top,
			vin->source.width, vin->source.height);
		break;
	case V4L2_SEL_TGT_COMPOSE:
		/* Make sure compose rect fits inside output format */
		max_rect.top = max_rect.left = 0;
		max_rect.width = vin->format.width;
		max_rect.height = vin->format.height;
		v4l2_rect_map_inside(&r, &max_rect);

		/*
		 * Composing is done by adding a offset to the buffer address,
		 * the HW wants this address to be aligned to HW_BUFFER_MASK.
		 * Make sure the top and left values meets this requirement.
		 */
		while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
			r.top--;

		fmt = rvin_format_from_pixel(vin->format.pixelformat);
		while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
			r.left--;

		vin->compose = s->r = r;

		vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n",
			r.width, r.height, r.left, r.top,
			vin->format.width, vin->format.height);
		break;
	default:
		return -EINVAL;
	}

	/* HW supports modifying configuration while running */
	rvin_crop_scale_comp(vin);

	return 0;
}

static int rvin_g_pixelaspect(struct file *file, void *priv,
			      int type, struct v4l2_fract *f)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);

	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	return v4l2_subdev_call(sd, video, g_pixelaspect, f);
}

static int rvin_enum_input(struct file *file, void *priv,
			   struct v4l2_input *i)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);
	int ret;

	if (i->index != 0)
		return -EINVAL;

	ret = v4l2_subdev_call(sd, video, g_input_status, &i->status);
	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
		return ret;

	i->type = V4L2_INPUT_TYPE_CAMERA;

	if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) {
		i->capabilities = V4L2_IN_CAP_DV_TIMINGS;
		i->std = 0;
	} else {
		i->capabilities = V4L2_IN_CAP_STD;
		i->std = vin->vdev.tvnorms;
	}

	strscpy(i->name, "Camera", sizeof(i->name));

	return 0;
}

static int rvin_g_input(struct file *file, void *priv, unsigned int *i)
{
	*i = 0;
	return 0;
}

static int rvin_s_input(struct file *file, void *priv, unsigned int i)
{
	if (i > 0)
		return -EINVAL;
	return 0;
}

static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);

	return v4l2_subdev_call(sd, video, querystd, a);
}

static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a)
{
	struct rvin_dev *vin = video_drvdata(file);
	int ret;

	ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a);
	if (ret < 0)
		return ret;

	vin->std = a;

	/* Changing the standard will change the width/height */
	return rvin_reset_format(vin);
}

static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a)
{
	struct rvin_dev *vin = video_drvdata(file);

	if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap))
		return -ENOIOCTLCMD;

	*a = vin->std;

	return 0;
}

static int rvin_subscribe_event(struct v4l2_fh *fh,
				const struct v4l2_event_subscription *sub)
{
	switch (sub->type) {
	case V4L2_EVENT_SOURCE_CHANGE:
		return v4l2_event_subscribe(fh, sub, 4, NULL);
	}
	return v4l2_ctrl_subscribe_event(fh, sub);
}

static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
				struct v4l2_enum_dv_timings *timings)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);
	int ret;

	if (timings->pad)
		return -EINVAL;

	timings->pad = vin->parallel->sink_pad;

	ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);

	timings->pad = 0;

	return ret;
}

static int rvin_s_dv_timings(struct file *file, void *priv_fh,
			     struct v4l2_dv_timings *timings)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);
	int ret;

	ret = v4l2_subdev_call(sd, video, s_dv_timings, timings);
	if (ret)
		return ret;

	/* Changing the timings will change the width/height */
	return rvin_reset_format(vin);
}

static int rvin_g_dv_timings(struct file *file, void *priv_fh,
			     struct v4l2_dv_timings *timings)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);

	return v4l2_subdev_call(sd, video, g_dv_timings, timings);
}

static int rvin_query_dv_timings(struct file *file, void *priv_fh,
				 struct v4l2_dv_timings *timings)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);

	return v4l2_subdev_call(sd, video, query_dv_timings, timings);
}

static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
			       struct v4l2_dv_timings_cap *cap)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);
	int ret;

	if (cap->pad)
		return -EINVAL;

	cap->pad = vin->parallel->sink_pad;

	ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);

	cap->pad = 0;

	return ret;
}

static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);
	int ret;

	if (edid->pad)
		return -EINVAL;

	edid->pad = vin->parallel->sink_pad;

	ret = v4l2_subdev_call(sd, pad, get_edid, edid);

	edid->pad = 0;

	return ret;
}

static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
{
	struct rvin_dev *vin = video_drvdata(file);
	struct v4l2_subdev *sd = vin_to_source(vin);
	int ret;

	if (edid->pad)
		return -EINVAL;

	edid->pad = vin->parallel->sink_pad;

	ret = v4l2_subdev_call(sd, pad, set_edid, edid);

	edid->pad = 0;

	return ret;
}

static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
	.vidioc_querycap		= rvin_querycap,
	.vidioc_try_fmt_vid_cap		= rvin_try_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap		= rvin_g_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap		= rvin_s_fmt_vid_cap,
	.vidioc_enum_fmt_vid_cap	= rvin_enum_fmt_vid_cap,

	.vidioc_g_selection		= rvin_g_selection,
	.vidioc_s_selection		= rvin_s_selection,

	.vidioc_g_pixelaspect		= rvin_g_pixelaspect,

	.vidioc_enum_input		= rvin_enum_input,
	.vidioc_g_input			= rvin_g_input,
	.vidioc_s_input			= rvin_s_input,

	.vidioc_dv_timings_cap		= rvin_dv_timings_cap,
	.vidioc_enum_dv_timings		= rvin_enum_dv_timings,
	.vidioc_g_dv_timings		= rvin_g_dv_timings,
	.vidioc_s_dv_timings		= rvin_s_dv_timings,
	.vidioc_query_dv_timings	= rvin_query_dv_timings,

	.vidioc_g_edid			= rvin_g_edid,
	.vidioc_s_edid			= rvin_s_edid,

	.vidioc_querystd		= rvin_querystd,
	.vidioc_g_std			= rvin_g_std,
	.vidioc_s_std			= rvin_s_std,

	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
	.vidioc_querybuf		= vb2_ioctl_querybuf,
	.vidioc_qbuf			= vb2_ioctl_qbuf,
	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
	.vidioc_expbuf			= vb2_ioctl_expbuf,
	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
	.vidioc_streamon		= vb2_ioctl_streamon,
	.vidioc_streamoff		= vb2_ioctl_streamoff,

	.vidioc_log_status		= v4l2_ctrl_log_status,
	.vidioc_subscribe_event		= rvin_subscribe_event,
	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
};

/* -----------------------------------------------------------------------------
 * V4L2 Media Controller
 */

static void rvin_mc_try_format(struct rvin_dev *vin,
			       struct v4l2_pix_format *pix)
{
	/*
	 * The V4L2 specification clearly documents the colorspace fields
	 * as being set by drivers for capture devices. Using the values
	 * supplied by userspace thus wouldn't comply with the API. Until
	 * the API is updated force fixed vaules.
	 */
	pix->colorspace = RVIN_DEFAULT_COLORSPACE;
	pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
	pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
	pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
							  pix->ycbcr_enc);

	rvin_format_align(vin, pix);
}

static int rvin_mc_try_fmt_vid_cap(struct file *file, void *priv,
				   struct v4l2_format *f)
{
	struct rvin_dev *vin = video_drvdata(file);

	rvin_mc_try_format(vin, &f->fmt.pix);

	return 0;
}

static int rvin_mc_s_fmt_vid_cap(struct file *file, void *priv,
				 struct v4l2_format *f)
{
	struct rvin_dev *vin = video_drvdata(file);

	if (vb2_is_busy(&vin->queue))
		return -EBUSY;

	rvin_mc_try_format(vin, &f->fmt.pix);

	vin->format = f->fmt.pix;

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

	return 0;
}

static int rvin_mc_enum_input(struct file *file, void *priv,
			      struct v4l2_input *i)
{
	if (i->index != 0)
		return -EINVAL;

	i->type = V4L2_INPUT_TYPE_CAMERA;
	strscpy(i->name, "Camera", sizeof(i->name));

	return 0;
}

static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = {
	.vidioc_querycap		= rvin_querycap,
	.vidioc_try_fmt_vid_cap		= rvin_mc_try_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap		= rvin_g_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap		= rvin_mc_s_fmt_vid_cap,
	.vidioc_enum_fmt_vid_cap	= rvin_enum_fmt_vid_cap,

	.vidioc_enum_input		= rvin_mc_enum_input,
	.vidioc_g_input			= rvin_g_input,
	.vidioc_s_input			= rvin_s_input,

	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
	.vidioc_querybuf		= vb2_ioctl_querybuf,
	.vidioc_qbuf			= vb2_ioctl_qbuf,
	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
	.vidioc_expbuf			= vb2_ioctl_expbuf,
	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
	.vidioc_streamon		= vb2_ioctl_streamon,
	.vidioc_streamoff		= vb2_ioctl_streamoff,

	.vidioc_log_status		= v4l2_ctrl_log_status,
	.vidioc_subscribe_event		= rvin_subscribe_event,
	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
};

/* -----------------------------------------------------------------------------
 * File Operations
 */

static int rvin_power_on(struct rvin_dev *vin)
{
	int ret;
	struct v4l2_subdev *sd = vin_to_source(vin);

	pm_runtime_get_sync(vin->v4l2_dev.dev);

	ret = v4l2_subdev_call(sd, core, s_power, 1);
	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
		return ret;
	return 0;
}