static int fimc_capture_close(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); int ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; if (--fimc->vid_cap.refcnt == 0) { 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); } pm_runtime_put(&fimc->pdev->dev); if (fimc->vid_cap.refcnt == 0) { vb2_queue_release(&fimc->vid_cap.vbq); fimc_ctrls_delete(fimc->vid_cap.ctx); } ret = v4l2_fh_release(file); mutex_unlock(&fimc->lock); return ret; }
static int fimc_md_link_notify(struct media_pad *source, struct media_pad *sink, u32 flags) { struct fimc_lite *fimc_lite = NULL; struct fimc_dev *fimc = NULL; struct fimc_pipeline *pipeline; struct v4l2_subdev *sd; int ret = 0; if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) return 0; sd = media_entity_to_v4l2_subdev(sink->entity); switch (sd->grp_id) { case FLITE_GROUP_ID: fimc_lite = v4l2_get_subdevdata(sd); pipeline = &fimc_lite->pipeline; break; case FIMC_GROUP_ID: fimc = v4l2_get_subdevdata(sd); pipeline = &fimc->pipeline; break; default: return 0; } if (!(flags & MEDIA_LNK_FL_ENABLED)) { ret = __fimc_pipeline_close(pipeline); pipeline->subdevs[IDX_SENSOR] = NULL; pipeline->subdevs[IDX_CSIS] = NULL; if (fimc) { mutex_lock(&fimc->lock); fimc_ctrls_delete(fimc->vid_cap.ctx); mutex_unlock(&fimc->lock); } return ret; } /* * Link activation. Enable power of pipeline elements only if the * pipeline is already in use, i.e. its video node is opened. * Recreate the controls destroyed during the link deactivation. */ if (fimc) { mutex_lock(&fimc->lock); if (fimc->vid_cap.refcnt > 0) { ret = __fimc_pipeline_open(pipeline, source->entity, true); if (!ret) ret = fimc_capture_ctrls_create(fimc); } mutex_unlock(&fimc->lock); } else { mutex_lock(&fimc_lite->lock); ret = __fimc_pipeline_open(pipeline, source->entity, true); mutex_unlock(&fimc_lite->lock); } return ret ? -EPIPE : ret; }
static int fimc_md_link_notify(struct media_pad *source, struct media_pad *sink, u32 flags) { struct v4l2_subdev *sd; struct fimc_dev *fimc; int ret = 0; if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) return 0; sd = media_entity_to_v4l2_subdev(sink->entity); fimc = v4l2_get_subdevdata(sd); if (!(flags & MEDIA_LNK_FL_ENABLED)) { ret = __fimc_pipeline_shutdown(fimc); fimc->pipeline.sensor = NULL; fimc->pipeline.csis = NULL; mutex_lock(&fimc->lock); fimc_ctrls_delete(fimc->vid_cap.ctx); mutex_unlock(&fimc->lock); return ret; } mutex_lock(&fimc->lock); if (fimc->vid_cap.refcnt > 0) { ret = __fimc_pipeline_initialize(fimc, source->entity, true); if (!ret) ret = fimc_capture_ctrls_create(fimc); } mutex_unlock(&fimc->lock); return ret ? -EPIPE : ret; }
static int fimc_capture_close(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (--fimc->vid_cap.refcnt == 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); fimc_pipeline_shutdown(fimc); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); } pm_runtime_put(&fimc->pdev->dev); if (fimc->vid_cap.refcnt == 0) { vb2_queue_release(&fimc->vid_cap.vbq); fimc_ctrls_delete(fimc->vid_cap.ctx); } return v4l2_fh_release(file); }
static int fimc_m2m_release(struct file *file) { struct fimc_ctx *ctx = fh_to_ctx(file->private_data); struct fimc_dev *fimc = ctx->fimc_dev; dbg("pid: %d, state: 0x%lx, refcnt= %d", task_pid_nr(current), fimc->state, fimc->m2m.refcnt); mutex_lock(&fimc->lock); v4l2_m2m_ctx_release(ctx->m2m_ctx); fimc_ctrls_delete(ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); if (--fimc->m2m.refcnt <= 0) clear_bit(ST_M2M_RUN, &fimc->state); kfree(ctx); mutex_unlock(&fimc->lock); return 0; }
static int fimc_md_link_notify(struct media_pad *source, struct media_pad *sink, u32 flags) { struct v4l2_subdev *sd; struct fimc_dev *fimc; int ret = 0; if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) return 0; sd = media_entity_to_v4l2_subdev(sink->entity); fimc = v4l2_get_subdevdata(sd); if (!(flags & MEDIA_LNK_FL_ENABLED)) { ret = __fimc_pipeline_shutdown(fimc); fimc->pipeline.sensor = NULL; fimc->pipeline.csis = NULL; mutex_lock(&fimc->lock); fimc_ctrls_delete(fimc->vid_cap.ctx); mutex_unlock(&fimc->lock); return ret; } /* * Link activation. Enable power of pipeline elements only if the * pipeline is already in use, i.e. its video node is opened. * Recreate the controls destroyed during the link deactivation. */ mutex_lock(&fimc->lock); if (fimc->vid_cap.refcnt > 0) { ret = __fimc_pipeline_initialize(fimc, source->entity, true); if (!ret) ret = fimc_capture_ctrls_create(fimc); } mutex_unlock(&fimc->lock); return ret ? -EPIPE : ret; }
static int fimc_m2m_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx; int ret = -EBUSY; pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; /* * Don't allow simultaneous open() of the mem-to-mem and the * capture video node that belong to same FIMC IP instance. */ if (test_bit(ST_CAPT_BUSY, &fimc->state)) goto unlock; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { ret = -ENOMEM; goto unlock; } v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd); ctx->fimc_dev = fimc; /* Default color format */ ctx->s_frame.fmt = fimc_get_format(0); ctx->d_frame.fmt = fimc_get_format(0); ret = fimc_ctrls_create(ctx); if (ret) goto error_fh; /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrls.handler; file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; ctx->flags = 0; ctx->in_path = FIMC_IO_DMA; ctx->out_path = FIMC_IO_DMA; ctx->scaler.enabled = 1; ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); if (IS_ERR(ctx->m2m_ctx)) { ret = PTR_ERR(ctx->m2m_ctx); goto error_c; } if (fimc->m2m.refcnt++ == 0) set_bit(ST_M2M_RUN, &fimc->state); ret = fimc_m2m_set_default_format(ctx); if (ret < 0) goto error_m2m_ctx; mutex_unlock(&fimc->lock); return 0; error_m2m_ctx: v4l2_m2m_ctx_release(ctx->m2m_ctx); error_c: fimc_ctrls_delete(ctx); error_fh: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); kfree(ctx); unlock: mutex_unlock(&fimc->lock); return ret; }
static int fimc_m2m_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx; int ret = -EBUSY; dbg("pid: %d, state: 0x%lx, refcnt: %d", task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; /* * Return if the corresponding video capture node * is already opened. */ if (fimc->vid_cap.refcnt > 0) goto unlock; ctx = kzalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) { ret = -ENOMEM; goto unlock; } v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); ctx->fimc_dev = fimc; /* Default color format */ ctx->s_frame.fmt = fimc_get_format(0); ctx->d_frame.fmt = fimc_get_format(0); ret = fimc_ctrls_create(ctx); if (ret) goto error_fh; /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrls.handler; file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; ctx->flags = 0; ctx->in_path = FIMC_IO_DMA; ctx->out_path = FIMC_IO_DMA; ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); if (IS_ERR(ctx->m2m_ctx)) { ret = PTR_ERR(ctx->m2m_ctx); goto error_c; } if (fimc->m2m.refcnt++ == 0) set_bit(ST_M2M_RUN, &fimc->state); mutex_unlock(&fimc->lock); return 0; error_c: fimc_ctrls_delete(ctx); error_fh: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); kfree(ctx); unlock: mutex_unlock(&fimc->lock); return ret; }