/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

File: oct6100_debug.c

    Copyright (c) 2001-2008 Octasic Inc.
    
Description: 

	This file contains functions used to debug the OCT6100.

This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API  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.

The OCT6100 GPL API 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 the OCT6100 GPL API; if not, write to the Free Software 
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.

$Octasic_Release: OCT612xAPI-01.01.01 $

$Octasic_Revision: 66 $

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/


/*****************************  INCLUDE FILES  *******************************/

#include "octdef.h"

#include "oct6100api/oct6100_defines.h"
#include "oct6100api/oct6100_errors.h"
#include "oct6100api/oct6100_apiud.h"

#include "oct6100api/oct6100_apiud.h"
#include "oct6100api/oct6100_tlv_inst.h"
#include "oct6100api/oct6100_chip_open_inst.h"
#include "oct6100api/oct6100_chip_stats_inst.h"
#include "oct6100api/oct6100_interrupts_inst.h"
#include "oct6100api/oct6100_remote_debug_inst.h"
#include "oct6100api/oct6100_debug_inst.h"
#include "oct6100api/oct6100_api_inst.h"
#include "oct6100api/oct6100_channel_inst.h"

#include "oct6100api/oct6100_interrupts_pub.h"
#include "oct6100api/oct6100_chip_open_pub.h"
#include "oct6100api/oct6100_channel_pub.h"
#include "oct6100api/oct6100_debug_pub.h"

#include "oct6100_chip_open_priv.h"
#include "oct6100_channel_priv.h"
#include "oct6100_miscellaneous_priv.h"
#include "oct6100_memory_priv.h"
#include "oct6100_debug_priv.h"
#include "oct6100_version.h"


/****************************  PUBLIC FUNCTIONS  ****************************/


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100DebugSelectChannel

Description:    This function sets the current debug channel.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pSelectDebugChan		Pointer to select debug channel structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100DebugSelectChannelDef(
				tPOCT6100_DEBUG_SELECT_CHANNEL	f_pSelectDebugChan )
{
	f_pSelectDebugChan->ulChannelHndl = cOCT6100_INVALID_VALUE;

	return cOCT6100_ERR_OK;
}

UINT32 Oct6100DebugSelectChannel(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_DEBUG_SELECT_CHANNEL	f_pSelectDebugChan )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100DebugSelectChannelSer( f_pApiInstance, f_pSelectDebugChan, TRUE );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100DebugGetData

Description:    This function retrieves the last recorded debug data.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pGetData				Pointer to debug get data structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100DebugGetDataDef(
				tPOCT6100_DEBUG_GET_DATA			f_pGetData )
{
	f_pGetData->ulGetDataMode = cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE;
	f_pGetData->ulGetDataContent = cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE;
	f_pGetData->ulRemainingNumBytes = cOCT6100_INVALID_VALUE;
	f_pGetData->ulTotalNumBytes = cOCT6100_INVALID_VALUE;
	f_pGetData->ulMaxBytes = cOCT6100_INVALID_VALUE;
	f_pGetData->ulValidNumBytes = cOCT6100_INVALID_VALUE;
	f_pGetData->pbyData = NULL;
	
	return cOCT6100_ERR_OK;
}

UINT32 Oct6100DebugGetData(
				tPOCT6100_INSTANCE_API				f_pApiInstance,
				tPOCT6100_DEBUG_GET_DATA			f_pGetData )
{
	tOCT6100_SEIZE_SERIALIZE_OBJECT		SeizeSerObj;
	tOCT6100_RELEASE_SERIALIZE_OBJECT	ReleaseSerObj;
	UINT32								ulSerRes = cOCT6100_ERR_OK;
	UINT32								ulFncRes = cOCT6100_ERR_OK;

	/* Set the process context of the serialize structure. */
	SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext;
	ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext;

	/* Seize all list semaphores needed by this function. */
	SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY;
	ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj );
	if ( ulSerRes == cOCT6100_ERR_OK )
	{
		/* Call the serialized function. */
		ulFncRes = Oct6100DebugGetDataSer( f_pApiInstance, f_pGetData );
	}
	else
	{
		return ulSerRes;
	}

	/* Release the seized semaphores. */
	ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj;
	ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj );

	/* If an error occured then return the error code. */
	if ( ulSerRes != cOCT6100_ERR_OK )
		return ulSerRes;
	if ( ulFncRes != cOCT6100_ERR_OK )
		return ulFncRes;

	return cOCT6100_ERR_OK;
}


/****************************  PRIVATE FUNCTIONS  ****************************/

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100DebugSelectChannelSer

Description:	This function sets the debug channel.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance				Pointer to API instance. This memory is used to keep the
							present state of the chip and all its resources.

f_pSelectDebugChan			Pointer to a tOCT6100_DEBUG_SELECT_CHANNEL structure.
f_fCheckChannelRecording	Check if channel recording is enabled or not.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100DebugSelectChannelSer(
				IN OUT	tPOCT6100_INSTANCE_API					f_pApiInstance,
				IN		tPOCT6100_DEBUG_SELECT_CHANNEL			f_pSelectDebugChan,
				IN		BOOL									f_fCheckChannelRecording )
{
	tPOCT6100_SHARED_INFO		pSharedInfo;
	tPOCT6100_API_CHANNEL		pChanEntry = NULL;
	tPOCT6100_API_CHANNEL		pTempChanEntry;
	tOCT6100_CHANNEL_OPEN		TempChanOpen;
	tOCT6100_WRITE_BURST_PARAMS	BurstParams;
	UINT16						usChanIndex = 0;
	UINT32						ulEntryOpenCnt;
	UINT16						ausWriteData[ 2 ];
	UINT32						ulResult;
	
	/* Get local pointer(s). */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	BurstParams.pProcessContext = f_pApiInstance->pProcessContext;

	BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;
	BurstParams.pusWriteData = ausWriteData;

	/* First release the resources reserved for the channel that was previously debugged. */
	if ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex != cOCT6100_INVALID_INDEX &&
		 pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE )
	{
		/*=======================================================================*/
		/* Get a pointer to the channel's list entry. */

		mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pTempChanEntry, pSharedInfo->DebugInfo.usCurrentDebugChanIndex  )

		/* Release the extra TSI memory entry and reprogram the TSST control memory if required. */
		if ( pTempChanEntry->usExtraSinTsiDependencyCnt >= 1 )
		{
			/*=======================================================================*/
			/* Clear memcpy operations. */

			BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			BurstParams.ulWriteLength = 2;

			ausWriteData[ 0 ] = cOCT6100_MIXER_CONTROL_MEM_NO_OP;
			ausWriteData[ 1 ] = 0x0;

			mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordSinEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );

			mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/*=======================================================================*/

			/* If we are the last dependency using the extra Sin TSI, release it */
			if ( pTempChanEntry->usExtraSinTsiDependencyCnt == 1 )
			{
				ulResult = Oct6100ApiReleaseTsiMemEntry( f_pApiInstance, pTempChanEntry->usExtraSinTsiMemIndex );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/* Do not forget to reprogram the TSST control memory. */
				if ( pTempChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
				{
					ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																	  pTempChanEntry->usSinTsstIndex,
																	  pTempChanEntry->usSinSoutTsiMemIndex,
																	  pTempChanEntry->TdmConfig.bySinPcmLaw );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}
				pTempChanEntry->usExtraSinTsiMemIndex = cOCT6100_INVALID_INDEX;

				/* XXX: What about the silence TSI usSinSilenceEventIndex ?? */
			}

			pTempChanEntry->usExtraSinTsiDependencyCnt--;
			
		}
	}

	/* Set the new parameters. */
	if ( f_pSelectDebugChan->ulChannelHndl != cOCT6100_INVALID_HANDLE )
	{
		/* Check the provided handle. */
		if ( (f_pSelectDebugChan->ulChannelHndl & cOCT6100_HNDL_TAG_MASK) != cOCT6100_HNDL_TAG_CHANNEL )
			return cOCT6100_ERR_DEBUG_CHANNEL_INVALID_HANDLE;

		usChanIndex = (UINT16)( f_pSelectDebugChan->ulChannelHndl & cOCT6100_HNDL_INDEX_MASK );
		if ( usChanIndex >= pSharedInfo->ChipConfig.usMaxChannels )
			return cOCT6100_ERR_DEBUG_CHANNEL_INVALID_HANDLE;

		if ( f_fCheckChannelRecording == TRUE )
		{
			if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE )
				return cOCT6100_ERR_DEBUG_CHANNEL_RECORDING_DISABLED;
		}

		/*=======================================================================*/
		/* Get a pointer to the channel's list entry. */

		mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, usChanIndex );

		/* Extract the entry open count from the provided handle. */
		ulEntryOpenCnt = ( f_pSelectDebugChan->ulChannelHndl >> cOCT6100_ENTRY_OPEN_CNT_SHIFT) & cOCT6100_ENTRY_OPEN_CNT_MASK;

		/* Check for errors. */
		if ( pChanEntry->fReserved != TRUE )
			return cOCT6100_ERR_CHANNEL_NOT_OPEN;
		if ( ulEntryOpenCnt != pChanEntry->byEntryOpenCnt )
			return cOCT6100_ERR_CHANNEL_INVALID_HANDLE;
		
		/*=======================================================================*/

		/* First program the mixer entry if the user wants to record. */
		/* Check if the API needs to reserve an extra TSI memory to load the SIN signal. */
		if ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE )
		{
			/* Reserve the extra Sin TSI memory if it was not already reserved. */
			if ( pChanEntry->usExtraSinTsiMemIndex == cOCT6100_INVALID_INDEX )
			{
				ulResult = Oct6100ApiReserveTsiMemEntry( f_pApiInstance, &pChanEntry->usExtraSinTsiMemIndex );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/* Reprogram the TSST control memory accordingly. */
				if ( pChanEntry->usSinTsstIndex != cOCT6100_INVALID_INDEX )
				{
					ulResult = Oct6100ApiWriteInputTsstControlMemory( f_pApiInstance,
																	  pChanEntry->usSinTsstIndex,
																	  pChanEntry->usExtraSinTsiMemIndex,
																	  pChanEntry->TdmConfig.bySinPcmLaw );
					if ( ulResult != cOCT6100_ERR_OK )
						return ulResult;
				}

				/* XXX: What about the silence TSI usSinSilenceEventIndex ?? */
			}
		
			
			/*=======================================================================*/
			/* Program the Sout Copy event. */
			BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordCopyEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			BurstParams.ulWriteLength = 2;

			ausWriteData[ 0 ]  = cOCT6100_MIXER_CONTROL_MEM_COPY;
			ausWriteData[ 0 ] |= pChanEntry->usSinSoutTsiMemIndex;
			ausWriteData[ 0 ] |= pChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			ausWriteData[ 1 ]  = (UINT16)( pSharedInfo->DebugInfo.usRecordRinRoutTsiMemIndex );

			mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
			/*=======================================================================*/

			/*=======================================================================*/
			/* Program the Sin copy event. */
			BurstParams.ulWriteAddress = cOCT6100_MIXER_CONTROL_MEM_BASE + ( pSharedInfo->MixerInfo.usRecordSinEventIndex * cOCT6100_MIXER_CONTROL_MEM_ENTRY_SIZE );
			BurstParams.ulWriteLength = 2;

			ausWriteData[ 0 ]  = cOCT6100_MIXER_CONTROL_MEM_COPY;
			ausWriteData[ 0 ] |= pChanEntry->usExtraSinTsiMemIndex;
			ausWriteData[ 0 ] |= pChanEntry->TdmConfig.bySinPcmLaw << cOCT6100_MIXER_CONTROL_MEM_LAW_OFFSET;
			ausWriteData[ 1 ]  = pChanEntry->usSinSoutTsiMemIndex;

			mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;
			/*=======================================================================*/

			pChanEntry->usExtraSinTsiDependencyCnt++;
		}
	}
	else
	{
		/* Set the index to invalid to deactivate the recording. */
		usChanIndex = cOCT6100_INVALID_INDEX;
	}

	/* Set law of newly selected hot channel. */
	if ( ( pSharedInfo->ChipConfig.fEnableChannelRecording == TRUE ) 
		&& ( f_pSelectDebugChan->ulChannelHndl != cOCT6100_INVALID_HANDLE )
		&& ( pChanEntry != NULL ) )
	{
		/* Set the PCM law of the debug channel. */
		/* Let's program the channel memory. */
		Oct6100ChannelOpenDef( &TempChanOpen );
		
		TempChanOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_HT_RESET;	/* Activate the channel. */
		TempChanOpen.VqeConfig.fEnableNlp = FALSE;
		TempChanOpen.VqeConfig.ulComfortNoiseMode = cOCT6100_COMFORT_NOISE_NORMAL;
		TempChanOpen.VqeConfig.fSinDcOffsetRemoval = FALSE;
		TempChanOpen.VqeConfig.fRinDcOffsetRemoval = FALSE;
		TempChanOpen.VqeConfig.lDefaultErlDb = 0;

		/* Use the law of the channel being recorded. */
		TempChanOpen.TdmConfig.ulRinPcmLaw = pChanEntry->TdmConfig.byRinPcmLaw;
		TempChanOpen.TdmConfig.ulSinPcmLaw = pChanEntry->TdmConfig.bySinPcmLaw;
		TempChanOpen.TdmConfig.ulRoutPcmLaw = pChanEntry->TdmConfig.byRoutPcmLaw;
		TempChanOpen.TdmConfig.ulSoutPcmLaw = pChanEntry->TdmConfig.bySoutPcmLaw;

		ulResult = Oct6100ApiWriteDebugChanMemory( f_pApiInstance,
											  &TempChanOpen.TdmConfig,
											  &TempChanOpen.VqeConfig,
											  &TempChanOpen,
											  pSharedInfo->DebugInfo.usRecordChanIndex,
											  pSharedInfo->DebugInfo.usRecordMemIndex,
											  pSharedInfo->DebugInfo.usRecordRinRoutTsiMemIndex,
											  pSharedInfo->DebugInfo.usRecordSinSoutTsiMemIndex );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;
	}		

	ausWriteData[ 0 ] = 0x0;
	ausWriteData[ 1 ] = (UINT16)(( usChanIndex >>  0) & 0xFFFF);

	/* Write the channel number into the Matrix hot channel field.*/
	BurstParams.ulWriteAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress;
	BurstParams.pusWriteData = ausWriteData;
	BurstParams.ulWriteLength = 2;

	mOCT6100_DRIVER_WRITE_BURST_API( BurstParams, ulResult );
	if ( ulResult != cOCT6100_ERR_OK )
		return ulResult;

	pSharedInfo->DebugInfo.usCurrentDebugChanIndex = usChanIndex;

	/* Cancel data dump request, if there was one. */
	pSharedInfo->DebugInfo.fDebugDataBeingDumped = FALSE;
	pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes = cOCT6100_INVALID_VALUE;

	/* Call from remote client. */
	if ( f_fCheckChannelRecording == FALSE )
	{
		/* If the user has not activated recording, let the remote client know. */
		if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE )
			return cOCT6100_ERR_DEBUG_RC_CHANNEL_RECORDING_DISABLED;
	}
		
	return cOCT6100_ERR_OK;
}


/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\

Function:		Oct6100DebugGetDataSer

Description:	This function retrieves the latest recorded debug data.

-------------------------------------------------------------------------------
|	Argument		|	Description
-------------------------------------------------------------------------------
f_pApiInstance			Pointer to API instance. This memory is used to keep the
						present state of the chip and all its resources.

f_pGetData				Pointer to a tOCT6100_DEBUG_GET_DATA structure.

\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
UINT32 Oct6100DebugGetDataSer(
				IN OUT	tPOCT6100_INSTANCE_API				f_pApiInstance,
				IN OUT	tPOCT6100_DEBUG_GET_DATA			f_pGetData )
{

	tPOCT6100_SHARED_INFO		pSharedInfo;
	tPOCT6100_API_CHANNEL		pChanEntry = NULL;
	tOCT6100_READ_PARAMS		ReadParams;
	tOCT6100_WRITE_PARAMS		WriteParams;
	tOCT6100_READ_BURST_PARAMS	ReadBurstParams;
	tOCT6100_WRITE_BURST_PARAMS	WriteBurstParams;

	UINT16	ausWriteData[ 2 ];
	UINT16	usReadData;
	UINT16	usDebugEventReadPtr;
	UINT16	usTempNumEvents;

	UINT32	ulResult;
	UINT32	ulToneEventIndex;
	UINT32	ulReadPointer;
	UINT32	ulUserBufWriteIndex = 0;
	UINT32	ulTimestamp;
	UINT32	ulDebugEventIndex = 0;
	UINT32	ulStreamIndex;
	UINT32	ulPcmSampleIndex;
	UINT32	ulNumAfEvents;
	UINT32	ulNumReads = 0;
	UINT32	ulTempIndex;
	UINT32	ulCopyIndex;
	UINT32	ulFeatureBytesOffset;
	UINT32	ulFeatureBitOffset;
	UINT32	ulFeatureFieldLength;
	UINT32	ulStreamIndexMin;
	UINT32	ulStreamIndexMax;
	UINT32	ulTempData;
	UINT32	ulMask;
	UINT32	ulDiff;
	UINT32	ulLastTimestamp = 0;
	BOOL	fResetRemainingDataFlag = FALSE;
	
	/* Get local pointer(s). */
	pSharedInfo = f_pApiInstance->pSharedInfo;

	ReadBurstParams.pProcessContext = f_pApiInstance->pProcessContext;

	ReadBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	ReadParams.pProcessContext = f_pApiInstance->pProcessContext;

	ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	WriteBurstParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteBurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	WriteParams.pProcessContext = f_pApiInstance->pProcessContext;

	WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId;

	/* Check all user parameters. */

	/* Check if channel recording is enabled. */
	if ( pSharedInfo->ChipConfig.fEnableChannelRecording == FALSE )
		return cOCT6100_ERR_DEBUG_CHANNEL_RECORDING_DISABLED;

	/* Check if a current debugging channel has been selected. */
	/* If not, the user has not yet called Oct6100DebugSelectChannel. */
	if ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex == cOCT6100_INVALID_INDEX )
		return cOCT6100_ERR_DEBUG_RECORD_NO_CHAN_SELECTED;

	/* Check that the user supplied a valid max bytes value. */
	if ( f_pGetData->ulMaxBytes == cOCT6100_INVALID_VALUE )
		return cOCT6100_ERR_DEBUG_GET_DATA_MAX_BYTES;

	/* Data buffer must be aligned on 1024 bytes. */
	if ( ( f_pGetData->ulMaxBytes % 1024 ) != 0 )
		return cOCT6100_ERR_DEBUG_GET_DATA_MAX_BYTES;

	/* Check that the user provided the required memory to transfer the information. */
	if ( f_pGetData->pbyData == NULL )
		return cOCT6100_ERR_DEBUG_GET_DATA_PTR_INVALID;

	/* Check dump type. */
	if ( ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE )
		&& ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE )
		&& ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_16S )
		&& ( f_pGetData->ulGetDataMode != cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
		return cOCT6100_ERR_DEBUG_GET_DATA_MODE;

	/* Check dump content. */
	if ( ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
		&& ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM )
		&& ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM )
		&& ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM ) )
		return cOCT6100_ERR_DEBUG_GET_DATA_CONTENT;

	/* Check if can accomodate the 120 seconds dump. */
	if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE )
		|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
	{
		if ( pSharedInfo->DebugInfo.ulDebugEventSize != 0x100 )
			return cOCT6100_ERR_NOT_SUPPORTED_DEBUG_DATA_MODE_120S;
	}

	mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pChanEntry, pSharedInfo->DebugInfo.usCurrentDebugChanIndex )

	/* Lets go dump the requested data. */

	usDebugEventReadPtr = 0;

	/* Check if this is the first time this function is called since the hot channel was set. */
	if ( pSharedInfo->DebugInfo.fDebugDataBeingDumped == FALSE )
	{
		/* Check that the channel is not in POWER_DOWN.  When the channel is in POWER_DOWN, */
		/* the debug events are not recorded correctly in external memory. */
		if ( pChanEntry->byEchoOperationMode == cOCT6100_ECHO_OP_MODE_POWER_DOWN )
			return cOCT6100_ERR_DEBUG_CHANNEL_IN_POWER_DOWN;
		
		pSharedInfo->DebugInfo.fDebugDataBeingDumped = TRUE;
		
		/* Flag the hot channel that it must stop recording.  The data is being transfered. */
		/* This also tells the remote client not to do anything right now. */

		ReadBurstParams.ulReadAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress;
		ReadBurstParams.ulReadLength = 2;
		ReadBurstParams.pusReadData = pSharedInfo->DebugInfo.ausHotChannelData;

		mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		WriteBurstParams.pusWriteData = ausWriteData;
		WriteBurstParams.ulWriteAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress;
		WriteBurstParams.ulWriteLength = 2;

		WriteBurstParams.pusWriteData[ 0 ] = 0xFFFF;
		WriteBurstParams.pusWriteData[ 1 ] = 0xFFFF;

		mOCT6100_DRIVER_WRITE_BURST_API( WriteBurstParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		/* Get the maximum number of events this firmware supports from the TLVs. */
		pSharedInfo->DebugInfo.usMatrixCBMask = (UINT16)( pSharedInfo->DebugInfo.ulDebugEventSize & 0xFFFF );
		pSharedInfo->DebugInfo.usMatrixCBMask -= 1;

		/* Find out the chip log write pointer. */

		/* Now get the current write pointer for matrix events. */
		ReadParams.pusReadData = &pSharedInfo->DebugInfo.usChipDebugEventWritePtr;
		ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixWpBaseAddress + 2;

		mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		ReadParams.pusReadData = &usReadData;
		
		/* This write pointer might have wrapped, but we don't know for sure.  */
		/* To be confident, the chip frame timestamp is read. */
		ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixTimestampBaseAddress;

		mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		ulTimestamp = usReadData << 16;

		ReadParams.ulReadAddress += 2;

		mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
		if ( ulResult != cOCT6100_ERR_OK )
			return ulResult;

		ulTimestamp |= usReadData;

		ulTimestamp >>= 12;  /* TDM time for 1 event (512 ms) */

		/* There is a probability here (once very 6.2 days) that the timestamp is close */
		/* to 0, because it has wrapped.  But still, we need a way to workaround the highly */
		/* occuring case of the chip just being opened. This will fix this problem. */
		if ( ulTimestamp < (UINT32)( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) )
		{
			if ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr >= 2 )
			{
				/* Must trash the first 2 events.  The chip is not yet ready. */
				pSharedInfo->DebugInfo.usNumEvents = (UINT16)( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - 2 );
			}
			else
			{
				pSharedInfo->DebugInfo.usNumEvents = 0x0;
			}
		}
		else
		{
			pSharedInfo->DebugInfo.usNumEvents = (UINT16)( pSharedInfo->DebugInfo.usMatrixCBMask + 1 );

			/* Account for event being created right now while the chip is running. */
			/* The event at the write pointer will be discarded. */
			if ( pSharedInfo->DebugInfo.usNumEvents > 0 )
				pSharedInfo->DebugInfo.usNumEvents--;
		}


		/* If the user only requested the last 16 seconds, cap the number of events. */
		if ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S
			|| f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE )
		{
			/* x events to get the last 16 seconds. */
			if ( pSharedInfo->DebugInfo.usNumEvents > ( 16000 / ( pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize / 8 ) ) )
				pSharedInfo->DebugInfo.usNumEvents = (UINT16)( ( 16000 / ( pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize / 8 ) ) & 0xFFFF );
		}

		/* Make sure that all the events are pertaining to the current hot channel. */
		/* Calculate the event read pointer. */
		ulReadPointer = ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - pSharedInfo->DebugInfo.usNumEvents ) & pSharedInfo->DebugInfo.usMatrixCBMask ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize;
		ulReadPointer %= ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize );

		/* Travel through the events and throw away the bad events. */
		usTempNumEvents = pSharedInfo->DebugInfo.usNumEvents;
		pSharedInfo->DebugInfo.usNumEvents = 0;
		for ( ulDebugEventIndex = 0; ulDebugEventIndex < usTempNumEvents; ulDebugEventIndex ++ )
		{
			/* The HOT channel index for the event is stored at offset 0xF2 (word offset) */

			ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ulReadPointer;
			ReadParams.ulReadAddress += 0xF2 * sizeof(UINT16);
			ReadParams.pusReadData = &usReadData;

			mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			/* Check if the current debug index is the same as the one found in the event. */
			if ( usReadData != pSharedInfo->DebugInfo.usCurrentDebugChanIndex )
				pSharedInfo->DebugInfo.usNumEvents = 0; /* As soon as we hit another channel, we reset the number of valid events. */
			else
				pSharedInfo->DebugInfo.usNumEvents++;

			/* If this event was valid.. */
			if ( pSharedInfo->DebugInfo.usNumEvents != 0 )
			{
				/* The HOT channel timestamp for the event is stored at offset 0x0 (word offset) */
				ReadBurstParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ulReadPointer;
				ReadBurstParams.ulReadLength = 2;
				ReadBurstParams.pusReadData = ausWriteData;

				mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/* Recreate timestamp at the time of the event. */
				ulTimestamp = ( ausWriteData[ 0 ] << 16 );
				ulTimestamp |= ausWriteData[ 1 ];

				/* TDM time for 1 event (512 ms) */
				ulTimestamp = ( ulTimestamp >> 12 );
				ulDiff = ulTimestamp - ulLastTimestamp;

				/* Check if difference makes some sense. */
				if ( pSharedInfo->DebugInfo.usNumEvents > 1 )
				{
					/* Check if the current timestamp is one less then the previous one. */
					if ( ulDiff != 1 )
					{
						pSharedInfo->DebugInfo.usNumEvents = 0; /* If it is not a difference of 1, throw this event. */
					}
					ulLastTimestamp = ulTimestamp;
				}
				else
				{
					ulLastTimestamp = ulTimestamp;
				}
			}

			/* Increment read pointer to get next event. */
			ulReadPointer = ( ulReadPointer + pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ) % ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize );
		}

		/* In heavy mode, the AF log pointer is retrieved. */
		if ( ( pSharedInfo->DebugInfo.usNumEvents >= 2 )
			&& ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S )
				|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) ) )
		{
			/* The latest AF log write pointer is at the latest matrix event. */
			ReadParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr  & pSharedInfo->DebugInfo.usMatrixCBMask ) * 1024 );

			/* To get the AF log write pointer, which is at offset pSharedInfo->ImageInfo.ulAfWritePtrByteOffset. */
			ReadParams.ulReadAddress += pSharedInfo->DebugInfo.ulAfWritePtrByteOffset;
			mOCT6100_DRIVER_READ_API( ReadParams, ulResult );
			if ( ulResult != cOCT6100_ERR_OK )
				return ulResult;

			pSharedInfo->DebugInfo.usAfLogWritePtr = usReadData;

			/* The AF event read pointer is the AF write pointer +4096 */
			/* This will make sure we do not get mixed up and fetch events that have */
			/* just been written, but we think are old. */

			/* To get the exact AF log pointer, the API would have to wait 512 milliseconds to make */
			/* sure logging had stopped.  This is not required since missing a few last events is not */
			/* important at this point (the user knows that valid data has already been recorded). */
			pSharedInfo->DebugInfo.usLastAfLogReadPtr = (UINT16)( ( pSharedInfo->DebugInfo.usAfLogWritePtr + 4096 ) & 0xFFFF );

			/* Note that if the chip has just been booted, some of the AF events might not be initialized. */
		}
		else
		{
			pSharedInfo->DebugInfo.usLastAfLogReadPtr = 0;
			pSharedInfo->DebugInfo.usAfLogWritePtr = 0;
		}

		/* To be aligned correctly for the bursts. */
		while ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) != 0 )
			pSharedInfo->DebugInfo.usLastAfLogReadPtr++;

		/* Remember the data mode for later checks.  Also, the user cannot change this "mode". */
		pSharedInfo->DebugInfo.ulCurrentGetDataMode = f_pGetData->ulGetDataMode;
	}
	else
	{
		/* Check that the user did not change the current data mode. */
		if ( pSharedInfo->DebugInfo.ulCurrentGetDataMode != f_pGetData->ulGetDataMode )
			return cOCT6100_ERR_DEBUG_GET_DATA_MODE_CANNOT_CHANGE;
	}

	/* Check if this is the first pass here. */
	if ( pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes == cOCT6100_INVALID_VALUE )
	{
		/* Calculate how many bytes of data will be returned with respect to the selected data content. */
		
		/* Check what content type the user requested.  */
		if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
		{
			/* Remember first AF Event Read Pointer. */
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr ) & 0xFF );
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr >> 8 ) & 0xFF );

			/* Remember the AF Event Write Pointer. */
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usAfLogWritePtr ) & 0xFF );
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usAfLogWritePtr >> 8 ) & 0xFF );

			/* Remember law and hot channel */
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( pChanEntry->TdmConfig.bySinPcmLaw | ( ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex >> 2 ) & 0xFE ) );
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( pChanEntry->TdmConfig.bySoutPcmLaw );

			/* Insert light or heavy mode in array. */
			if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S_LITE )
				|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S_LITE ) )
			{
				f_pGetData->pbyData[ ulUserBufWriteIndex - 1 ] |= 0x80;
			}
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( pChanEntry->TdmConfig.byRinPcmLaw | ( ( pSharedInfo->DebugInfo.usCurrentDebugChanIndex & 0x1F ) << 3 ) );

			/* Remember usNumEvents */
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usNumEvents ) & 0xFF );
			f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->DebugInfo.usNumEvents >> 8 ) & 0xFF );
		}
		
		/* Last indexes set to '0'! */
		pSharedInfo->DebugInfo.usLastDebugEventIndex = 0;
		pSharedInfo->DebugInfo.ulLastPcmSampleIndex = 0;

		/* No tone event has been retrieved. */
		pSharedInfo->DebugInfo.usLastToneEventIndex = 0;

		/* The version strings have not yet been copied. */
		pSharedInfo->DebugInfo.fImageVersionCopied = FALSE;
		pSharedInfo->DebugInfo.fApiVersionCopied = FALSE;

		/* Estimate the total size of the buffer that will be returned. */
		f_pGetData->ulTotalNumBytes = ulUserBufWriteIndex;

		/* If the full content is requested, add all the debug data. */
		if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
		{
			/* Add the matrix events. */
			if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S )
				|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
			{
				/* Heavy mode!  Grab everything! */
				f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize;
			}
			else
			{
				/* Lite mode!  Only the most important stuff. */
				f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize;
			}

			/* Add the PCM samples. */
			f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize * 3;

			/* If requested, add the AF log events. */
			if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S )
				|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
			{
				f_pGetData->ulTotalNumBytes += (UINT32)( ( pSharedInfo->DebugInfo.usAfLogWritePtr - pSharedInfo->DebugInfo.usLastAfLogReadPtr ) & 0xFFFF ) * 16;
			}

			/* Add the tone events strings. */
			f_pGetData->ulTotalNumBytes += cOCT6100_TLV_MAX_TONE_NAME_SIZE * pSharedInfo->ImageInfo.byNumToneDetectors;

			/* Add the image version string. */
			f_pGetData->ulTotalNumBytes += 512;

			/* Add the API version string. */
			f_pGetData->ulTotalNumBytes += sizeof( cOCT6100_API_VERSION );
		}
		else /* if ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) */
		{
			/* Add one PCM stream. */
			f_pGetData->ulTotalNumBytes += pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize;
		}

		/* Save this in the instance for further calls. */
		pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes = f_pGetData->ulTotalNumBytes;

		/* Calculate remaining bytes.  All the bytes for now! */
		f_pGetData->ulRemainingNumBytes = f_pGetData->ulTotalNumBytes;

		/* Save this in the instance for the next calls. */
		pSharedInfo->DebugInfo.ulDebugDataRemainingNumBytes = f_pGetData->ulRemainingNumBytes;
	}
	else
	{
		f_pGetData->ulTotalNumBytes = pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes;
	}

	/* Calculate the event read pointer. */
	ulReadPointer = ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - pSharedInfo->DebugInfo.usNumEvents ) & pSharedInfo->DebugInfo.usMatrixCBMask ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize;

	ulReadPointer += pSharedInfo->DebugInfo.ulDebugChanStatsByteSize * pSharedInfo->DebugInfo.usLastDebugEventIndex;
	ulReadPointer %= ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize );

	if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
	{
		/* Copy the debug events in the user buffer. */
		for( ulDebugEventIndex = pSharedInfo->DebugInfo.usLastDebugEventIndex; ulDebugEventIndex < pSharedInfo->DebugInfo.usNumEvents; ulDebugEventIndex ++ )
		{
			ReadBurstParams.ulReadAddress = pSharedInfo->DebugInfo.ulMatrixBaseAddress + ulReadPointer;

			/* Check if we are in light or heavy mode.  The burst size is not the same. */
			if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S )
				|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
			{
				if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= pSharedInfo->DebugInfo.ulDebugChanStatsByteSize )
					ulNumReads = pSharedInfo->DebugInfo.ulDebugChanStatsByteSize / 2;
				else
					break;
			}
			else
			{
				if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize )
					ulNumReads = pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize / 2;
				else
					break;
			}

			ulTempIndex = 0;
			while ( ulNumReads != 0 )
			{
				if ( ulNumReads >= pSharedInfo->ChipConfig.usMaxRwAccesses )
					ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses;
				else
					ReadBurstParams.ulReadLength = ulNumReads;

				/* Set pointer where to write data. */
				ReadBurstParams.pusReadData = pSharedInfo->MiscVars.ausSuperArray;

				mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult );
				if ( ulResult != cOCT6100_ERR_OK )
					return ulResult;

				/* Copy data byte per byte to avoid endianess problems. */
				for ( ulCopyIndex = 0; ulCopyIndex < ReadBurstParams.ulReadLength; ulCopyIndex ++ )
				{
					f_pGetData->pbyData[ ulUserBufWriteIndex + ulTempIndex + ( 2 * ulCopyIndex ) ] = (UINT8)( ReadBurstParams.pusReadData[ ulCopyIndex ] & 0xFF );
					f_pGetData->pbyData[ ulUserBufWriteIndex + ulTempIndex + ( 2 * ulCopyIndex ) + 1 ] = (UINT8)( ( ReadBurstParams.pusReadData[ ulCopyIndex ] >> 8 ) & 0xFF );
				}

				/* Update indexes, temp variables, addresses. */
				ulNumReads -= ReadBurstParams.ulReadLength;
				ulTempIndex += ReadBurstParams.ulReadLength * 2;
				ReadBurstParams.ulReadAddress += ReadBurstParams.ulReadLength * 2;
			}

			/* Store register 0x202 in the event structure. */
			f_pGetData->pbyData[ ulUserBufWriteIndex + 255 ] = (UINT8)( pSharedInfo->IntrptManage.usRegister202h & 0xFF );
			f_pGetData->pbyData[ ulUserBufWriteIndex + 256 ] = (UINT8)( ( pSharedInfo->IntrptManage.usRegister202h >> 8 ) & 0xFF );

			/* Increment index. */
			if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S )
				|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
			{
				ulUserBufWriteIndex += pSharedInfo->DebugInfo.ulDebugChanStatsByteSize;
			}
			else
			{
				ulUserBufWriteIndex += pSharedInfo->DebugInfo.ulDebugChanLiteStatsByteSize;
			}

			/* Increment read pointer to get next event. */
			ulReadPointer = ( ulReadPointer + pSharedInfo->DebugInfo.ulDebugChanStatsByteSize ) % ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulDebugChanStatsByteSize );

			/* Save in the instance that one of the events was dumped. */
			pSharedInfo->DebugInfo.usLastDebugEventIndex ++;
		}
	}

	/* Check if all debug events have been transfered. */
	if ( ( ulDebugEventIndex == pSharedInfo->DebugInfo.usNumEvents )
		|| ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) )
	{
		/* Fetch all streams per event. */
		for ( ulPcmSampleIndex = pSharedInfo->DebugInfo.ulLastPcmSampleIndex; ulPcmSampleIndex < ( (UINT32)pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ); ulPcmSampleIndex ++ )
		{
			/* Check if enough room for this sample. */
			if ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
			{
				if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < 1 )
					break;
			}
			else /* if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) */
			{
				if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < 3 )
					break;
			}
			
			/* Check if must retrieve data from external memory. */
			if ( ( ulPcmSampleIndex % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE * 2 ) ) == 0x0 )
			{
				ulReadPointer = ( ( ( pSharedInfo->DebugInfo.usChipDebugEventWritePtr - pSharedInfo->DebugInfo.usNumEvents ) * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) & ( pSharedInfo->DebugInfo.usMatrixCBMask * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) );
				ulReadPointer += ( ulPcmSampleIndex / pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize;
				ulReadPointer &= ( pSharedInfo->DebugInfo.usMatrixCBMask * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize );
				ulReadPointer += ulPcmSampleIndex % pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize;

				/* Retrieve more data from external memory. */
				switch ( f_pGetData->ulGetDataContent )
				{
				case cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM:
					ulStreamIndexMin = 0;
					ulStreamIndexMax = 1;
					break;
				case cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM:
					ulStreamIndexMin = 1;
					ulStreamIndexMax = 2;
					break;
				case cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM:
					ulStreamIndexMin = 2;
					ulStreamIndexMax = 3;
					break;
				case cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE:
				default:
					ulStreamIndexMin = 0;
					ulStreamIndexMax = 3;
					break;
				}

				for ( ulStreamIndex = ulStreamIndexMin; ulStreamIndex < ulStreamIndexMax; ulStreamIndex ++ )
				{
					ReadBurstParams.ulReadAddress = pSharedInfo->MemoryMap.ulChanMainMemBase;
					/* To get right channel information. */
					ReadBurstParams.ulReadAddress += ( ( pSharedInfo->DebugInfo.usRecordMemIndex + 2 ) * pSharedInfo->MemoryMap.ulChanMainMemSize ) + pSharedInfo->DebugInfo.ulAfEventCbByteSize;
					/* To get correct stream. */
					ReadBurstParams.ulReadAddress += ( ( pSharedInfo->DebugInfo.usMatrixCBMask + 1 ) * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize * ulStreamIndex );
					/* PCM sample pointer in that stream. */
					ReadBurstParams.ulReadAddress += ulReadPointer;

					/* As much as we can for the burst. */
					ulTempIndex = 0;
					ulNumReads = cOCT6100_INTERNAL_SUPER_ARRAY_SIZE;
					while ( ulNumReads != 0 )
					{
						if ( ulNumReads >= pSharedInfo->ChipConfig.usMaxRwAccesses )
							ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses;
						else
							ReadBurstParams.ulReadLength = ulNumReads;

						/* Set pointer where to write data. */
						if ( ulStreamIndex == 0 )
							ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray[ ulTempIndex ];
						else if ( ulStreamIndex == 1 )
							ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray1[ ulTempIndex ];
						else /* if ( ulStreamIndex == 2 ) */
							ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray2[ ulTempIndex ];

						mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						/* Update indexes, temp variables, addresses. */
						ulNumReads -= ReadBurstParams.ulReadLength;
						ulTempIndex += ReadBurstParams.ulReadLength;
						ReadBurstParams.ulReadAddress += ReadBurstParams.ulReadLength * 2;
					}
				}
			}

			/* We now have the stream data for all streams for 1 event. */
			/* Return what we can to the user. */
			if ( ( ulPcmSampleIndex % 2 ) == 0 )
			{
				if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
					|| ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM ) )
					f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 8 ) & 0xFF );

				if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
					|| ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM ) )
					f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray1[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 8 ) & 0xFF );
				
				if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
					|| ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM ) )
					f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray2[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 8 ) & 0xFF );
			}
			else /* if ( ulPcmSampleIndex % 2 == 1 ) */
			{
				if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
					|| ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_RIN_PCM ) )
				f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 0 ) & 0xFF );

				if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
					|| ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SIN_PCM ) )
					f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray1[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 0 ) & 0xFF );

				if ( ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
					|| ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_SOUT_PCM ) )
					f_pGetData->pbyData[ ulUserBufWriteIndex++ ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray2[ ( ulPcmSampleIndex / 2 ) % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE ) ] >> 0 ) & 0xFF );
			}

			pSharedInfo->DebugInfo.ulLastPcmSampleIndex++;
		}

		/* Check if we are done dumping the PCM samples! */
		if ( pSharedInfo->DebugInfo.ulLastPcmSampleIndex == ( (UINT32)pSharedInfo->DebugInfo.usNumEvents * pSharedInfo->DebugInfo.ulRecordedPcmEventByteSize ) )
		{
			if ( f_pGetData->ulGetDataContent == cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE )
			{

				/* Go for the AF events.  The AF events are only copied in heavy mode. */
				if ( ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_16S )
					|| ( f_pGetData->ulGetDataMode == cOCT6100_DEBUG_GET_DATA_MODE_120S ) )
				{
					while ( pSharedInfo->DebugInfo.usLastAfLogReadPtr != pSharedInfo->DebugInfo.usAfLogWritePtr )
					{
						/* Check if enough room for an event. */
						if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < 16 )
							break;

						/* Check if must fill our buffer. */
						if ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) == 0x0 )
						{
							ulNumAfEvents = ( pSharedInfo->DebugInfo.usAfLogWritePtr - pSharedInfo->DebugInfo.usLastAfLogReadPtr ) & 0xFFFF;

							/* Check for the size of the available buffer. */
							if ( ulNumAfEvents > ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) 
								ulNumAfEvents = ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 );

							/* Start at channel main base address. */
							ReadBurstParams.ulReadAddress = pSharedInfo->MemoryMap.ulChanMainMemBase;
							/* To get right channel information. */
							ReadBurstParams.ulReadAddress += ( ( pSharedInfo->DebugInfo.usRecordMemIndex + 2 ) * pSharedInfo->MemoryMap.ulChanMainMemSize );
							/* To get the right AF log. */
							ReadBurstParams.ulReadAddress += ( pSharedInfo->DebugInfo.usLastAfLogReadPtr * 16 );

							ulTempIndex = 0;
							ulNumReads = ulNumAfEvents * 8;

							while ( ulNumReads != 0 )
							{
								if ( ulNumReads >= pSharedInfo->ChipConfig.usMaxRwAccesses )
									ReadBurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses;
								else
									ReadBurstParams.ulReadLength = ulNumReads;

								/* Set pointer where to write data. */
								ReadBurstParams.pusReadData = &pSharedInfo->MiscVars.ausSuperArray[ ulTempIndex ];

								mOCT6100_DRIVER_READ_BURST_API( ReadBurstParams, ulResult );
								if ( ulResult != cOCT6100_ERR_OK )
									return ulResult;

								/* Update indexes, temp variables, addresses. */
								ulNumReads -= ReadBurstParams.ulReadLength;
								ulTempIndex += ReadBurstParams.ulReadLength;
								ReadBurstParams.ulReadAddress += ReadBurstParams.ulReadLength * 2;
							}
						}

						/* Copy data byte per byte to avoid endianess problems. */
						for ( ulCopyIndex = 0; ulCopyIndex < 8; ulCopyIndex ++ )
						{
							f_pGetData->pbyData[ ulUserBufWriteIndex + ( 2 * ulCopyIndex ) ] = (UINT8)( pSharedInfo->MiscVars.ausSuperArray[ ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) * 8 ) + ulCopyIndex ] & 0xFF );
							f_pGetData->pbyData[ ulUserBufWriteIndex + ( 2 * ulCopyIndex ) + 1 ] = (UINT8)( ( pSharedInfo->MiscVars.ausSuperArray[ ( ( pSharedInfo->DebugInfo.usLastAfLogReadPtr % ( cOCT6100_INTERNAL_SUPER_ARRAY_SIZE / 8 ) ) * 8 ) + ulCopyIndex ] >> 8 ) & 0xFF );
						}

						ulUserBufWriteIndex += 16;

						/* Increment AF log read ptr. */
						pSharedInfo->DebugInfo.usLastAfLogReadPtr = (UINT16)(( pSharedInfo->DebugInfo.usLastAfLogReadPtr + 1 ) & 0xFFFF );
					}
				}

				/* Check if we are done with the AF events. */
				if ( pSharedInfo->DebugInfo.usLastAfLogReadPtr == pSharedInfo->DebugInfo.usAfLogWritePtr )
				{
					/* Insert the tone event information. */
					for ( ulToneEventIndex = pSharedInfo->DebugInfo.usLastToneEventIndex; ulToneEventIndex < pSharedInfo->ImageInfo.byNumToneDetectors; ulToneEventIndex++ )
					{
						if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) < cOCT6100_TLV_MAX_TONE_NAME_SIZE )
							break;

						Oct6100UserMemCopy( &f_pGetData->pbyData[ ulUserBufWriteIndex ], pSharedInfo->ImageInfo.aToneInfo[ ulToneEventIndex ].aszToneName, cOCT6100_TLV_MAX_TONE_NAME_SIZE );

						ulUserBufWriteIndex += cOCT6100_TLV_MAX_TONE_NAME_SIZE;

						pSharedInfo->DebugInfo.usLastToneEventIndex++;
					}

					/* If all the tone information has been copied. */
					if ( ulToneEventIndex == pSharedInfo->ImageInfo.byNumToneDetectors )
					{
						/* Copy the image version. */
						if ( pSharedInfo->DebugInfo.fImageVersionCopied == FALSE )
						{
							if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= 512 )
							{
								Oct6100UserMemCopy( &f_pGetData->pbyData[ ulUserBufWriteIndex ], pSharedInfo->ImageInfo.szVersionNumber, 512 );

								/* Get PLL jitter count from external memory. */
								if ( pSharedInfo->DebugInfo.fPouchCounter == TRUE )
								{
									ulFeatureBytesOffset = pSharedInfo->MemoryMap.PouchCounterFieldOfst.usDwordOffset * 4;
									ulFeatureBitOffset	 = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byBitOffset;
									ulFeatureFieldLength = pSharedInfo->MemoryMap.PouchCounterFieldOfst.byFieldSize;

									ulResult = Oct6100ApiReadDword(	f_pApiInstance,
																	cOCT6100_POUCH_BASE + ulFeatureBytesOffset,
																	&ulTempData );
									
									/* Create the mask to retrieve the appropriate value. */
									mOCT6100_CREATE_FEATURE_MASK( ulFeatureFieldLength, ulFeatureBitOffset, &ulMask );

									/* Mask data. */
									ulTempData &= ulMask;
									/* Move to right position. */
									ulTempData = ulTempData >> ulFeatureBitOffset;

									f_pGetData->pbyData[ ulUserBufWriteIndex + 510 ] = (UINT8)( ( ulTempData >> 8 ) & 0xFF );
									f_pGetData->pbyData[ ulUserBufWriteIndex + 511 ] = (UINT8)( ( ulTempData >> 0 ) & 0xFF );
								}

								/* Add "ISR is not called" bit. */
								if ( pSharedInfo->IntrptManage.fIsrCalled == FALSE )
								{
									f_pGetData->pbyData[ ulUserBufWriteIndex + 510 ] |= 0x80;
								}

								ulUserBufWriteIndex += 512;

								/* The version has been copied. */
								pSharedInfo->DebugInfo.fImageVersionCopied = TRUE;
							}
						}

						/* If the image version has been copied, proceed with the API version. */
						if ( pSharedInfo->DebugInfo.fImageVersionCopied == TRUE )
						{
							if ( pSharedInfo->DebugInfo.fApiVersionCopied == FALSE )
							{
								if ( ( f_pGetData->ulMaxBytes - ulUserBufWriteIndex ) >= sizeof(cOCT6100_API_VERSION) )
								{
									Oct6100UserMemCopy( &f_pGetData->pbyData[ ulUserBufWriteIndex ], cOCT6100_API_VERSION, sizeof(cOCT6100_API_VERSION) );
									ulUserBufWriteIndex += sizeof(cOCT6100_API_VERSION);

									/* The API version has been copied. */
									pSharedInfo->DebugInfo.fApiVersionCopied = TRUE;
								}
							}
						}
					}

					/* Check if we are done! */
					if ( pSharedInfo->DebugInfo.fApiVersionCopied == TRUE )
					{
						/* Done dumping. */

						/* Reset data being dumpped flag. */
						pSharedInfo->DebugInfo.fDebugDataBeingDumped = FALSE;

						/* Reset data recording in the chip. */
						WriteBurstParams.ulWriteAddress = pSharedInfo->DebugInfo.ulHotChannelSelectBaseAddress;
						WriteBurstParams.ulWriteLength = 2;
						WriteBurstParams.pusWriteData = pSharedInfo->DebugInfo.ausHotChannelData;

						mOCT6100_DRIVER_WRITE_BURST_API( WriteBurstParams, ulResult );
						if ( ulResult != cOCT6100_ERR_OK )
							return ulResult;

						fResetRemainingDataFlag = TRUE;
					}
				}
			}
			else /* if ( f_pGetData->ulGetDataContent != cOCT6100_DEBUG_GET_DATA_CONTENT_COMPLETE ) */
			{
				fResetRemainingDataFlag = TRUE;
			}
		}
	}

	/* Return number of valid bytes in buffer to user. */
	f_pGetData->ulValidNumBytes = ulUserBufWriteIndex;

	/* Update remaining bytes. */
	pSharedInfo->DebugInfo.ulDebugDataRemainingNumBytes -= ulUserBufWriteIndex;

	/* Return remaining bytes. */
	f_pGetData->ulRemainingNumBytes = pSharedInfo->DebugInfo.ulDebugDataRemainingNumBytes;

	/* Return total number of bytes. */
	f_pGetData->ulTotalNumBytes = pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes;

	/* Check if we are done dump the requested content. */
	if ( fResetRemainingDataFlag == TRUE )
		pSharedInfo->DebugInfo.ulDebugDataTotalNumBytes = cOCT6100_INVALID_VALUE;

	return cOCT6100_ERR_OK;
}
