/*
 **********************************************************************
 *     recmgr.c -- Recording manager for emu10k1 driver
 *     Copyright 1999, 2000 Creative Labs, Inc.
 *
 **********************************************************************
 *
 *     Date                 Author          Summary of changes
 *     ----                 ------          ------------------
 *     October 20, 1999     Bertrand Lee    base code release
 *
 **********************************************************************
 *
 *     This program is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License as
 *     published by the Free Software Foundation; either version 2 of
 *     the License, or (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public
 *     License along with this program; if not, write to the Free
 *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *     USA.
 *
 **********************************************************************
 */

#include "hwaccess.h"
#include "recmgr.h"

/****************************************************************************/
/**  Function: recmgrInit                                                  **/
/**                                                                        **/
/**  Input   : rec_ptr - pointer recording object                          **/
/**                                                                        **/
/**  About   : stop recording when init                                    **/
/****************************************************************************/
int recmgrInit(struct record *rec_ptr)
{
	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;

	/* Disable record transfer */
	sblive_writeptr(hw_ptr, ADCBS, 0, ADCBS_BUFSIZE_NONE);
	sblive_writeptr(hw_ptr, ADCCR, 0, 0);

	return CTSTATUS_SUCCESS;
}


/****************************************************************************/
/**  Function: recmgrStartRecord                                           **/
/**                                                                        **/
/**  Input   : rec_ptr - pointer recording object                          **/
/**                                                                        **/
/**  About   : start recording                                             **/
/****************************************************************************/
int recmgrStartRecord(struct record *rec_ptr)
{
	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
	u32 adcsr;


#ifdef RECTEST
	DPD(" data in 0x120 -> %x", sblive_readptr(hw_ptr, FXGPREGBASE + 0x20, 0));
	DPD(" data in 0x121 -> %x", sblive_readptr(hw_ptr, FXGPREGBASE + 0x21, 0));
#endif

	DPD("recmgrStartRecord: base addx: %x", rec_ptr->physaddx >> 12);
	sblive_writeptr(hw_ptr, ADCBA, 0, rec_ptr->physaddx);

	switch (rec_ptr->samplingrate) 
	{
	case 0xBB80: adcsr = ADCCR_SAMPLERATE_48; break;
	case 0xAC44: adcsr = ADCCR_SAMPLERATE_44; break;
	case 0x7D00: adcsr = ADCCR_SAMPLERATE_32; break;
	case 0x5DC0: adcsr = ADCCR_SAMPLERATE_24; break;
	case 0x5622: adcsr = ADCCR_SAMPLERATE_22; break;
	case 0x3E80: adcsr = ADCCR_SAMPLERATE_16; break;
	case 0x2B11: adcsr = ADCCR_SAMPLERATE_11; break;
	case 0x1F40: adcsr = ADCCR_SAMPLERATE_8; break;
	default:
		DPF("Unknown sampling rate!\n");
		return CTSTATUS_ERROR;
	}

	adcsr |= ADCCR_LCHANENABLE;

	if (rec_ptr->is_stereo)
	  adcsr |= ADCCR_RCHANENABLE;

	sblive_writeptr(hw_ptr, ADCCR, 0, adcsr);
	sblive_writeptr(hw_ptr, ADCBS, 0, rec_ptr->bufsizereg);

	return CTSTATUS_SUCCESS;
}


/****************************************************************************/
/**  Function: recmgrStopRecord                                            **/
/**                                                                        **/
/**  Input   : rec_ptr - pointer recording object                          **/
/**                                                                        **/
/**  About   : stop recording                                              **/
/****************************************************************************/
int recmgrStopRecord(struct record *rec_ptr)
{
	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;

	/* Disable record transfer */
	sblive_writeptr(hw_ptr, ADCBS, 0, ADCBS_BUFSIZE_NONE);
	sblive_writeptr(hw_ptr, ADCCR, 0, 0);

	return CTSTATUS_SUCCESS;
}


/****************************************************************************/
/**  Function: recmgrSetControl                                            **/
/**                                                                        **/
/**  Input   : rec_ptr - pointer recording object                          **/
/**            controlid - control ID                                      **/
/**            value - value to set for a specified control                **/
/**                                                                        **/
/**  About   : set recording resource                                      **/
/**                                                                        **/
/**  Note    :                                                             **/
/**                                                                        **/
/**  XD, DMA, WR and RIGHT bits in CCCA register controls the way to       **/
/**  record for 8005.                                                      **/
/**                                                                        **/
/**  XD   DMA    WR    RIGHT                                               **/
/**  1     1     0      0      --- record from external(AC97, SPDIF, MIC)  **/
/**  1     1     1      0      --- record from the output of Emu8000       **/
/**                                effects engine.                         **/
/**                                                                        **/
/****************************************************************************/
int recmgrSetControl(struct record *rec_ptr, u32 controlid, u32 value)
{
	/* FIXME: Implement me! */
	return CTSTATUS_SUCCESS;
}


/****************************************************************************/
/**  Function: recmgrGetPos                                                **/
/**                                                                        **/
/**  Input   : rec_ptr - pointer recording object                          **/
/**            pos -  pointer to position returned                         **/
/**                                                                        **/
/**  About   : get recording position(no. of bytes per channel)            **/
/**                                                                        **/
/**  Formula : (WC*SamplingRate/48kHz)%(record buffer size)                **/
/****************************************************************************/
int recmgrGetPos(struct record *rec_ptr, u32 *pos)
{
	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;

	u32 curidx;

	curidx = recmgrGetRecIdx(hw_ptr);
	if (curidx >= rec_ptr->prevadcidx)
	  *pos = curidx - rec_ptr->prevadcidx;
	else
	  *pos = 0xfffff - (rec_ptr->prevadcidx - curidx);

	*pos = (*pos) * ((u16) rec_ptr->samplingrate) / 48000
	  * 2 * (rec_ptr->is_stereo + 1);

	DPD(" Recmgr: *pos: %x\n", *pos);
	
	if (rec_ptr->pong) 
	  *pos += rec_ptr->recbufsize / 2;

	return CTSTATUS_SUCCESS;
}


u32 recmgrGetRecIdx(struct sblive_hw *sb_hw)
{
	return READ_FN0(sb_hw, WC_SAMPLECOUNTER);
}
