#include "PR/os_internal.h"
#include "PR/ultraerror.h"
#include "PR/rcp.h"
#include "PRinternal/osint.h"

// TODO: this comes from a header
#ident "$Revision: 1.17 $"

/**
 * Submits an audio buffer to be consumed by the Audio DAC. The audio interface can queue a second DMA
 * while another is in progress and automatically begin the next one as soon as the current DMA
 * completes. If there is already a second DMA queued (DMA is full), -1 is returned to indicate the
 * buffer could not be submitted.
 *
 * @param bufPtr Next audio buffer. Must be an 8-byte aligned KSEG0 (0x80XXXXXX) address.
 * @param size Length of next audio buffer in bytes, maximum size 0x40000 bytes / 256 KiB. Should be a
 * multiple of 8.
 * @return 0 if the DMA was enqueued successfully, -1 if the DMA could not yet be queued.
 */
s32 osAiSetNextBuffer(void* bufPtr, u32 size) {
    static u8 hdwrBugFlag = FALSE;
    char* bptr;

#if BUILD_VERSION >= VERSION_J
    if (__osAiDeviceBusy()) {
        return -1;
    }
#endif

#ifdef _DEBUG
    if ((u32)bufPtr & (8 - 1)) {
        __osError(ERR_OSAISETNEXTBUFFER_ADDR, 1, bufPtr);
        return -1;
    }

    if ((u32)size & (8 - 1)) {
        __osError(ERR_OSAISETNEXTBUFFER_SIZE, 1, size);
        return -1;
    }
#endif

    bptr = bufPtr;

    if (hdwrBugFlag) {
        bptr = (u8*)bufPtr - 0x2000;
    }

    if ((((u32)bufPtr + size) & 0x1fff) == 0) {
        hdwrBugFlag = TRUE;
    } else {
        hdwrBugFlag = FALSE;
    }

#if BUILD_VERSION < VERSION_J
    //! @bug The __osAiDeviceBusy call should be above the hardware bug workaround to ensure that it was
    //! only performed when a transfer was guaranteed to start. If this condition passes and this
    //! function returns without submitting a buffer for DMA, the code above will lose track of when to
    //! apply the workaround.
    if (__osAiDeviceBusy()) {
        return -1;
    }
#endif

    IO_WRITE(AI_DRAM_ADDR_REG, osVirtualToPhysical(bptr));
    IO_WRITE(AI_LEN_REG, size);
    return 0;
}
