static void trackWorkLoop(_DALSYSWorkLoopObj * newWL)
{
   static unsigned int workLoopListIndex = (DALSYS_WL_TRACK_CNT-1);
   unsigned int index;

   DALSYS_SyncEnter(workLoopListSyncHdl);

   index = workLoopListIndex;
   do
   {
      index = (index + 1) % DALSYS_WL_TRACK_CNT;
   }
   while (PD_VAR(DALSYSWorkLoopList)[index] && index != workLoopListIndex);

   if (NULL == PD_VAR(DALSYSWorkLoopList)[index])
   {
      PD_VAR(DALSYSWorkLoopList)[index] = newWL;
      workLoopListIndex = index;
   }
   else
   {
      DALSYS_LOG_ERROR_EVENT("WL tracking list is full");
   }

   DALSYS_SyncLeave(workLoopListSyncHdl);
}
static DALResult dequeue(_DALSYSWorkLoopEvent *pRemoveWorkLoopEvent)
{
   _DALSYSWorkLoopObj * pWorkLoopObj = (_DALSYSWorkLoopObj *)
      pRemoveWorkLoopEvent->hWorkLoop;

   if(NULL == pWorkLoopObj)
      return DAL_ERROR;

   /* Check if the event is in Work Loop Queue */
   if(WL_EVENT_ENQUEUED == pRemoveWorkLoopEvent->dwState)
   {
      DALSYS_SyncEnter(pWorkLoopObj->hSync);

      /* Work Loop queue update */
      if (pWorkLoopObj->hWorkLoopEventHead)
      {
         if (pWorkLoopObj->hWorkLoopEventHead == pRemoveWorkLoopEvent)
         {
            // deleted event is at the head of the queue
            pWorkLoopObj->hWorkLoopEventHead = pRemoveWorkLoopEvent->nextEvent;
            if (pWorkLoopObj->hWorkLoopEventTail == pRemoveWorkLoopEvent)
            {
               // deleted event is the only event on queue
               pWorkLoopObj->hWorkLoopEventTail = NULL;
            }
         }
         else 
         {
            _DALSYSWorkLoopEvent *pCurWorkLoopEvent = pWorkLoopObj->hWorkLoopEventHead;
            while (pCurWorkLoopEvent->nextEvent && pCurWorkLoopEvent->nextEvent != pRemoveWorkLoopEvent)
            {
               // iterate until the end of the list or the deleted event is found
               pCurWorkLoopEvent = pCurWorkLoopEvent->nextEvent;
            }
            if (pCurWorkLoopEvent->nextEvent == pRemoveWorkLoopEvent)
            {
               // found the deleted event
               pCurWorkLoopEvent->nextEvent = pRemoveWorkLoopEvent->nextEvent;
               if (pWorkLoopObj->hWorkLoopEventTail == pRemoveWorkLoopEvent)
               {
                  // deleted event is at the end of the event queue
                  pWorkLoopObj->hWorkLoopEventTail = pCurWorkLoopEvent;
               }
            }
         }
      }

      DALSYS_SyncLeave(pWorkLoopObj->hSync);

      pRemoveWorkLoopEvent->dwState = WL_EVENT_DEQUEUED;
      pRemoveWorkLoopEvent->nextEvent = NULL;
   }
   return DAL_SUCCESS;
}
/*==================================================================================================
  @brief FTM driver Close

  This API can be used to Close the FTM driver.

  @param OpenHdl:   Input -   handle created in Audio_FTM_Open

  @return return code, AUDIO_FTM_SUCCESS on successful completion, error code otherwise
==================================================================================================*/
AUDIO_FTM_STS_T
audio_ftm_toneplay_close
(
    AUDIO_FTM_CLIENT_HANDLE_T  pOpenContext       /* Input: client handle */
)
{
    Aud_FTM_ClientCtxt_T   *pExplicitOpenContext;
    Aud_FTM_DrvCtxt_T      *pDrvCtx;
    uint32                  nClient_id;
    uint32                  i;
    AUDIO_FTM_STS_T         res;

    if (pOpenContext == NULL)
    {
        return AUDIO_FTM_ERR_INVALID_PARAM;
    }

    pExplicitOpenContext = (Aud_FTM_ClientCtxt_T *)pOpenContext;

    pDrvCtx = pExplicitOpenContext->pDrvCtxt;

  res=audio_ftm_hw_close(pDrvCtx->pDevCtxt);
  if(res != AUDIO_FTM_SUCCESS) return AUDIO_FTM_ERROR;

    nClient_id=pExplicitOpenContext->dwClientID;

  DALSYS_Free(pExplicitOpenContext); pExplicitOpenContext=NULL;

  DALSYS_SyncEnter(pDrvCtx->hClientSync);

  aud_ftm_cbuf_clear(&(pDrvCtx->fifo_data_buf));

  for(i=nClient_id; i< DALSYS_atomic_read(&pDrvCtx->dwOpenCount)-1; i++)
  {
    pDrvCtx->apClientCtxt[i]=pDrvCtx->apClientCtxt[i+1];
      pDrvCtx->apClientCtxt[i]->dwClientID--;
  }
  pDrvCtx->apClientCtxt[i]=NULL;

    // Decrease opened device counter
  Release(&pDrvCtx->dwOpenCount);
    if(DALSYS_atomic_read(&pDrvCtx->dwOpenCount) == 0)
    {
      pDrvCtx->bOpened=FALSE;
    aud_ftm_cbuf_deinit(&(pDrvCtx->fifo_data_buf));
    DALSYS_Free(pTmpBuf); pTmpBuf=NULL;
    DALSYS_Free(pAud_ftm_rx_buf); pAud_ftm_rx_buf=NULL;
    }

  DALSYS_SyncLeave(pDrvCtx->hClientSync);

    return AUDIO_FTM_SUCCESS;

}
static void untrackWorkLoop(_DALSYSWorkLoopObj * deletedWL)
{
   unsigned int index;

   DALSYS_SyncEnter(workLoopListSyncHdl);
   for (index = 0; index < DALSYS_WL_TRACK_CNT; index++)
   {
      if (PD_VAR(DALSYSWorkLoopList)[index] == deletedWL)
      {
         PD_VAR(DALSYSWorkLoopList)[index] = NULL;
         break;
      }
   }
   DALSYS_SyncLeave(workLoopListSyncHdl);
}
/*------------------------------------------------------------------------------
Internal API to insert Event into Work Loop queue
-------------------------------------------------------------------------------*/
DALResult DALSYS_EnqueueAndTrigger(_DALSYSWorkLoopEvent *pWorkLoopEvent)
{
   _DALSYSWorkLoopObj *pWorkLoopObj;

   if(!pWorkLoopEvent)
   {
      DALSYS_LOG_ERROR_EVENT("pWorkLoopEvent is NULL");
      return DAL_ERROR;
   }

   pWorkLoopObj = (_DALSYSWorkLoopObj *)pWorkLoopEvent->hWorkLoop;

   if(NULL == pWorkLoopObj)
   {
      DALSYS_LOG_ERROR_EVENT("pWorkLoopObj is NULL");
      return DAL_ERROR;
   }

   /* Check if the event is not already in Work Loop Queue */
   if(WL_EVENT_ENQUEUED != pWorkLoopEvent->dwState)
   {
      DALSYS_SyncEnter(pWorkLoopObj->hSync);

      /* Work Loop queue update */
      (!pWorkLoopObj->hWorkLoopEventHead) ?
         (pWorkLoopObj->hWorkLoopEventHead = pWorkLoopEvent) :
         (pWorkLoopObj->hWorkLoopEventTail->nextEvent = pWorkLoopEvent);
      pWorkLoopObj->hWorkLoopEventTail = pWorkLoopEvent;

      pWorkLoopEvent->dwState = WL_EVENT_ENQUEUED;
      pWorkLoopEvent->nextEvent = NULL;

      DALSYS_SyncLeave(pWorkLoopObj->hSync);
   }

   /* Trigger the Work Loop signal */
   qurt_anysignal_set(&pWorkLoopObj->signal, SIGNAL_EVENT);
   return DAL_SUCCESS;
}
/*------------------------------------------------------------------------------
Work Loops thread of execution
------------------------------------------------------------------------------*/
void _WorkLoopExecute(void *pArg)
{
   _DALSYSWorkLoopObj *pWorkLoopObj = (_DALSYSWorkLoopObj *) pArg;

   trackWorkLoop(pWorkLoopObj);

   for(;;)
   {
      unsigned int signal;

      /*----------------------------------------------------------------------
      Wait for commands
      ----------------------------------------------------------------------*/
      signal = qurt_anysignal_wait(&pWorkLoopObj->signal, 
            SIGNAL_EVENT | SIGNAL_EXIT );
      qurt_anysignal_clear(&pWorkLoopObj->signal, SIGNAL_EVENT | SIGNAL_EXIT);

      if (signal & SIGNAL_EXIT)
      {
         untrackWorkLoop(pWorkLoopObj);
         DALSYS_WorkLoopThreadExit(pWorkLoopObj);
         // this thread is terminated
         // DALSYS_DestroyWorkLoopObject must be called to free the 
         // workloop memory and resources
      }
      if (signal & SIGNAL_EVENT)
      {
         /* Process Work Loop queue */
         for(;;)
         {
            DALSYSEventHandle hEvent;
            _DALSYSWorkLoopEvent *pWorkLoopEvent;
            DALResult ret;

            DALSYS_SyncEnter(pWorkLoopObj->hSync);

            if(!pWorkLoopObj->hWorkLoopEventHead)
            {  /* Queue is empty */
               DALSYS_SyncLeave(pWorkLoopObj->hSync);
               break;
            }

            /* Remove Event from queue head */
            pWorkLoopEvent = pWorkLoopObj->hWorkLoopEventHead;
            pWorkLoopEvent->dwState = WL_EVENT_DEQUEUED;

            /* Adjust queue after the above removal */
            pWorkLoopObj->hWorkLoopEventHead = pWorkLoopEvent->nextEvent;
            if(!pWorkLoopObj->hWorkLoopEventHead) /* There was just 1  Event */
               pWorkLoopObj->hWorkLoopEventTail = NULL;

            DALSYS_SyncLeave(pWorkLoopObj->hSync);

            hEvent = DALSYSCMN_CONTAINEROF(pWorkLoopEvent, _DALSYSEventObj, p.wl);
            /* Process the event */
            if(pWorkLoopEvent->hSync)
                DALSYS_SyncEnter(pWorkLoopEvent->hSync);

            ret = pWorkLoopEvent->pWorkLoopFunc(hEvent, pWorkLoopEvent->pArg);

            if(pWorkLoopEvent->hSync)
                DALSYS_SyncLeave(pWorkLoopEvent->hSync);

            if (DAL_WORK_LOOP_EXIT == ret)
            {
               untrackWorkLoop(pWorkLoopObj);
               DALSYS_WorkLoopThreadExit(pWorkLoopObj);
               // this thread is terminated
               // DALSYS_DestroyWorkLoopObject must be called to free the 
               // workloop memory and resources
            }

         }
      }
   }
}
/**
  @copydoc AxiCfgOs_MutexUnlock
 */   
void AxiCfgOs_MutexUnlock( void  )
{
  DALSYS_SyncLeave( Info.hMutex );
}
/*==================================================================================================
  @brief FTM driver open

  This API can be used to open the FTM driver.

  @param DriverHdl:   Input -   handle created in Audio_FTM_Attach
         AccessMode:  Input -   Read/Write/RD_WR
         ShareMode:   Input -   Exclusive or Share
         pClientHdl:  Output -  point to the returned Open handle

  @return return code, AUDIO_FTM_SUCCESS on successful completion, error code otherwise
==================================================================================================*/
AUDIO_FTM_STS_T
audio_ftm_toneplay_open
(
    AUDIO_FTM_DRIVER_HANDLE_T pDriverContext ,  /* Input: driver handle */
    AUD_FTM_ACCESS_MODE_T AccessMode,           /* Input: Access mode */
    AUD_FTM_SHARE_MODE_T  ShareMode,            /* Input: Share mode */
    AUDIO_FTM_CLIENT_HANDLE_T * pClientContext  /* Output: client handle */
)
{
    Aud_FTM_DrvCtxt_T * pDrvCxt = (Aud_FTM_DrvCtxt_T *)pDriverContext;
    Aud_FTM_ClientCtxt_T * pOpenContext = NULL;
    AUDIO_FTM_STS_T  res;
    int16 i;
    uint32 dev_buf_size, fifo_buf_size;

    if (pDrvCxt == NULL)
    {
        DALSYS_Log_Err("%s: failed %d\n",__func__,__LINE__);
        return AUDIO_FTM_ERR_INVALID_PARAM;
    }

    DALSYS_SyncEnter(pDrvCxt->hClientSync);

    if((ShareMode == AUD_FTM_SHAREMODE_EXCLU ) && (DALSYS_atomic_read(&pDrvCxt->dwOpenCount) != 0))
        /* ShareMode = 0: exclusive mode; =FILE_SHARE_READ: read only; =FILE_SHARE_WRITE: write only */
    {
        DALSYS_SyncLeave(pDrvCxt->hClientSync);
        DALSYS_Log_Err("%s: failed %d\n",__func__,__LINE__);
        return AUDIO_FTM_ERROR;
    }

  if(DAL_SUCCESS != DALSYS_Malloc(sizeof(Aud_FTM_ClientCtxt_T), (void **)&pOpenContext))
    {
        DALSYS_Log_Err("%s: failed %d\n",__func__,__LINE__);
        DALSYS_SyncLeave(pDrvCxt->hClientSync);
        return AUDIO_FTM_ERR_MEM_ALLOC_FAIL;
    }

    if (pOpenContext == NULL)
    {
      DALSYS_SyncLeave(pDrvCxt->hClientSync);
        DALSYS_Log_Err("%s: failed %d\n",__func__,__LINE__);
      return AUDIO_FTM_ERR_MEM_ALLOC_FAIL;
    }
  DALSYS_memset(pOpenContext,0,sizeof(Aud_FTM_ClientCtxt_T));

    // Store device settings for future use
    pOpenContext->pDrvCtxt = pDrvCxt;
    pOpenContext->dwAccessCode = AccessMode;
    pOpenContext->dwShareMode = ShareMode;

  pOpenContext->dwClientID=DALSYS_atomic_read(&pDrvCxt->dwOpenCount);

  pDrvCxt->apClientCtxt[pOpenContext->dwClientID]=pOpenContext;

#ifdef MSM8960_ALSA
  pDrvCxt->pDevCtxt->read_write_flag = PCM_OUT;
#endif

  /***** open HW *****/
  DALSYS_Log_Info("%s: open hw\n",__func__);
  pDrvCxt->pDevCtxt->playbackdevice =
  pDrvCxt->pDevCtxt->pDrvCtxt->client_param.device;
  res=audio_ftm_hw_open(pDrvCxt->pDevCtxt);
  if(res != AUDIO_FTM_SUCCESS)
  {
    DALSYS_Log_Err("%s: failed %d\n",__func__,__LINE__);
    DALSYS_SyncLeave(pDrvCxt->hClientSync);
    return AUDIO_FTM_ERROR;
  }

    audio_ftm_hw_iocontrol(pDrvCxt->pDevCtxt, IOCTL_AUDIO_FTM_RX_DEV_BUF_SIZE, NULL, 0, &dev_buf_size, sizeof(dev_buf_size), NULL);
    pDrvCxt->nRx_blk_convey_samples=dev_buf_size/sizeof(int16);

  /********* init circular buf ********/
    fifo_buf_size=dev_buf_size*AUD_FTM_TONE_PLAY_FIFO_FACTOR+4;    // reserve 4 bytes

  DALSYS_Log_Info("%s: init buf\n",__func__);
  aud_ftm_cbuf_init(&(pDrvCxt->fifo_data_buf), fifo_buf_size);

  if(DAL_SUCCESS != DALSYS_Malloc(dev_buf_size*AUD_FTM_TONE_PLAY_FIFO_FACTOR, (void **)&pTmpBuf))  /* buffer for DTMF data producing */
  {
          DALSYS_SyncLeave(pDrvCxt->hClientSync);
      DALSYS_Log_Err(" pTmpBuf allocation fail\n");
      return DAL_ERROR;
    }
  DALSYS_memset(pTmpBuf,0,dev_buf_size*AUD_FTM_TONE_PLAY_FIFO_FACTOR);

  if(DAL_SUCCESS != DALSYS_Malloc(dev_buf_size, (void **)&pAud_ftm_rx_buf))  /* buffer for fetch data from FIFO and pass to low layer driver for consuming */
  {
          DALSYS_SyncLeave(pDrvCxt->hClientSync);
      DALSYS_Log_Err(" pAud_ftm_rx_buf allocation fail\n");
      return DAL_ERROR;
    }
  DALSYS_memset(pAud_ftm_rx_buf,0,dev_buf_size);

  /***** prefill the circular buffer with DTMF data *****/

  for(i=0; i<((dev_buf_size*AUD_FTM_TONE_PLAY_FIFO_FACTOR)/sizeof(int16)); i++)
  {
    *(pTmpBuf+i)=audio_ftm_dtmf_tone_sample_gen(&(pDrvCxt->dtmfGen),pDrvCxt->nDTMF_Gain);
  }
  aud_ftm_cbuf_write (&(pDrvCxt->fifo_data_buf),(uint8 *)pTmpBuf,(int32)(dev_buf_size*AUD_FTM_TONE_PLAY_FIFO_FACTOR));

    // Increase opened device counter
  AddRef(&pDrvCxt->dwOpenCount);
    pDrvCxt->bOpened=TRUE;

    DALSYS_SyncLeave(pDrvCxt->hClientSync);

    *pClientContext=  (AUDIO_FTM_CLIENT_HANDLE_T)pOpenContext;

    return AUDIO_FTM_SUCCESS;
}
AUDIO_FTM_STS_T
audio_ftm_toneplay_attach
(
    void *pParam,                                 /* Input: parameters  */
    AUDIO_FTM_DRIVER_HANDLE_T *pDriverHdl        /* Output: driver handle */
)
{
  /************* Context creation ***********/

  Aud_FTM_DevCtxt_T *pDeviceCtxt;
  Aud_FTM_DrvCtxt_T *pDriverCtxt;

    Aud_FTM_HW_INIT_PARAM_T hw_param;
    int16 freq1,freq2, sampling_freq;

    AUDIO_FTM_STS_T sts;

    if (g_bDriverInitialized)
  {
      DALSYS_Log_Err("%s: error: already initialized\n", __func__);
        return  AUDIO_FTM_ERROR;    //  already inited,
  }

  DALSYS_Log_Info("Attach TonePlay Driver\n");

    /****************** create context object ******************/

  if((DAL_SUCCESS != DALSYS_Malloc(sizeof(Aud_FTM_DevCtxt_T), (void **)&pDeviceCtxt)) ||
        (pDeviceCtxt == NULL))
    {
      DALSYS_Log_Err("Memory allocation fail\n");
        return AUDIO_FTM_ERR_MEM_ALLOC_FAIL;
    }

  DALSYS_memset(pDeviceCtxt,0,sizeof(Aud_FTM_DevCtxt_T));

  if((DAL_SUCCESS != DALSYS_Malloc(sizeof(Aud_FTM_DrvCtxt_T), (void **)&pDriverCtxt)) ||
        (pDriverCtxt == NULL))
    {
      DALSYS_Log_Err("Memory allocation fail\n");
                DALSYS_Free(pDeviceCtxt);
        return AUDIO_FTM_ERR_MEM_ALLOC_FAIL;
    }

  DALSYS_memset(pDriverCtxt,0,sizeof(Aud_FTM_DevCtxt_T));

    DALSYS_atomic_init(&pDriverCtxt->dwOpenCount);
    pDriverCtxt->pDevCtxt=pDeviceCtxt;
    pDeviceCtxt->pDrvCtxt=pDriverCtxt;

  /************* Create Critical Section ***********/

    if(DAL_SUCCESS != DALSYS_SyncCreate(DALSYS_SYNC_ATTR_RESOURCE,
        &(pDriverCtxt->hClientSync),
        NULL))
    {
      DALSYS_Log_Err("hClientSync creation fail\n");
        return AUDIO_FTM_ERROR;
    }

   if(DAL_SUCCESS != DALSYS_EventCreate(DALSYS_EVENT_ATTR_WORKLOOP_EVENT,       //Not used for work loops
                              &(pDriverCtxt->hReq_Data_Event),          //Return event handle
                              NULL))
   {
    DALSYS_Log_Err("%s: failed to create event\n", __func__);
    DALSYS_SyncLeave(pDriverCtxt->hClientSync);
    DALSYS_Free(pDriverCtxt->hClientSync);
    return AUDIO_FTM_ERROR;
   }

    /*************  hardware initialization ***********/

   DALSYS_memcpy((uint8*)&(pDriverCtxt->client_param),
                  (uint8*)pParam, sizeof(AUD_FTM_TONE_PLAY_PARAM_T));

   hw_param.inpath=AUDIO_FTM_IN_INVALID;
   hw_param.outpath=pDriverCtxt->client_param.path.outpath;
   hw_param.rate=AUDIO_FTM_PCM_RATE_8K;
   hw_param.width=AUDIO_FTM_BIT_WIDTH_16;
   hw_param.channel=AUDIO_FTM_CHN_1;
   hw_param.gain=pDriverCtxt->client_param.gain;
     hw_param.bLoopbackCase=FALSE;

   sts=aud_ftm_hw_init(pDeviceCtxt, &hw_param);
   if(sts != AUDIO_FTM_SUCCESS) {
      DALSYS_Log_Err("%s: failed to init hw\n", __func__);
        return AUDIO_FTM_ERROR;
   }

      /* Tone generator init */

    freq1=((AUD_FTM_TONE_PLAY_PARAM_T*)pParam)->dtmf_low;
    freq2=((AUD_FTM_TONE_PLAY_PARAM_T*)pParam)->dtmf_hi;
    sampling_freq=8000;

    audio_ftm_dtmf_tone_init(&(pDriverCtxt->dtmfGen),freq1,freq2,sampling_freq);
    pDriverCtxt->nDTMF_Gain = vol_map[3];

    /***** end of Init *****/

        pDriverCtxt->bOpened=FALSE;
      g_bDriverInitialized=TRUE;
    *pDriverHdl=(AUDIO_FTM_DRIVER_HANDLE_T)pDriverCtxt;

      return AUDIO_FTM_SUCCESS;

}
/**
  Leaves a synchronized context.

  Leaves a synchronized context.

  @param[in,out]  sync    Sync object to be used

  @return
  None.

*/
BAM_API_NON_PAGED void bam_osal_syncleave(bam_osal_sync_type *sync)
{
    #ifndef BAM_MBA
    DALSYS_SyncLeave(*((DALSYSSyncHandle*)sync));
    #endif // #ifndef BAM_MBA
}
static void
STMTrace_FreePort( DalDeviceHandle * h, uint32 uPort)
{
   STMTraceClientCtxt *pClientCtxt = ((DalSTMTraceHandle *)h)->pClientCtxt;
   STMTraceDevCtxt *pDevCtxt = pClientCtxt->pSTMTraceDevCtxt;

   STMPortRangeItem * currRange = NULL;
   STMPortRangeItem * prevRange = NULL;
   uint32 uBitPos = 0;

   DALSYS_SyncEnter(pDevCtxt->hSync);
   currRange =  pDevCtxt->listHead;
   while(NULL != currRange)
   {
      // does the uPort fall in the current range ?
      if(currRange->uBaseAddr <= uPort &&
         uPort < currRange->uBaseAddr + STM_PORT_SIZE*currRange->portRange.uNumPorts)
      {
         goto free_port;
      }

      prevRange = currRange;
      currRange = currRange->next;
   }
   DALSYS_SyncLeave(pDevCtxt->hSync);
   return;

free_port:

   uBitPos = (uPort-currRange->uBaseAddr)/STM_PORT_SIZE;

   if(DAL_SUCCESS != _FreeBit(currRange->portRange.pBitMask, MAX_STM_PORTS_PER_PAGE, uBitPos))
   {
      DALSYS_SyncLeave(pDevCtxt->hSync);
      return;
   }

   currRange->uNumFreePorts++;
   if(currRange->uNumFreePorts == currRange->portRange.uNumPorts)
   {
      // all ports in this range have been freed so free the bit from
      // main mask
      if(DAL_SUCCESS != _FreeBit(currRange->mainPortRange->pBitMask,
                                 currRange->mainPortRange->uNumPorts/MAX_STM_PORTS_PER_PAGE,
                                 currRange->portRange.uBasePort/MAX_STM_PORTS_PER_PAGE))
      {
         DALSYS_SyncLeave(pDevCtxt->hSync);
         return;
      }

      if(NULL != currRange->hMem)
      {
         DALSYS_DestroyObject(currRange->hMem);
      }

      if(NULL != prevRange)
      {
         prevRange->next = currRange->next;
      }
      else
      {
         pDevCtxt->listHead = pDevCtxt->listHead->next;
      }

      DALSYS_Free(currRange->portRange.pBitMask);
      DALSYS_Free(currRange);
   }
   DALSYS_SyncLeave(pDevCtxt->hSync);
   return;
}
static DALResult
STMTrace_NewPort( DalDeviceHandle * h, uint32 * uPort, uint32 * uPortDMA)
{
   STMTraceClientCtxt *pClientCtxt = ((DalSTMTraceHandle *)h)->pClientCtxt;
   STMTraceDevCtxt *pDevCtxt = pClientCtxt->pSTMTraceDevCtxt;
   STMPortRange *pMainPortRange;
   STMPortRangeItem * currRange = NULL;
   STMPortRangeItem * prevRange = NULL;
   uint32 uBitPos;
   DALSYSMemInfo memInfo;


   if(NULL != uPortDMA) // DMA'able port requested ?
   {
      pMainPortRange = &pDevCtxt->portRangeDMA;
      if(!pMainPortRange->uNumPorts)
      {
         return DAL_ERROR;
      }
   }
   else
   {
      pMainPortRange = &pDevCtxt->portRange;
   }

   DALSYS_SyncEnter(pDevCtxt->hSync);

   currRange = pDevCtxt->listHead;
   while(NULL != currRange)
   {
      // previously allocated range has a free port?
      if(0 != currRange->uNumFreePorts)
         goto alloc_port;

      prevRange = currRange;
      currRange = currRange->next;
   }

   // carve out a new range from the master range now
   if(DAL_SUCCESS != DALSYS_Malloc(sizeof(STMPortRangeItem),(void **)&currRange))
   {
      DALSYS_SyncLeave(pDevCtxt->hSync);
      return DAL_ERROR;
   }

   memset(currRange, 0, sizeof(STMPortRangeItem));

   if(DAL_SUCCESS != _AllocBit(pMainPortRange->pBitMask,
                                pMainPortRange->uNumPorts/MAX_STM_PORTS_PER_PAGE,
                                &uBitPos))
   {
      DALSYS_Free(currRange);
      DALSYS_SyncLeave(pDevCtxt->hSync);
      return DAL_ERROR;
   }
   currRange->portRange.uBasePort = pMainPortRange->uBasePort + (uBitPos * MAX_STM_PORTS_PER_PAGE);
   currRange->portRange.uNumPorts = MAX_STM_PORTS_PER_PAGE;
   currRange->uNumFreePorts = MAX_STM_PORTS_PER_PAGE;
   currRange->mainPortRange = pMainPortRange;

   if(DAL_SUCCESS != _AllocateMemForBitMasks(&currRange->portRange.pBitMask, MAX_STM_PORTS_PER_PAGE))
   {
      _FreeBit(pMainPortRange->pBitMask, pMainPortRange->uNumPorts/MAX_STM_PORTS_PER_PAGE, uBitPos);
      DALSYS_Free(currRange);
      DALSYS_SyncLeave(pDevCtxt->hSync);
      return DAL_ERROR;
   }

   if(DAL_SUCCESS != DALSYS_MemRegionAlloc(DALSYS_MEM_PROPS_HWIO, DALSYS_MEM_ADDR_NOT_SPECIFIED,
                                           pDevCtxt->uSTMSPBaseAddr +
                                           (currRange->portRange.uBasePort * STM_PORT_SIZE),
                                           4096, &currRange->hMem, NULL))
   {
      _FreeBit(pMainPortRange->pBitMask, pMainPortRange->uNumPorts/MAX_STM_PORTS_PER_PAGE, uBitPos);
      DALSYS_Free(currRange->portRange.pBitMask);
      DALSYS_Free(currRange);
      DALSYS_SyncLeave(pDevCtxt->hSync);
      return DAL_ERROR;
   }

   DALSYS_MemInfo(currRange->hMem, &memInfo);
   currRange->uBaseAddr = memInfo.VirtualAddr;

   if(NULL != prevRange)
   {
      prevRange->next = currRange;
   }
   else
   {
      pDevCtxt->listHead = currRange;
   }

alloc_port:

   if(DAL_SUCCESS != _AllocBit(currRange->portRange.pBitMask, MAX_STM_PORTS_PER_PAGE, &uBitPos))
   {
      DALSYS_SyncLeave(pDevCtxt->hSync);
      return DAL_ERROR;
   }

   *uPort = currRange->uBaseAddr + (STM_PORT_SIZE * uBitPos);
   if(NULL != uPortDMA)
   {
      /* prepare a 32 bit int with 7 bits starting at 17th bit */
      uint32 uPortOffset = ((currRange->portRange.uBasePort+uBitPos)&0x7F)<<17;
      /* first get the physical address of the allocated port */
      *uPortDMA = pDevCtxt->uSTMSPBaseAddr +
                  ((currRange->portRange.uBasePort + uBitPos) * STM_PORT_SIZE);
      /* then set the 7 bits starting at 17th bit pos to 0's */
      *uPortDMA = *uPortDMA &(~(0x7F<<17));
      /* finally set the lower 7 bits of the stimulus port number at the 17th bit pos */
      *uPortDMA |= uPortOffset;
   }
   currRange->uNumFreePorts--;

   DALSYS_SyncLeave(pDevCtxt->hSync);

   return DAL_SUCCESS;
}