diff options
Diffstat (limited to 'drivers/media/platform/exynos4-is/fimc-capture.c')
-rw-r--r-- | drivers/media/platform/exynos4-is/fimc-capture.c | 412 |
1 files changed, 218 insertions, 194 deletions
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 528f41369364..fb27ff7e1e07 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -27,9 +27,10 @@ #include <media/videobuf2-core.h> #include <media/videobuf2-dma-contig.h> -#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) { @@ -119,8 +120,7 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) 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,8 +178,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) 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; @@ -287,8 +288,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) 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; @@ -312,7 +312,7 @@ int fimc_capture_suspend(struct fimc_dev *fimc) 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 +320,7 @@ static void buffer_queue(struct vb2_buffer *vb); 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 +329,7 @@ int fimc_capture_resume(struct fimc_dev *fimc) 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); @@ -397,7 +397,7 @@ static int buffer_prepare(struct vb2_buffer *vb) 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; @@ -415,6 +415,7 @@ static void buffer_queue(struct vb2_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; @@ -452,9 +453,9 @@ static void buffer_queue(struct vb2_buffer *vb) 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 +471,17 @@ static struct vb2_ops fimc_capture_qops = { .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 +494,42 @@ static int fimc_capture_open(struct file *file) 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) - ret = fimc_capture_ctrls_create(fimc); + 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++; + + 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 +537,31 @@ static int fimc_capture_release(struct file *file) { 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); - 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); - ret = vb2_fop_release(file); + fimc_md_graph_lock(&vc->ve); + vc->ve.vdev.entity.use_count--; + fimc_md_graph_unlock(&vc->ve); + } + + pm_runtime_put_sync(&fimc->pdev->dev); mutex_unlock(&fimc->lock); return ret; @@ -773,7 +759,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me) 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 +783,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, 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 +832,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, 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 +916,101 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, 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; + /* 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(ffmt, pix->width, pix->height, pix); + fimc_adjust_mplane_format(*out_fmt, 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); + 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 +1028,23 @@ static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, 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 +1058,8 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, 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 +1071,28 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, 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 +1118,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) 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 +1135,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) 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 +1172,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) 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 +1196,8 @@ static int fimc_cap_streamon(struct file *file, void *priv, 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 +1205,11 @@ static int fimc_cap_streamon(struct file *file, void *priv, 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 +1247,15 @@ static int fimc_cap_streamoff(struct file *file, void *priv, 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 +1394,8 @@ static int fimc_link_setup(struct media_entity *entity, { 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 +1407,26 @@ static int fimc_link_setup(struct media_entity *entity, 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 = { @@ -1720,8 +1722,8 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc) 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 +1737,11 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc) 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); @@ -1784,22 +1787,34 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, 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 +1822,11 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, 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 +1843,12 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd) 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 +1857,26 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd) 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 = { |