view src/g23m-fad/l2r/l2r_dnf.c @ 624:012028896cfb

FFS dev.c, Leonardo target: Fujitsu MB84VF5F5F4J2 #if 0'ed out The FFS code we got from TI/Openmoko had a stanza for "Fujitsu MB84VF5F5F4J2 stacked device", using a fake device ID code that would need to be patched manually into cfgffs.c (suppressing and overriding autodetection) and using an FFS base address in the nCS2 bank, indicating that this FFS config was probably meant for the MCP version of Leonardo which allows for 16 MiB flash with a second bank on nCS2. We previously had this FFS config stanza conditionalized under CONFIG_TARGET_LEONARDO because the base address contained therein is invalid for other targets, but now that we actually have a Leonardo build target in FC Magnetite, I realize that the better approach is to #if 0 out this stanza altogether: it is already non-functional because it uses a fake device ID code, thus it is does not add support for more Leonardo board variants, instead it is just noise.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 22 Dec 2019 21:24:29 +0000
parents 90eb61ecd093
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  CSD (8411)
|  Modul   :  L2r_dnf.c
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This Modul defines the procedures and functions for
|             the component L2R of the base station
+----------------------------------------------------------------------------- 
*/ 

#ifndef L2R_DNF_C
#define L2R_DNF_C
#endif

#define ENTITY_L2R

/*==== INCLUDES ===================================================*/

#include <string.h>
#include "typedefs.h"
#include "pconst.cdg"
#include "vsi.h"
#include "macdef.h"
#include "custom.h"
#include "gsm.h"
#include "cus_l2r.h"
#include "cnf_l2r.h"
#include "mon_l2r.h"
#include "prim.h"
#include "pei.h"
#include "tok.h"
#include "dti.h"      /* functionality of the dti library */

#include "cl_ribu.h"
#include "l2r.h"

/*==== CONST =======================================================*/

/*==== TYPES =======================================================*/

/*==== VAR EXPORT ==================================================*/

/*==== VAR LOCAL ===================================================*/

/*==== FUNCTIONS ===================================================*/

/*
+------------------------------------------------------------------------------
|  Function    : dn_init
+------------------------------------------------------------------------------
|  Description : initialise the l2r data for the downlink process
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_init(T_DN *ddn)
{
  TRACE_FUNCTION ("dn_init()");

  ddn->FlowCtrlUsed = FALSE;
  ddn->DnFlow = FL_INACTIVE;
  ddn->UpFlow = FL_INACTIVE;
#ifdef L2R_TRACE_FLOW
  ddn->LastSentFlow = FL_INVALID;
#endif
  ddn->FlowThresh = MAX_DPRIM_RIBU_SIZE / 2;
  ddn->LastState = 0 << SO_SA_BIT | 0 << SO_SB_BIT;

  ddn->RiBu.idx.depth = MAX_DPRIM_RIBU_SIZE;
  INIT_STATE (DN_LL, IW_IDLE);
  INIT_STATE (DN_UL, IW_IDLE);
  INIT_STATE (DN, DN_DISCONNECTED);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_check_flow
+------------------------------------------------------------------------------
|  Description : checks flow control staus
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_check_flow(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_check_flow()");

  if (!ddn->FlowCtrlUsed)
  {
    return;
  }

  if (ddn->RiBu.idx.filled >= ddn->FlowThresh)
  {
    switch (ddn->DnFlow)
    {
    case FL_ACTIVE:
      return;

    case FL_INACTIVE:
      ddn->DnFlow = FL_ACTIVE;
      break;
    }
  }
  else
  {
    switch (ddn->DnFlow)
    {
    case FL_ACTIVE:
      ddn->DnFlow = FL_INACTIVE;
      break;

    case FL_INACTIVE:
      return;
    }
  }
  sig_dn_up_flow (ddn->DnFlow);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_next_frame
+------------------------------------------------------------------------------
|  Description : Local function, which is used by up_copy_data_from_l2r 
|                to advance to the next frame in the primitive.
|                The variable primDesc of the calling function is updated.
|
|  Parameters  : primDesc   -
|
|  Return      : 1  -
|                0  -
+------------------------------------------------------------------------------
*/

LOCAL UBYTE dn_next_frame(T_P_DPRIM_DESCRIPTOR *primDesc)
{
  T_DN *ddn = &l2r_data->dn;

#ifdef _SIMULATION_
  TRACE_FUNCTION ("dn_next_frame()");
#endif

  (*primDesc)->index++; /* next frame */

  if ((*primDesc)->index >= (*primDesc)->nFr)
  {
#ifdef _SIMULATION_
    TRACE_EVENT ("next primitive");
#endif
    cl_ribu_read_index(&ddn->RiBu.idx); /* point to next primitive */

    if (!ddn->RiBu.idx.filled) /* no primitive is ready */
    {
#ifdef _SIMULATION_
      TRACE_EVENT ("no primitive is ready");
#endif
      return (0);
    }

    *primDesc = ddn->RiBu._primDesc[ddn->RiBu.idx.ri]; /* point to next primitive descriptor */
    (*primDesc)->index = 0;
  }
  return (1);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_copy_data_from_l2r
+------------------------------------------------------------------------------
|  Description : Copies data from l2r into ring buffer.
||               Moreover the return value of the calling function
|                bytesCopied are set

|  Parameters  : buf          -
|                len          -
|                sa           -
|                sb           -
|                flow         -
|                bytesCopied  -
|
|  Return      : -
+------------------------------------------------------------------------------
*/

LOCAL U16 dn_copy_data_from_l2r(U8 *buf, U16 len, U8 *sa, U8 *sb, U8 *flow)
{
  T_DN *ddn = &l2r_data->dn;

  T_P_DPRIM_DESCRIPTOR primDesc;
  T_P_L2R_FRAME frame;
  
  register T_P_UBYTE pFrame;
  register T_P_UBYTE pBuf;
  register T_P_UBYTE pStat;
  
  USHORT bytesToCopy;
  USHORT blocklen;
  UBYTE frameCount;
  UBYTE statOct;

#ifdef _SIMULATION_
  TRACE_EVENT ("dn_copy_data_from_l2r()");
#endif

  ddn->ReportMrgFlow = FALSE;

  if (!ddn->RiBu.idx.filled) /* don't copy into buffer if no primitive is ready */
  {
#ifdef _SIMULATION_
    TRACE_EVENT ("no primitive ready");
#endif
    switch (ddn->MrgFlow)
    {
    case FL_ACTIVE:
      *flow = DTI_FLOW_OFF;
      break;
    case FL_INACTIVE:
      *flow = DTI_FLOW_ON;
      break;
    }
    *sa = GET_SO_SA_BIT(ddn->LastState);
    *sb = GET_SO_SB_BIT(ddn->LastState);
    return 0;
  }

  if (ddn->ULFlow EQ FL_ACTIVE)
  {
    len = 0; /* upper layer has raised flow control; don't send data */
  }

  bytesToCopy = len;
  primDesc = ddn->RiBu._primDesc[ddn->RiBu.idx.ri]; /* point to current primitive descriptor */

  if (primDesc->nFr EQ 0) /* skip empty primitive */
  {
#ifdef _SIMULATION_
    TRACE_EVENT ("empty primitive");
#endif
    switch (ddn->MrgFlow)
    {
    case FL_ACTIVE:
      *flow = DTI_FLOW_OFF;
      break;
    case FL_INACTIVE:
      *flow = DTI_FLOW_ON;
      break;
    }
    *sa = GET_SO_SA_BIT(ddn->LastState);
    *sb = GET_SO_SB_BIT(ddn->LastState);
    return 0;
  }

#ifdef _TARGET_
  if (primDesc->prim->data_size > DATA_SIZE_SHORT)
  {
    frameCount = 1;
  }
  else
  {
    frameCount = 2;
  }
#else
  {
    frameCount = 100;
  }
#endif

  frame   = (*primDesc->dadr)[primDesc->index];   /* dn_copy_data_from_l2r: point to current l2r frame in primitive */
  pBuf    = buf;                                  /* point to destination buffer */
  pFrame  = &((*frame)[primDesc->offset]);
  pStat   = &((*frame)[primDesc->off_status]);

  if (pFrame EQ pStat)
  {
    /* current byte is status octet */
    ddn->LastState = *pFrame & SO_STATUS_BITS_MASK;
  }

  /* merge flow control conditions */

  switch (ddn->MrgFlow)
  {
  case FL_ACTIVE:
    *flow = DTI_FLOW_OFF;
    break;
  case FL_INACTIVE:
    *flow = DTI_FLOW_ON;
    break;
  }

  *sa = GET_SO_SA_BIT(ddn->LastState);
  *sb = GET_SO_SB_BIT(ddn->LastState);

  /************************************************************************************
   * loop until either
   *   -  no more data are available or
   *   -  status in L2R frame changes or
   *   -  buffer for data is full
   ************************************************************************************/

  for (;;)
  {
    blocklen = pStat - pFrame;

    if (blocklen EQ 0)
    {
      /*
       * current byte is status octet;
       * only in the first pass of the loop, there may be no status octet
       */

      /*****************************
       *  evaluate status bits
       *****************************/
      statOct = *pFrame;
      if (ddn->LastState NEQ (statOct & SO_STATUS_BITS_MASK))
      {
        /*
         *  Status has changed.
         *  We have to stop,
         *  since only one state can be transmitted to the upper layer.
         */
        primDesc->offset = primDesc->off_status = pFrame - (T_P_UBYTE)frame;

#ifdef _SIMULATION_
        TRACE_EVENT ("return because of status change");
#endif
        return len - bytesToCopy;
      }

      pFrame++;

      /************************************
       *  evaluate address bits
       ************************************/
      
      statOct &= SO_ADR_MASK;
      
      switch (statOct)
      {
      case SO_BREAK_ACK:
      case SO_BREAK_REQ:
      case SO_END_EMPTY:
        /*
         * no more data in this frame
         */
        if (dn_next_frame(&primDesc) EQ 0) /* no more data available */
        {
          primDesc->offset = 0;
          primDesc->off_status = 0;

#ifdef _SIMULATION_
          TRACE_EVENT ("return because no more data available");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }

        frameCount--;

        if (frameCount EQ 0)
        {
          primDesc->offset = 0;
          primDesc->off_status = 0;
#ifdef _SIMULATION_
          TRACE_EVENT ("return because number of frames reached");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }
        
        frame  = (*primDesc->dadr)[primDesc->index]; /* dn_copy_data_from_l2r */
        pFrame = (T_P_UBYTE)frame;
        pStat  = (T_P_UBYTE)frame;
        continue;  /* continue with next frame */

      case SO_END_FULL:
        pStat = &((*frame)[primDesc->prim->data_size]);
        blocklen = pStat - pFrame;
        break;

      case SO_TWO_OCTET:
        blocklen = *pFrame++ & SO_ADR_MASK_TWO_OCT;
        pStat = pFrame + blocklen;
        break;

      default:
        blocklen = statOct;
        pStat = pFrame + blocklen;
        break;
      }
    }

    if (bytesToCopy < blocklen)
    {
      /***************************************
       *  There is not enough space in the
       *  buffer to copy the complete block
       ***************************************/

      T_P_UBYTE pEnd = pFrame + bytesToCopy; /* save end mark */

      while (pFrame < pEnd)
      {
        *pBuf++ = *pFrame++;
      }

      if (pFrame >= &((*frame)[primDesc->prim->data_size]))
      {
        /*
         * end of frame reached 
         * actually this case can never occur, 
         * since bytesToCopy < blocklen
        */
        dn_next_frame(&primDesc);
        primDesc->offset = 0;
        primDesc->off_status = 0;
      }
      else
      {
        primDesc->offset = pFrame - (T_P_UBYTE)frame;
        primDesc->off_status = pStat  - (T_P_UBYTE)frame;
      }

#ifdef _SIMULATION_
      TRACE_EVENT ("return because buffer is full");
#endif
      return len; /* this much data could be copied */
    
    }
    else /* bytesToCopy >= blocklen */
    {
      /***************************************
       *  Copy the complete block
       ***************************************/
      
      bytesToCopy -= blocklen;

      while (pFrame < pStat)
      {
        *pBuf++ = *pFrame++;
      }

      if (pFrame >= &((*frame)[primDesc->prim->data_size])) /* end of frame reached */
      {
        if (dn_next_frame(&primDesc) EQ 0) /* no more data available */
        {
#ifdef _SIMULATION_
          TRACE_EVENT ("return because no more data available");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }
      
        frameCount--;

        if (frameCount EQ 0)
        {
          primDesc->offset = 0;
          primDesc->off_status = 0;

#ifdef _SIMULATION_
          TRACE_EVENT ("return because number of frames reached");
#endif
          return len - bytesToCopy; /* this much data could be copied */
        }
        
        frame  = (*primDesc->dadr)[primDesc->index]; /* dn_copy_data_from_l2r */
        pFrame = (T_P_UBYTE)frame;
        pStat  = (T_P_UBYTE)frame;
      }
      
      if (bytesToCopy EQ 0)
      {
        primDesc->offset = pFrame - (T_P_UBYTE)frame;
        primDesc->off_status = pStat - (T_P_UBYTE)frame;

#ifdef _SIMULATION_
        TRACE_EVENT ("return because all data are copied");
#endif
        return len; /* this much data could be copied */
      }

    } /* bytesToCopy >= blocklen */
  } /* for (;;) */
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_send_data_ind
+------------------------------------------------------------------------------
|  Description : This procedure copies data from the downlink ring buffer 
|                into a DTI_DATA_IND primitive
|                and sends this primitive to the relay entity.
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_send_data_ind(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_send_data_ind()");

  if (ddn->DtiConnected EQ FALSE)
  {
    TRACE_EVENT("DTI not connected, but dn_send_data_ind() called");
    return;
  }

  {
  USHORT len = L2R_FRAMES_PER_PRIM_MAX * (RLP_FRAME_SIZE_SHORT - HT_LEN - 1);
  UBYTE sa;
  UBYTE sb;
  UBYTE flow;
  T_desc2* desc;

  PALLOC (dti_data_ind, DTI2_DATA_IND);

  MALLOC (desc, (USHORT)(sizeof(T_desc2) - 1 + len));
  desc->len  = dn_copy_data_from_l2r ((U8*)&desc->buffer[0], len, &sa, &sb, &flow);
  desc->size = desc->len;
  desc->offset = 0;
  desc->next = 0;

  dti_data_ind->desc_list2.first = (ULONG)desc;
  dti_data_ind->desc_list2.list_len = desc->len;
  
  dti_data_ind->parameters.st_lines.st_line_sa    = sa;
  dti_data_ind->parameters.st_lines.st_line_sb    = sb;
  dti_data_ind->parameters.st_lines.st_flow       = flow;
  dti_data_ind->parameters.st_lines.st_break_len  = DTI_BREAK_OFF;
  dti_data_ind->parameters.p_id                   = DTI_PID_UOS;
  dti_data_ind->link_id                           = ddn->link_id;

#ifdef L2R_TRACE_FLOW
  if (ddn->LastSentFlow NEQ dti_data_ind->parameters.st_lines.st_flow)
  {
    switch (dti_data_ind->parameters.st_lines.st_flow)
    {
    case FL_ACTIVE:
      TRACE_EVENT("DTI downlink: FL_ACTIVE");
      break;

    case FL_INACTIVE:
      TRACE_EVENT("DTI downlink: FL_INACTIVE");
      break;
    }
    ddn->LastSentFlow = dti_data_ind->parameters.st_lines.st_flow;
  }
#endif

  dti_send_data (
    l2r_hDTI,
    L2R_DTI_UP_DEF_INSTANCE,
    L2R_DTI_UP_INTERFACE,
    L2R_DTI_UP_CHANNEL,
    dti_data_ind
    );        
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_scan_break_req
+------------------------------------------------------------------------------
|  Description : This procedure scans a rlp_data_ind primitive for L2R BREAK
|                status octets. It returnes the index of the frame following
|                the last BREAK status octet in the primitive.
|                Moreover the total number of frames in the primitive 
|                as well as the status bits of the last BREAK are returned.
|                In addition the x bit of the last status octet is returned.
|                It is important to search the last BREAK in the primitive,
|                because the data following a break signal
|                are used in the case of no data compression.
|
|  Parameters  : data_ind -
|                found
|                index
|                frames
|                emptyfr
|                sa
|                sb
|                flow_brk
|                flow_gen
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_scan_break_req
            (
              T_P_RLP_DATA_IND  data_ind,
              BOOL             *found,
              T_PRIM_INDEX     *index,
              T_PRIM_INDEX     *frames,
              T_PRIM_INDEX     *emptyfr,
              T_BIT            *sa,
              T_BIT            *sb,
              T_FLOW           *flow_brk,
              T_FLOW           *flow_gen
            )

{
  T_PRIM_INDEX ind;
  UBYTE off;
  UBYTE statOct;
  UBYTE brkStatOct = (UBYTE)(0 << SO_SA_BIT | 0 << SO_SB_BIT | 0 << SO_X_BIT);
  UBYTE genStatOct = (UBYTE)(0 << SO_SA_BIT | 0 << SO_SB_BIT | 0 << SO_X_BIT);

  T_P_L2R_FRAME frame;

  TRACE_FUNCTION ("dn_scan_break_req()");

  *found   = FALSE;
  *frames  = data_ind->sdu.l_buf / (8 * data_ind->data_size + HT_LEN);
  *emptyfr = 0;

  frame = (T_P_L2R_FRAME)(data_ind->sdu.buf + (data_ind->sdu.o_buf>>3) + HEADER_LEN);
  off = 0;
  ind = 0;

  while (ind < *frames)
  {
    statOct = (*frame)[off];

    switch (statOct & SO_ADR_MASK)
    {
    case SO_BREAK_REQ:
      *found  = TRUE;
      *index  = ind + 1;
      brkStatOct = statOct;
      genStatOct = statOct;
      ind++;
      frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
      off = 0;
      break;

    case SO_END_EMPTY:
      if (off EQ 0)
      {
        (*emptyfr)++;
      }
      /* fall through!!! */

    case SO_BREAK_ACK:
    case SO_END_FULL:
      genStatOct = statOct;
      ind++;
      frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
      off = 0;
      break;

    case SO_TWO_OCTET:
      genStatOct = statOct;
      off += ((*frame)[off] & SO_ADR_MASK_TWO_OCT) + 2;
      if (off >= data_ind->data_size)
      {
        ind++;
        frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
        off = 0;
      }
      break;

    default:
      genStatOct = statOct;
      off += (statOct & SO_ADR_MASK) + 1;
      if (off >= data_ind->data_size)
      {
        ind++;
        frame = (T_P_L2R_FRAME)((UBYTE*)frame + data_ind->data_size + HT_LEN);
        off = 0;
      }
      break;
    }
  }

  if (*found)
  {
    *sa    = GET_SO_SA_BIT(brkStatOct);
    *sb    = GET_SO_SB_BIT(brkStatOct);
  }
  else
  {
    *sa    = GET_SO_SA_BIT(genStatOct);
    *sb    = GET_SO_SB_BIT(genStatOct);
  }

  if (l2r_data->dn.FlowCtrlUsed)
  {
    if (GET_SO_X_BIT (brkStatOct) EQ 0)
    {
      *flow_brk = FL_INACTIVE;
    }
    else
    {
      *flow_brk = FL_ACTIVE;
    }
    
    if (GET_SO_X_BIT (genStatOct) EQ 0)
    {
      *flow_gen = FL_INACTIVE;
    }
    else
    {
      *flow_gen = FL_ACTIVE;
    }
  }
  else
  {
    *flow_brk = FL_INACTIVE;
    *flow_gen = FL_INACTIVE;
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_free_prim
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : primDesc -
|
|
|  Return      :
+------------------------------------------------------------------------------
*/

LOCAL void dn_free_prim(T_P_DPRIM_DESCRIPTOR primDesc)
{
  TRACE_FUNCTION ("dn_free_prim()");

  if (primDesc->prim NEQ NULL)
  {
    PFREE (primDesc->prim);
    primDesc->prim = NULL;
    primDesc->nFr = 0;
    primDesc->index = 0;
    primDesc->offset = 0;
    primDesc->off_status = 0;
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_free_all_prims
+------------------------------------------------------------------------------
|  Description : frees all primititives
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_free_all_prims(void)
{
  T_DN *ddn = &l2r_data->dn;

  T_PRIM_DESC_RIBU_INDEX n;

  TRACE_FUNCTION ("dn_free_all_prims()");

  for (n = 0; n < ddn->RiBu.idx.depth; n++)
  {
    dn_free_prim (ddn->RiBu._primDesc[n]);
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_cond_free_prims
+------------------------------------------------------------------------------
|  Description : frees all primitive if r
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_cond_free_prims(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_cond_free_prims()");

  while (ddn->RiBu.free NEQ ddn->RiBu.idx.ri)
  {
    dn_free_prim (ddn->RiBu._primDesc[ddn->RiBu.free]);

    ddn->RiBu.free++;
    if (ddn->RiBu.free EQ ddn->RiBu.idx.depth)
    {
      ddn->RiBu.free = 0;
    }
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_store_prim
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : data_ind -
|                index    -
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_store_prim(T_P_RLP_DATA_IND data_ind, T_PRIM_INDEX index)
{
  T_DN *ddn = &l2r_data->dn;

  T_PRIM_INDEX m;
  T_P_DPRIM_DESCRIPTOR primDesc;

  T_PRIM_INDEX frames = data_ind->sdu.l_buf / (8 * data_ind->data_size + HT_LEN);
  UBYTE *pos = data_ind->sdu.buf + (data_ind->sdu.o_buf>>3) + HEADER_LEN;

  TRACE_FUNCTION ("dn_store_prim()");

  primDesc = ddn->RiBu._primDesc[cl_ribu_write_index(&ddn->RiBu.idx)];

  primDesc->prim = data_ind;
  primDesc->index = index;    /* if BREAK then not equal 0 */
  primDesc->offset = 0;
  primDesc->off_status = 0;
  primDesc->nFr = frames;

  for (m = 0; m < frames; m++)
  {
    (*primDesc->dadr)[m] = (T_P_L2R_FRAME)(pos + m * (data_ind->data_size + HT_LEN));
  }

  dn_check_flow();

  if (GET_STATE (DN_UL) EQ IW_WAIT AND ddn->ULFlow EQ FL_INACTIVE AND
      ddn->DtiConnected) /*jk: data send only when DTI connected*/
  {
    dn_send_data_ind();
    SET_STATE (DN_UL, IW_IDLE);
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)             MODULE  : L2R_DNF             |
| STATE   : code                       ROUTINE : dn_init_ribu        |
+--------------------------------------------------------------------+

  PURPOSE :

*/

GLOBAL void dn_init_ribu(void)
{
  T_DN *ddn = &l2r_data->dn;

  T_PRIM_DESC_RIBU_INDEX n;
  T_PRIM_INDEX m;

  TRACE_FUNCTION ("dn_init_ribu()");

  cl_ribu_init(&ddn->RiBu.idx, ddn->RiBu.idx.depth);
  ddn->RiBu.free = 0;

  for (n = 0; n < ddn->RiBu.idx.depth; n++)
  {
    ddn->RiBu._primDesc[n]      = &(ddn->PrimDesc[n]);
    ddn->PrimDesc[n].nFr        = 0;
    ddn->PrimDesc[n].dadr       = (T_P_ADR_VECTOR)&(ddn->AdrVec[n]); /* dn_init_ribu */
    ddn->PrimDesc[n].index      = 0;
    ddn->PrimDesc[n].offset     = 0;
    ddn->PrimDesc[n].off_status = 0;
    ddn->PrimDesc[n].prim       = NULL;

    for (m = 0; m < L2R_FRAMES_PER_PRIM_MAX; m++)
    {
      ddn->AdrVec[n][m] = NULL;
    }
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_cond_req_data
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_cond_req_data(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_cond_req_data()");

  /* ring buffer full? */

  if ((ddn->RiBu.idx.wi + 1) % ddn->RiBu.idx.depth EQ ddn->RiBu.free)
  {
    SET_STATE (DN_LL, IW_IDLE);
  }
  else
  {
    PALLOC (rlp_getdata_req, RLP_GETDATA_REQ);
    PSENDX (RLP, rlp_getdata_req);
    SET_STATE (DN_LL, IW_WAIT);
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_store_status
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : flow -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_store_status(T_FLOW flow)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_store_status()");

  if (flow EQ ddn->LLFlow)
  {
    return;
  }

  ddn->LLFlow = flow;
  dn_merge_flow();
  sig_dn_up_ll_flow(ddn->LLFlow);
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_merge_flow
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_merge_flow(void)
{
  T_DN *ddn = &l2r_data->dn;

  TRACE_FUNCTION ("dn_merge_flow()");

  if (ddn->FlowCtrlUsed AND (ddn->UpFlow EQ FL_ACTIVE OR ddn->LLFlow EQ FL_ACTIVE)     )
  {
    if (ddn->MrgFlow EQ FL_INACTIVE)
    {
      ddn->ReportMrgFlow = TRUE;
      /*
      TRACE_EVENT("DN: Merged flow set active");
      */
    }
    ddn->MrgFlow = FL_ACTIVE;
  }
  else
  {
    if (ddn->MrgFlow EQ FL_ACTIVE)
    {
      ddn->ReportMrgFlow = TRUE;
      /*
      TRACE_EVENT("DN: Merged flow set inactive");
      */
    }
    ddn->MrgFlow = FL_INACTIVE;
  }
}

/*
+------------------------------------------------------------------------------
|  Function    : dn_cond_report_status
+------------------------------------------------------------------------------
|  Description :
|
|  Parameters  : -
|
|
|  Return      : -
+------------------------------------------------------------------------------
*/

GLOBAL void dn_cond_report_status(void)
{
  TRACE_FUNCTION ("dn_cond_report_status()");

  if (l2r_data->dn.ReportMrgFlow AND GET_STATE (DN_UL) EQ IW_WAIT)
  {
    if (l2r_data->dn.DtiConnected) /*jk: data send only when DTI connected*/
    {
      dn_send_data_ind();
      SET_STATE (DN_UL, IW_IDLE);
    }
  }
}