root/drivers/media/test-drivers/visl/visl-debugfs.c
// SPDX-License-Identifier: GPL-2.0+
/*
 * Debugfs tracing for bitstream buffers. This is similar to VA-API's
 * LIBVA_TRACE_BUFDATA in that the raw bitstream can be dumped as a debugging
 * aid.
 *
 * Produces one file per OUTPUT buffer. Files are automatically cleared on
 * STREAMOFF unless the module parameter "keep_bitstream_buffers" is set.
 */

#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <media/v4l2-mem2mem.h>

#include "visl-debugfs.h"

int visl_debugfs_init(struct visl_dev *dev)
{
        dev->debugfs_root = debugfs_create_dir("visl", NULL);
        INIT_LIST_HEAD(&dev->bitstream_blobs);
        mutex_init(&dev->bitstream_lock);

        if (IS_ERR(dev->debugfs_root))
                return PTR_ERR(dev->debugfs_root);

        return visl_debugfs_bitstream_init(dev);
}

int visl_debugfs_bitstream_init(struct visl_dev *dev)
{
        dev->bitstream_debugfs = debugfs_create_dir("bitstream",
                                                    dev->debugfs_root);
        if (IS_ERR(dev->bitstream_debugfs))
                return PTR_ERR(dev->bitstream_debugfs);

        return 0;
}

void visl_trace_bitstream(struct visl_ctx *ctx, struct visl_run *run)
{
        u8 *vaddr = vb2_plane_vaddr(&run->src->vb2_buf, 0);
        struct visl_blob *blob;
        size_t data_sz = vb2_get_plane_payload(&run->src->vb2_buf, 0);
        struct dentry *dentry;
        char name[32];

        blob = kzalloc_obj(*blob);
        if (!blob)
                return;

        blob->blob.data = vzalloc(data_sz);
        if (!blob->blob.data)
                goto err_vmalloc;

        blob->blob.size = data_sz;
        snprintf(name, 32, "bitstream%d", run->src->sequence);

        memcpy(blob->blob.data, vaddr, data_sz);

        dentry = debugfs_create_blob(name, 0444, ctx->dev->bitstream_debugfs,
                                     &blob->blob);
        if (IS_ERR(dentry))
                goto err_debugfs;

        blob->dentry = dentry;

        mutex_lock(&ctx->dev->bitstream_lock);
        list_add_tail(&blob->list, &ctx->dev->bitstream_blobs);
        mutex_unlock(&ctx->dev->bitstream_lock);

        return;

err_debugfs:
        vfree(blob->blob.data);
err_vmalloc:
        kfree(blob);
}

void visl_debugfs_clear_bitstream(struct visl_dev *dev)
{
        struct visl_blob *blob;
        struct visl_blob *tmp;

        mutex_lock(&dev->bitstream_lock);
        if (list_empty(&dev->bitstream_blobs))
                goto unlock;

        list_for_each_entry_safe(blob, tmp, &dev->bitstream_blobs, list) {
                list_del(&blob->list);
                debugfs_remove(blob->dentry);
                vfree(blob->blob.data);
                kfree(blob);
        }

unlock:
        mutex_unlock(&dev->bitstream_lock);
}

void visl_debugfs_bitstream_deinit(struct visl_dev *dev)
{
        visl_debugfs_clear_bitstream(dev);
        debugfs_remove_recursive(dev->bitstream_debugfs);
        dev->bitstream_debugfs = NULL;
}

void visl_debugfs_deinit(struct visl_dev *dev)
{
        visl_debugfs_bitstream_deinit(dev);
        debugfs_remove_recursive(dev->debugfs_root);
        dev->debugfs_root = NULL;
}