--- zzzz-none-000/linux-3.10.107/drivers/media/platform/exynos4-is/fimc-capture.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/platform/exynos4-is/fimc-capture.c 2021-02-04 17:41:59.000000000 +0000 @@ -24,12 +24,13 @@ #include #include #include -#include +#include #include -#include "media-dev.h" +#include "common.h" #include "fimc-core.h" #include "fimc-reg.h" +#include "media-dev.h" static int fimc_capture_hw_init(struct fimc_dev *fimc) { @@ -102,7 +103,7 @@ /* Release unused buffers */ while (!suspend && !list_empty(&cap->pending_buf_q)) { buf = fimc_pending_queue_pop(cap); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } /* If suspending put unused buffers onto pending queue */ while (!list_empty(&cap->active_buf_q)) { @@ -110,7 +111,7 @@ if (suspend) fimc_pending_queue_add(cap, buf); else - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } fimc_hw_reset(fimc); @@ -119,8 +120,7 @@ spin_unlock_irqrestore(&fimc->slock, flags); if (streaming) - return fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 0); + return fimc_pipeline_call(&cap->ve, set_stream, 0); else return 0; } @@ -178,12 +178,11 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { - struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_pipeline *p = to_fimc_pipeline(cap->ve.pipe); + struct v4l2_subdev *csis = p->subdevs[IDX_CSIS]; struct fimc_frame *f = &cap->ctx->d_frame; struct fimc_vid_buffer *v_buf; - struct timeval *tv; - struct timespec ts; if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { wake_up(&fimc->irq_queue); @@ -192,16 +191,12 @@ if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) { - ktime_get_real_ts(&ts); - v_buf = fimc_active_queue_pop(cap); - tv = &v_buf->vb.v4l2_buf.timestamp; - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; - v_buf->vb.v4l2_buf.sequence = cap->frame_count++; + v4l2_get_timestamp(&v_buf->vb.timestamp); + v_buf->vb.sequence = cap->frame_count++; - vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); + vb2_buffer_done(&v_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } if (!list_empty(&cap->pending_buf_q)) { @@ -232,7 +227,7 @@ list_for_each_entry(v_buf, &cap->active_buf_q, list) { if (v_buf->index != index) continue; - vaddr = vb2_plane_vaddr(&v_buf->vb, plane); + vaddr = vb2_plane_vaddr(&v_buf->vb.vb2_buf, plane); v4l2_subdev_call(csis, video, s_rx_buffer, vaddr, &size); break; @@ -287,22 +282,21 @@ fimc_activate_capture(ctx); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - return fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); + return fimc_pipeline_call(&vid_cap->ve, set_stream, 1); } return 0; } -static int stop_streaming(struct vb2_queue *q) +static void stop_streaming(struct vb2_queue *q) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; if (!fimc_capture_active(fimc)) - return -EINVAL; + return; - return fimc_stop_capture(fimc, false); + fimc_stop_capture(fimc, false); } int fimc_capture_suspend(struct fimc_dev *fimc) @@ -312,7 +306,7 @@ int ret = fimc_stop_capture(fimc, suspend); if (ret) return ret; - return fimc_pipeline_call(fimc, close, &fimc->pipeline); + return fimc_pipeline_call(&fimc->vid_cap.ve, close); } static void buffer_queue(struct vb2_buffer *vb); @@ -320,6 +314,7 @@ int fimc_capture_resume(struct fimc_dev *fimc) { struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + struct exynos_video_entity *ve = &vid_cap->ve; struct fimc_vid_buffer *buf; int i; @@ -328,8 +323,7 @@ INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); vid_cap->buf_index = 0; - fimc_pipeline_call(fimc, open, &fimc->pipeline, - &vid_cap->vfd.entity, false); + fimc_pipeline_call(ve, open, &ve->vdev.entity, false); fimc_capture_hw_init(fimc); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); @@ -338,16 +332,17 @@ if (list_empty(&vid_cap->pending_buf_q)) break; buf = fimc_pending_queue_pop(vid_cap); - buffer_queue(&buf->vb); + buffer_queue(&buf->vb.vb2_buf); } return 0; } -static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, +static int queue_setup(struct vb2_queue *vq, const void *parg, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { + const struct v4l2_format *pfmt = parg; const struct v4l2_pix_format_mplane *pixm = NULL; struct fimc_ctx *ctx = vq->drv_priv; struct fimc_frame *frame = &ctx->d_frame; @@ -397,7 +392,7 @@ unsigned long size = ctx->d_frame.payload[i]; if (vb2_plane_size(vb, i) < size) { - v4l2_err(&ctx->fimc_dev->vid_cap.vfd, + v4l2_err(&ctx->fimc_dev->vid_cap.ve.vdev, "User buffer too small (%ld < %ld)\n", vb2_plane_size(vb, i), size); return -EINVAL; @@ -410,16 +405,18 @@ static void buffer_queue(struct vb2_buffer *vb) { + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct fimc_vid_buffer *buf - = container_of(vb, struct fimc_vid_buffer, vb); + = container_of(vbuf, struct fimc_vid_buffer, vb); struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + struct exynos_video_entity *ve = &vid_cap->ve; unsigned long flags; int min_bufs; spin_lock_irqsave(&fimc->slock, flags); - fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); + fimc_prepare_addr(ctx, &buf->vb.vb2_buf, &ctx->d_frame, &buf->paddr); if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) && !test_bit(ST_CAPT_STREAM, &fimc->state) && @@ -452,9 +449,9 @@ if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) return; - ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); + ret = fimc_pipeline_call(ve, set_stream, 1); if (ret < 0) - v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret); + v4l2_err(&ve->vdev, "stream on failed: %d\n", ret); return; } spin_unlock_irqrestore(&fimc->slock, flags); @@ -470,44 +467,17 @@ .stop_streaming = stop_streaming, }; -/** - * fimc_capture_ctrls_create - initialize the control handler - * Initialize the capture video node control handler and fill it - * with the FIMC controls. Inherit any sensor's controls if the - * 'user_subdev_api' flag is false (default behaviour). - * This function need to be called with the graph mutex held. - */ -int fimc_capture_ctrls_create(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR]; - int ret; - - if (WARN_ON(vid_cap->ctx == NULL)) - return -ENXIO; - if (vid_cap->ctx->ctrls.ready) - return 0; - - ret = fimc_ctrls_create(vid_cap->ctx); - - if (ret || vid_cap->user_subdev_api || !sensor || - !vid_cap->ctx->ctrls.ready) - return ret; - - return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler, - sensor->ctrl_handler, NULL); -} - static int fimc_capture_set_default_format(struct fimc_dev *fimc); static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct exynos_video_entity *ve = &vc->ve; int ret = -EBUSY; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - fimc_md_graph_lock(fimc); mutex_lock(&fimc->lock); if (fimc_m2m_active(fimc)) @@ -520,31 +490,42 @@ ret = v4l2_fh_open(file); if (ret) { - pm_runtime_put(&fimc->pdev->dev); + pm_runtime_put_sync(&fimc->pdev->dev); goto unlock; } if (v4l2_fh_is_singular_file(file)) { - ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, - &fimc->vid_cap.vfd.entity, true); + fimc_md_graph_lock(ve); - if (!ret && !fimc->vid_cap.user_subdev_api) - ret = fimc_capture_set_default_format(fimc); + ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true); + + if (ret == 0 && vc->user_subdev_api && vc->inh_sensor_ctrls) { + /* + * Recreate controls of the the video node to drop + * any controls inherited from the sensor subdev. + */ + fimc_ctrls_delete(vc->ctx); + + ret = fimc_ctrls_create(vc->ctx); + if (ret == 0) + vc->inh_sensor_ctrls = false; + } + if (ret == 0) + ve->vdev.entity.use_count++; - if (!ret) - ret = fimc_capture_ctrls_create(fimc); + fimc_md_graph_unlock(ve); + + if (ret == 0) + ret = fimc_capture_set_default_format(fimc); if (ret < 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); pm_runtime_put_sync(&fimc->pdev->dev); v4l2_fh_release(file); - } else { - fimc->vid_cap.refcnt++; } } unlock: mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(fimc); return ret; } @@ -552,30 +533,31 @@ { struct fimc_dev *fimc = video_drvdata(file); struct fimc_vid_cap *vc = &fimc->vid_cap; + bool close = v4l2_fh_is_singular_file(file); int ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); mutex_lock(&fimc->lock); - if (v4l2_fh_is_singular_file(file)) { - if (vc->streaming) { - media_entity_pipeline_stop(&vc->vfd.entity); - vc->streaming = false; - } - clear_bit(ST_CAPT_BUSY, &fimc->state); - fimc_stop_capture(fimc, false); - fimc_pipeline_call(fimc, close, &fimc->pipeline); - clear_bit(ST_CAPT_SUSPENDED, &fimc->state); - fimc->vid_cap.refcnt--; + if (close && vc->streaming) { + media_entity_pipeline_stop(&vc->ve.vdev.entity); + vc->streaming = false; } - pm_runtime_put(&fimc->pdev->dev); + ret = _vb2_fop_release(file, NULL); - if (v4l2_fh_is_singular_file(file)) - fimc_ctrls_delete(fimc->vid_cap.ctx); + if (close) { + clear_bit(ST_CAPT_BUSY, &fimc->state); + fimc_pipeline_call(&vc->ve, close); + clear_bit(ST_CAPT_SUSPENDED, &fimc->state); + + fimc_md_graph_lock(&vc->ve); + vc->ve.vdev.entity.use_count--; + fimc_md_graph_unlock(&vc->ve); + } - ret = vb2_fop_release(file); + pm_runtime_put_sync(&fimc->pdev->dev); mutex_unlock(&fimc->lock); return ret; @@ -763,7 +745,7 @@ return -EINVAL; strncpy(f->description, fmt->name, sizeof(f->description) - 1); f->pixelformat = fmt->fourcc; - if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8) + if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8) f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } @@ -773,7 +755,7 @@ struct media_pad *pad = &me->pads[0]; while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) { - pad = media_entity_remote_source(pad); + pad = media_entity_remote_pad(pad); if (!pad) break; me = pad->entity; @@ -797,7 +779,8 @@ bool set) { struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; + struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe); + struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR]; struct v4l2_subdev_format sfmt; struct v4l2_mbus_framefmt *mf = &sfmt.format; struct media_entity *me; @@ -845,7 +828,7 @@ return ret; } - pad = media_entity_remote_source(&me->pads[sfmt.pad]); + pad = media_entity_remote_pad(&me->pads[sfmt.pad]); if (!pad) return -EINVAL; me = pad->entity; @@ -929,57 +912,101 @@ return 0; } -static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) +/* + * Try or set format on the fimc.X.capture video node and additionally + * on the whole pipeline if @try is false. + * Locking: the caller must _not_ hold the graph mutex. + */ +static int __video_try_or_set_format(struct fimc_dev *fimc, + struct v4l2_format *f, bool try, + struct fimc_fmt **inp_fmt, + struct fimc_fmt **out_fmt) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct v4l2_mbus_framefmt mf; - struct fimc_fmt *ffmt = NULL; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct exynos_video_entity *ve = &vc->ve; + struct fimc_ctx *ctx = vc->ctx; + unsigned int width = 0, height = 0; int ret = 0; - fimc_md_graph_lock(fimc); - mutex_lock(&fimc->lock); - + /* Pre-configure format at the camera input interface, for JPEG only */ if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK_CAM); - ctx->s_frame.f_width = pix->width; - ctx->s_frame.f_height = pix->height; + if (try) { + width = pix->width; + height = pix->height; + } else { + ctx->s_frame.f_width = pix->width; + ctx->s_frame.f_height = pix->height; + } } - ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, - NULL, &pix->pixelformat, - FIMC_SD_PAD_SOURCE); - if (!ffmt) { - ret = -EINVAL; - goto unlock; + + /* Try the format at the scaler and the DMA output */ + *out_fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SOURCE); + if (*out_fmt == NULL) + return -EINVAL; + + /* Restore image width/height for JPEG (no resizing supported). */ + if (try && fimc_jpeg_fourcc(pix->pixelformat)) { + pix->width = width; + pix->height = height; } - if (!fimc->vid_cap.user_subdev_api) { - mf.width = pix->width; - mf.height = pix->height; - mf.code = ffmt->mbus_code; - fimc_pipeline_try_format(ctx, &mf, &ffmt, false); - pix->width = mf.width; - pix->height = mf.height; - if (ffmt) - pix->pixelformat = ffmt->fourcc; - } - - fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); - - if (ffmt->flags & FMT_FLAGS_COMPRESSED) - fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], - pix->plane_fmt, ffmt->memplanes, true); -unlock: - mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(fimc); + /* Try to match format at the host and the sensor */ + if (!vc->user_subdev_api) { + struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_mbus_framefmt *mf; + + mf = try ? &mbus_fmt : &fimc->vid_cap.ci_fmt; + + mf->code = (*out_fmt)->mbus_code; + mf->width = pix->width; + mf->height = pix->height; + + fimc_md_graph_lock(ve); + ret = fimc_pipeline_try_format(ctx, mf, inp_fmt, try); + fimc_md_graph_unlock(ve); + + if (ret < 0) + return ret; + + pix->width = mf->width; + pix->height = mf->height; + } + + fimc_adjust_mplane_format(*out_fmt, pix->width, pix->height, pix); + + if ((*out_fmt)->flags & FMT_FLAGS_COMPRESSED) { + struct v4l2_subdev *sensor; + + fimc_md_graph_lock(ve); + + sensor = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR); + if (sensor) + fimc_get_sensor_frame_desc(sensor, pix->plane_fmt, + (*out_fmt)->memplanes, try); + else + ret = -EPIPE; + + fimc_md_graph_unlock(ve); + } return ret; } +static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_fmt *out_fmt = NULL, *inp_fmt = NULL; + + return __video_try_or_set_format(fimc, f, true, &inp_fmt, &out_fmt); +} + static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, enum fimc_color_fmt color) { @@ -997,57 +1024,23 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) { - struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct fimc_ctx *ctx = vc->ctx; struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt; struct fimc_frame *ff = &ctx->d_frame; - struct fimc_fmt *s_fmt = NULL; + struct fimc_fmt *inp_fmt = NULL; int ret, i; if (vb2_is_busy(&fimc->vid_cap.vbq)) return -EBUSY; - /* Pre-configure format at camera interface input, for JPEG only */ - if (fimc_jpeg_fourcc(pix->pixelformat)) { - fimc_capture_try_format(ctx, &pix->width, &pix->height, - NULL, &pix->pixelformat, - FIMC_SD_PAD_SINK_CAM); - 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; + ret = __video_try_or_set_format(fimc, f, false, &inp_fmt, &ff->fmt); + if (ret < 0) + return ret; /* 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; - ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true); - if (ret) - return ret; - - pix->width = mf->width; - pix->height = mf->height; - } - - fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); - - if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { - ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], - pix->plane_fmt, ff->fmt->memplanes, - true); - if (ret < 0) - return ret; - } - for (i = 0; i < ff->fmt->memplanes; i++) { ff->bytesperline[i] = pix->plane_fmt[i].bytesperline; ff->payload[i] = pix->plane_fmt[i].sizeimage; @@ -1061,8 +1054,8 @@ fimc_capture_mark_jpeg_xfer(ctx, 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; + if (!vc->user_subdev_api) { + ctx->s_frame.fmt = inp_fmt; set_frame_bounds(&ctx->s_frame, pix->width, pix->height); set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height); } @@ -1074,37 +1067,28 @@ struct v4l2_format *f) { struct fimc_dev *fimc = video_drvdata(file); - int ret; - fimc_md_graph_lock(fimc); - mutex_lock(&fimc->lock); - /* - * The graph is walked within __fimc_capture_set_format() to set - * the format at subdevs thus the graph mutex needs to be held at - * this point and acquired before the video mutex, to avoid AB-BA - * deadlock when fimc_md_link_notify() is called by other thread. - * Ideally the graph walking and setting format at the whole pipeline - * should be removed from this driver and handled in userspace only. - */ - ret = __fimc_capture_set_format(fimc, f); - - mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(fimc); - return ret; + return __fimc_capture_set_format(fimc, f); } static int fimc_cap_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct fimc_dev *fimc = video_drvdata(file); - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; + struct exynos_video_entity *ve = &fimc->vid_cap.ve; + struct v4l2_subdev *sd; if (i->index != 0) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; + fimc_md_graph_lock(ve); + sd = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR); + fimc_md_graph_unlock(ve); + if (sd) strlcpy(i->name, sd->name, sizeof(i->name)); + return 0; } @@ -1130,6 +1114,7 @@ struct v4l2_subdev_format sink_fmt, src_fmt; struct fimc_vid_cap *vc = &fimc->vid_cap; struct v4l2_subdev *sd = &vc->subdev; + struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe); struct media_pad *sink_pad, *src_pad; int i, ret; @@ -1146,7 +1131,7 @@ if (p->flags & MEDIA_PAD_FL_SINK) { sink_pad = p; - src_pad = media_entity_remote_source(sink_pad); + src_pad = media_entity_remote_pad(sink_pad); if (src_pad) break; } @@ -1183,7 +1168,7 @@ src_fmt.format.code != sink_fmt.format.code) return -EPIPE; - if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && + if (sd == p->subdevs[IDX_SENSOR] && fimc_user_defined_mbus_fmt(src_fmt.format.code)) { struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; struct fimc_frame *frame = &vc->ctx->d_frame; @@ -1207,9 +1192,8 @@ enum v4l2_buf_type type) { struct fimc_dev *fimc = video_drvdata(file); - struct fimc_pipeline *p = &fimc->pipeline; struct fimc_vid_cap *vc = &fimc->vid_cap; - struct media_entity *entity = &vc->vfd.entity; + struct media_entity *entity = &vc->ve.vdev.entity; struct fimc_source_info *si = NULL; struct v4l2_subdev *sd; int ret; @@ -1217,11 +1201,11 @@ if (fimc_capture_active(fimc)) return -EBUSY; - ret = media_entity_pipeline_start(entity, p->m_pipeline); + ret = media_entity_pipeline_start(entity, &vc->ve.pipe->mp); if (ret < 0) return ret; - sd = p->subdevs[IDX_SENSOR]; + sd = __fimc_md_get_subdev(vc->ve.pipe, IDX_SENSOR); if (sd) si = v4l2_get_subdev_hostdata(sd); @@ -1259,14 +1243,15 @@ enum v4l2_buf_type type) { struct fimc_dev *fimc = video_drvdata(file); + struct fimc_vid_cap *vc = &fimc->vid_cap; int ret; ret = vb2_ioctl_streamoff(file, priv, type); if (ret < 0) return ret; - media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); - fimc->vid_cap.streaming = false; + media_entity_pipeline_stop(&vc->ve.vdev.entity); + vc->streaming = false; return 0; } @@ -1405,6 +1390,8 @@ { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct v4l2_subdev *sensor; if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) return -EINVAL; @@ -1416,15 +1403,26 @@ local->entity->name, remote->entity->name, flags, fimc->vid_cap.input); - if (flags & MEDIA_LNK_FL_ENABLED) { - if (fimc->vid_cap.input != 0) - return -EBUSY; - fimc->vid_cap.input = sd->grp_id; + if (!(flags & MEDIA_LNK_FL_ENABLED)) { + fimc->vid_cap.input = 0; return 0; } - fimc->vid_cap.input = 0; - return 0; + if (vc->input != 0) + return -EBUSY; + + vc->input = sd->grp_id; + + if (vc->user_subdev_api || vc->inh_sensor_ctrls) + return 0; + + /* Inherit V4L2 controls from the image sensor subdev. */ + sensor = fimc_find_remote_sensor(&vc->subdev.entity); + if (sensor == NULL) + return 0; + + return v4l2_ctrl_add_handler(&vc->ctx->ctrls.handler, + sensor->ctrl_handler, NULL); } static const struct media_entity_operations fimc_sd_media_ops = { @@ -1470,7 +1468,8 @@ if (!list_empty(&fimc->vid_cap.active_buf_q)) { buf = list_entry(fimc->vid_cap.active_buf_q.next, struct fimc_vid_buffer, list); - vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg)); + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, + *((u32 *)arg)); } fimc_capture_irq_handler(fimc, 1); fimc_deactivate_capture(fimc); @@ -1480,7 +1479,7 @@ } static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct fimc_fmt *fmt; @@ -1493,7 +1492,7 @@ } static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1502,7 +1501,7 @@ struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1534,7 +1533,7 @@ } static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1557,7 +1556,7 @@ mf->colorspace = V4L2_COLORSPACE_JPEG; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; return 0; } @@ -1600,7 +1599,7 @@ } static int fimc_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1626,10 +1625,10 @@ return 0; case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); f = &ctx->d_frame; break; default: @@ -1655,7 +1654,7 @@ } static int fimc_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1673,10 +1672,10 @@ switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); f = &ctx->d_frame; break; default: @@ -1720,8 +1719,8 @@ struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, .fmt.pix_mp = { - .width = 640, - .height = 480, + .width = FIMC_DEFAULT_WIDTH, + .height = FIMC_DEFAULT_HEIGHT, .pixelformat = V4L2_PIX_FMT_YUYV, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_JPEG, @@ -1735,10 +1734,11 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev) { - struct video_device *vfd = &fimc->vid_cap.vfd; + struct video_device *vfd = &fimc->vid_cap.ve.vdev; struct vb2_queue *q = &fimc->vid_cap.vbq; struct fimc_ctx *ctx; struct fimc_vid_cap *vid_cap; + struct fimc_fmt *fmt; int ret = -ENOMEM; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -1779,27 +1779,39 @@ q->ops = &fimc_capture_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &fimc->lock; ret = vb2_queue_init(q); if (ret) - goto err_ent; + goto err_free_ctx; + + /* Default format configuration */ + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); + vid_cap->ci_fmt.width = FIMC_DEFAULT_WIDTH; + vid_cap->ci_fmt.height = FIMC_DEFAULT_HEIGHT; + vid_cap->ci_fmt.code = fmt->mbus_code; + + ctx->s_frame.width = FIMC_DEFAULT_WIDTH; + ctx->s_frame.height = FIMC_DEFAULT_HEIGHT; + ctx->s_frame.fmt = fmt; + + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_WRITEBACK, 0); + vid_cap->wb_fmt = vid_cap->ci_fmt; + vid_cap->wb_fmt.code = fmt->mbus_code; vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0); if (ret) - goto err_ent; - /* - * For proper order of acquiring/releasing the video - * and the graph mutex. - */ - v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT); - v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT); + goto err_free_ctx; + + ret = fimc_ctrls_create(ctx); + if (ret) + goto err_me_cleanup; ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) - goto err_vd; + goto err_ctrl_free; v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", vfd->name, video_device_node_name(vfd)); @@ -1807,9 +1819,11 @@ vfd->ctrl_handler = &ctx->ctrls.handler; return 0; -err_vd: +err_ctrl_free: + fimc_ctrls_delete(ctx); +err_me_cleanup: media_entity_cleanup(&vfd->entity); -err_ent: +err_free_ctx: kfree(ctx); return ret; } @@ -1826,12 +1840,12 @@ if (ret) return ret; - fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); + fimc->vid_cap.ve.pipe = v4l2_get_subdev_hostdata(sd); ret = fimc_register_capture_device(fimc, sd->v4l2_dev); if (ret) { fimc_unregister_m2m_device(fimc); - fimc->pipeline_ops = NULL; + fimc->vid_cap.ve.pipe = NULL; } return ret; @@ -1840,19 +1854,26 @@ static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct video_device *vdev; if (fimc == NULL) return; + mutex_lock(&fimc->lock); + fimc_unregister_m2m_device(fimc); + vdev = &fimc->vid_cap.ve.vdev; - if (video_is_registered(&fimc->vid_cap.vfd)) { - video_unregister_device(&fimc->vid_cap.vfd); - media_entity_cleanup(&fimc->vid_cap.vfd.entity); - fimc->pipeline_ops = NULL; + if (video_is_registered(vdev)) { + video_unregister_device(vdev); + media_entity_cleanup(&vdev->entity); + fimc_ctrls_delete(fimc->vid_cap.ctx); + fimc->vid_cap.ve.pipe = NULL; } kfree(fimc->vid_cap.ctx); fimc->vid_cap.ctx = NULL; + + mutex_unlock(&fimc->lock); } static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {