File dmabuf_platform_driver.h

File List > dmabuf > dmabuf_platform_driver.h

Go to the documentation of this file

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __AKOZLINS_DMABUF_PLATFORM_DRIVER_H
#define __AKOZLINS_DMABUF_PLATFORM_DRIVER_H

#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>

#include "dmabuf.h"

struct dmabuf_device {
    int id;
    char* name;
    struct dmabuf* dmabuf;
    struct miscdevice miscdevice;
};

static DEFINE_IDA(dmabuf_ida);

static int dmabuf_fops_open(struct inode* inode, struct file* file) {
    struct dmabuf_device* dmabuf_device;
    struct dmabuf* dmabuf;

    M_INFO("\n");

    dmabuf_device = container_of(file->private_data, struct dmabuf_device, miscdevice);
    if (dmabuf_device == NULL) {
        M_ERR("dmabuf_device == NULL\n");
        return -ENODEV;
    }

    dmabuf = dmabuf_device->dmabuf;
    if (dmabuf == NULL) {
        M_ERR("dmabuf == NULL\n");
        return -ENODEV;
    }

    file->private_data = dmabuf;

    return 0;
}

#include "dmabuf_fops.h"

static int dmabuf_platform_driver_probe(struct platform_device* pdev) {
    int error;
    struct dmabuf_device* dmabuf_device = NULL;

    M_INFO("\n");

    error = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
    if (error != 0) {
        M_ERR("dma_set_mask_and_coherent(mask = DMA_BIT_MASK(64)): error = %d\n", error);
        goto err_out;
    }

    dmabuf_device = kzalloc(sizeof(*dmabuf_device), GFP_KERNEL);
    if (IS_ERR_OR_NULL(dmabuf_device)) {
        error = PTR_ERR(dmabuf_device);
        if (error == 0)
            error = -ENOMEM;
        dmabuf_device = NULL;
        M_ERR("kzalloc(): error = %d\n", error);
        goto err_out;
    }

    dmabuf_device->id = ida_alloc(&dmabuf_ida, GFP_KERNEL);
    if (dmabuf_device->id < 0) {
        error = dmabuf_device->id;
        M_ERR("ida_alloc: error = %d\n", error);
        goto err_out;
    }

    dmabuf_device->name = kasprintf(GFP_KERNEL, "%s%d", THIS_MODULE->name, dmabuf_device->id);
    if (IS_ERR_OR_NULL(dmabuf_device->name)) {
        error = PTR_ERR(dmabuf_device->name);
        if (error == 0)
            error = -ENOMEM;
        dmabuf_device->name = NULL;
        M_ERR("kasprintf(): error = %d\n", error);
        goto err_out;
    }

    dmabuf_device->dmabuf = dmabuf_alloc(&pdev->dev, 1024 * 1024 * 1024);
    if (IS_ERR_OR_NULL(dmabuf_device->dmabuf)) {
        error = PTR_ERR(dmabuf_device->dmabuf);
        M_ERR("dmabuf_alloc(): error = %d\n", error);
        goto err_out;
    }

    dmabuf_device->miscdevice.minor = MISC_DYNAMIC_MINOR;
    dmabuf_device->miscdevice.name = dmabuf_device->name;
    dmabuf_device->miscdevice.fops = &dmabuf_fops;
    dmabuf_device->miscdevice.parent = &pdev->dev;

    error = misc_register(&dmabuf_device->miscdevice);
    if (error != 0) {
        dmabuf_device->miscdevice.minor = MISC_DYNAMIC_MINOR;  // mark not registered
        M_ERR("misc_register(): error = %d\n", error);
        goto err_out;
    }

    platform_set_drvdata(pdev, dmabuf_device);

    return 0;

err_out:
    if (dmabuf_device != NULL) {
        if (dmabuf_device->miscdevice.minor != MISC_DYNAMIC_MINOR)
            misc_deregister(&dmabuf_device->miscdevice);

        dmabuf_free(dmabuf_device->dmabuf);
        if (dmabuf_device->name != NULL)
            kfree(dmabuf_device->name);
        if (dmabuf_device->id >= 0)
            ida_free(&dmabuf_ida, dmabuf_device->id);
        kfree(dmabuf_device);
    }
    return error;
}

static int dmabuf_platform_driver_remove(struct platform_device* pdev) {
    struct dmabuf_device* dmabuf_device = platform_get_drvdata(pdev);
    platform_set_drvdata(pdev, NULL);

    M_INFO("\n");

    if (dmabuf_device != NULL) {
        if (dmabuf_device->miscdevice.minor != MISC_DYNAMIC_MINOR)
            misc_deregister(&dmabuf_device->miscdevice);

        dmabuf_free(dmabuf_device->dmabuf);
        if (dmabuf_device->name != NULL)
            kfree(dmabuf_device->name);
        if (dmabuf_device->id >= 0)
            ida_free(&dmabuf_ida, dmabuf_device->id);
        kfree(dmabuf_device);
    }

    return 0;
}

static struct platform_driver dmabuf_platform_driver = {
    .probe = dmabuf_platform_driver_probe,
    .remove = dmabuf_platform_driver_remove,
    .driver =
        {
            .owner = THIS_MODULE,
            .name = THIS_MODULE->name,
        },
};

#endif  // __AKOZLINS_DMABUF_PLATFORM_DRIVER_H