

#include "ddc_ti_dsl.h"


#ifdef YAMUNA
#define DSL_PHYS_ADDR   HOST_MEM_V2P
#define DSL_PHYS_TO_K1  HOST_MEM_V2P
#endif


#define CLEAREOC_ACK    0x80
#define CEOC_RESP     0x02  // define clearEoc Ctrl as in G.992.3 sec7.8.2.4.1
#define CEOC_CMD      0x00

static int eocctrl_resp=0;
static int eocctrl_cmd=0;

/*
 * Max clear eoc msgsize must be equal to
 * OVHD_clearEOC_hostBufSize, which is defined
 * <dev_host_interface.h>
 */

#define MAX_RAW_CLEAR_EOC_MSGSIZE  514       // see ITU G997.1

#define HDLC_INIT      0xFFFF
#define HDLC_FLAG      0x7E
#define HDLC_ESC       0x7D
#define HDLC_INV       0x20
#define HDLC_GENPOL    0x8408
#define HDLC_GOOD      0xF0B8

typedef struct
{
  unsigned int  len;                               // packet length
  unsigned char   data[MAX_CLEAR_EOC_BUF_SIZE];      // data field
} clearEocBufDesc_type;

/* *INDENT-OFF* */
typedef struct
{
  unsigned int            clearEocEnabled;   // 0: disabled; 1: enabled
  clearEocBufDesc_type   *pTxBufDesc[4];     // Tx buffer desc pointer array
  clearEocBufDesc_type   *pRxBufDesc[4];     // Rx buffer desc pointer array
  unsigned int            txRdIndex;         // host write
  unsigned int            txWrIndex;         // DSP write
  unsigned int            rxRdIndex;         // DSP write
  unsigned int            rxWrIndex;         // host write
} clearEocParm_t;
/* *INDENT-ON* */

//L2 Buffer Struct Type
typedef struct {
  unsigned short L2UBufInInx;              //L2 module write, OVHD module read only
  unsigned short L2UBufOutInx;             //OVHD module write, L2 module read only
  unsigned short L2DBufInInx;              //OVHD module write, L2 module read only
  unsigned short L2DBufOutInx;             //L2 module write, OVHD module read only
  unsigned char  L2StatusFlag;             //rcv L2 status Flag
  unsigned char  dummy[3];
  unsigned char  *L2UBuf;                   //L2 upstream buffer
  unsigned char  *L2DBuf;                   //L2 downstream buffer
  unsigned short L2TxBufSize;              //L2  transmit buffer size
  unsigned short L2RxBufSize;              //L2  receive buffer size
} DI_L2_BufDef_t;

typedef DI_L2_BufDef_t DEV_HOST_L2clearEocDef_t;
static clearEocParm_t    ClrEoc;
static clearEocParm_t   *pClrEOC = &ClrEoc;
static int   EocRxTotalPackets;
static int   EocTxTotalPackets;
static int   EocRxTotalBytes;
static int   EocTxTotalBytes;
static int   ErrEocBufFull;
static int   ErrEocBufIndex;
static int   ErrEocBufMax;
static int   ErrEocMsgOversized;
static int   ErrEocTxHdlcCRC;
static int   ErrEocRxHdlcCRC;
static int   ErrEocRxHdlcFraming;
static int   ErrEocRxPush;

//CQ10269 cph 1/16/06 Fixed clearEoc Crash problem
static clearEocBufDesc_type   *pTxBufDescSave[4];     // Tx buffer desc pointer array
static clearEocBufDesc_type   *pRxBufDescSave[4];

/************************************************************
NEED FN HEADER
************************************************************/
int DDC_dsl_clear_eoc_setup(DDC_DslPriv *priv)
{
  int   i;
  int   offset[2] = {34, 0};
  int   offset_int[]={11};  // internal interface
  DEV_HOST_L2clearEocDef_t L2ceoc, *L2ceoc_p = NULL;
  char *p;
  int   eoc_ptr;
  clearEocParm_t   peoc;
  unsigned int phyAddr;

  dslhal_api_dspInterfaceRead(priv->pIhw, (unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)pClrEOC, sizeof(clearEocParm_t));

  for (i=0; i<4; i++)
  {
    clearEocBufDesc_type  *pBuf;

    // Alloc buf and descriptor for Tx
    p = DDA_malloc(sizeof(clearEocBufDesc_type));
    //p = shim_osAllocateDmaMemory(sizeof(clearEocBufDesc_type));
    if (p == NULL)
    {
      int j;

//    DDA_printf("DDC_dsl_clear_eoc_setup: DDA_malloc() failed\n");

      for (j=i-1; j>=0; j--)
      {
         //shim_osFreeDmaMemory(pClrEOC->pTxBufDesc[j], sizeof(clearEocBufDesc_type));
//         DDA_free(pClrEOC->pTxBufDesc[j]);
         DDA_free(pTxBufDescSave[j]); //cph 1/16/06
         //shim_osFreeDmaMemory(pClrEOC->pRxBufDesc[j], sizeof(clearEocBufDesc_type));
//         DDA_free(pClrEOC->pRxBufDesc[j]);
         DDA_free(pRxBufDescSave[j]); //cph 1/16/06
      }

      return(1);
    }

    pBuf = (clearEocBufDesc_type *)p;
    pBuf->len  = 0;
    pTxBufDescSave[i] = pBuf; //cph 1/16/06
    pClrEOC->pTxBufDesc[i] = (clearEocBufDesc_type *) DSL_PHYS_TO_K1((unsigned int) pBuf);

    /*
     * Alloc buf and descriptor for Rx
     */
     p = DDA_malloc(sizeof(clearEocBufDesc_type));
    //p = shim_osAllocateDmaMemory(sizeof(clearEocBufDesc_type));
    if (p == NULL)
    {
      int j;

//    DDA_printf("DDC_dsl_clear_eoc_setup: DDA_malloc() failed\n");

      //shim_osFreeDmaMemory(pClrEOC->pTxBufDesc[i], sizeof(clearEocBufDesc_type));
//      DDA_free(pClrEOC->pTxBufDesc[i]);
      DDA_free(pTxBufDescSave[i]); //cph 1/16/06

      for (j=i-1; j>=0; j--)
      {
         //shim_osFreeDmaMemory(pClrEOC->pTxBufDesc[j], sizeof(clearEocBufDesc_type));
//         DDA_free(pClrEOC->pTxBufDesc[j]);
         DDA_free(pTxBufDescSave[j]); //cph 1/16/06
         //shim_osFreeDmaMemory(pClrEOC->pRxBufDesc[j], sizeof(clearEocBufDesc_type));
//         DDA_free(pClrEOC->pRxBufDesc[j]);
         DDA_free(pRxBufDescSave[j]); //cph 1/16/06
      }

      return(1);
    }

    pBuf = (clearEocBufDesc_type *)p;
    pBuf->len  = 0;
    pRxBufDescSave[i] = pBuf; //cph 1/16/06
    pClrEOC->pRxBufDesc[i] = (clearEocBufDesc_type *) DSL_PHYS_TO_K1((unsigned int) pBuf);
  }

  pClrEOC->txRdIndex = pClrEOC->txWrIndex = 0;
  pClrEOC->rxRdIndex = pClrEOC->rxWrIndex = 0;

  pClrEOC->clearEocEnabled = 1;

  for (i=0; i<4; i++)
  {
    /*shim_osInvalidateCache(pClrEOC->pTxBufDesc[i], sizeof(clearEocBufDesc_type)); */
    DDC_atm_data_invalidate(pClrEOC->pTxBufDesc[i], sizeof(clearEocBufDesc_type));

    eoc_ptr = host2dspAddrMapping((unsigned int)pClrEOC->pTxBufDesc[i]);
    peoc.pTxBufDesc[i] = (clearEocBufDesc_type *)dslhal_support_byteSwap32(eoc_ptr);
//  DDA_printf("pTxBufDesc[%d] = 0x%08x\n", i, (unsigned int)peoc.pTxBufDesc[i]);
  }

  for (i = 0; i < 4; i++)
  {
    /*shim_osInvalidateCache(pClrEOC->pRxBufDesc[i], sizeof(clearEocBufDesc_type));*/
    DDC_atm_data_invalidate(pClrEOC->pRxBufDesc[i], sizeof(clearEocBufDesc_type));

    eoc_ptr = host2dspAddrMapping((unsigned int)pClrEOC->pRxBufDesc[i]);
    peoc.pRxBufDesc[i] = (clearEocBufDesc_type *)dslhal_support_byteSwap32(eoc_ptr);
//  DDA_printf("pRxBufDesc[%d] = 0x%08x\n", i, (unsigned int)peoc.pRxBufDesc[i]);
  }

  peoc.clearEocEnabled = dslhal_support_byteSwap32(1);
//DDA_printf("clearEocEnabled = %d\n", peoc.clearEocEnabled);

  peoc.txRdIndex = peoc.txWrIndex = 0;
  peoc.rxRdIndex = peoc.rxWrIndex = 0;

#if 1 // clearEoc L2 buffer setup
  // read
#if 1  /*UR8 DSLHAL*/
  dslhal_api_dspInterfaceRead(priv->pIhw,(unsigned int)priv->pIhw->pIntAddr, 1, (unsigned int *)&offset_int, 
          (unsigned char *)L2ceoc_p, sizeof(void *));
#else
  L2ceoc_p = (DEV_HOST_L2clearEocDef_t *) dslhal_support_readInternalOffset(priv->pIhw, 1, offset_int);
#endif
  dslhal_support_blockRead((void *) L2ceoc_p, &L2ceoc, sizeof(DEV_HOST_L2clearEocDef_t));

  phyAddr =  DSL_PHYS_ADDR((unsigned int) pClrEOC->pTxBufDesc[0]->data);
  L2ceoc.L2UBuf= (unsigned char *) dslhal_support_byteSwap32(phyAddr);

  phyAddr =  DSL_PHYS_ADDR((unsigned int) pClrEOC->pRxBufDesc[0]->data);
  L2ceoc.L2DBuf= (unsigned char *) dslhal_support_byteSwap32(phyAddr);

  dslhal_support_blockWrite(&L2ceoc, (void *) L2ceoc_p, sizeof(DEV_HOST_L2clearEocDef_t));
#endif
  // write the clear eoc memory ptr to DSP
  dslhal_api_dspInterfaceWrite(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)&peoc, sizeof(clearEocParm_t));

  return(0);
}

/************************************************************
NEED FN HEADER
************************************************************/
int DDC_dsl_clear_eoc_close(DDC_DslPriv * priv)
{
  int    i;
  int    offset[2] = {34, 0};
  clearEocBufDesc_type  *p;

  EocRxTotalPackets  = 0;
  EocTxTotalPackets  = 0;
  EocRxTotalBytes    = 0;
  EocTxTotalBytes    = 0;

  ErrEocBufFull      = 0;
  ErrEocBufIndex     = 0;
  ErrEocBufMax       = 0;
  ErrEocMsgOversized = 0;
  ErrEocTxHdlcCRC    = 0;
  ErrEocRxHdlcCRC    = 0;
  ErrEocRxHdlcFraming= 0;
  ErrEocRxPush       = 0;

  for (i=0; i<4; i++)
  {
//     p = pClrEOC->pTxBufDesc[i];
     p = pTxBufDescSave[i];
     if (p)
     {
        //shim_osFreeDmaMemory((char *)p, sizeof(clearEocBufDesc_type));
        DDA_free(p);
     }

     pTxBufDescSave[i] = pClrEOC->pTxBufDesc[i] = 0;

//     p = pClrEOC->pRxBufDesc[i];
     p = pRxBufDescSave[i];
     if (p)
     {
        //shim_osFreeDmaMemory((char *)p, sizeof(clearEocBufDesc_type));
        DDA_free(p);
     }

     pTxBufDescSave[i] = pClrEOC->pRxBufDesc[i] = 0;
  }

  pClrEOC->clearEocEnabled = 0;
  pClrEOC->txRdIndex = pClrEOC->txWrIndex = 0;
  pClrEOC->rxRdIndex = pClrEOC->rxWrIndex = 0;

  dslhal_api_dspInterfaceWrite(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)pClrEOC, sizeof(clearEocParm_t));

  return(0);
}



/**********************************************************************
**                                                                    *
**  DDC_dsl_hdlc_update_crc() -- Calculate CRC                         *
**                                                                    *
**  Input Parms:                                                      *
**      new_byte  --  data byte to be counted into CRC                *
**      crc_reg   --  current CRC value before the new_byte           *
**                                                                    *
**  Output:                                                           *
**      --                                                            *
**                                                                    *
**  Return:                                                           *
**      new_crc   --  new CRC value after new_byte is calculated in   *
**                                                                    *
***********************************************************************/
static unsigned short DDC_dsl_hdlc_update_crc (unsigned char new_byte,
                                              unsigned short crc_reg)
{
  int i;

  crc_reg = crc_reg ^ new_byte;
  for (i=0; i<8; i++)
     if (crc_reg & 0x0001)
        crc_reg = (crc_reg>>1) ^ HDLC_GENPOL;
     else
        crc_reg = crc_reg >> 1;

  return (crc_reg);
}

/**********************************************************************
**                                                                    *
**  DDC_dsl_hdlc_tx_process()  -- HDLC Framing                         *
**                                                                    *
**  Input Parms:                                                      *
**      data   --   pointer to HDLC framed data btyes (output)        *
**      msg    --   pointer to data bytes to be HDLC framed (input)   *
**      len    --   length of data bytes pointed to by msg            *
**      msgOriented_flag --                                           *
**                  1= message oriented clear eoc (ADSL2/2+)          *
**                  0= bit oriented clear eoc (GDMT)                  *
**  Output:                                                           *
**      data   --   pointer to HDLC frame generated                   *
**      len    --   length of data bytes in the HDLC frame pointed to *
**                  by 'data' pointer                                 *
**                                                                    *
**  Return:                                                           *
**      0  --  Success                                                *
**      1  --  Failure                                                *
**                                                                    *
***********************************************************************/
static int DDC_dsl_hdlc_tx_process(unsigned char *data, unsigned char *msg, unsigned int *len, int msgOriented_flag)
{
  unsigned short int crc; /* 16 bit unsigned integer */
  int      N, j, msglen;
  char     temp;

  if ((data==NULL) || (msg==NULL))
  {
     return(1);
  }

 if (msgOriented_flag)
  {
// message oriented clear eoc
    // used in ADSL2/2+
    // CTRL:   LSB: 0 & 1 Alternate when send
    //     2nd LSB: 0=command, 1=response.
    data[0]= 0x01; // NORMAL_PRIORITY (addr)
    data[2]= 0x08;  // clearEoc cmd
    if (msgOriented_flag & CLEAREOC_ACK)
    {
      data[1]= CEOC_RESP | eocctrl_resp; // CTRL: response
      data[3]= 0x80;  // ACK Response
      *len=4;
      eocctrl_resp ^=0x01;   // Toggle resp LSB
    }
    else
    {
      data[1]= CEOC_CMD | eocctrl_cmd; // CTRL: response
      data[3]= 0x01;    // clearEoc sub-command
      data[4]= 0x81;
      data[5]= 0x4c;

    //shim_osMoveMemory(&data[6], msg, *len);
      DDA_memcpy((int *)&data[6], (int *)msg, *len);
      *len+=6;
      eocctrl_cmd ^= 0x01; // Toggle cmd LSB
    }
    return 0;
  }

  msglen = *len;

  data[0] = 0x7E;
  crc     = HDLC_INIT;
  data[1] = 0xFF;
  crc     = DDC_dsl_hdlc_update_crc(data[1], crc);
  data[2] = 0x03;
  crc     = DDC_dsl_hdlc_update_crc(data[2], crc);

  data[3] = 0x81;      // SNMP protocol identifier -- G.997.1
  crc     = DDC_dsl_hdlc_update_crc(data[3], crc);
  data[4] = 0x4C;      // SNMP protocol identifier -- G.997.1
  crc     = DDC_dsl_hdlc_update_crc(data[4], crc);

  N = 5;
  j = 0;
  while (j < msglen)
  {
     temp = msg[j++];
     crc = DDC_dsl_hdlc_update_crc(temp, crc);
     if ((temp == HDLC_FLAG) || (temp == HDLC_ESC))
     {
        data[N] = HDLC_ESC;
        data[N+1] = temp ^ HDLC_INV;
        N = N + 2;
     }
     else
     {
        data[N] = temp;
        N = N + 1;
     }
  }

  crc = ~crc;

  for (j=0; j<2; crc >>= 8, j++)
  {
     temp = crc & 0x00FF;
     if ((temp == HDLC_FLAG) || (temp == HDLC_ESC))
     {
        data[N] = HDLC_ESC;
        data[N+1] = temp ^ HDLC_INV;
        N = N + 2;
     }
     else
     {
        data[N] = temp;
        N = N + 1;
     }
  }

  data[N] = 0x7E;

  *len = N + 1;

  return(0);
}

/**********************************************************************
**                                                                    *
**  DDC_dsl_hdlc_rx_process()  -- HDLC De-Framing                      *
**                                                                    *
**  Input Parms:                                                      *
**      data   --   pointer to HDLC-deframed data bytes (output)      *
**      msg    --   pointer to HDLC frame (input)                     *
**      len    --   length of data bytes pointed to by msg            *
**      msgOriented_flag --                                           *
**                  1= message oriented clear eoc (ADSL2/2+)          *
**                  0= bit oriented clear eoc (GDMT)                  *
**  Output:                                                           *
**      data   --   pointer to HDLC de-framed                         *
**      len    --   length of data bytes pointed to by 'data'         *
**                                                                    *
**  Return:                                                           *
**      0  --  Success                                                *
**      1  --  Failure                                                *
**                                                                    *
***********************************************************************/
static int DDC_dsl_hdlc_rx_process(unsigned char *data, unsigned char *msg, unsigned int *len, int msgOriented_flag)
{
  unsigned short int crc; /* 16 bit unsigned integer */
  unsigned char  rxbyte;
  int      N, j, msglen;
  int      ret = 1;

  if ((data==NULL) || (msg==NULL))
  {
     return(1);
  }

  msglen = *len;
  rxbyte = msg[0];
 DDA_printf("hdlc rx v0.6 len %d msg %x,%x,%x,%x,%x,%x,%x\n",*len,msg[0],msg[1],msg[2],msg[3],msg[4],msg[5],msg[6]);

  if (msgOriented_flag)
  {
    // message oriented clearEoc, used in ADSL2/2+
    // ADSL2/2+; expected pattern: 01 01 08 01 81 4c ....
    if (rxbyte != 0x01) // Normal priority
      return(ret);

    if (msglen<6||((msg[2]!= 0x08) && (msg[3]!= 0x01)) || (msg[4]!= 0x81) || (msg[5]!= 0x4c))
    {
      ErrEocRxHdlcFraming++;
      return(ret);   // not an expected clear EOC frame
    }

    *len -= 6; // data[] start from msg[6]
//    for (i=0; i<*len; i++) *data++ = *msg1++;
    //shim_osMoveMemory(data, &msg[6], *len);
    DDA_memcpy((int *)data, (int *)&msg[6], *len);
    return 0;
  }


  if (rxbyte != HDLC_FLAG)
  {
     return(ret);   // invalid HDLC frame
  }

  if ((msg[1] != 0xFF) || (msg[2] != 0x03) ||
      (msg[3] != 0x81) || (msg[4] != 0x4c))
  {
     ErrEocRxHdlcFraming++;
     return(ret);   // not an expected clear EOC frame
  }

  crc = HDLC_INIT;
  j = 1;
  N = 0;

  while (j < msglen)
  {
     rxbyte = msg[j++];
     if (rxbyte == HDLC_ESC)
     {
        rxbyte = msg[j++];
        if ((rxbyte == (HDLC_ESC ^ HDLC_INV)) ||
            (rxbyte == (HDLC_FLAG ^ HDLC_INV)))
        {
           rxbyte ^= HDLC_INV;
        }
        else
        {
           break;
        }
     }
     else if (rxbyte == HDLC_FLAG)
     {
        break;
     }

     crc = DDC_dsl_hdlc_update_crc(rxbyte, crc);

     if (j > 5)
     {
       data[N] = rxbyte;
       N++;
     }
  }

  if (crc == HDLC_GOOD && N >= 2)  // since 0xFF 03 81 4C are not counted in
  {
     N   = N - 2; // uncount FCS bytes
     ret = 0;     // success
  }

  *len = N;

  return(ret);
}

/************************************************************
NEED FN HEADER
************************************************************/
int DDC_dsl_clear_eoc_send(DDC_DslPriv *priv, unsigned char *data, unsigned int len, int ackFlag)
{
  unsigned int   indx;
  unsigned int   index[2];
  unsigned int   enabled;
  int            offset0[2] = {34, 9};  // Tx buffer Read Index
  int            offset[2]  = {34, 10}; // Tx buffer Write Index
  int            offset2[2] = {34, 0};  // point to buffer parameter data structure
  int            ret = 0;
  unsigned int   i, num_swap, *pInt32;

  if (len > MAX_RAW_CLEAR_EOC_MSGSIZE)
  {
     ErrEocMsgOversized++;
//   DDA_printf("DDC_dsl_clear_eoc_send: ClearEOC max packet size is exceeded\n");
     return(1);
  }

  dslhal_api_dspInterfaceRead(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset2, (unsigned char *)&enabled, 4);
  if (!enabled)
  {
//   DDA_printf("DDC_dsl_clear_eoc_send: ClearEOC not enabled\n");
     return(1);
  }

  dslhal_api_dspInterfaceRead(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset0, (unsigned char *)&index[0], 8);
  pClrEOC->txRdIndex = dslhal_support_byteSwap32(index[0]);
  indx = dslhal_support_byteSwap32(index[1]);

  if (indx >= 4)
  {
     ErrEocBufIndex++;
//   DDA_printf("DDC_dsl_clear_eoc_send: Invalid txWrIndex (=%d)\n", indx);
     return(1);
  }

  if (((indx+1)%4) == pClrEOC->txRdIndex)
  {
     ErrEocBufFull++;
//   DDA_printf("tndsl_clear_eoc_send: buffer full\n");
     return(1);
  }

  // HDLC framing, calculate FCS and pad HDLC
  ret = DDC_dsl_hdlc_tx_process(pClrEOC->pTxBufDesc[indx]->data, data, &len,
          (priv->pIhw->AppData.TrainedMode & (ADSL2_MODE|ADSL2_PLUS)) | ackFlag);

  if (!ret)
  {
     unsigned int wrIndex;

    // don't need to do endian swap because pTxBufDesc is in external SDRAM & len is 32 bit
     pClrEOC->pTxBufDesc[indx]->len = len;  // set HDLC frame length

    // do endian swap for data since they are bytes
     pInt32=(unsigned int *) pClrEOC->pTxBufDesc[indx]->data;

     for (i=0,num_swap=(len+3)>>2; i<num_swap; i++, pInt32++)
     {
        *pInt32=dslhal_support_byteSwap32(*pInt32);
     }
     DDC_atm_data_writeback(pClrEOC->pTxBufDesc[indx], sizeof(clearEocBufDesc_type));

     pClrEOC->txWrIndex = (indx+1)%4;

     wrIndex = dslhal_support_byteSwap32(pClrEOC->txWrIndex);
     dslhal_api_dspInterfaceWrite(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)&wrIndex, 4);

     EocTxTotalPackets++;
     EocTxTotalBytes += len;
  }
  else
  {
     ErrEocTxHdlcCRC++;
   //DDA_printf("DDC_dsl_clear_eoc_send: tx HDLC processing error\n");
  }

  return(ret);
}

/************************************************************
NEED FN HEADER
************************************************************/
int DDC_dsl_clear_eoc_receive(DDC_DslPriv *priv)
{
  int               rc, ch;
  int               ret = 0;
  int               enabled;
  int               offset[2]  = {34, 11};  // Rx buffer read index
  int               offset2[2] = {34, 0};   // point to buffer parameter data structure
  void              *recvinfo, *skb;
  unsigned char    *data;
  unsigned int      indx;
  unsigned int      index[2], len0, len;

  rc = 0;

  while (1)
  {
    dslhal_api_dspInterfaceRead(priv->pIhw, (unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)&index[0], 8);
    indx = dslhal_support_byteSwap32(index[0]);
    pClrEOC->rxWrIndex = dslhal_support_byteSwap32(index[1]);

    if (indx == pClrEOC->rxWrIndex)
    {
       return(0);
    }

    if (indx >= 4)
    {
       ErrEocBufIndex++;
     //DDA_printf("DDC_dsl_clear_eoc_receive: Invalid rxRdIndex (=%d)\n", indx);
       indx = (indx + 1)%4;
       rc = 1;
       goto clrEoc_rx_exit;
    }

    dslhal_api_dspInterfaceRead(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset2, (unsigned char *)&enabled, 4);
    if (!enabled)
    {
     //DDA_printf("DDC_dsl_clear_eoc_receive: ClearEOC not enabled\n");
       rc = 1;
       goto clrEoc_rx_exit;
    }

//
//Note: don't need to swap 'len' because pClrEOC->pRxBufDesc[indx] already point to
// external SDRAM
//    len = dslhal_support_byteSwap32(pClrEOC->pRxBufDesc[indx]->len);
    len = pClrEOC->pRxBufDesc[indx]->len;
    len0 = len;

    //Sending ClearEoc ACK(80)
    // Check for length > 4 so we don't ACk the ACK packet from CO.
    // ACK packet: 01 <01|03> 08 80 (4 bytes)
    if (pClrEOC->pRxBufDesc[indx]->len>4)
    {
      char dummy[4];
      DDC_dsl_clear_eoc_send(priv,dummy, 4, CLEAREOC_ACK);
    }
    if (len > MAX_CLEAR_EOC_BUF_SIZE)
    {
     //DDA_printf("DDC_dsl_clear_eoc_receive: buf size is exceeded\n");
       ErrEocBufMax++;
       rc = 1;
       goto clrEoc_rx_exit;
    }

    // chanid for clear eoc
    ch = EOC_DMA_CHAN;

    // allocate packet data memory
    //AV_DDM
    //priv = (DDC_atm_private_t *)mydev->dev_data;
    //data = (unsigned char *)DDC_atm_allocate_rx_skb(priv->dev, &recvinfo, len, (void *)priv->lut[ch].vcc);
    data = (unsigned char *)DDA_malloc_rxbuffer(len, 0, 0, (void *)priv->lut[ch].vcc, 0, &recvinfo, priv->dev);
    if (data == NULL)
    {
     //DDA_printf("DDC_dsl_clear_eoc_receive: DDA_malloc() failed\n");
       rc = 1;
       goto clrEoc_rx_exit;
    }

    skb = recvinfo;

    ret = DDC_dsl_hdlc_rx_process(data, pClrEOC->pRxBufDesc[indx]->data, &len,
            (priv->pIhw->AppData.TrainedMode & (ADSL2_MODE|ADSL2_PLUS)) );

    if (ret)
    {
       //DDA_printf("DDC_dsl_clear_eoc_receive: rx processing error\n");

       // free skb
       DDA_free_buffer(skb, NULL);

       ErrEocRxHdlcCRC++;
       rc = 1;
       goto clrEoc_rx_exit;
    }

    if (len > MAX_RAW_CLEAR_EOC_MSGSIZE)
    {
       ErrEocMsgOversized++;
       DDA_printf("WARNING: DDC_dsl -- max_raw_clear_eoc_msgsize is exceeded\n");
    }

    // send packet to network stacks
    ret = DDA_atm_receive(priv->dev, ch, len, skb, data);

    if (ret)
    {
     //DDA_printf("DDC_dsl_clear_eoc_receive: failed to push up packet\n");
       DDA_free_buffer(skb, NULL);

       ErrEocRxPush++;
       rc = 1;
    }

    EocRxTotalPackets++;
    EocRxTotalBytes += len0;

clrEoc_rx_exit:
    // update rxRdIndex anyway
    pClrEOC->rxRdIndex = (indx+1)%4;

    pClrEOC->pRxBufDesc[indx]->len = 0;

    /*shim_osInvalidateCache(pClrEOC->pRxBufDesc[indx], sizeof(clearEocBufDesc_type));*/
    DDC_atm_data_invalidate(pClrEOC->pRxBufDesc[indx], sizeof(clearEocBufDesc_type));

    indx = dslhal_support_byteSwap32(pClrEOC->rxRdIndex);
    dslhal_api_dspInterfaceWrite(priv->pIhw,(unsigned int)priv->pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)&indx, 4);
  } // while

  return(rc);
}

/************************************************************
NEED FN HEADER
************************************************************/
int DDC_dsl_proc_eoc (char *buf, int count, int *eof, DDC_DslPriv *priv)
{
  int len = 0;
  int limit = count - 80;
  int offset[2] = {34, 0};  // point to buffer parameter data structure
  clearEocParm_t   peoc;
  PITIDSLHW_T pIhw = priv->pIhw;

  dslhal_api_dspInterfaceRead (pIhw, (unsigned int) pIhw->pmainAddr, 2,
                               (unsigned int *) &offset,
                               (unsigned char *) &peoc,
                               sizeof (clearEocParm_t));

  if (len <= limit)
     len += DDA_sprintf(buf+len, "\nClear EOC Channel:\n\n");
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  Enabled:\t%d\n", dslhal_support_byteSwap32(peoc.clearEocEnabled));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TxBuf[0]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pTxBufDesc[0]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TxBuf[1]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pTxBufDesc[1]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TxBuf[2]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pTxBufDesc[2]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TxBuf[3]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pTxBufDesc[3]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  RxBuf[0]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pRxBufDesc[0]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  RxBuf[1]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pRxBufDesc[1]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  RxBuf[2]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pRxBufDesc[2]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  RxBuf[3]:\t0x%08x\n", dslhal_support_byteSwap32((unsigned int)peoc.pRxBufDesc[3]));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  txRdIndex:\t%d\n", dslhal_support_byteSwap32(peoc.txRdIndex));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  txWrIndex:\t%d\n", dslhal_support_byteSwap32(peoc.txWrIndex));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  rxRdIndex:\t%d\n", dslhal_support_byteSwap32(peoc.rxRdIndex));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  rxWrIndex:\t%d\n\n", dslhal_support_byteSwap32(peoc.rxWrIndex));
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TotalTxPkts:\t%d\n", EocTxTotalPackets);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TotalRxPkts:\t%d\n", EocRxTotalPackets);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TotalTxBytes:\t%d\n", EocTxTotalBytes);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  TotalRxBytes:\t%d\n\n", EocRxTotalBytes);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrBufFull:\t%d\n", ErrEocBufFull);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrBufIndx:\t%d\n", ErrEocBufIndex);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrBufMax:\t%d\n", ErrEocBufMax);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrMsgMax:\t%d\n", ErrEocMsgOversized);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrTxHDLC:\t%d\n", ErrEocTxHdlcCRC);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrRxHDLC:\t%d\n", ErrEocRxHdlcCRC);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrRxSnmp:\t%d\n", ErrEocRxHdlcFraming);
  if (len <= limit)
     len += DDA_sprintf(buf+len, "  ErrRxPush:\t%d\n\n", ErrEocRxPush);

  if (len <= limit)
    *eof = DDC_DSL_FINISHED;

  return len;
}
