/**
 *  \file   dsl_hal_api.c
 *
 *  \author Copyright (C) 2001-2006 Texas Instruments Incorporated.
 *
 *  \brief  This file contains DSL HAL API source code for DSL device driver.
 *  
 *  \date   18May06     0.00.00     EP      Created: Ported from AR7.
 *          13Dec06     0.00.01     EP      CQ11241: Fixed handling of invalid values.
 *          15Dec06     0.00.02     MK      CQ11264: Added support for host controlled LED 
 *                                          in dslhal_api_configureLed().
 *          01Feb07     0.00.03     EP      Added DSL interrupt acknowledgement API for entry/exit.
 *          16Feb07     0.00.04     EP      Fixed DSL interrupt acknowledgement API for entry/exit.
 */

#include <dev_host_interface.h>

#include <dsl_hal_support.h>
#include <dsl_hal_version.h>

#ifndef NO_ACT
#include <dsl_hal_advcfg.h>
#endif

#include <dsl_hal_logtable.h>


/** 
 *  \brief  Constants used for calculation
 */
#define US_NOMINAL_POWER                          (-38)
/** 
 *  \brief  Constants used for calculation
 */
#define LOG43125                                  9303

/**
 *  \brief  Maximum number of bytes allowed for DSP image file size.
 */
#define DSP_FIRMWARE_MALLOC_SIZE    0x80000  /** 512KB */

#ifdef YAMUNA
#define HOST_CONTROLLED_LED 1
#endif //YAMUNA

/*** Public Basic API ***/

/**
 *  \brief  Entry point to initialize and load DSL.
 *  
 *  @param  ppIHw   Main DSL HAL data structure to be initialized.
 *  @return 0:      Success
 *          other:  Failure
 */
int dslhal_api_dslStartup(PITIDSLHW_T *ppIHw)
{
  ITIDSLHW_T *ptidsl;
  int rc;
#ifndef YAMUNA
  extern unsigned char triggerDsp250MHZ;
#endif

  dgprintf(4,"dslhal_api_dslStartup() NEW 1\n");

  ptidsl=(ITIDSLHW_T *)shim_osAllocateMemory(sizeof(ITIDSLHW_T));
  if(ptidsl==NULL)
  {
    dgprintf(1, "unable to allocate memory for ptidsl\n");
    return 1;
  }
  *ppIHw=ptidsl;
  shim_osZeroMemory((char *) ptidsl, sizeof(ITIDSLHW_T));

  rc = dslhal_support_resetDsp();
  if(rc)
  {
    dgprintf(1, " unable to reset DSL DSP\n");
    rc = DSLHAL_ERROR_RESET_DSP;
  }
  rc = dslhal_support_resetDslSubsystem();
  if(rc)
  {
    dgprintf(1, " unable to reset DSL subsystem \n");
    rc = DSLHAL_ERROR_RESET_ADSLSS;
  }

  /* Unreset the ADSL Subsystem  */
  rc=dslhal_support_unresetDslSubsystem();
  if(rc)
  {
    dgprintf(1, "unable to reset ADSL Subsystem \n");
    shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
    return DSLHAL_ERROR_UNRESET_ADSLSS;
  }
#if 1  /*EP*/
  ptidsl->fwimage = shim_osAllocateVMemory(DSP_FIRMWARE_MALLOC_SIZE);
  if(!ptidsl->fwimage)
  {
    dgprintf(1,"Failed to Allocate Memory for DSP firmware binary \n");
    return DSLHAL_ERROR_FIRMWARE_MALLOC;
  }
  /* read firmware file from flash   */
  rc=shim_osLoadFWImage(ptidsl->fwimage);
  if(rc<0)
  {
    dgprintf(1, "unable to get fw image\n");
    shim_osFreeVMemory((void *)ptidsl->fwimage, 0 /*unused*/);
    shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
    return DSLHAL_ERROR_NO_FIRMWARE_IMAGE;
  }
  else
  {
    ptidsl->imagesize = rc;
  }
#else  /*HACK*/
  ptidsl->fwimage = (void *)(0xb4800000);
#endif

  /* 
   * Enable DSPSS UART
   */
  {
    unsigned reg;
    
    reg = *(volatile unsigned *)(0xa861090c);
    reg &= ~(0x180);
    *(volatile unsigned *)(0xa861090c) = reg;
  }

  /* Compute the CRC checksum on the image and validate the image */

  /* Validate the image in the RAM */

  /* load fw to DSP  */

  if(dslhal_support_hostDspCodeDownload(ptidsl))
  {
    dgprintf(0,"dsp load error\n");
#ifndef YAMUNA
    dslhal_support_freeOverlayPage(ptidsl);
#endif
    shim_osFreeVMemory((void *)ptidsl->fwimage,DSP_FIRMWARE_MALLOC_SIZE);
    shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
    return DSLHAL_ERROR_CODE_DOWNLOAD;
  }

#ifndef YAMUNA
  /* set flag to indicated overlay pages are loaded */
  ptidsl->bOverlayPageLoaded = 1;
  /* set auto retrain to 1 to disble the overlay page reload */
  ptidsl->bAutoRetrain = 1;

  if (triggerDsp250MHZ)
  {
    dslhal_support_setDsp250MHzTrigger(ptidsl);
  }
#endif

  /* unreset Raptor */
  /* change this to new function */
  /* This function should basically bring DSP out of reset bit 23  of PRCR */
  /* Function is ready but bypassed for Pre-Silicon */
  rc=dslhal_support_unresetDsp();

  if (rc)
  {
    dgprintf(0,"unable to bring DSP out of Reset\n");
#ifndef YAMUNA
    dslhal_support_freeOverlayPage(ptidsl);
#endif
    shim_osFreeVMemory((void *)ptidsl->fwimage, 0 /*unused*/);
    shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
    return DSLHAL_ERROR_UNRESET_DSP;
  }
  shim_osFreeVMemory((void *)ptidsl->fwimage, 0 /*unused*/);
  
  dgprintf(4,"dslhal_api_dslStartup() done\n");

  /* Add the code to initialize the host interface variables */
  ptidsl->AppData.useBitField = FALSE;

  /* Add code to tickle the host interface */
  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  Shutdown DSL modem and free the resource.
 *  
 *  @param  ptidsl  Main DSL HAL data structure to be initialized.
 *  @return 0:      Success
 *          other:  Failure
 */
int dslhal_api_dslShutdown(tidsl_t *ptidsl)
{
  int rc= DSLHAL_ERROR_NO_ERRORS;

  dgprintf(5, "dslhal_api_dslShutdown\n");
  rc = dslhal_support_writeHostMailbox(ptidsl, HOST_DSLSS_SHUTDOWN, 0, 0, 0);
  if(rc)
  {
    dgprintf(1, " unable to reset DSP \n");
    rc = DSLHAL_ERROR_RESET_DSP;
  }
  /* DSP need 50 ms to send out the message*/

  shim_osClockWait(60 * 1000);

  rc = dslhal_support_writeHostMailbox(ptidsl, HOST_DGASP, 0, 0, 0);

  /* free memory allocated*/

#ifndef YAMUNA
  dslhal_support_freeOverlayPage(ptidsl);
#endif

  shim_osFreeMemory((void *)ptidsl, sizeof(tidsl_t));

  rc = dslhal_support_resetDsp();
  if(rc)
  {
    dgprintf(1, " unable to reset ADSL subsystem \n");
    rc = DSLHAL_ERROR_RESET_DSP;
  }
  rc = dslhal_support_resetDslSubsystem();
  if(rc)
  {
    dgprintf(1, " unable to reset ADSL subsystem \n");
    rc = DSLHAL_ERROR_RESET_ADSLSS;
  }
  return rc;
}


/**
 *  \brief  Collect statistics infromation from DSL modem.
 *  
 *  @param  ptidsl  Main DSL HAL data structure to be initialized.
 *  @return none
 */
void dslhal_api_gatherStatistics(tidsl_t * ptidsl)
{
  int rc,optIdxU,optIdxD;

  unsigned offset[] = {
      2, 
      IFACE_OFFSET(dspWriteNegoParams_p),   
      0
    };

  DEV_HOST_dspWrNegoParaDef_t   rateparms;
  DEV_HOST_oamWrNegoParaDef_t   configParms;
#if 1 // LOF  CQ10226
  DEV_HOST_MGMTCount_t          mgmt_Count;
  BIS_MGMT_CountersDef_t        BIS_MGMT_Counters;
#endif

  dgprintf(5, "dslhal_api_gatherStatistics\n");

#if 1
  /*EP: 20061001, disabled */
  if (ptidsl->AppData.bState != RSTATE_SHOWTIME)
      return;
#endif

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &rateparms, sizeof(DEV_HOST_dspWrNegoParaDef_t));
  if (rc)
    return;

  {
    /* rate */
    /*    shim_osMoveMemory((void *)ptidsl->AppData.bCRates1, (void *)rateparms.cRates1, 120); */
    ptidsl->AppData.bCRates2 = rateparms.cRates2;
    /*    shim_osMoveMemory((void *)ptidsl->AppData.bRRates1, (void *)rateparms.rRates1, 44); */
    ptidsl->AppData.bRRates2 = rateparms.rRates2;
    shim_osMoveMemory((void *)ptidsl->AppData.bCMsgs1, (void *)rateparms.cMsgs1, 12);
    shim_osMoveMemory((void *)ptidsl->AppData.bCMsgs2, (void *)rateparms.cMsgs2, 4);
    shim_osMoveMemory((void *)ptidsl->AppData.bRMsgs2, (void *)rateparms.rMsgs2, 4);
    ptidsl->AppData.atucVendorId = (unsigned)rateparms.atucVendorId;
    ptidsl->AppData.lineLength = (unsigned)dslhal_support_byteSwap16((unsigned short)rateparms.lineLength);
    ptidsl->AppData.atucRevisionNum = (unsigned)rateparms.atucGhsRevisionNum;

    dgprintf(4, "cRates2=%d\n", rateparms.cRates2);
    dgprintf(4, "ptidsl=%08X\n", (unsigned)ptidsl);

    /* Obtain the US Rates using Opt# and CRates1 Table */
    /* Rate(US) = [Bf(LS0) + Bi(LS0)]*32                */
    if (dslhal_support_IsADSL1Mode(ptidsl))
    {
        dgprintf(4, "ADSL1 mode\n");

    if((rateparms.cRates2 & 0x0f) == 0x01)
      optIdxU = 0;
    else if((rateparms.cRates2 & 0x0f) == 0x02)
      optIdxU = 1;
    else if((rateparms.cRates2 & 0x0f) == 0x04)
      optIdxU = 2;
    else if((rateparms.cRates2 & 0x0f) == 0x08)
      optIdxU = 3;
        else {
            dgprintf(-1, "Warning: rateparms.cRates2 is invalid! (%X)\n", rateparms.cRates2);
            return;
        }

        ptidsl->AppData.usLineAttn = (ptidsl->AppData.bCMsgs2[3] >>2)&0x003f;
        ptidsl->AppData.usMargin = (ptidsl->AppData.bCMsgs2[2])&0x001f;

      ptidsl->AppData.USConRate = ((rateparms.cRates1[optIdxU][CRATES1_BF_LS0] + rateparms.cRates1[optIdxU][CRATES1_BI_LS0]) * 32);

      if(((rateparms.cRates2 >> 4) & 0x0f) == 0x01)
        optIdxD = 0;
      else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x02)
        optIdxD = 1;
      else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x04)
        optIdxD = 2;
      else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x08)
        optIdxD = 3;
      else {
            dgprintf(-1, "Warning: rateparms.cRates2 is invalid! (%X)\n", rateparms.cRates2);
            return;
      }
      
      ptidsl->AppData.DSConRate =  (((rateparms.cRates1[optIdxD][CRATES1_BF_AS0]|((rateparms.cRates1[optIdxD][CRATES1_BF_DSRS]&0x80)<<1))+ (rateparms.cRates1[optIdxD][CRATES1_BI_AS0]|((rateparms.cRates1[optIdxD][CRATES1_BI_DSRS]&0x80)<<1)))* 32);

      /* Determine which Path has Modem Trained with */
      if((rateparms.cRates1[optIdxU][CRATES1_BF_LS0]) && (rateparms.cRates1[optIdxD][CRATES1_BF_AS0]))
        ptidsl->AppData.TrainedPath = FAST_PATH;
      else
        ptidsl->AppData.TrainedPath = INTERLEAVED_PATH;

      if(ptidsl->AppData.TrainedPath == FAST_PATH)
        ptidsl->AppData.dsFastParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BF_DSRS]&0x1f);
      else
        ptidsl->AppData.dsIntlvParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BI_DSRS]&0x1f);
      ptidsl->AppData.dsSymbolsPerCodeWord = (rateparms.cRates1[optIdxU][CRATES1_BFI_DSS]&0x1f);
      ptidsl->AppData.dsInterleaverDepth = ((rateparms.cRates1[optIdxU][CRATES1_BFI_DSI])|((rateparms.cRates1[optIdxU][CRATES1_BFI_DSS]&0xc0)<<2));

      if(ptidsl->AppData.TrainedPath == FAST_PATH)
        ptidsl->AppData.usFastParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BF_USRS]&0x1f);
      else
        ptidsl->AppData.usIntlvParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BI_USRS]&0x1f);
      ptidsl->AppData.usSymbolsPerCodeWord = (rateparms.cRates1[optIdxU][CRATES1_BFI_USS]&0x1f);
      ptidsl->AppData.usInterleaverDepth = ((rateparms.cRates1[optIdxU][CRATES1_BFI_USI])|((rateparms.cRates1[optIdxU][CRATES1_BFI_USS]&0xc0)<<2));
    }
    else
    {
        dgprintf(4, "ADSL2 mode\n");

        /* Attenuation is precise to the steps of 0.1 dB, however, to maintain uniformity, being reported in 0.5 dB steps */
        ptidsl->AppData.usLineAttn = (ptidsl->adsl2TrainingMessages.cParams[1] & 0x3);
        ptidsl->AppData.usLineAttn <<=8;
        ptidsl->AppData.usLineAttn += ptidsl->adsl2TrainingMessages.cParams[0];
        ptidsl->AppData.usLineAttn = ptidsl->AppData.usLineAttn/5;
        ptidsl->AppData.usMargin = ptidsl->adsl2TrainingMessages.cParams[5];
        ptidsl->AppData.usMargin <<=8;
        ptidsl->AppData.usMargin += ptidsl->adsl2TrainingMessages.cParams[4];
        ptidsl->AppData.usMargin = ptidsl->AppData.usMargin/10;

      ptidsl->AppData.USConRate =  dslhal_support_byteSwap16((unsigned short)rateparms.adsl2USRate);
      ptidsl->AppData.DSConRate = dslhal_support_byteSwap16((unsigned short)rateparms.adsl2DSRate);

      /* Determine which Path has Modem Trained with */
      if((ptidsl->adsl2TrainingMessages.rParams[10] & 0x07) == 0)
        ptidsl->AppData.TrainedPath = FAST_PATH;
      else
        ptidsl->AppData.TrainedPath = INTERLEAVED_PATH;
    }
    dgprintf(4, "ptidsl->AppData.wDSConRate=%d\n", ptidsl->AppData.DSConRate);

  }

#if 1 // LOF  CQ10226
  offset[1] = IFACE_OFFSET(mgmt_Count_p);
  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &mgmt_Count, sizeof(DEV_HOST_MGMTCount_t));
  if (rc)
    return;

  {
    mgmt_Count.bis_Mgmt_Count_DS_p = (BIS_MGMT_CountersDef_t *)
                    dslhal_support_byteSwap32((unsigned)mgmt_Count.bis_Mgmt_Count_DS_p);
    rc = dslhal_support_blockRead((PVOID)mgmt_Count.bis_Mgmt_Count_DS_p,
                    &BIS_MGMT_Counters, sizeof(BIS_MGMT_CountersDef_t));
    if (!rc)
    {
      ptidsl->AppData.erroredSeconds = dslhal_support_byteSwap32((unsigned)BIS_MGMT_Counters.errored_seconds);
//      printf("erroredSeconds: %X, errored_seconds: %X \n", ptidsl->AppData.erroredSeconds, BIS_MGMT_Counters.errored_seconds);
    }
    else
    {
      dgprintf(1,"dslhal_support_blockRead failed\n");
      return;
    }
  }
#endif

  dslhal_support_getModemStatistics(ptidsl);
  dslhal_support_getDspSharedTbls(ptidsl);

  /* Read Configured Options */
  offset[1] = IFACE_OFFSET(oamWriteNegoParams_p);
  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &configParms, sizeof(DEV_HOST_oamWrNegoParaDef_t));
  if (rc)
    return;

  {
#if 1  /*ep*/
    /* r-Msg1 */
    ptidsl->AppData.StdMode = (unsigned)configParms.stdMode;

    /* Translate only if we are using bit feild mode. */
    if(!ptidsl->AppData.useBitField)
    {
        if(configParms.stdMode == T1413_MODE)
            ptidsl->AppData.StdMode = DSLTRAIN_T1413_MODE;
        else if(configParms.stdMode == GDMT_MODE)
            ptidsl->AppData.StdMode = DSLTRAIN_GDMT_MODE;
        else if(configParms.stdMode == MULTI_MODE8)
            ptidsl->AppData.StdMode = DSLTRAIN_MULTI_MODE;
    }
#endif

    shim_osMoveMemory((void *)ptidsl->AppData.bRMsgs1, (void *)configParms.rMsgs1, 6*sizeof(char));

#if 1 // TR69
    // extract t1413ATUCVendorId
    if ((!ptidsl->AppData.useBitField &&
          ptidsl->AppData.TrainedMode == DSLTRAIN_T1413_MODE)
      || (ptidsl->AppData.useBitField &&
          ptidsl->AppData.TrainedMode == T1413_ANSI))
    {
      // Trained Mode is T1413 mode
      ptidsl->AppData.t1413ATUC.VendorId[0] = (ptidsl->AppData.bCMsgs1[3]>>4)
        | (ptidsl->AppData.bCMsgs1[4]<<4);

      ptidsl->AppData.t1413ATUC.VendorId[1] = (ptidsl->AppData.bCMsgs1[5]<<4)
        | (ptidsl->AppData.bCMsgs1[4]>>4);

      ptidsl->AppData.t1413ATUC.t1413Revision = ((ptidsl->AppData.bCMsgs1[3] & 0x03) << 1)
        | (ptidsl->AppData.bCMsgs1[2]>> 7);

      ptidsl->AppData.t1413ATUC.VendorRevision = (ptidsl->AppData.bCMsgs1[2]>>2) & 0x1F;

      ptidsl->AppData.t1413ATUR.t1413Revision = ((ptidsl->AppData.bRMsgs1[3] & 0x03) << 1)
        | (ptidsl->AppData.bCMsgs1[2]>> 7);

      ptidsl->AppData.t1413ATUR.VendorRevision = (ptidsl->AppData.bRMsgs1[2]>>2) & 0x1F;

      // extract t1413ATURVendorId
      shim_osMoveMemory((void*)ptidsl->AppData.t1413ATUR.VendorId,(void *)configParms.t1413VendorId, 2);

      shim_osZeroMemory((char *)ptidsl->AppData.ghsATUCVendorId, 8);
      shim_osZeroMemory((char *)ptidsl->AppData.ghsATURVendorId, 8);
    }
    else
    {
      // extract ghsATUCVendorId
      dslhal_support_getATUCVendorId(ptidsl, ptidsl->AppData.ghsATUCVendorId);

      // extract ghsATURVendorId
      shim_osMoveMemory((void*)ptidsl->AppData.ghsATURVendorId,(void *)configParms.gdmtVendorId, 8);

      shim_osZeroMemory((char *)&ptidsl->AppData.t1413ATUC, sizeof(T1413INFO));
      shim_osZeroMemory((char *)&ptidsl->AppData.t1413ATUR, sizeof(T1413INFO));
    }

#endif
  }

  /* EP: Moved here from Driver code */
  dslhal_support_getTrellis(ptidsl);
  dslhal_support_getRMsgsRa(ptidsl);

  dslhal_api_usBitSwap(ptidsl, 1, 0/*unused*/);
  dslhal_api_dsBitSwap(ptidsl, 1, 0/*unused*/);

  if (ptidsl->AppData.bState == RSTATE_SHOWTIME)
  { // Don't call getAdvStat before showtime, it will hang
    rc = dslhal_api_getAdvancedStats(ptidsl);
  }

  return;
}


/**
 *  \brief  Collect advanced statistics infromation from DSL modem.
 *          It is assumed that dslhal_api_gatherstatistics() has been invoked.
 *  
 *  @param  ptidsl  Main DSL HAL data structure to be initialized.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_getAdvancedStats(tidsl_t * ptidsl)
{
  int rc,i;

  unsigned offset[] = {
      2, 
      IFACE_OFFSET(phyPerf_p),
      0
    };
  DEV_HOST_phyPerf_t            phyPerf;

  unsigned char                 usBits[64],dsBits[512];
  int                           dsPowerCutBack, usPowerCutBack;
  short                         hLog,dsGains[512], tmp16;
  unsigned short                snrBits[16]={0,1072,1242,1650,1837,2092,2364,
                                             2611,2883,3121,3393,3640,3903,
                                             4150,4414,4660};
  int                           codingGain=0;
  int                           usNumLoadedTones=0, dsNumLoadedTones=0;

  dgprintf(5, "dslhal_api_gatherStatistics\n");

  shim_osZeroMemory(usBits, sizeof(usBits));
  shim_osZeroMemory(dsBits, sizeof(dsBits));
  shim_osZeroMemory((void *)dsGains, sizeof(dsGains));

    for(i=1;i<ptidsl->AppData.max_us_tones;i++)
    {
      usBits[i]=((ptidsl->AppData.cBng[(i-1)*2])&0xf);
      dgprintf(6,"Bit #%d : 0x%x\n",i,usBits[i]);
    }
    for(i=1;i<ptidsl->AppData.max_us_tones;i++)
    {
      if(usBits[i])
        usNumLoadedTones++;
    }

  /* Determine Number U/S of Loaded Tones */

  /* U/S Power Computation */
  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &phyPerf, sizeof(DEV_HOST_phyPerf_t));
  if (rc)
    return rc;

  /*EP*/
  ptidsl->AppData.currentHybridNum = phyPerf.currentHybridNumUsed;

  phyPerf.usAvgGain = dslhal_support_byteSwap32(phyPerf.usAvgGain);
  if(dslhal_support_IsADSL1Mode(ptidsl))
    usPowerCutBack = US_NOMINAL_POWER;
  else
    {
      usPowerCutBack = (((ptidsl->adsl2TrainingMessages.rMsgPcb[0] & 0xc0) >>6)+((ptidsl->adsl2TrainingMessages.rMsgPcb[1] & 0xf) <<2));
      rc = (((ptidsl->adsl2TrainingMessages.cMsgPcb[0] & 0xc0) >>6)+((ptidsl->adsl2TrainingMessages.cMsgPcb[1] & 0xf) <<2));
      if(usPowerCutBack < rc)
         usPowerCutBack = rc;
      usPowerCutBack =  US_NOMINAL_POWER - usPowerCutBack;
    }
  ptidsl->AppData.usTxPower = LOG43125 + phyPerf.usAvgGain + (256*usPowerCutBack)+LUT_log10[usNumLoadedTones-1];
  dgprintf(7,"Avg Gain: 0x%x  usNumLoadedTones: 0x%x  USPCB=%d  log: 0x%x\n",phyPerf.usAvgGain, usNumLoadedTones, usPowerCutBack, LUT_log10[usNumLoadedTones-1]);

  /* Determine Number D/S of Loaded Tones */
//use shim_osZeroMemory() & move up
//  dsBits[0]=0;
//  for(i=0;i<dsNumTones;i++)
//    {
//     dsBits[i]=0;
//     dsGains[i]=0;
//    }
  for(i=1;i<ptidsl->AppData.max_ds_tones;i++)
    {
     dsBits[i]=((ptidsl->AppData.rBng[(i-1)*2])&0xf);
     dsGains[i]= ((ptidsl->AppData.rBng[(2*i)-1]) <<4);
     dsGains[i]+= (((ptidsl->AppData.rBng[(i-1)*2])&0xf0) >>4);
     dgprintf(6,"Bit #%d : 0x%x  0x%x\n",i,ptidsl->AppData.rBng[i],dsGains[i]);
    }
  for(i=1;i<ptidsl->AppData.max_ds_tones;i++)
    {
     if(dsBits[i])
       dsNumLoadedTones++;
    }
  /* D/S Power Computation */
  /* D/S Power Cutback */
  if(dslhal_support_IsADSL1Mode(ptidsl))
    dsPowerCutBack = 2*((((((ptidsl->AppData.bCMsgs1[0]) >>6) &0x3)+(((ptidsl->AppData.bCMsgs1[1]) &0x1) <<2))) - 1) - 52;
  else
    {
      dsPowerCutBack = (ptidsl->adsl2TrainingMessages.rMsgPcb[0] & 0x3f);
      rc = (ptidsl->adsl2TrainingMessages.cMsgPcb[0] & 0x3f);
      if(dsPowerCutBack < rc)
        dsPowerCutBack = rc;
      dsPowerCutBack = -40 - dsPowerCutBack;
    }
  phyPerf.dsAvgGain = dslhal_support_byteSwap32(phyPerf.dsAvgGain);
  ptidsl->AppData.dsTxPower = LOG43125 + phyPerf.dsAvgGain + (256*dsPowerCutBack) + LUT_log10[dsNumLoadedTones-1];
  dgprintf(7,"Avg Gain: %d  dsNumLoadedTones: %d  log: %d  pcb: %d \n",phyPerf.dsAvgGain, dsNumLoadedTones, LUT_log10[dsNumLoadedTones-1], dsPowerCutBack);

  /* Advanced Error Parameters */
  /* Downstream PSD Computation : from Powercutback obtained from C-Msg1 */
  /*  dsPsd = (2*(dsPowerCutBack - 1) - 52); */
  /* Derivation of Coding Gain from R-MSG-RA */
  codingGain = (((ptidsl->AppData.rMsgRa[2] & 0xe0) >> 5) + ((ptidsl->AppData.rMsgRa[3] & 0x1)<<3));

  dgprintf(7,"dsPowerCutBack:%d Cg:%d \n",dsPowerCutBack,codingGain/2);
  for(i=1;i<ptidsl->AppData.max_ds_tones;i++)
  {
    /* Compute G(i) = 20*log10(g(i)) computed in-place in the dsNoise global variable */
    /* log10 table already is 256 * 10log10 */
    /* dsGains is scaled by 512, so log of that term factored out */
    if(dsGains[i]==0)
      ptidsl->AppData.dsNoise[i] = 0;
    else
    {
//      ptidsl->AppData.dsNoise[i] = -2*(log10[((dsGains[i])/8)-1] - log10[63]);
      tmp16 = (dsGains[i]<8) ? 8: dsGains[i];
      ptidsl->AppData.dsNoise[i] = -2*(LUT_log10[(tmp16/8)-1] - LUT_log10[63]);
    }

    hLog = dslhal_support_getHlog(ptidsl,i);
    /* Compute DS Noise in dB from all derived factors with appropriate scaling to get output in dB */
    ptidsl->AppData.dsNoise[i] = (256*hLog)/10 + 256*dsPowerCutBack - (256*snrBits[(dsBits[i])])/85 - 128*(ptidsl->AppData.marginTblDstrm[i] - codingGain);
    /* Debug Print to verify output */
    dgprintf(7, "i=%3d hLog: %3d snr: %3d M: %3d  No:%3d\n",
            i,hLog/10,(snrBits[(dsBits[i])]/85),ptidsl->AppData.marginTblDstrm[i]/2,ptidsl->AppData.dsNoise[i]/256);
  }

  return DSLHAL_ERROR_NO_ERRORS;
}


#ifndef NO_ADV_STATS

/**
 *
 */
static unsigned GetPsds(tidsl_t *ptidsl, unsigned index, void *buf)
{
  unsigned offset[] = {
      2, 
      7,  //IFACE_INT_OFFSET(modemEnv_p),   /*7*/
      index
      };
  unsigned i, num;
  unsigned addr;
  unsigned *src = NULL;
  unsigned *dst = NULL;
    
  // Must be ADSL2/2+ mode
  if (!(ptidsl->AppData.TrainedMode & (ADSL2PLUS_MASKS|ADSL2_MASKS)) )
    return DSLHAL_ERROR_UNSUPPORTED_MODE;

  dslhal_support_interfaceRW((unsigned)ptidsl->pIntAddr, offset, 1, &addr, 4);

  // The buffer is in external SDRAM.
  src = (unsigned *)(HOST_MEM_V2P(dslhal_support_byteSwap32(addr)));
  dst = (unsigned *)(buf);
  num = ptidsl->AppData.max_ds_tones>>2;

  for (i=0; i<num; i++, dst++, src++)
  {
    *dst = dslhal_support_byteSwap32(*src);
  }
  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  Get downstream HLOGpsds in ADSL2/2+ mode, as defined in g.997.1.
 *  
 *  @param  ptidsl  Main DSL HAL data structure to be initialized.
 *  @param  outbuf  Output buffer supplied from caller.
 *                      for ADSL2 mode, 2*256=512 bytes are expected.
 *                      for ADSL2+ mode, 2*512=1k bytes are expected.
 *  @param  flag    0: training HLOGpsds. 
 *                  1: showtime HLOGpsds.
 *                  **Note: Currently only training HLOGpsds is supported.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_getHLOGpsds(tidsl_t * ptidsl, unsigned short *outbuf, int flag)
{
  dgprintf(5, "dslhal_api_getHLOGpsds\n");

  if (flag!=0)
    return DSLHAL_ERROR_INVALID_PARAM;

  return GetPsds(ptidsl, 14/*IFACE_INT_MDMENV_OFFSET(TestParmHlogfMsgAddr)*/, outbuf);
}

/**
 *  \brief  Get downstream Quiet Line Noise (QLNpsds) in ADSL2/2+ mode, as defined in g.997.1.
 *  
 *  @param  ptidsl  Main DSL HAL data structure to be initialized.
 *  @param  outbuf  Output buffer supplied from caller.
 *                      for ADSL2 mode, 1*256=256 bytes are expected.
 *                      for ADSL2+ mode, 1*512=512 bytes are expected.
 *  @param  flag    0: training QLNpsds. 
 *                  1: showtime QLNpsds.
 *                  **Note: Currently only training QLNpsds is supported.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_getQLNpsds(tidsl_t * ptidsl, unsigned char *outbuf, int flag)
{
  dgprintf(5,"dslhal_api_getQLNpsds\n");

  if (flag!=0)
    return DSLHAL_ERROR_INVALID_PARAM;

  return GetPsds(ptidsl, 15/*IFACE_INT_MDMENV_OFFSET(TestParmQLNfMsgAddr)*/, outbuf);
}

/**
 *  \brief  Get downstream SNRpsds in ADSL2/2+ mode, as defined in g.997.1.
 *  
 *  @param  ptidsl  Main DSL HAL data structure to be initialized.
 *  @param  outbuf  Output buffer supplied from caller.
 *                      for ADSL2 mode, 1*256=256 bytes are expected.
 *                      for ADSL2+ mode, 1*512=512 bytes are expected.
 *  @param  flag    0: training SNRpsds. 
 *                  1: showtime SNRpsds.
 *                  **Note: Currently only showtime SNRpsds is supported.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_getSNRpsds(tidsl_t * ptidsl, unsigned char *outbuf, int flag)
{
  dgprintf(5, "dslhal_api_getSNRpsds\n");

  if (flag!=1)
    return DSLHAL_ERROR_INVALID_PARAM;

  return GetPsds(ptidsl, 16/*IFACE_INT_MDMENV_OFFSET(TestParmSNRfMsgAddr)*/, outbuf);
}

#endif  /*NO_ADV_STATS*/


/*******************************************************************************
* EP-modified, 20060201
*******************************************************************************/
#include <dsl_hal_csl.h>


/**
 *  \brief  Parse host interrupt bit-mask and re-enable interrupts.
 *  
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @return >0:     Interrupt Bit Mask.
 *          =0:     None.
 */
unsigned dslhal_api_acknowledgeInterrupt(tidsl_t * ptidsl)
{
  unsigned intrSrc = 0;

  dslhal_support_parseInterruptSource(ptidsl, &intrSrc);

  dslhal_csl_clearInterrupt();

  return intrSrc;
}

/**
 *  \brief  Clear DSL interrupt.
 *  
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @return None.
 */
void dslhal_api_acknowledgeInterrupt_entry(tidsl_t * ptidsl)
{
  dslhal_support_setInterruptMask(ptidsl, MASK_INTR_ALL);
  dslhal_csl_clearInterrupt();
}

/**
 *  \brief  Re-enable DSL interrupt.
 *  
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @return None.
 */
void dslhal_api_acknowledgeInterrupt_exit(tidsl_t * ptidsl)
{
  dslhal_support_setInterruptMask(ptidsl, 0);
}


/**
 *  \brief  Host interrupt service routine (ISR).
 *          TBD: Pending changes for Yamuna.
 *  
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @param  intrSrc Unused.
 *  @return >=0:    Modem status.
 *          -1:     Failure.
 */
int dslhal_api_handleTrainingInterrupt(tidsl_t *ptidsl, int intrSrc)
{
  return dslhal_api_pollTrainingStatus(ptidsl);
}


/**
 *  \brief  Host interrupt service routine (ISR).
 *  
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @return >=0:    Modem status.
 *          -1:     Failure.
 */
int dslhal_api_pollTrainingStatus(tidsl_t *ptidsl)
{
  //dgprintf(5,"dslhal_api_pollTrainingStatus\n");

  if (dslhal_support_processModemStateBitField(ptidsl))
  {
    return -1;
  }
#ifndef NO_ACT
  if (dslhal_advcfg_logTrainingState(ptidsl))
  {
    return -1;
  }
#endif

  if (dslhal_support_processMailBox(ptidsl, 0)) // 0 for polling
  {
    return -1;
  }

  dgprintf(6,"dslhal_api_pollTrainingStatus done\n");

  return (ptidsl->AppData.bState);
}


/**
 *  \brief  Get DSL Driver version.
 *  
 *  @param  pVer    Pointer to DSL driver version data structure.
 *  @return         None.
 */
void dslhal_api_getDslHalVersion(void  *pVer)
{
  dslVer *pVersion;
  pVersion = (dslVer *)pVer;
  pVersion->major = (unsigned char) DSLHAL_VERSION_MAJOR;
  pVersion->minor = (unsigned char) DSLHAL_VERSION_MINOR;
  pVersion->bugfix = (unsigned char) DSLHAL_VERSION_BUGFIX;
  pVersion->buildNum = (unsigned char) DSLHAL_VERSION_BUILDNUM;
  pVersion->timeStamp = (unsigned char) DSLHAL_VERSION_TIMESTAMP;
}


/**
 *  \brief  Get DSP Datapump version.
 *  
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @param  pVer    Pointer to DSP datapump version data structure.
 *  @return 0:      Success.
 *          -1:     Failure.
 */
int dslhal_api_getDspVersion(tidsl_t *ptidsl, void *pVer)
{
  dgprintf(5, "dslhal_api_getDspVersion\n");

  if (!pVer)
    return -1;

  if (dslhal_support_getDspVersion(ptidsl, pVer))
  {
    return -1;
  }

  return 0;
}


/*TBD*/
/**
 *  \brief  Reads from a Generic Location in the DSP Host Interface
 *
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @param  baseAddr
 *  @param  numOffsets
 *  @param  offsets
 *  @param  localBuffer
 *  @param  numBytes
 *
 *  @return 0:  Success
 *          1:  Failure
 */
unsigned dslhal_api_dspInterfaceRead(
        tidsl_t * ptidsl, 
        unsigned baseAddr, 
        unsigned numOffsets,
        unsigned *offsets, 
        unsigned char *localBuffer, 
        unsigned numBytes)
{
  unsigned i, offset[numOffsets+1];

  if (!ptidsl)
  {
    dgprintf(3,"dslhal_api_dspInterfaceRead(): Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  offset[0] = numOffsets;
  for (i=0; i<numOffsets; i++)
      offset[i+1] = offsets[i];

  return dslhal_support_interfaceRW(baseAddr, offset, 1, localBuffer, numBytes);
}

/*TBD*/
/**
 *  \brief  Writes to a Generic Location in the DSP Host Interface
 *
 *  @param  ptidsl  Main DSL HAL data structure.
 *  @param  baseAddr
 *  @param  numOffsets
 *  @param  offsets
 *  @param  localBuffer
 *  @param  numBytes
 *
 *  @return 0:  Success
 *          1:  Failure
 */
unsigned dslhal_api_dspInterfaceWrite(
        tidsl_t * ptidsl, 
        unsigned baseAddr, 
        unsigned numOffsets,
        unsigned *offsets, 
        unsigned char *localBuffer, 
        unsigned numBytes)
{
  unsigned i, offset[numOffsets+1];

  if (!ptidsl)
  {
    dgprintf(3,"dslhal_api_dspInterfaceWrite(): Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  offset[0] = numOffsets;
  for (i=0; i<numOffsets; i++)
      offset[i+1] = offsets[i];

  return dslhal_support_interfaceRW(baseAddr, offset, 0, localBuffer, numBytes);
}


/*** Public Advanced API ***/

/**
 *  \brief  This fuction Sets the Desired Training Mode.
 *  
 *  @param  ptidsl      Pointer to main DSL HAL data structure.
 *  @param  trainmode   Training mode to be set.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
/*TBD*/
unsigned dslhal_api_setTrainingMode(tidsl_t *ptidsl, unsigned trainmode)
{
  DEV_HOST_oamWrNegoParaDef_t NegoPara;
  DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
  int rc;


  dgprintf(5," dslhal_api_setTrainingMode()\n");

//  if(trainmode>255)
  if(trainmode>0xFFFF) // new trainmode is 16 bit
  {
    dgprintf(3,"Invalid Value (%08x) for Desired Training Mode (must be <0xFFFF)\n", trainmode);
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  if(!ptidsl)
  {
    dgprintf(3, "Error: PTIDSL pointer invalid\n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
  rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
                                sizeof(DEV_HOST_dspOamSharedInterface_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }

  dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned)dspOamSharedInterface.oamWriteNegoParams_p);

  rc = dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&NegoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }

  /* Enum Translation to maintain backwards compatibility for train modes */
  NegoPara.stdMode_byte2 = 0;  // clear std_mode extention byte2-4
  NegoPara.stdMode_bytes34 = 0;
  if(!ptidsl->AppData.useBitField)
  {
      if(trainmode == DSLTRAIN_MULTI_MODE)
        trainmode = MULTI_MODE8;
      if(trainmode == DSLTRAIN_T1413_MODE)
        trainmode = T1413_MODE;
      if(trainmode == DSLTRAIN_GDMT_MODE)
        trainmode = GDMT_MODE;
  }

  NegoPara.stdMode = trainmode & 0xFF;
  if (NegoPara.stdMode==MULTI_MODE8)  // for backward compatibility
    NegoPara.stdMode_byte2 = MULTI_MODE8; // extend multi mode to extra byte
  else
    NegoPara.stdMode_byte2 = (trainmode >> 8) & 0xFF;

  dgprintf(5,"Train Mode: 0x%x\n",trainmode);
  rc = dslhal_support_blockWrite(&NegoPara,(PVOID)dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
  if(rc)
    return DSLHAL_ERROR_CONFIG_API_FAILURE;

  dgprintf(5," dslhal_api_setTrainingMode() Done\n");
  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  This fuction send HOST_QUIET message to DSP.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_dslRetrain(tidsl_t *ptidsl)
{
  return dslhal_support_writeHostMailbox(ptidsl, HOST_QUIET, 0, 0, 0);
}

/**
 *  \brief  This fuction send HOST_IDLE message to DSP.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_sendIdle(tidsl_t *ptidsl)
{
  return dslhal_support_writeHostMailbox(ptidsl, HOST_IDLE, 0, 0, 0);
}

/**
 *  \brief  This fuction send HOST_QUIET message to DSP.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_sendQuiet(tidsl_t *ptidsl)
{
  return dslhal_support_writeHostMailbox(ptidsl, HOST_QUIET, 0, 0, 0);
}

/**
 *  \brief  This fuction send HOST_DGASP message to DSP.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_sendDgasp(tidsl_t *ptidsl)
{
  return dslhal_support_writeHostMailbox(ptidsl, HOST_DGASP, 0, 0, 0);
}

/**
 *  \brief  This fuction send HOST_RJ11SELECT message to DSP 
 *          to select inner/outer pair on RJ11.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  select  inner/outer pair selected.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_selectInnerOuterPair(tidsl_t *ptidsl, unsigned select)
{
  return dslhal_support_writeHostMailbox(ptidsl, HOST_RJ11SELECT, select, 0, 0);
}


/**
 *  \brief  This fuction set the Margin monitoring flag.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  t_flag  Training margin monitoring flag.
 *  @param  s_flag  Showtime margin monitoring flag.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setMarginMonitorFlags(tidsl_t *ptidsl,unsigned t_flag, unsigned s_flag)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(oamWriteNegoParams_p),   /*4*/
      IFACE_OAMWRI_OFFSET(hostFixPga2)      /*12*/  /*TBD*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= dslhal_support_byteSwap32(0xffff0000);
  if (t_flag) 
    data |= dslhal_support_byteSwap32(0x00000001);
  if (s_flag) 
    data |= dslhal_support_byteSwap32(0x00000100);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  This fuction set the Margin threshold.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  value   Margin threshold.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setMarginThreshold(tidsl_t *ptidsl, int value)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(oamWriteNegoParams_p),   /*4*/
      IFACE_OAMWRI_OFFSET(marginThreshold)  /*12*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= dslhal_support_byteSwap32(0x00ffffff);
  data |= dslhal_support_byteSwap32((value & 0xff) << 24);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  This fuction set the LOS alarm flag.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  flag    LOS alarm flag, TRUE to disable, FALSE to enable.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_disableLosAlarm(tidsl_t *ptidsl, unsigned flag)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(oamWriteNegoParams_p),   /*4*/
      IFACE_OAMWRI_OFFSET(disableLosAlarm)  /*13*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= dslhal_support_byteSwap32(0xffff0000);
  if (flag) 
    data |= dslhal_support_byteSwap32(0x01000000);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  This fuction set the 8-byte EOC Vendor ID.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  idBuf   8-byte Vendor ID.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setEocVendorId(tidsl_t *ptidsl, char *idBuf)
{
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(oamWriteNegoParams_p),   /*4*/
      IFACE_OAMWRI_OFFSET(gdmtVendorId)     /*14*/
    };

  return dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, idBuf, 8);
}

/**
 *  \brief  This fuction set the 32-byte EOC Serial Number.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  snBuf   32-byte serial number.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setEocSerialNumber(tidsl_t *ptidsl, char *snBuf)
{
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(eocVar_p),               /*11*/
      IFACE_EOCVAR_OFFSET(serialNumber)     /*19*/
    };

  return dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, snBuf, 32);
}

/**
 *  \brief  This fuction set the EOC Revision Number.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  revBuf  16-byte in ADSL2/2+, 4-byte in G.992.1.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setEocRevisionNumber(tidsl_t *ptidsl, char *revBuf)
{
  int count = 0;  //CQ10037
  char *temp = revBuf; //CQ10037

  unsigned offset[] = {
      2, 
      IFACE_OFFSET(eocVar_p),           /*11*/
      IFACE_EOCVAR_OFFSET(revNumber)    /*18*/
    };

  // CQ10037: If length of RevNumber is 16 bytes, 
  // then it is used to set version number in ADSL2, ADSL2+ modes
  // else it is used to set revision number in G.992.1 mode.
  
  while (*temp++ != '\0') count++;                    
  
  if (count == 16)
  {
    offset[2] = IFACE_EOCVAR_OFFSET(revNumber_2p);    
  }
  else 
  {
    count = 4;
  }

  return dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, revBuf, count);
}


/**
 *  \brief  This fuction set the Trellis Coding Enable Flag
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  flag    if flag = TRUE, set trellis flag else reset.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_setTrellisFlag(tidsl_t *ptidsl, unsigned flag)
{
  DEV_HOST_msg_t aturMsg;
  DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
  DEV_HOST_oamWrNegoParaDef_t negoPara;
  int rc;
  dgprintf(5," dslhal_api_setTrellisFlag()\n");
  if(!ptidsl)
  {
    dgprintf(3, "Error: PTIDSL pointer invalid\n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }
  pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;

  rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }

  dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *)dslhal_support_byteSwap32((unsigned)dspOamSharedInterface.aturMsg_p);
  rc += dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,&aturMsg, sizeof(DEV_HOST_msg_t));
  dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned)dspOamSharedInterface.oamWriteNegoParams_p);
  rc += dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&negoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }

  if(flag)
  {
    aturMsg.trellis = TRUE;
    negoPara.rMsgs1[2] |= 0x02;
  }
  else
  {
    aturMsg.trellis = FALSE;
    negoPara.rMsgs1[2] &= 0xFD;
  }
  rc=0;
  rc+=dslhal_support_blockWrite(&aturMsg,dspOamSharedInterface.aturMsg_p,sizeof(DEV_HOST_msg_t));
  rc+= dslhal_support_blockWrite(&negoPara,dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
  if(rc)
    return DSLHAL_ERROR_CONFIG_API_FAILURE;

  dgprintf(5," dslhal_api_setTrellisFlag() Done\n");
  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  This fuction set the Rate Adapt flag.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  flag    Rate Adapt flag, TRUE to enable, FALSE to disable.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setRateAdaptFlag(tidsl_t *ptidsl, unsigned flag)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(aturMsg_p),      /*8*/
      IFACE_HSTMSG_OFFSET(vendorId) /*0*/  /*TBD: rateAdapt*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= dslhal_support_byteSwap32(0xffffff00);
  if (flag) 
    data |= dslhal_support_byteSwap32(0x00000001);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  This fuction set the Maximum bits per carrier value in Upstream band.
 *  
 *  @param  ptidsl     Pointer to main DSL HAL data structure.
 *  @param  maxbits    should be a value between 0-15.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setMaxBitsPerCarrierUpstream(tidsl_t *ptidsl, unsigned maxbits)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(aturMsg_p),      /*8*/
      IFACE_HSTMSG_OFFSET(trellis)  /*1*/  /*TBD: maxBits*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= dslhal_support_byteSwap32(0xffff00ff);
  data |= dslhal_support_byteSwap32((maxbits & 0xF) << 8);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  This fuction set the the Maximum Interleave Depth Supported.
 *  
 *  @param  ptidsl     Pointer to main DSL HAL data structure.
 *  @param  maxdepth   0, 1, 2, or 3 for 64, 128, 256, or 512 max depth.
 *  @return - 0:    Success
 *          - 1:    Failure
 */
unsigned dslhal_api_setMaxInterleaverDepth(tidsl_t *ptidsl, unsigned maxdepth)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(aturMsg_p),          /*8*/
      IFACE_HSTMSG_OFFSET(actualPsd)    /*2*/  /*TBD: maxIntlvDepth*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= dslhal_support_byteSwap32(0xff00ffff);
  data |= dslhal_support_byteSwap32((maxdepth & 0x3) << 16);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  This fuction configure LED.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  idLed   LED ID.
 *  @param  onOff   ON or OFF.   
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned int dslhal_api_configureLed(tidsl_t * ptidsl, unsigned int idLed, unsigned int onOff)
{
  int rc = 0;
  DEV_HOST_modemEnvPublic_t modemEnv;
  DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
  
#ifdef HOST_CONTROLLED_LED  
  volatile unsigned int *GPIO_DIR = (volatile unsigned int*)(0xa1000700);
  volatile unsigned int *GPIO_OUT = (volatile unsigned int*)(0xa1000704);
  unsigned int LED_BIT = 2;
 #endif
 
  if(idLed>2 || onOff>2)
  {
    dgprintf(3,"Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  if(!ptidsl)
  {
    dgprintf(3, "Error: PTIDSL pointer invalid\n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }
  
  //Host controlled for DSLSS LED  
  #ifdef HOST_CONTROLLED_LED 
  if (onOff==2) // Configure LED
  {   
    pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;

    rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
    if (rc)
    {
      dgprintf(1,"dslhal_support_blockRead failed\n");
      return DSLHAL_ERROR_BLOCK_READ;
    }
  
    dspOamSharedInterface.modemEnvPublic_p = (DEV_HOST_modemEnvPublic_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemEnvPublic_p);
    rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemEnvPublic_p,
                                  &modemEnv, sizeof(DEV_HOST_modemEnvPublic_t));
    if (rc)
    {
      dgprintf(1,"dslhal_support_blockRead failed\n");
      return DSLHAL_ERROR_BLOCK_READ;
    }
    modemEnv.overrideDslLinkLed_f = TRUE;
    rc = dslhal_support_blockWrite(&modemEnv,dspOamSharedInterface.modemEnvPublic_p,sizeof(DEV_HOST_modemEnvPublic_t));
     
    *GPIO_DIR &= ~LED_BIT; //configure GPIO direction as output
  }
  else if(onOff==0) //ON
  {
    *GPIO_OUT &= ~LED_BIT;
  }
  else if (onOff==1) //OFF
  {
    *GPIO_OUT |= LED_BIT;
  }
  #else   
  
  pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;

  rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }

  dspOamSharedInterface.modemEnvPublic_p = (DEV_HOST_modemEnvPublic_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemEnvPublic_p);
  rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemEnvPublic_p,
                                &modemEnv, sizeof(DEV_HOST_modemEnvPublic_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }
  if(idLed==ID_DSL_LINK_LED)
  {
    modemEnv.overrideDslLinkLed_f = TRUE;
    if(onOff!=2)
      modemEnv.dslLinkLedState_f = onOff;
  }
  if(idLed==ID_DSL_ACT_LED)
  {
    modemEnv.overrideDslActLed_f = TRUE;
    if(onOff!=2)
      modemEnv.dslActLedState_f = onOff;
  }
  if(idLed==ID_RESTORE_DEFAULT_LED)
  {
    modemEnv.overrideDslLinkLed_f = FALSE;
    modemEnv.overrideDslActLed_f = FALSE;
  }
  rc=dslhal_support_blockWrite(&modemEnv,dspOamSharedInterface.modemEnvPublic_p,sizeof(DEV_HOST_modemEnvPublic_t));
#endif //HOST_CONTROLLED_LED
  if(rc)
    return DSLHAL_ERROR_MODEMENV_API_FAILURE;
  else 
    return DSLHAL_ERROR_NO_ERRORS;

}


/**
 *  \brief  This fuction configure dying gasp LPR signal.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  cfgPrm  Select to configure LPR intepretation or override.
 *  @param  prmVal  if LPR interpretation, 0 = LPR is active-low; 1 = LPR is active-high.
 *                  if LPR override, 0 = DSP detects LPR; 1 = Host detects LPR and sends "HOST_DGASP" to DSP.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_configureDgaspLpr(tidsl_t * ptidsl, unsigned cfgPrm, unsigned prmVal)
{
  int rc;
  DEV_HOST_modemEnvPublic_t modemEnv;
  DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
  if(cfgPrm>1 || prmVal>1)
  {
    dgprintf(3,"Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  if(!ptidsl)
  {
    dgprintf(3, "Error: PTIDSL pointer invalid\n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }
  pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;

  rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }

  dspOamSharedInterface.modemEnvPublic_p = (DEV_HOST_modemEnvPublic_t *)dslhal_support_byteSwap32((unsigned)dspOamSharedInterface.modemEnvPublic_p);
  rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemEnvPublic_p,
                                &modemEnv, sizeof(DEV_HOST_modemEnvPublic_t));
  if (rc)
  {
    dgprintf(1,"dslhal_support_blockRead failed\n");
    return DSLHAL_ERROR_BLOCK_READ;
  }
  if(cfgPrm==0)
  {
    modemEnv.dGaspLprIndicator_f = prmVal;
  }
  if(cfgPrm==1)
  {
    modemEnv.overrideDspLprGasp_f = prmVal;
  }
  rc=dslhal_support_blockWrite(&modemEnv,dspOamSharedInterface.modemEnvPublic_p,sizeof(DEV_HOST_modemEnvPublic_t));
  if(rc)
    return DSLHAL_ERROR_MODEMENV_API_FAILURE;
  else
    return DSLHAL_ERROR_NO_ERRORS;
}


// DW 12/29/04 CQ 9356 Common declarations
/**
 *  \brief  Currently 4 parameter IDs exist:
 *          0-1 for Phy features and 2-3 for Interop features.
 */
#define MAX_PHY_FEATURE_PARAMID 3

/**
 *  \brief  This fuction configure PHY features that will be controlled by the MIPS.
 *          This will over-ride DSP defaults.
 *          Notes:
 *          The dslhal_api_enableDisablePhyFeature function should be called after this fxn
 *          to actually turn on/off the specific features
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  prmId   Selected Feature list #.
 *  @param  ctrlWd  Control bits to be set.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_setPhyFeatureController(tidsl_t *ptidsl, unsigned prmId, unsigned ctrlWd)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      3, 
      IFACE_OFFSET(phyControl_p),       /*35*/
      prmId,
      IFACE_PHYCNF_OFFSET(phyControl)   /*1*/
    };

  if (prmId > MAX_PHY_FEATURE_PARAMID)
  {
    dgprintf(3,"Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data = dslhal_support_byteSwap32(ctrlWd);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  This fuction configure PHY features that will be controlled by the MIPS.
 *          This will over-ride DSP defaults.
 *          Notes:
 *          This function is useless if called on its own. dslhal_api_setPhyFeatureController 
 *          and dslhal_api_readPhyFeatureController should be called with reqd params to 
 *          enable this function to turn on/off DSP features.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  prmId   Selected Feature list #.
 *  @param  ftrWd   Feature bits to be set.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_enableDisablePhyFeatures(tidsl_t *ptidsl, unsigned prmId, unsigned ftrWd)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      3, 
      IFACE_OFFSET(phyControl_p),       /*35*/
      prmId,
      IFACE_PHYCNF_OFFSET(phyFeature)   /*0*/
    };

  if (prmId > MAX_PHY_FEATURE_PARAMID)
  {
    dgprintf(3,"Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data = dslhal_support_byteSwap32(ftrWd);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  This fuction read the PHY features control & enable/disable settings
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  prmId   Selected Feature list #.
 *  @param  phyPtr  Pointer to PHY Feature Configuration data structure.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_readPhyFeatureSettings(tidsl_t *ptidsl, unsigned prmId, void *phyPtr)
{
  unsigned rc = 0, data[2] = {0,0};
  unsigned offset[] = {
      3, 
      IFACE_OFFSET(phyControl_p),       /*35*/
      prmId,
      IFACE_PHYCNF_OFFSET(phyFeature)   /*0*/
    };
  phySettings *pPhySetting = (phySettings *)phyPtr;

  if (prmId > MAX_PHY_FEATURE_PARAMID)
  {
    dgprintf(3,"Invalid input parameter \n");
    return DSLHAL_ERROR_INVALID_PARAM;
  }

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 8);
  if (rc)
    return rc;

  pPhySetting->phyEnableDisableWord = dslhal_support_byteSwap32(data[0]);
  pPhySetting->phyControlWord       = dslhal_support_byteSwap32(data[1]);

  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  Read/Write upstream Bitswap enable byte in host interface.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  rw      1: read, 0: write.
 *  @param  byte    Enable/Disable upstream Bitswap.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_usBitSwap(tidsl_t *ptidsl, unsigned rw, unsigned byte)
{
  unsigned rc = 0, data;
  unsigned offset[] = {
      2,
      IFACE_OFFSET(olrDspRx_p), /*32*/
      0
      };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);

  if (rw == 0)
  {  /*write*/
    data &= BYTE_SWAP32(0xFFFFFF00);
    if (byte)  data |= BYTE_SWAP32(byte & 0xFF);
    rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  }

  ptidsl->AppData.usBitSwap = BYTE_GET(data, 0);

  return rc;
}


/**
 *  \brief  Read/Write downstream Bitswap enable byte in host interface.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  rw      1: read, 0: write.
 *  @param  byte    Enable/Disable downstream Bitswap.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_dsBitSwap(tidsl_t *ptidsl, unsigned rw, unsigned byte)
{
  unsigned rc = 0, data;
  unsigned offset[] = {
      2,
      IFACE_OFFSET(olrDspRx_p), /*33*/
      0
      };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);

  if (rw == 0)
  {  /*write*/
    data &= BYTE_SWAP32(0xFFFFFF00);
    if (byte)  data |= BYTE_SWAP32(byte & 0xFF);
    rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  }

  ptidsl->AppData.dsBitSwap = BYTE_GET(data, 0);

  return rc;
}


/**
 *  \brief  Set Fine Gain Control byte in host interface.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  value   0: datapump controls the maximum average fine gain value,
                    1: host controls the maximum average fine gain value.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_setFineGainCtrl(tidsl_t *ptidsl, unsigned value)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(modemEnvPublic_p),           /*25*/
      IFACE_MDMENV_OFFSET(dGaspLprIndicator_f)  /*2*/  /*TBD*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  if(value == 1)
  {
    data |= BYTE_SWAP32(0x01000000);
  }
  else
  {
    data &= BYTE_SWAP32(0x00ffffff);
  }

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}

/**
 *  \brief  Set Fine Gain max value in host interface.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  value   Maximum average fine gain level in 256log2 units.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_setFineGainValue(tidsl_t *ptidsl, unsigned value)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(modemEnvPublic_p),           /*25*/
      IFACE_MDMENV_OFFSET(maxAverageFineGain)   /*4*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data &= BYTE_SWAP32(0xffff0000);
  data |= BYTE_SWAP32(value & 0x0000ffff);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}


/**
 *  \brief  Set OAM Feature (32-bit word) in host interface.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  value   32-bit OAM feaure word.
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_setOamFeature(tidsl_t *ptidsl, unsigned value)
{
  unsigned rc = 0, data = 0;
  unsigned offset[] = {
      2, 
      IFACE_OFFSET(oamWriteNegoParams_p),   /*4*/
      IFACE_OAMWRI_OFFSET(oamFeature)       /*11*/
    };

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 1, &data, 4);
  if (rc)
    return rc;

  data |= BYTE_SWAP32(value);

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pmainAddr, offset, 0, &data, 4);
  if (rc)
    return rc;

  return DSLHAL_ERROR_NO_ERRORS;
}


#ifdef AFE_DIAG

#include "afe_diag.h"
#include <asm-mips/uaccess.h> 

unsigned test_status = AFE_TEST_DEFAULT;
afe_diag_config_t tmpConfig;
UINT8 tmpTestdata[AFE_DIAG_TESTDATA_SIZE * AFE_DIAG_NUM_FRAMES];

/**
 *  \brief  Config AFE diagnostics.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  pConfig Pointer to config data structure.
 *
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_afeDiagConfig(tidsl_t *ptidsl, void *pConfig)
{
  unsigned rc = 0, addr = 0;
  unsigned offset[] = {
      1, 
      13    /*afe_diag_config_p*/
    };

  dgprintf(3,"dslhal_api_afeDiagConfig(): size=%d\n", sizeof(afe_diag_config_t));

  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pIntAddr, offset, 1, &addr, 4);

  if (rc)
    return rc;

  addr = BYTE_SWAP32(addr);
  rc = copy_from_user((void *)&tmpConfig, pConfig, sizeof(afe_diag_config_t));
  // TODO decide return error code
  if (rc)
    return rc; 
  rc = dslhal_support_blockWrite((void *)&tmpConfig, (void *)(addr), sizeof(afe_diag_config_t));

  if (rc)
    return rc;

  /* Send AFE_START mailbox message to DSP */
  rc = dslhal_support_writeHostMailbox(ptidsl, HOST_USER_ADIAG, 0, 0, 0);

  return rc;
}

/**
 *  \brief  Fetch AFE diagnostics.
 *  
 *  @param  ptidsl  Pointer to main DSL HAL data structure.
 *  @param  pBuf    Pointer to test out data buffer.
 *  @param  pLen    Pointer to the length (in bytes) of the buffer.
 *
 *  @return 0:      Success
 *          other:  Failure
 */
unsigned dslhal_api_afeDiagFetch(tidsl_t *ptidsl, void *pBuf, unsigned *pLen)
{
  unsigned rc = 0, data[3];
  unsigned offset[] = {
      1,
      14    /*afe_diag_testdata_p*/
    };

// test_status is not used
#if 0
  if (test_status != AFE_TEST_STOP)
  {
    *pLen = 0;
    dgprintf(3,"dslhal_api_afeDiagFetch(): test not stop yet\n");
    return rc;  /*TBD*/
  }
  test_status = AFE_TEST_DEFAULT;

#endif
  rc = dslhal_support_interfaceRW((unsigned)ptidsl->pIntAddr, offset, 1, &data[2], 4);
  dgprintf(4, "pIntAddr=%x, data[2]=%x\n", (unsigned)ptidsl->pIntAddr, data[2]);
  if (rc)
    return rc;

  data[2] = BYTE_SWAP32(data[2]);
  rc = dslhal_support_blockRead((void *)(data[2]), (void *)(&data[0]), 8);
  dgprintf(4,"data[0]=%x, data[2]=%x\n",data[0], data[2]);

  if (rc)
    return rc;

  if (data[0])
  {
    data[0] = BYTE_SWAP32(data[0]);
    data[1] = BYTE_SWAP32(data[1]);
    {
    rc = dslhal_support_blockRead((void *)(data[1]), (void *)tmpTestdata, data[0]*AFE_DIAG_TESTDATA_SIZE);
    if (rc)
      return rc;
    // TODO decide error code 
    rc = copy_to_user(pBuf, (void *)tmpTestdata,data[0]*AFE_DIAG_TESTDATA_SIZE);
    if (rc)
      return rc;
    }
    
    
    *pLen = data[0];
  }

  dgprintf(4,"dslhal_api_afeDiagFetch(): FrameNr=%d, buf addr=%x\n", data[0], data[1]);
  return rc;
}

#endif //#ifdef AFE_DIAG

