drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c

Source file repositories/reference/linux-study-clean/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c

File Facts

System
Linux kernel
Corpus path
drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
Extension
.c
Size
14058 bytes
Lines
498
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (ret < 0) {
			/*
			 * Return 0 if downloading firmware successfully,
			 * otherwise it is failed
			 */
			mtk_v4l2_venc_err(ctx, "vpu_load_firmware failed!");
			goto err_load_fw;
		}

		dev->enc_capability =
			mtk_vcodec_fw_get_venc_capa(dev->fw_handler);
		mtk_v4l2_venc_dbg(0, ctx, "encoder capability %x", dev->enc_capability);
	}

	mtk_v4l2_venc_dbg(2, ctx, "Create instance [%d]@%p m2m_ctx=%p ",
			  ctx->id, ctx, ctx->m2m_ctx);

	spin_lock_irqsave(&dev->dev_ctx_lock, flags);
	list_add(&ctx->list, &dev->ctx_list);
	spin_unlock_irqrestore(&dev->dev_ctx_lock, flags);

	mutex_unlock(&dev->dev_mutex);
	mtk_v4l2_venc_dbg(0, ctx, "%s encoder [%d]", dev_name(&dev->plat_dev->dev),
			  ctx->id);
	return ret;

	/* Deinit when failure occurred */
err_load_fw:
	v4l2_m2m_ctx_release(ctx->m2m_ctx);
err_m2m_ctx_init:
	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
err_ctrls_setup:
	v4l2_fh_del(&ctx->fh, file);
	v4l2_fh_exit(&ctx->fh);
	kfree(ctx);
	mutex_unlock(&dev->dev_mutex);

	return ret;
}

static int fops_vcodec_release(struct file *file)
{
	struct mtk_vcodec_enc_dev *dev = video_drvdata(file);
	struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file);
	unsigned long flags;

	mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id);
	mutex_lock(&dev->dev_mutex);

	v4l2_m2m_ctx_release(ctx->m2m_ctx);
	mtk_vcodec_enc_release(ctx);
	v4l2_fh_del(&ctx->fh, file);
	v4l2_fh_exit(&ctx->fh);
	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);

	/*
	 * Cancel any pending encode work before freeing the context.
	 * Although v4l2_m2m_ctx_release() waits for m2m job completion,
	 * the workqueue handler (mtk_venc_worker) may still be accessing
	 * the context after v4l2_m2m_job_finish() returns. Without this,
	 * a use-after-free occurs when the worker accesses ctx after kfree.
	 */
	cancel_work_sync(&ctx->encode_work);

	spin_lock_irqsave(&dev->dev_ctx_lock, flags);
	list_del_init(&ctx->list);
	spin_unlock_irqrestore(&dev->dev_ctx_lock, flags);
	kfree(ctx);
	mutex_unlock(&dev->dev_mutex);
	return 0;
}

static const struct v4l2_file_operations mtk_vcodec_fops = {
	.owner		= THIS_MODULE,
	.open		= fops_vcodec_open,
	.release	= fops_vcodec_release,
	.poll		= v4l2_m2m_fop_poll,
	.unlocked_ioctl	= video_ioctl2,
	.mmap		= v4l2_m2m_fop_mmap,
};

static int mtk_vcodec_probe(struct platform_device *pdev)
{
	struct mtk_vcodec_enc_dev *dev;
	struct video_device *vfd_enc;
	phandle rproc_phandle;
	enum mtk_vcodec_fw_type fw_type;
	int ret;

	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);

Annotation

Implementation Notes