#include <time.h>
#include "cdswi.h"
#ifndef NULL
#define NULL (void*) 0
#endif

#include "WimpLib:Log.h"

const _kernel_oserror* FCDFS_GetNumberOfDrives(int* drives)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;

	ENTER("CDFS_GetNumberOfDrives");

	*drives = 0;
	if ((e = _kernel_swi(0x061e84, &regs, &regs)) != NULL) RETURN_ERROR(e);
	*drives = regs.r[0];

	RETURN(NULL);
}

const _kernel_oserror* FCDFS_ConvertDriveToDevice(unsigned int drive, sCDControlBlock* pCDBlock)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;

	ENTER("CDFS_ConvertDriveToDevice");

	regs.r[0] = drive;
	regs.r[7] = (int) pCDBlock;
	if ((e = _kernel_swi(0x061e80, &regs, &regs)) != NULL) RETURN_ERROR(e);
	drive = regs.r[1];

	pCDBlock->r[0] = (drive & 0x00000007);
	pCDBlock->r[1] = (drive & 0x00000018) >> 3;
	pCDBlock->r[2] = (drive & 0x000000e0) >> 5;
	pCDBlock->r[3] = (drive & 0x0000ff00) >> 8;
	pCDBlock->r[4] = (drive & 0xffff0000) >> 16;

	RETURN(NULL);
}

const _kernel_oserror* FCD_OpenDrawer(sCDControlBlock* pCDBlock)
{
	_kernel_swi_regs regs;

	ENTER("CD_OpenDrawer");

	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x061247, &regs, &regs));
}

const _kernel_oserror* FCD_EjectButton(sCDControlBlock* pCDBlock, bool enable)
{
	_kernel_swi_regs regs;

	ENTER("CD_EjectButton");

	regs.r[0] = enable;
	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x061248, &regs, &regs));
}

const _kernel_oserror* FCD_EnquireAddress(sCDControlBlock* pCDBlock, int mode, unsigned int* phead)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;

	ENTER("CD_EnquireAddress");

	*phead = 0;
	regs.r[0] = mode;
	regs.r[7] = (int) pCDBlock;
	if ((e = _kernel_swi(0x061249, &regs, &regs)) != NULL) RETURN_ERROR(e);
	*phead = regs.r[0];

	RETURN(NULL);
}

const _kernel_oserror* FCD_PlayAudio(sCDControlBlock* pCDBlock, int mode, unsigned int from, unsigned int to)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;
//	clock_t time;

	ENTER("CD_PlayAudio");

	regs.r[0] = mode;
	regs.r[1] = from;
	regs.r[2] = to;
	regs.r[7] = (int) pCDBlock;
	if ((e = _kernel_swi(0x06124b, &regs, &regs)) != NULL) RETURN_ERROR(e);

	RETURN(NULL);
}

const _kernel_oserror* FCD_PlayTrack(sCDControlBlock* pCDBlock, int first, int last)
{
	_kernel_swi_regs regs;

	ENTER("CD_PlayTrack");

	regs.r[0] = first;
	regs.r[1] = last;
	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x06124c, &regs, &regs));
}

const _kernel_oserror* FCD_AudioPause(sCDControlBlock* pCDBlock, bool on)
{
	_kernel_swi_regs regs;

	ENTER("CD_AudioPause");

	regs.r[0] = on;
	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x06124d, &regs, &regs));
}

const _kernel_oserror* FCD_EnquireTrack(sCDControlBlock* pCDBlock, int track, sCDDiscTrackRange* prange)
{
	_kernel_swi_regs regs;

	ENTER("CD_EnquireTrack");

	regs.r[0] = track;
	regs.r[1] = (int) prange;
	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x06124e, &regs, &regs));
}

const _kernel_oserror* FCD_StopDisc(sCDControlBlock* pCDBlock)
{
	_kernel_swi_regs regs;

	ENTER("CD_StopDisc");

	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x061252, &regs, &regs));
}

const _kernel_oserror* FCD_DiscUsed(sCDControlBlock* pCDBlock, int mode, sCDDiscSize* psize)
{
	_kernel_swi_regs regs;

	ENTER("CD_DiscUsed");

	regs.r[0] = mode;
	regs.r[1] = (int) psize;
	regs.r[7] = (int) pCDBlock;
	RETURN_ERROR(_kernel_swi(0x061253, &regs, &regs));
}

const _kernel_oserror* FCD_AudioStatus(sCDControlBlock* pCDBlock, int* pstatus)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;

	ENTER("CD_AudioStatus");

	regs.r[7] = (int) pCDBlock;
	if ((e = _kernel_swi(0x061254, &regs, &regs)) != NULL) RETURN_ERROR(e);
	*pstatus = regs.r[0];
	RETURN(NULL);
}

// On input *id = nudge size value
const _kernel_oserror* FCD_GetIdentifier(sCDControlBlock* pCDBlock, unsigned long* id, bool bHasData)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;
	char buf[0x0800];
	sCDDiscSize size;

	ENTER("CD_GetIdentifier");

	if ((e = FCD_DiscUsed(pCDBlock, 0, &size)) != NULL) RETURN_ERROR(e);

	if (bHasData)
	{
		regs.r[0] = 0;
		regs.r[1] = 0x010;
		regs.r[2] = 1;
		regs.r[3] = (int) buf;
		regs.r[4] = 0x0800;
		regs.r[7] = (int) pCDBlock;
		if ((e = _kernel_swi(0x061241, &regs, &regs)) == NULL)
		{
			regs.r[0] = 0;
			regs.r[1] = regs.r[3];
			regs.r[2] = regs.r[1] + 0x03c;
			regs.r[3] = 1;
			_kernel_swi(0x02005b, &regs, &regs);
		}
		else regs.r[0] = 0;
	}
	else regs.r[0] = 0;

	*id = (int)(regs.r[0] ^ (size.size + *id));

	RETURN(NULL);
}

const _kernel_oserror* FCD_GetAudioParams(sCDControlBlock* pCDBlock, int* volumes)
{
	_kernel_swi_regs regs;
	const _kernel_oserror* e;

	ENTER("CD_GetAudioParams");

	regs.r[0] = 0;
	regs.r[1] = (int) volumes;
	regs.r[2] = 8;
	regs.r[7] = (int) pCDBlock;

	if ((e = _kernel_swi(0x061269, &regs, &regs)) != NULL)
		volumes[0] = volumes[1] = 0xffff;

	RETURN_ERROR(e);
}

const _kernel_oserror* FCD_SetAudioParams(sCDControlBlock* pCDBlock, int* volumes)
{
	_kernel_swi_regs regs;

	ENTER("CD_SetAudioParams");

	regs.r[0] = 0;
	regs.r[1] = (int) volumes;
	regs.r[2] = 8;
	regs.r[7] = (int) pCDBlock;

	RETURN_ERROR(_kernel_swi(0x06126a, &regs, &regs));
}
