static void hva_device_run(void *priv) { struct hva_ctx *ctx = priv; struct hva_dev *hva = ctx_to_hdev(ctx); queue_work(hva->work_queue, &ctx->run_work); }
static int hva_release(struct file *file) { struct hva_ctx *ctx = fh_to_ctx(file->private_data); struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); const struct hva_enc *enc = ctx->enc; if (enc) { dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); enc->close(ctx); ctx->enc = NULL; /* clear instance context in instances array */ hva->instances[ctx->id] = NULL; hva->nb_of_instances--; } v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); dev_info(dev, "%s encoder instance released\n", ctx->name); kfree(ctx); return 0; }
static int hva_enum_fmt_frame(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct hva_ctx *ctx = fh_to_ctx(file->private_data); struct hva_dev *hva = ctx_to_hdev(ctx); if (unlikely(f->index >= hva->nb_of_pixelformats)) return -EINVAL; f->pixelformat = hva->pixelformats[f->index]; return 0; }
static int hva_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct hva_ctx *ctx = fh_to_ctx(file->private_data); struct hva_dev *hva = ctx_to_hdev(ctx); strlcpy(cap->driver, HVA_NAME, sizeof(cap->driver)); strlcpy(cap->card, hva->vdev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", hva->pdev->name); return 0; }
static void hva_stop_streaming(struct vb2_queue *vq) { struct hva_ctx *ctx = vb2_get_drv_priv(vq); struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); const struct hva_enc *enc = ctx->enc; struct vb2_v4l2_buffer *vbuf; dev_dbg(dev, "%s %s stop streaming\n", ctx->name, to_type_str(vq->type)); if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* return of all pending buffers to vb2 (in error state) */ ctx->frame_num = 0; while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } else { /* return of all pending buffers to vb2 (in error state) */ ctx->stream_num = 0; while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } if ((V4L2_TYPE_IS_OUTPUT(vq->type) && vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || (!V4L2_TYPE_IS_OUTPUT(vq->type) && vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { dev_dbg(dev, "%s %s out=%d cap=%d\n", ctx->name, to_type_str(vq->type), vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q), vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)); return; } /* close encoder when both stop_streaming have been called */ if (enc) { dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); enc->close(ctx); ctx->enc = NULL; /* clear instance context in instances array */ hva->instances[ctx->id] = NULL; hva->nb_of_instances--; } ctx->aborting = false; }
static const struct hva_enc *hva_find_encoder(struct hva_ctx *ctx, u32 pixelformat, u32 streamformat) { struct hva_dev *hva = ctx_to_hdev(ctx); const struct hva_enc *enc; unsigned int i; for (i = 0; i < hva->nb_of_encoders; i++) { enc = hva->encoders[i]; if ((enc->pixelformat == pixelformat) && (enc->streamformat == streamformat)) return enc; } return NULL; }
static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat, u32 pixelformat, struct hva_enc **penc) { struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); struct hva_enc *enc; int ret; /* find an encoder which can deal with these formats */ enc = (struct hva_enc *)hva_find_encoder(ctx, pixelformat, streamformat); if (!enc) { dev_err(dev, "%s no encoder found matching %4.4s => %4.4s\n", ctx->name, (char *)&pixelformat, (char *)&streamformat); return -EINVAL; } dev_dbg(dev, "%s one encoder matching %4.4s => %4.4s\n", ctx->name, (char *)&pixelformat, (char *)&streamformat); /* update instance name */ snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]", hva->instance_id, (char *)&streamformat); /* open encoder instance */ ret = enc->open(ctx); if (ret) { dev_err(dev, "%s failed to open encoder instance (%d)\n", ctx->name, ret); return ret; } dev_dbg(dev, "%s %s encoder opened\n", ctx->name, enc->name); *penc = enc; return ret; }
static int hva_release(struct file *file) { struct hva_ctx *ctx = fh_to_ctx(file->private_data); struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); const struct hva_enc *enc = ctx->enc; if (enc) { dev_dbg(dev, "%s %s encoder closed\n", ctx->name, enc->name); enc->close(ctx); ctx->enc = NULL; /* clear instance context in instances array */ hva->instances[ctx->id] = NULL; hva->nb_of_instances--; } /* trace a summary of instance before closing (debug purpose) */ hva_dbg_summary(ctx); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS hva_dbg_ctx_remove(ctx); #endif dev_info(dev, "%s encoder instance released\n", ctx->name); kfree(ctx); return 0; }
static int hva_start_streaming(struct vb2_queue *vq, unsigned int count) { struct hva_ctx *ctx = vb2_get_drv_priv(vq); struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); struct vb2_v4l2_buffer *vbuf; int ret; unsigned int i; bool found = false; dev_dbg(dev, "%s %s start streaming\n", ctx->name, to_type_str(vq->type)); /* open encoder when both start_streaming have been called */ if (V4L2_TYPE_IS_OUTPUT(vq->type)) { if (!vb2_start_streaming_called(&ctx->fh.m2m_ctx->cap_q_ctx.q)) return 0; } else { if (!vb2_start_streaming_called(&ctx->fh.m2m_ctx->out_q_ctx.q)) return 0; } /* store the instance context in the instances array */ for (i = 0; i < HVA_MAX_INSTANCES; i++) { if (!hva->instances[i]) { hva->instances[i] = ctx; /* save the context identifier in the context */ ctx->id = i; found = true; break; } } if (!found) { dev_err(dev, "%s maximum instances reached\n", ctx->name); ret = -ENOMEM; goto err; } hva->nb_of_instances++; if (!ctx->enc) { ret = hva_open_encoder(ctx, ctx->streaminfo.streamformat, ctx->frameinfo.pixelformat, &ctx->enc); if (ret < 0) goto err_ctx; } return 0; err_ctx: hva->instances[ctx->id] = NULL; hva->nb_of_instances--; err: if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* return of all pending buffers to vb2 (in queued state) */ while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); } else { /* return of all pending buffers to vb2 (in queued state) */ while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED); } return ret; }