/* **********************************
 * *                                *  
 * *           DSP Driver           *
 * *                                *  
 * **********************************  
 * file: libs/dsp/DspResetFifo.c
 *
 *                    COPYRIGHT (c) 2003, 2004 BY
 *         SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.  
 *     
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED. 
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <errno.h>

#include "sigtypes.h"
#include "setup.h"
#include "user_lib.h"
#include "dsp.h"
#include "rda.h"
#include "dsp_lib.h"

#include "dsp_def.h"

/* ======================================================================
 * Routine to reliably reset the output FIFO of any RVP-style signal
 * processor.
 */
MESSAGE DspResetFifo( Dsp *pDsp_a )
{
  MESSAGE iStatus ;
  if ( pDsp_a->itype < DSP_TYPE_RVP8 )
    {
      /* -------- Code for RVP6 or RVP7 --------
       * Clear any data that may be in the output buffer.  Send the FIFO
       * reset command once, then wait, then send it again.  This will
       * allow any preprocessors to have a chance to flush any data they 
       * read after the first command.
       */
      iStatus = dspw_reset( pDsp_a, FALSE, TRUE, FALSE ) ;
      if( iStatus != SS_NORMAL ) return( iStatus ) ;
      
      sig_microSleep( 300000 ) ; /* Wait 0.3 seconds */
      
      iStatus = dspw_reset( pDsp_a, FALSE, TRUE, FALSE ) ;
      if( iStatus != SS_NORMAL ) return( iStatus ) ;
    }
  else
    {
      UINT2 icmd, iStat ; SINT4 iWaitMs = 0 ; UINT1 lSent = FALSE ;
      /* -------- Code for RVP8 or later --------
       * Reset the kernel FIFO from the DSP, and then check whether
       * there are any opcode/data words still pending for the DSP.
       * Write a RESET-FIFO opcode followed by a NOP as soon as that
       * can be done with no possibility of blocking, then continue
       * resetting the kernel output FIFO until we see that the words
       * we wrote to the input FIFO have been gobbled by the DSP.  In
       * this way we keep flushing whatever remaining words the DSP
       * produces until seeing that it has resumed processing its
       * input.
       */
      for(;;) {
	iStatus = DspResetKernelFifos( pDsp_a, RESKFF_FROMDSP ) ;
	if( iStatus != SS_NORMAL ) return( iStatus ) ;

	iStatus = dspr_status( pDsp_a, &iStat ) ;
	if( iStatus != SS_NORMAL ) return( iStatus ) ;

	if( 0 == (iStat & DSPSTS_INQUEUED) ) {
	  if( lSent ) break ; lSent = TRUE ;
	  iStatus = dspw_reset( pDsp_a, FALSE, TRUE, FALSE ) ;
	  if( iStatus != SS_NORMAL ) return( iStatus ) ;
	  icmd = OP_NOP ; iStatus = dsp_write( pDsp_a, &icmd, 1 ) ;
	  if( iStatus != SS_NORMAL ) return( iStatus ) ;
	}
	if( iWaitMs > DSP_TIMEOUT_MS )
	  return( iMessageMod_va( USER_DEVTIMEOUT, 1, "DspResetFifo" ) ) ;

	sig_microSleep( 100000 ) ; iWaitMs += 100 ;
      }
    }
  return( iStatus ) ;
}

/* ======================================================================
 * Reset the kernel FIFOs, if such an operation makes sense on the
 * current interface.
 */
MESSAGE DspResetKernelFifos( Dsp *dsp_a, UINT4 iOper_a )
{
  MESSAGE istatus = SS_NORMAL ;
  switch( dsp_a->interface ) {
    /* -------------------- Native Interface -------------------- */
  case DSPIFACE_NATIVE:
    {
      if( iOper_a & RESKFF_TODSP ) {
        if( ioctl( dsp_a->idsplu, RVPIOC_WRFLUSH ) < 0 ) {
	  istatus = errno_to_message_va( errno, 1, "DspResetKernelFifos(-->DSP)" ) ;
	  break ;
	}
      }
      if( iOper_a & RESKFF_FROMDSP ) {
        if( ioctl( dsp_a->idsplu, RVPIOC_RDFLUSH ) < 0 ) {
	  istatus = errno_to_message_va( errno, 1, "DspResetKernelFifos(<--DSP)" ) ;
	  break ;
	}
      }
    }
    break ;
    /* -------------------- Socket Interface -------------------- */
  case DSPIFACE_SOCKET:
    {
      char sCommand[40] ;
      sprintf( sCommand, "RKFF|%d|", iOper_a ) ;
      istatus = WriteSocketString( dsp_a->idsplu, sCommand, FALSE ) ;

      if (istatus==SS_NORMAL)
	{
	  /* Read back the acknowledge */
	  istatus = ReadSocketAck( dsp_a->idsplu, FALSE, DSP_TIMEOUT_MS );
	}
    }
    break ;
  }
  return( istatus ) ;
}

/* ======================================================================
 * Routine to check that the byte order of the signal processor is
 * correct for this workstation.
 */
MESSAGE DspCheckByteOrder( Dsp *dsp_a )
{
  UINT2 iDspStatus ; MESSAGE iStatus ;
  UINT2 icmd, ipattern[16] ; SINT4 iActualCnt ;

  /* Skip the byte order test entirely if the user does not want it.
   * Certain third party DSPs seem to fail this test, and those
   * customers prefer that it never be done at all.
   */
  if( ! dspdrv_setup_c.lCheckByteOrder ) return( SS_NORMAL ) ;

  /* Make sure that there is nothing in the DSP's outgoing FIFO.  The
   * byte order check can not be done if there are other data waiting
   * to be read.
   */
  iStatus = dspr_status( dsp_a, &iDspStatus ) ;
  if( iStatus != SS_NORMAL ) return( iStatus ) ;
  if( iDspStatus & DSPSTS_OUTAVAIL ) return( DSP_BYTEORDER_UNK ) ;

  /* Check to see if the Walking Ones test returns any data at all.
   */
  icmd = OP_OTEST ; iStatus = dsp_write( dsp_a, &icmd, 1 ) ;
  if( iStatus != SS_NORMAL ) return( iStatus ) ;

  sig_microSleep(100000);		/* Just so we don't miss it... */

  iStatus = dspr_status( dsp_a, &iDspStatus ) ;	
  if( iStatus != SS_NORMAL ) return( iStatus ) ;

  if( iDspStatus & DSPSTS_OUTAVAIL ) {
    /* We got some data back, so the byte order of the original opcode
     * must have been okay.  Check that the return data look basically
     * okay, and signal "Unknown Byte Order" if not.
     */
    iStatus = dsp_read( dsp_a, &ipattern, 16, &iActualCnt ) ;
    if( iStatus != SS_NORMAL ) return( iStatus ) ;
    if( (ipattern[0] != 0x0001) || (iActualCnt != 16) )
      iStatus = DSP_BYTEORDER_UNK ;

  } else {
    /* If the original opcode returned nothing, then try the swapped
     * version of it.  We are definitely going to return some sort of
     * error at this point.
     */
    icmd = (icmd << 8) | (icmd >> 8) ; iStatus = dsp_write( dsp_a, &icmd, 1 ) ;	  
    if( iStatus != SS_NORMAL ) return( iStatus ) ;

    sig_microSleep(100000) ;		/* Just so we don't miss it... */

    iStatus = dspr_status( dsp_a, &iDspStatus ) ;	
    if( iStatus != SS_NORMAL ) return( iStatus ) ;

    if( iDspStatus & DSPSTS_OUTAVAIL ) {
      iStatus = dsp_read( dsp_a, &ipattern, 16, &iActualCnt ) ;
      if( iStatus != SS_NORMAL ) return( iStatus ) ;
      if( (ipattern[0] != 0x0100) || (iActualCnt != 16) )
	iStatus = DSP_BYTEORDER_UNK ;	      
      else
	iStatus = DSP_BYTEORDER_ERR ;
    } else {
      iStatus = DSP_BYTEORDER_UNK ;	      
    }
  }
  return( iStatus ) ;
}
