示例#1
0
/**
 @brief    This helper function is used to clean up the pending 
           messages in the transport queue

 @param wctsHandlehandle:  transport handle

 @see
 @return   0 for success
*/
wpt_uint32
WCTS_ClearPendingQueue
(
   WCTS_HandleType      wctsHandle
)
{
   WCTS_ControlBlockType* pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   wpt_list_node*      pNode = NULL;
   WCTS_BufferType*    pBufferQueue = NULL;
   void*               pBuffer = NULL;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_ClearPendingQueue: Invalid parameters received.");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   /*Free the buffers in the pending queue.*/
   while (eWLAN_PAL_STATUS_SUCCESS ==
          wpal_list_remove_front(&pWCTSCb->wctsPendingQueue, &pNode)) {
      pBufferQueue = container_of(pNode, WCTS_BufferType, node);
      pBuffer = pBufferQueue->pBuffer;
      wpalMemoryFree(pBuffer);
      wpalMemoryFree(pBufferQueue);
   }
   return eWLAN_PAL_STATUS_SUCCESS;

}/*WCTS_ClearPendingQueue*/
static void
WCTS_PALWriteCallback
(
   WCTS_ControlBlockType*  pWCTSCb
)
{
   wpt_list_node*      pNode;
   WCTS_BufferType*    pBufferQueue;
   void*               pBuffer;
   int                 len;
   int                 available;
   int                 written;

   

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_PALWriteCallback: Invalid parameter received.");
      return;
   }

   
   if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {
      return;
   }

   while (eWLAN_PAL_STATUS_SUCCESS ==
          wpal_list_peek_front(&pWCTSCb->wctsPendingQueue, &pNode)) {
      pBufferQueue = container_of(pNode, WCTS_BufferType, node);
      pBuffer = pBufferQueue->pBuffer;
      len = pBufferQueue->bufferSize;

      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available < len) {
         
         return;
      }

      wpal_list_remove_front(&pWCTSCb->wctsPendingQueue, &pNode);


      written = smd_write(pWCTSCb->wctsChannel, pBuffer, len);
      if (written != len) {
         
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALWriteCallback: channel write failure");

      }

      
      wpalMemoryFree(pBuffer);
      wpalMemoryFree(pBufferQueue);

   }

   pWCTSCb->wctsState = WCTS_STATE_OPEN;
   smd_disable_read_intr(pWCTSCb->wctsChannel);

} 
/*
 * Destroy the memory pool
 */
void WDI_DS_MemPoolDestroy(WDI_DS_BdMemPoolType *memPool)
{
  //Allocate all the max size.
  wpalDmaMemoryFree(memPool->pVirtBaseAddress);
  wpalMemoryFree(memPool->AllocationBitmap);
  wpalMemoryZero(memPool, sizeof(*memPool));
}
示例#4
0
/*---------------------------------------------------------------------------
    wpalPacketFree – Free a wpt_packet chain for one particular type.
    For our legacy UMAC, it is not needed because vos_packet contains pal_packet.
    Param: 
        pPkt – pointer to a wpt_packet
    Return:
        eWLAN_PAL_STATUS_SUCCESS - success
---------------------------------------------------------------------------*/
wpt_status wpalPacketFree(wpt_packet *pPkt)
{
   VOS_STATUS vosStatus;

   if(NULL != pPkt->pInternalData)
   {
      wpalMemoryFree(pPkt->pInternalData);
   }
   vosStatus = vos_pkt_return_packet(WPAL_TO_VOS_PKT(pPkt));

   //With VOSS support, we can cast between wpt_status and VOS_STATUS
   return (wpt_status)vosStatus;
}/*wpalPacketFree*/
wpt_status wpalPacketFree(wpt_packet *pPkt)
{
   VOS_STATUS vosStatus;

   if(NULL != pPkt->pInternalData)
   {
      wpalMemoryFree(pPkt->pInternalData);
   }
   vosStatus = vos_pkt_return_packet(WPAL_TO_VOS_PKT(pPkt));

   //                                                                
   return (wpt_status)vosStatus;
}/*              */
wpt_status wpalIteratorNext(wpt_iterator *pIter, wpt_packet *pPacket, void **ppAddr, wpt_uint32 *pLen)
{
   wpt_iterator_info* pCurInfo  = NULL;
   /*                                                                       */
   
   /*                                                                         
                 
                                                                            */
   if (unlikely(( NULL == pIter )||( NULL == pPacket ) || 
      ( NULL == ppAddr ) || ( NULL == pLen )))
   {
     WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, 
                "%s  Invalid input parameters \n",  __func__ );
     return eWLAN_PAL_STATUS_E_INVAL;
   }

   pCurInfo = (wpt_iterator_info*)pIter->pCur; 
   /*                                                                         
                                                                         
                                                                            */
   if( pIter->pCur == NULL )
   {
      *ppAddr = NULL; 
      *pLen   = 0;
      return eWLAN_PAL_STATUS_SUCCESS;
   }

   /*                                                */
   *ppAddr = pCurInfo->pPhyAddr; 
   *pLen   = pCurInfo->uLen;
    
   if( NULL == pIter->pNext )
   {
     /*                             */
     pPacket->pInternalData = pIter->pCur; 
     pIter->pCur            = NULL; 
   }
   else
   {
     /*                                                       */
     wpalMemoryFree(pCurInfo); 
  
     /*                                                               
                                         */
     pIter->pCur     = pIter->pNext;
     pIter->pNext    = NULL;
   }
   
   return eWLAN_PAL_STATUS_SUCCESS;
}
示例#7
0
/*---------------------------------------------------------------------------
    wpalIteratorNext – Get the address for the next item
    Param: 
        pIter – pointer to a caller allocated wpt_iterator
        pPacket – pointer to a wpt_packet
        ppAddr – Caller allocated pointer to return the address of the item.
        For DMA-able devices, this is the physical address of the item.
        pLen – To return the number of bytes in the item.
    Return:
        eWLAN_PAL_STATUS_SUCCESS - success
---------------------------------------------------------------------------*/
wpt_status wpalIteratorNext(wpt_iterator *pIter, wpt_packet *pPacket, void **ppAddr, wpt_uint32 *pLen)
{
   wpt_iterator_info* pCurInfo  = NULL;
   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
   
   /*-------------------------------------------------------------------------
     Sanity check
   -------------------------------------------------------------------------*/
   if (unlikely(( NULL == pIter )||( NULL == pPacket ) || 
      ( NULL == ppAddr ) || ( NULL == pLen )))
   {
     WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, 
                "%s  Invalid input parameters",  __func__ );
     return eWLAN_PAL_STATUS_E_INVAL;
   }

   pCurInfo = (wpt_iterator_info*)pIter->pCur; 
   /*-------------------------------------------------------------------------
     If current pointer is NULL - there is no data in the packet - return
   -------------------------------------------------------------------------*/
   if( pIter->pCur == NULL )
   {
      *ppAddr = NULL; 
      *pLen   = 0;
      return eWLAN_PAL_STATUS_SUCCESS;
   }

   /*Address and length are kept in the current field*/
   *ppAddr = pCurInfo->pPhyAddr; 
   *pLen   = pCurInfo->uLen;
    
   if( NULL == pIter->pNext )
   {
     /*Save the iterator for cleanup*/
     pPacket->pInternalData = pIter->pCur; 
     pIter->pCur            = NULL; 
   }
   else
   {
     /*Release the memory saved for storing the BD information*/
     wpalMemoryFree(pCurInfo); 
  
     /*For LA - the packet is represented by maximum 2 fields of data 
       - BD and actual data from sk buff */
     pIter->pCur     = pIter->pNext;
     pIter->pNext    = NULL;
   }
   
   return eWLAN_PAL_STATUS_SUCCESS;
}
/**
 @brief WDI_STATableClose - frees the resources used by the STA 
        table.

 
 @param  pWDICtx:         pointer to the WLAN DAL context 
  
 @see
 @return Result of the function call
*/
WDI_Status 
WDI_STATableClose
(
  WDI_ControlBlockType*  pWDICtx
)
{
    WDI_Status status = WDI_STATUS_SUCCESS;
        
    // Free memory
    if (pWDICtx->staTable != NULL)
        wpalMemoryFree( pWDICtx->staTable);

    pWDICtx->staTable = NULL;
    return status;
}/*WDI_STATableClose*/
/* DTS Stop function. 
 * Stop Transport driver, ie DXE, SDIO
 * Parameters:
 * pContext:Cookie that should be passed back to the caller along with the callback.
 * Return Value: SUCCESS  Completed successfully.
 *     FAILURE_XXX  Request was rejected due XXX Reason.
 *
 */
wpt_status WDTS_Close(void *pContext)
{
  void *pDTDriverContext = WDT_GetTransportDriverContext(pContext);
  WDI_DS_ClientDataType *pClientData = WDI_DS_GetDatapathContext(pContext);
  wpt_status status = eWLAN_PAL_STATUS_SUCCESS;

  /*Destroy the mem pool for mgmt BD headers*/
  WDI_DS_MemPoolDestroy(&pClientData->mgmtMemPool);
  
  /*Destroy the mem pool for mgmt BD headers*/
  WDI_DS_MemPoolDestroy(&pClientData->dataMemPool);
  
  status =  gTransportDriver.close(pDTDriverContext);

  wpalMemoryFree(pClientData);

  return status;
}
示例#10
0
/**
 @brief    Callback function for serializing WCTS Write
           processing in the control context

 @param    pWCTSCb  WCTS Control Block

 @see
 @return void
*/
static void
WCTS_PALWriteCallback
(
   WCTS_ControlBlockType*  pWCTSCb
)
{
   wpt_list_node*      pNode;
   WCTS_BufferType*    pBufferQueue;
   void*               pBuffer;
   int                 len;
   int                 available;
   int                 written;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   /*--------------------------------------------------------------------
     Sanity check
     --------------------------------------------------------------------*/
   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_PALWriteCallback: Invalid parameter received.");
      return;
   }

   /* if we are not deferred, then there are no pending packets */
   if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {
      return;
   }

   /* Keep sending deferred messages as long as there is room in
      the channel.  Note that we initially peek at the head of the
      list to access the parameters for the next message; we don't
      actually remove the next message from the deferred list until
      we know the channel can handle it */
   while (eWLAN_PAL_STATUS_SUCCESS ==
          wpal_list_peek_front(&pWCTSCb->wctsPendingQueue, &pNode)) {
      pBufferQueue = container_of(pNode, WCTS_BufferType, node);
      pBuffer = pBufferQueue->pBuffer;
      len = pBufferQueue->bufferSize;

      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available < len) {
         /* channel has no room for the next packet so we are done */
         return;
      }

      /* there is room for the next message, so we can now remove
         it from the deferred message queue and send it */
      wpal_list_remove_front(&pWCTSCb->wctsPendingQueue, &pNode);

      /* note that pNode will be the same as when we peeked, so
         there is no need to update pBuffer or len */

      written = smd_write(pWCTSCb->wctsChannel, pBuffer, len);
      if (written != len) {
         /* Something went wrong */
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALWriteCallback: channel write failure");

         /* we were unable to send the message that was at the head
            of the deferred list.  there is nothing else we can do
            other than drop it, so we will just fall through to the
            "success" processing.
            hopefully the client can recover from this since there is
            nothing else we can do here */
      }

      /* whether we had success or failure, reclaim all memory */
      wpalMemoryFree(pBuffer);
      wpalMemoryFree(pBufferQueue);

      /* we'll continue to iterate until the channel is full or all
         of the deferred messages have been sent */
   }

   /* if we've exited the loop, then we have drained the deferred queue.
      set the state to indicate we are no longer deferred, and turn off
      the remote read interrupt */
   pWCTSCb->wctsState = WCTS_STATE_OPEN;
   smd_disable_read_intr(pWCTSCb->wctsChannel);

} /*WCTS_PALWriteCallback*/
示例#11
0
/*---------------------------------------------------------------------------
    wpalUnlockPacket – Unmap the data buffer from dma so that cpu can regain
                          ownership on it
    Param: 
        pPacket – pointer to a wpt_packet
 
    Return:
        eWLAN_PAL_STATUS_SUCCESS - success
---------------------------------------------------------------------------*/
wpt_status wpalUnlockPacket( wpt_packet *pPacket)
{

   wpt_iterator_info* pInfo;

   // Validate the parameter pointers
   if (unlikely(NULL == pPacket))
   {
      WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                "%s : NULL input pointer pPacket", __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   pInfo  = (wpt_iterator_info*)pPacket->pInternalData;

   // Validate pInfo
   if (unlikely(NULL == pInfo))
   {
      WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_FATAL,
                "%s : NULL input pointer pInfo", __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   switch(WPAL_PACKET_GET_TYPE(pPacket))
   {
      /* For management frames, BD is allocated by WDI, header is in raw buffer,
         rest of the frame is also in raw buffer */
   case eWLAN_PAL_PKT_TYPE_TX_802_11_MGMT:
      {
         /*TX Packets need to be DMA-ed to the device, perform DMA mapping 
           accordingly */
        itReturnOSPktAddrForDevice(pPacket, pInfo->pPhyAddr, pInfo->uLen);   
      }
      break;
         /* Data packets - BD (allocated by WDI), header (in VOSS header),
            rest of the packet (DSM items) */
   case eWLAN_PAL_PKT_TYPE_TX_802_11_DATA:
   case eWLAN_PAL_PKT_TYPE_TX_802_3_DATA:
      {
         /*TX Packets need to be DMA-ed to the device, perform DMA mapping 
           accordingly */
         itReturnOSPktAddrForDevice(pPacket, pInfo->pPhyAddr, pInfo->uLen);   
      }
      break;

      /* For Raw RX, BD + header + rest of the packet is all contained in the raw
         buffer */
   case eWLAN_PAL_PKT_TYPE_RX_RAW:
      {
         /*RX Packets need to be DMA-ed from the device, perform DMA mapping 
           accordingly */
         if(NULL == pInfo->pPhyAddr)
         {
            WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, 
                       " WLAN_PAL: %s: RX frame was not locked properly",  __func__); 
         }
         else
         {
            itReturnOSPktAddrFromDevice(pPacket, pInfo->pPhyAddr, pInfo->uLen);   
         }
      }
      break;

   default:
      {
         WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, 
                    " WLAN_PAL: %s: Invalid packet type %d!",  __func__, 
                    WPAL_PACKET_GET_TYPE(pPacket) ); 
         WPAL_ASSERT(0); 
         return eWLAN_PAL_STATUS_E_FAILURE;
      }
   }

  wpalMemoryFree(pInfo);
  pPacket->pInternalData = NULL;
  return eWLAN_PAL_STATUS_SUCCESS;
}/*wpalUnlockPacket*/
static void
WCTS_PALReadCallback
(
   WCTS_ControlBlockType*  pWCTSCb
)
{
   void* buffer;
   int packet_size;
   int available;
   int bytes_read;

   

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_PALReadCallback: Invalid parameter received.");
      return;
   }

   
   while (1) {
      
      packet_size = smd_cur_packet_size(pWCTSCb->wctsChannel);
      if (0 == packet_size) {
         
         return;
      }

      
      available = smd_read_avail(pWCTSCb->wctsChannel);
      if (available < packet_size) {
         return;
      }

      buffer = wpalMemoryAllocate(packet_size);
      if (NULL ==  buffer) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALReadCallback: Memory allocation failure");
         WPAL_ASSERT(0);
         return;
      }

      bytes_read = smd_read(pWCTSCb->wctsChannel,
                            buffer,
                            packet_size);

      if (bytes_read != packet_size) {
         
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALReadCallback: Failed to read data from SMD");
         wpalMemoryFree(buffer);
         WPAL_ASSERT(0);
         return;
      }

      
      pWCTSCb->wctsRxMsgCB((WCTS_HandleType)pWCTSCb,
                           buffer,
                           packet_size,
                           pWCTSCb->wctsRxMsgCBData);

      
      wpalMemoryFree(buffer);
   }

} 
wpt_status wpalUnlockPacket( wpt_packet *pPacket)
{

   wpt_iterator_info* pInfo;

   //                                
   if (unlikely(NULL == pPacket))
   {
      WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                "%s : NULL input pointer pPacket", __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   pInfo  = (wpt_iterator_info*)pPacket->pInternalData;

   //               
   if (unlikely(NULL == pInfo))
   {
      WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_FATAL,
                "%s : NULL input pointer pInfo", __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   switch(WPAL_PACKET_GET_TYPE(pPacket))
   {
      /*                                                                        
                                                 */
   case eWLAN_PAL_PKT_TYPE_TX_802_11_MGMT:
      {
         /*                                                                
                       */
        itReturnOSPktAddrForDevice(pPacket, pInfo->pPhyAddr, pInfo->uLen);   
      }
      break;
         /*                                                               
                                           */
   case eWLAN_PAL_PKT_TYPE_TX_802_11_DATA:
   case eWLAN_PAL_PKT_TYPE_TX_802_3_DATA:
      {
         /*                                                                
                       */
         itReturnOSPktAddrForDevice(pPacket, pInfo->pPhyAddr, pInfo->uLen);   
      }
      break;

      /*                                                                         
                */
   case eWLAN_PAL_PKT_TYPE_RX_RAW:
      {
         /*                                                                  
                       */
         if(NULL == pInfo->pPhyAddr)
         {
            WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, 
                       " WLAN_PAL: %s: RX frame was not locked properly",  __func__); 
         }
         else
         {
            itReturnOSPktAddrFromDevice(pPacket, pInfo->pPhyAddr, pInfo->uLen);   
         }
      }
      break;

   default:
      {
         WPAL_TRACE(eWLAN_MODULE_PAL, eWLAN_PAL_TRACE_LEVEL_ERROR, 
                    " WLAN_PAL: %s: Invalid packet type %d!",  __func__, 
                    WPAL_PACKET_GET_TYPE(pPacket) ); 
         WPAL_ASSERT(0); 
         return eWLAN_PAL_STATUS_E_FAILURE;
      }
   }

  wpalMemoryFree(pInfo);
  pPacket->pInternalData = NULL;
  return eWLAN_PAL_STATUS_SUCCESS;
}/*                */
示例#14
0
/**
 @brief    This function is used by the DAL Core to close the
           Control Transport when its services are no longer
           needed. Full close notification will be receive
           asynchronously on the notification callback
           registered on Open


 @param wctsHandlehandle:  received upon open

 @see
 @return   0 for success
*/
wpt_uint32
WCTS_CloseTransport
(
   WCTS_HandleType      wctsHandle
)
{
   WCTS_ControlBlockType* pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   wpt_list_node*      pNode = NULL;
   WCTS_BufferType*    pBufferQueue = NULL;
   void*               pBuffer = NULL;
   wpt_status          status;
   int                 smdstatus;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_CloseTransport: Invalid parameters received.");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

#ifdef FEATURE_R33D
   /* Not actually close port, just pretend */
   /* notified registered client that the channel is closed */
   pWCTSCb->wctsState = WCTS_STATE_CLOSED;
   pWCTSCb->wctsNotifyCB((WCTS_HandleType)pWCTSCb,
                         WCTS_EVENT_CLOSE,
                         pWCTSCb->wctsNotifyCBData);

   printk(KERN_ERR "R33D Not need to close");
   return eWLAN_PAL_STATUS_SUCCESS;
#endif /* FEATURE_R33D */

   /*Free the buffers in the pending queue.*/
   while (eWLAN_PAL_STATUS_SUCCESS ==
          wpal_list_remove_front(&pWCTSCb->wctsPendingQueue, &pNode)) {
      pBufferQueue = container_of(pNode, WCTS_BufferType, node);
      pBuffer = pBufferQueue->pBuffer;
      wpalMemoryFree(pBuffer);
      wpalMemoryFree(pBufferQueue);
   }

   /* Reset the state */
   pWCTSCb->wctsState = WCTS_STATE_CLOSED;

   wpalEventReset(&pWCTSCb->wctsEvent);
   smdstatus = smd_close(pWCTSCb->wctsChannel);
   if (0 != smdstatus) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: smd_close failed with status %d",
                 __func__, smdstatus);
      /* SMD did not successfully close the channel, therefore we
         won't receive an asynchronous close notification so don't
         bother to wait for an event that won't come */

   } else {
      /* close command was sent -- wait for the callback to complete */
      status = wpalEventWait(&pWCTSCb->wctsEvent, WCTS_SMD_CLOSE_TIMEOUT);
      if (eWLAN_PAL_STATUS_SUCCESS != status) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "%s: failed to receive SMD_EVENT_REOPEN_READY",
                    __func__);
      }

      /* During the close sequence we deregistered from SMD.  As part
         of deregistration SMD will call back into our driver with an
         event to let us know the channel is closed.  We need to
         insert a brief delay to allow that thread of execution to
         exit our module.  Otherwise our module may be unloaded while
         there is still code running within the address space, and
         that code will crash when the memory is unmapped  */
      msleep(50);
   }

   /* channel has (hopefully) been closed */
   pWCTSCb->wctsNotifyCB((WCTS_HandleType)pWCTSCb,
                         WCTS_EVENT_CLOSE,
                         pWCTSCb->wctsNotifyCBData);

   /* release the resource */
   pWCTSCb->wctsMagic = 0;
   wpalMemoryFree(pWCTSCb);
   gwctsHandle = NULL;

   return eWLAN_PAL_STATUS_SUCCESS;

}/*WCTS_CloseTransport*/
示例#15
0
/**
 @brief    This function is used by the DAL Core to to send a
           message over to the WLAN sub-system.

           Once a buffer has been passed into the Send Message
 API, CT takes full ownership of it and it is responsible for
 freeing the associated resources. (This prevents a memcpy in
 case of a deferred write)

 The messages transported through the CT on both RX and TX are
 flat memory buffers that can be accessed and manipulated
 through standard memory functions.

 @param wctsHandlehandle:  received upon open
        pMsg:  the message to be sent
        uLen: the length of the message

 @see
 @return   0 for success
*/
wpt_uint32
WCTS_SendMessage
(
   WCTS_HandleType      wctsHandle,
   void*                pMsg,
   wpt_uint32           uLen
)
{
   WCTS_ControlBlockType*    pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   WCTS_BufferType*          pBufferQueue;
   int                       len;
   int                       written = 0;
   int                       available;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   /*--------------------------------------------------------------------
     Sanity check
     --------------------------------------------------------------------*/
   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic) ||
       (NULL == pMsg) || (0 == uLen) || (0x7fffffff < uLen)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Invalid parameters received.");
      WPAL_ASSERT(0);
      if (NULL != pMsg) {
         wpalMemoryFree(pMsg);
      }
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   /* the SMD API uses int instead of uint, so change types here */
   len = (int)uLen;

   if (WCTS_STATE_OPEN == pWCTSCb->wctsState) {
      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available >= len) {
         written = smd_write(pWCTSCb->wctsChannel, pMsg, len);
      }
   } else if (WCTS_STATE_DEFERRED == pWCTSCb->wctsState) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
                 "WCTS_SendMessage: FIFO space not available, the packets will be queued");
   } else {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Channel in illegal state [%d].",
                 pWCTSCb->wctsState);
      /* force following logic to reclaim the buffer */
      written = -1;
   }

   if (-1 == written) {
      /*Something wrong*/
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Failed to send message over the bus.");
      wpalMemoryFree(pMsg);
      WPAL_ASSERT(0);
      return eWLAN_PAL_STATUS_E_FAILURE;
   } else if (written == len) {
      /* Message sent! No deferred state, free the buffer*/
      wpalMemoryFree(pMsg);
   } else {
      /* This much data cannot be written at this time,
         queue the rest of the data for later*/
      pBufferQueue = wpalMemoryAllocate(sizeof(WCTS_BufferType));
      if (NULL == pBufferQueue) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_SendMessage: Cannot allocate memory for queuing the buffer");
         wpalMemoryFree(pMsg);
         WPAL_ASSERT(0);
         return eWLAN_PAL_STATUS_E_NOMEM;
      }

      pBufferQueue->bufferSize = len;
      pBufferQueue->pBuffer = pMsg;
      wpal_list_insert_back(&pWCTSCb->wctsPendingQueue, &pBufferQueue->node);

      /* if we are not already in the deferred state, then transition
         to that state.  when we do so, we enable the remote read
         interrupt so that we'll be notified when messages are read
         from the remote end */
      if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {

         /* Mark the state as deferred.
            Later: We may need to protect wctsState by locks*/
         pWCTSCb->wctsState = WCTS_STATE_DEFERRED;

         smd_enable_read_intr(pWCTSCb->wctsChannel);
      }

      /*indicate to client that message was placed in deferred queue*/
      return eWLAN_PAL_STATUS_E_RESOURCES;
   }

   return eWLAN_PAL_STATUS_SUCCESS;

}/*WCTS_SendMessage*/
示例#16
0
/**
 @brief     This function is used by the DAL Core to initialize the Control
            Transport for processing. It must be called prior to calling any
            other APIs of the Control Transport.


 @param szName:   unique name for the channel that is to be opened
         uSize:   size of the channel that must be opened (should fit the
                  largest size of  packet that the Dal Core wishes to send)
         wctsCBs:  a list of callbacks that the CT needs to use to send
                  notification and messages back to DAL

 @see
 @return  A handle that must be used for further communication with the CTS.
         This is an opaque structure for the caller and it will be used in
         all communications to and from the CTS.

*/
WCTS_HandleType
WCTS_OpenTransport
(
   const wpt_uint8*         szName,
   wpt_uint32               uSize,
   WCTS_TransportCBsType*   wctsCBs
)
{
   WCTS_ControlBlockType*    pWCTSCb;
   wpt_status                status;
   int                       smdstatus;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

   /*---------------------------------------------------------------------
     Sanity check
     ---------------------------------------------------------------------*/
   if ((NULL == wctsCBs) || (NULL == szName) ||
       (NULL == wctsCBs->wctsNotifyCB) || (NULL == wctsCBs->wctsRxMsgCB)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_OpenTransport: Invalid parameters received.");

      return NULL;
   }

   /* This open is coming after a SSR, we don't need to reopen SMD,
    * the SMD port was never closed during SSR*/
   if (gwctsHandle) {
       WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
               "WCTS_OpenTransport port is already open\n");

       pWCTSCb = gwctsHandle;
       if (WCTS_CB_MAGIC != pWCTSCb->wctsMagic) {
           WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL,
                   "WCTS_OpenTransport: Invalid magic.");
           return NULL;
       }   
       pWCTSCb->wctsState = WCTS_STATE_OPEN;

       pWCTSCb->wctsNotifyCB((WCTS_HandleType)pWCTSCb,
               WCTS_EVENT_OPEN,
               pWCTSCb->wctsNotifyCBData);

       /* we initially don't want read interrupts
         (we only want them if we get into deferred write mode) */
       smd_disable_read_intr(pWCTSCb->wctsChannel);

       return (WCTS_HandleType)pWCTSCb;
   }

#ifdef FEATURE_R33D
   if(port_open)
   {
      /* Port open before, not need to open again */
      /* notified registered client that the channel is open */
      ctsCB->wctsState = WCTS_STATE_OPEN;
      ctsCB->wctsNotifyCB((WCTS_HandleType)ctsCB,
                           WCTS_EVENT_OPEN,
                           ctsCB->wctsNotifyCBData);
      return (WCTS_HandleType)ctsCB;
   }
#endif /* FEATURE_R33D */

   /* allocate a ControlBlock to hold all context */
   pWCTSCb = wpalMemoryAllocate(sizeof(*pWCTSCb));
   if (NULL == pWCTSCb) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_OpenTransport: Memory allocation failure.");
      return NULL;
   }

   /* make sure the control block is initialized.  in particular we need
      to make sure the embedded event and list structures are initialized
      to prevent "magic number" tests from being run against uninitialized
      values */
   wpalMemoryZero(pWCTSCb, sizeof(*pWCTSCb));

#ifdef FEATURE_R33D
   smd_init(0);
   port_open = 1;
   ctsCB = pWCTSCb;
#endif /* FEATURE_R33D */

   /*Initialise the event*/
   wpalEventInit(&pWCTSCb->wctsEvent);

   /* save the user-supplied information */
   pWCTSCb->wctsNotifyCB       = wctsCBs->wctsNotifyCB;
   pWCTSCb->wctsNotifyCBData   = wctsCBs->wctsNotifyCBData;
   pWCTSCb->wctsRxMsgCB        = wctsCBs->wctsRxMsgCB;
   pWCTSCb->wctsRxMsgCBData    = wctsCBs->wctsRxMsgCBData;

   /* initialize the remaining fields */
   wpal_list_init(&pWCTSCb->wctsPendingQueue);
   pWCTSCb->wctsMagic   = WCTS_CB_MAGIC;
   pWCTSCb->wctsState   = WCTS_STATE_OPEN_PENDING;
   pWCTSCb->wctsChannel = NULL;

   /* since SMD will callback in interrupt context, we will used
    * canned messages to serialize the SMD events into a thread
    * context
    */
   pWCTSCb->wctsOpenMsg.callback = WCTS_PALOpenCallback;
   pWCTSCb->wctsOpenMsg.pContext = pWCTSCb;

   pWCTSCb->wctsDataMsg.callback = WCTS_PALDataCallback;
   pWCTSCb->wctsDataMsg.pContext = pWCTSCb;

   /*---------------------------------------------------------------------
     Open the SMD channel
     ---------------------------------------------------------------------*/

   wpalEventReset(&pWCTSCb->wctsEvent);
   smdstatus = smd_named_open_on_edge(szName,
                                      SMD_APPS_WCNSS,
                                      &pWCTSCb->wctsChannel,
                                      pWCTSCb,
                                      WCTS_NotifyCallback);
   if (0 != smdstatus) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: smd_named_open_on_edge failed with status %d",
                 __func__, smdstatus);
      goto fail;
   }

   /* wait for the channel to be fully opened before we proceed */
   status = wpalEventWait(&pWCTSCb->wctsEvent, WCTS_SMD_OPEN_TIMEOUT);
   if (eWLAN_PAL_STATUS_SUCCESS != status) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: failed to receive SMD_EVENT_OPEN",
                 __func__);
      /* since we opened one end of the channel, close it */
      smdstatus = smd_close(pWCTSCb->wctsChannel);
      if (0 != smdstatus) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "%s: smd_close failed with status %d",
                    __func__, smdstatus);
      }
      goto fail;
   }

   /* we initially don't want read interrupts
      (we only want them if we get into deferred write mode) */
   smd_disable_read_intr(pWCTSCb->wctsChannel);

   /* we have successfully opened the SMD channel */
   gwctsHandle = pWCTSCb;
   return (WCTS_HandleType)pWCTSCb;

 fail:
   /* we were unable to open the SMD channel */
   pWCTSCb->wctsMagic = 0;
   wpalMemoryFree(pWCTSCb);
   return NULL;

}/*WCTS_OpenTransport*/
WCTS_HandleType
WCTS_OpenTransport
(
   const wpt_uint8*         szName,
   wpt_uint32               uSize,
   WCTS_TransportCBsType*   wctsCBs
)
{
   WCTS_ControlBlockType*    pWCTSCb;
   wpt_status                status;
   int                       smdstatus;

   

   if ((NULL == wctsCBs) || (NULL == szName) ||
       (NULL == wctsCBs->wctsNotifyCB) || (NULL == wctsCBs->wctsRxMsgCB)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_OpenTransport: Invalid parameters received.");

      return NULL;
   }

   if (gwctsHandle) {
       WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
               "WCTS_OpenTransport port is already open");

       pWCTSCb = gwctsHandle;
       if (WCTS_CB_MAGIC != pWCTSCb->wctsMagic) {
           WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_FATAL,
                   "WCTS_OpenTransport: Invalid magic.");
           return NULL;
       }   
       pWCTSCb->wctsState = WCTS_STATE_OPEN;

       pWCTSCb->wctsNotifyCB((WCTS_HandleType)pWCTSCb,
               WCTS_EVENT_OPEN,
               pWCTSCb->wctsNotifyCBData);

       smd_disable_read_intr(pWCTSCb->wctsChannel);

       return (WCTS_HandleType)pWCTSCb;
   }

#ifdef FEATURE_R33D
   if(port_open)
   {
      
      
      ctsCB->wctsState = WCTS_STATE_OPEN;
      ctsCB->wctsNotifyCB((WCTS_HandleType)ctsCB,
                           WCTS_EVENT_OPEN,
                           ctsCB->wctsNotifyCBData);
      return (WCTS_HandleType)ctsCB;
   }
#endif 

   
   pWCTSCb = wpalMemoryAllocate(sizeof(*pWCTSCb));
   if (NULL == pWCTSCb) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_OpenTransport: Memory allocation failure.");
      return NULL;
   }

   wpalMemoryZero(pWCTSCb, sizeof(*pWCTSCb));

#ifdef FEATURE_R33D
   smd_init(0);
   port_open = 1;
   ctsCB = pWCTSCb;
#endif 

   
   wpalEventInit(&pWCTSCb->wctsEvent);

   
   pWCTSCb->wctsNotifyCB       = wctsCBs->wctsNotifyCB;
   pWCTSCb->wctsNotifyCBData   = wctsCBs->wctsNotifyCBData;
   pWCTSCb->wctsRxMsgCB        = wctsCBs->wctsRxMsgCB;
   pWCTSCb->wctsRxMsgCBData    = wctsCBs->wctsRxMsgCBData;

   
   wpal_list_init(&pWCTSCb->wctsPendingQueue);
   pWCTSCb->wctsMagic   = WCTS_CB_MAGIC;
   pWCTSCb->wctsState   = WCTS_STATE_OPEN_PENDING;
   pWCTSCb->wctsChannel = NULL;

   pWCTSCb->wctsOpenMsg.callback = WCTS_PALOpenCallback;
   pWCTSCb->wctsOpenMsg.pContext = pWCTSCb;
   pWCTSCb->wctsOpenMsg.type= WPAL_MC_MSG_SMD_NOTIF_OPEN_SIG;

   pWCTSCb->wctsDataMsg.callback = WCTS_PALDataCallback;
   pWCTSCb->wctsDataMsg.pContext = pWCTSCb;
   pWCTSCb-> wctsDataMsg.type= WPAL_MC_MSG_SMD_NOTIF_DATA_SIG;


   wpalEventReset(&pWCTSCb->wctsEvent);
   smdstatus = smd_named_open_on_edge(szName,
                                      SMD_APPS_WCNSS,
                                      &pWCTSCb->wctsChannel,
                                      pWCTSCb,
                                      WCTS_NotifyCallback);
   if (0 != smdstatus) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: smd_named_open_on_edge failed with status %d",
                 __func__, smdstatus);
      goto fail;
   }

   
   status = wpalEventWait(&pWCTSCb->wctsEvent, WCTS_SMD_OPEN_TIMEOUT);
   if (eWLAN_PAL_STATUS_SUCCESS != status) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: failed to receive SMD_EVENT_OPEN",
                 __func__);
      
      smdstatus = smd_close(pWCTSCb->wctsChannel);
      if (0 != smdstatus) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "%s: smd_close failed with status %d",
                    __func__, smdstatus);
      }
      goto fail;
   }

   smd_disable_read_intr(pWCTSCb->wctsChannel);

   
   gwctsHandle = pWCTSCb;
   return (WCTS_HandleType)pWCTSCb;

 fail:
   
   pWCTSCb->wctsMagic = 0;
   wpalMemoryFree(pWCTSCb);
   return NULL;

}
wpt_uint32
WCTS_CloseTransport
(
   WCTS_HandleType      wctsHandle
)
{
   WCTS_ControlBlockType* pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   wpt_list_node*      pNode = NULL;
   WCTS_BufferType*    pBufferQueue = NULL;
   void*               pBuffer = NULL;
   wpt_status          status;
   int                 smdstatus;

   

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_CloseTransport: Invalid parameters received.");
      return eWLAN_PAL_STATUS_E_INVAL;
   }

#ifdef FEATURE_R33D
   
   
   pWCTSCb->wctsState = WCTS_STATE_CLOSED;
   pWCTSCb->wctsNotifyCB((WCTS_HandleType)pWCTSCb,
                         WCTS_EVENT_CLOSE,
                         pWCTSCb->wctsNotifyCBData);

   printk(KERN_ERR "R33D Not need to close");
   return eWLAN_PAL_STATUS_SUCCESS;
#endif 

   
   while (eWLAN_PAL_STATUS_SUCCESS ==
          wpal_list_remove_front(&pWCTSCb->wctsPendingQueue, &pNode)) {
      pBufferQueue = container_of(pNode, WCTS_BufferType, node);
      pBuffer = pBufferQueue->pBuffer;
      wpalMemoryFree(pBuffer);
      wpalMemoryFree(pBufferQueue);
   }

   
   pWCTSCb->wctsState = WCTS_STATE_CLOSED;

   wpalEventReset(&pWCTSCb->wctsEvent);
   smdstatus = smd_close(pWCTSCb->wctsChannel);
   if (0 != smdstatus) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: smd_close failed with status %d",
                 __func__, smdstatus);

   } else {
      
      status = wpalEventWait(&pWCTSCb->wctsEvent, WCTS_SMD_CLOSE_TIMEOUT);
      if (eWLAN_PAL_STATUS_SUCCESS != status) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "%s: failed to receive SMD_EVENT_REOPEN_READY",
                    __func__);
      }

      msleep(50);
   }

   
   pWCTSCb->wctsNotifyCB((WCTS_HandleType)pWCTSCb,
                         WCTS_EVENT_CLOSE,
                         pWCTSCb->wctsNotifyCBData);

   
   pWCTSCb->wctsMagic = 0;
   wpalMemoryFree(pWCTSCb);
   gwctsHandle = NULL;

   return eWLAN_PAL_STATUS_SUCCESS;

}
示例#19
0
/**
 @brief    Callback function for serializing WCTS Read
           processing in the control context

 @param    pWCTSCb  WCTS Control Block

 @see
 @return void
*/
static void
WCTS_PALReadCallback
(
   WCTS_ControlBlockType*  pWCTSCb
)
{
   void* buffer;
   int packet_size;
   int available;
   int bytes_read;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   /*--------------------------------------------------------------------
     Sanity check
     --------------------------------------------------------------------*/
   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_PALReadCallback: Invalid parameter received.");
      return;
   }

   /* iterate until no more packets are available */
   while (1) {
      /* check the length of the next packet */
      packet_size = smd_cur_packet_size(pWCTSCb->wctsChannel);
      if (0 == packet_size) {
         /* No more data to be read */
         return;
      }

      /* Check how much of the data is available */
      available = smd_read_avail(pWCTSCb->wctsChannel);
      if (available < packet_size) {
         /* Entire packet not yet ready to be read --
            There will be another notification when it is ready */
         return;
      }

      buffer = wpalMemoryAllocate(packet_size);
      if (NULL ==  buffer) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALReadCallback: Memory allocation failure");
         WPAL_ASSERT(0);
         return;
      }

      bytes_read = smd_read(pWCTSCb->wctsChannel,
                            buffer,
                            packet_size);

      if (bytes_read != packet_size) {
         /*Some problem, do not forward it to WDI.*/
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALReadCallback: Failed to read data from SMD");
         wpalMemoryFree(buffer);
         WPAL_ASSERT(0);
         return;
      }

      /* forward the message to the registered handler */
      pWCTSCb->wctsRxMsgCB((WCTS_HandleType)pWCTSCb,
                           buffer,
                           packet_size,
                           pWCTSCb->wctsRxMsgCBData);

      /* Free the allocated buffer*/
      wpalMemoryFree(buffer);
   }

} /*WCTS_PALReadCallback*/
wpt_uint32
WCTS_SendMessage
(
   WCTS_HandleType      wctsHandle,
   void*                pMsg,
   wpt_uint32           uLen
)
{
   WCTS_ControlBlockType*    pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   WCTS_BufferType*          pBufferQueue;
   int                       len;
   int                       written = 0;
   int                       available;

   

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic) ||
       (NULL == pMsg) || (0 == uLen) || (0x7fffffff < uLen)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Invalid parameters received.");
      WPAL_ASSERT(0);
      if (NULL != pMsg) {
         wpalMemoryFree(pMsg);
      }
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   
   len = (int)uLen;

   if (WCTS_STATE_OPEN == pWCTSCb->wctsState) {
      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available >= len) {
         written = smd_write(pWCTSCb->wctsChannel, pMsg, len);
      }
   } else if (WCTS_STATE_DEFERRED == pWCTSCb->wctsState) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
                 "WCTS_SendMessage: FIFO space not available, the packets will be queued");
   } else {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Channel in illegal state [%d].",
                 pWCTSCb->wctsState);
      
      written = -1;
   }

   if (-1 == written) {
      
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Failed to send message over the bus.");
      wpalMemoryFree(pMsg);
      return eWLAN_PAL_STATUS_E_FAILURE;
   } else if (written == len) {
      
      wpalMemoryFree(pMsg);
   } else {
      /* This much data cannot be written at this time,
         queue the rest of the data for later*/
      pBufferQueue = wpalMemoryAllocate(sizeof(WCTS_BufferType));
      if (NULL == pBufferQueue) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_SendMessage: Cannot allocate memory for queuing the buffer");
         wpalMemoryFree(pMsg);
         WPAL_ASSERT(0);
         return eWLAN_PAL_STATUS_E_NOMEM;
      }

      pBufferQueue->bufferSize = len;
      pBufferQueue->pBuffer = pMsg;
      wpal_list_insert_back(&pWCTSCb->wctsPendingQueue, &pBufferQueue->node);

      if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {

         pWCTSCb->wctsState = WCTS_STATE_DEFERRED;

         smd_enable_read_intr(pWCTSCb->wctsChannel);
      }

      
      return eWLAN_PAL_STATUS_E_RESOURCES;
   }

   return eWLAN_PAL_STATUS_SUCCESS;

}