/*
 * # Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>

#include "gstionallocator.h"
#include "ion_coral.h"

GST_DEBUG_CATEGORY_STATIC (ion_debug);
#define GST_CAT_DEFAULT ion_debug
#define gst_allocator_ion_parent_class parent_class
G_DEFINE_TYPE (GstAllocatorIon, gst_allocator_ion, GST_TYPE_DMABUF_ALLOCATOR);

static void gst_allocator_ion_finalize (GObject * object);
static GstMemory * gst_allocator_ion_alloc (GstAllocator * allocator,
    gsize size,GstAllocationParams * params);

static void
gst_allocator_ion_class_init (GstAllocatorIonClass * klass)
{
  GST_ALLOCATOR_CLASS (klass)->alloc = gst_allocator_ion_alloc;
  G_OBJECT_CLASS (klass)->finalize = gst_allocator_ion_finalize;

  GST_DEBUG_CATEGORY_INIT (ion_debug, "ion", 0,
      "Linux dma-buf allocator based on ION");
}

static void
gst_allocator_ion_init (GstAllocatorIon * ion)
{
  GstAllocator *allocator = GST_ALLOCATOR (ion);

  allocator->mem_type = GST_ALLOCATOR_ION_NAME;

  ion->fd = -1;
  ion->heap_mask = -1;
  g_mutex_init (&ion->mutex);
}

static void
gst_allocator_ion_finalize (GObject * object)
{
  GstAllocatorIon *ion = GST_ALLOCATOR_ION (object);

  if (ion->fd > -1) {
    close (ion->fd);
    ion->fd = -1;
  }
  g_mutex_clear (&ion->mutex);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

gboolean
gst_allocator_ion_init_check (GstAllocatorIon * ion)
{
  int fd, buf_fd, heap_mask, i;
  gboolean success;
  struct ion_heap_query query;
  struct ion_allocation_data alloc_data;
  struct ion_heap_data *heap_data = NULL;

  g_mutex_lock (&ion->mutex);

  fd = 1;
  buf_fd = -1;
  heap_mask = 0;
  success = FALSE;

  if (ion->fd > -1) {
    GST_DEBUG_OBJECT (ion, "Already initialized");
    goto beach;
  }

  GST_DEBUG_OBJECT (ion, "Opening /dev/ion");
  fd = open ("/dev/ion", O_RDWR);
  if (fd == -1) {
    GST_INFO_OBJECT (ion, "ION allocator not supported");
    g_mutex_unlock (&ion->mutex);
    return FALSE;
  }
  GST_DEBUG_OBJECT (ion, "/dev/ion opened with fd=%d", fd);

  memset (&query, 0, sizeof(query));
  if (ioctl (fd, ION_IOC_HEAP_QUERY, &query) < 0) {
    GST_ERROR_OBJECT (ion, "ION_IOC_HEAP_QUERY failed: %d", errno);
    goto beach;
  }

  GST_DEBUG_OBJECT (ion, "ION_IOC_HEAP_QUERY returned %u heaps", query.cnt);
  heap_data = g_malloc0_n (query.cnt, sizeof(*heap_data));
  query.heaps = (uintptr_t) heap_data;
  if (ioctl (fd, ION_IOC_HEAP_QUERY, &query) < 0) {
    GST_ERROR_OBJECT (ion, "ION_IOC_HEAP_QUERY failed: %d", errno);
    goto beach;
  }

  for (i = 0; i < query.cnt; ++i) {
    if (heap_data[i].type == ION_HEAP_TYPE_DMA) {
      heap_mask |= 1 << heap_data[i].heap_id;
    }
  }

  memset (&alloc_data, 0, sizeof(alloc_data));
  alloc_data.len = 42;
  alloc_data.heap_id_mask = heap_mask;
  alloc_data.flags = ION_FLAG_CACHED;

  if (ioctl (fd, ION_IOC_ALLOC, &alloc_data) < 0) {
    GST_ERROR_OBJECT (ion, "ION_IOC_ALLOC failed: %d", errno);
    goto beach;
  }
  buf_fd = alloc_data.fd;

beach:
  success = buf_fd != -1;
  if (success) {
    close (buf_fd);
    ion->fd = fd;
    ion->heap_mask = heap_mask;
    GST_INFO_OBJECT (ion, "ION allocator initialized");
  } else {
    GST_ERROR_OBJECT (ion, "ION allocator initialization failed");
  }

  g_mutex_unlock (&ion->mutex);

  return success;
}



static GstMemory *
gst_allocator_ion_alloc (GstAllocator * allocator, gsize size,
    GstAllocationParams * params)
{
  GstAllocatorIon *ion = GST_ALLOCATOR_ION (allocator);
  struct ion_allocation_data alloc_data = { 0 };

  alloc_data.len = size;
  alloc_data.heap_id_mask = ion->heap_mask;
  alloc_data.flags = ION_FLAG_CACHED;

  if (ioctl (ion->fd, ION_IOC_ALLOC, &alloc_data) < 0) {
    GST_ERROR_OBJECT (ion, "ION_IOC_ALLOC failed: %d", errno);
    return NULL;
  }

  GST_DEBUG_OBJECT (ion, "allocated size %" G_GSIZE_FORMAT " b, fd %d",
      size, alloc_data.fd);
  return gst_dmabuf_allocator_alloc (allocator, alloc_data.fd, size);
}


gboolean gst_allocator_ion_init_check (GstAllocatorIon * ion);