/* * Create a memory pool which is DMA capabale */ WDI_Status WDI_DS_MemPoolCreate(WDI_DS_BdMemPoolType *memPool, wpt_uint8 chunkSize, wpt_uint8 numChunks) { wpt_uint8 staLoop; //Allocate all the max size and align them to a double word boundary. The first 8 bytes are control bytes. memPool->numChunks = 0; memPool->chunkSize = chunkSize + 16 - (chunkSize%8); memPool->pVirtBaseAddress = wpalDmaMemoryAllocate((numChunks * memPool->chunkSize), &(memPool->pPhysBaseAddress)); if( memPool->pVirtBaseAddress == 0) return WDI_STATUS_E_FAILURE; memPool->AllocationBitmap = (wpt_uint32*)wpalMemoryAllocate( (numChunks/32 + 1) * sizeof(wpt_uint32)); if( NULL == memPool->AllocationBitmap) return WDI_STATUS_E_FAILURE; wpalMemoryZero(memPool->AllocationBitmap, (numChunks/32+1)*sizeof(wpt_uint32)); //Initialize resource infor per STA for(staLoop = 0; staLoop < WDI_DS_MAX_STA_ID; staLoop++) { memPool->numChunkSTA[staLoop].STAIndex = 0xFF; memPool->numChunkSTA[staLoop].numChunkReservedBySTA = 0; memPool->numChunkSTA[staLoop].validIdx = 0; } return WDI_STATUS_SUCCESS; }
/** @brief WDI_STATableInit - Initializes the STA tables. Allocates the necesary memory. @param pWDICtx: pointer to the WLAN DAL context @see @return Result of the function call */ WDI_Status WDI_STATableInit ( WDI_ControlBlockType* pWDICtx ) { wpt_uint8 ucMaxStations; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ ucMaxStations = (wpt_uint8) pWDICtx->ucMaxStations; /*---------------------------------------------------------------------- Allocate the memory for sta table ------------------------------------------------------------------------*/ pWDICtx->staTable = wpalMemoryAllocate(ucMaxStations * sizeof(WDI_StaStruct)); if (NULL == pWDICtx->staTable) { WDI_STATableClose(pWDICtx); WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, "Error allocating memory on WDI_STATableInit"); return WDI_STATUS_E_FAILURE; } wpalMemoryZero( pWDICtx->staTable, ucMaxStations * sizeof( WDI_StaStruct )); #ifndef HAL_SELF_STA_PER_BSS // Initialize the Self STAID to an invalid value pWDICtx->ucSelfStaId = WDI_STA_INVALID_IDX; #endif return WDI_STATUS_SUCCESS; }/*WDI_STATableInit*/
/** @brief WDI_STATableDelSta - Function to Delete a Station @param pWDICtx: pointer to the WLAN DAL context ucSTAIdx: station to be deleted @see @return Result of the function call */ WDI_Status WDI_STATableDelSta ( WDI_ControlBlockType* pWDICtx, wpt_uint8 ucSTAIdx ) { WDI_StaStruct* pSTATable = (WDI_StaStruct*) pWDICtx->staTable; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /*----------------------------------------------------------------------- Sanity check - station ids are allocated by the HAL located on RIVA SS - they must always be valid -----------------------------------------------------------------------*/ if(( ucSTAIdx == WDI_STA_INVALID_IDX )|| ( ucSTAIdx >= pWDICtx->ucMaxStations )) { WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, "STA Id invalid on Del STA - internal failure"); WDI_ASSERT(0); return WDI_STATUS_E_FAILURE; } wpalMemoryZero(&pSTATable[ucSTAIdx], sizeof(pSTATable[ucSTAIdx])); pSTATable->valid = 0; return WDI_STATUS_SUCCESS; }/*WDI_STATableDelSta*/
/* * 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)); }
WDI_Status WDI_DS_MemPoolCreate(WDI_DS_BdMemPoolType *memPool, wpt_uint8 chunkSize, wpt_uint8 numChunks) { wpt_uint8 staLoop; memPool->numChunks = 0; memPool->chunkSize = chunkSize + 16 - (chunkSize%8); memPool->pVirtBaseAddress = wpalDmaMemoryAllocate((numChunks * memPool->chunkSize), &(memPool->pPhysBaseAddress)); if( memPool->pVirtBaseAddress == 0) return WDI_STATUS_E_FAILURE; memPool->AllocationBitmap = (wpt_uint32*)wpalMemoryAllocate( (numChunks/32 + 1) * sizeof(wpt_uint32)); if( NULL == memPool->AllocationBitmap) return WDI_STATUS_E_FAILURE; wpalMemoryZero(memPool->AllocationBitmap, (numChunks/32+1)*sizeof(wpt_uint32)); for(staLoop = 0; staLoop < WDI_DS_MAX_STA_ID; staLoop++) { memPool->numChunkSTA[staLoop].STAIndex = 0xFF; memPool->numChunkSTA[staLoop].numChunkReservedBySTA = 0; memPool->numChunkSTA[staLoop].validIdx = 0; } return WDI_STATUS_SUCCESS; }
/* 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_Stop(void *pContext) { void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); wpt_status status = eWLAN_PAL_STATUS_SUCCESS; status = gTransportDriver.stop(pDTDriverContext); wpalMemoryZero(&gDsTrafficStats, sizeof(gDsTrafficStats)); return status; }
/* DTS open function. * On open the transport device should initialize itself. * 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_openTransport( void *pContext) { void *pDTDriverContext; WDI_DS_ClientDataType *pClientData; WDI_Status sWdiStatus = WDI_STATUS_SUCCESS; WDTS_ClientCallbacks WDTSCb; pClientData = (WDI_DS_ClientDataType*) wpalMemoryAllocate(sizeof(WDI_DS_ClientDataType)); if (!pClientData){ return eWLAN_PAL_STATUS_E_NOMEM; } pClientData->suspend = 0; WDI_DS_AssignDatapathContext(pContext, (void*)pClientData); pDTDriverContext = gTransportDriver.open(); if( NULL == pDTDriverContext ) { DTI_TRACE( DTI_TRACE_LEVEL_ERROR, " %s fail from transport open", __func__); return eWLAN_PAL_STATUS_E_FAILURE; } WDT_AssignTransportDriverContext(pContext, pDTDriverContext); WDTSCb.rxFrameReadyCB = WDTS_RxPacket; WDTSCb.txCompleteCB = WDTS_TxPacketComplete; WDTSCb.lowResourceCB = WDTS_OOResourceNotification; WDTSCb.receiveMbMsgCB = WDTS_MbReceiveMsg; WDTSCb.receiveLogCompleteCB = WDTS_LogRxDone; gTransportDriver.register_client(pDTDriverContext, WDTSCb, (void*)pClientData); /* Create a memory pool for Mgmt BDheaders.*/ sWdiStatus = WDI_DS_MemPoolCreate(&pClientData->mgmtMemPool, WDI_DS_MAX_CHUNK_SIZE, WDI_DS_HI_PRI_RES_NUM); if (WDI_STATUS_SUCCESS != sWdiStatus){ return eWLAN_PAL_STATUS_E_NOMEM; } /* Create a memory pool for Data BDheaders.*/ sWdiStatus = WDI_DS_MemPoolCreate(&pClientData->dataMemPool, WDI_DS_MAX_CHUNK_SIZE, WDI_DS_LO_PRI_RES_NUM); if (WDI_STATUS_SUCCESS != sWdiStatus){ return eWLAN_PAL_STATUS_E_NOMEM; } wpalMemoryZero(&gDsTrafficStats, sizeof(gDsTrafficStats)); WDI_DS_LoggingMbCreate(&pClientData->loggingMbContext, sizeof(tLoggingMailBox)); if (WDI_STATUS_SUCCESS != sWdiStatus) return eWLAN_PAL_STATUS_E_NOMEM; return eWLAN_PAL_STATUS_SUCCESS; }
void WDTS_MbReceiveMsg(void *pContext) { tpLoggingMailBox pLoggingMb; WDI_DS_LoggingSessionType *pLoggingSession; wpt_int8 i, noMem = 0; wpt_uint32 totalLen = 0; pLoggingMb = (tpLoggingMailBox)WDI_DS_GetLoggingMbAddr(pContext); pLoggingSession = (WDI_DS_LoggingSessionType *) WDI_DS_GetLoggingSession(pContext); for(i = 0; i < MAX_NUM_OF_BUFFER; i++) { pLoggingSession->logBuffAddress[i] = pLoggingMb->logBuffAddress[i]; if (!noMem && (pLoggingMb->logBuffLength[i] <= MAX_LOG_BUFFER_LENGTH)) { pLoggingSession->logBuffLength[i] = gTransportDriver.setupLogTransfer( pLoggingMb->logBuffAddress[i], pLoggingMb->logBuffLength[i]); } else { pLoggingSession->logBuffLength[i] = 0; continue; } totalLen += pLoggingSession->logBuffLength[i]; if (pLoggingSession->logBuffLength[i] < pLoggingMb->logBuffLength[i]) { noMem = 1; } } pLoggingSession->done = pLoggingMb->done; pLoggingSession->logType = pLoggingMb->logType; // Done using Mailbox, zero out the memory. wpalMemoryZero(pLoggingMb, sizeof(tLoggingMailBox)); if (totalLen) { if (gTransportDriver.startLogTransfer() == eWLAN_PAL_STATUS_SUCCESS) return; } // Send Done event to upper layers, since we wont be getting any from DXE }
/* Tx/Rx stats function * This function should be invoked to fetch the current stats * Parameters: * pStats:Pointer to the collected stats * len: length of buffer pointed to by pStats * Return Status: None */ void WDTS_GetTrafficStats(WDI_TrafficStatsType** pStats, wpt_uint32 *len) { if(gDsTrafficStats.running) { uint8 staIdx, rate; WDI_TrafficStatsType *pNetTxRxStats = gDsTrafficStats.netTxRxStats; wpalMemoryZero(pNetTxRxStats, sizeof(gDsTrafficStats.netTxRxStats)); for(staIdx = 0; staIdx < HAL_NUM_STA; staIdx++, pNetTxRxStats++) { pNetTxRxStats->txBytesPushed += gDsTrafficStats.txStats[staIdx].txBytesPushed; pNetTxRxStats->txPacketsPushed+= gDsTrafficStats.txStats[staIdx].txPacketsPushed; for(rate = 0; rate < WDTS_MAX_11B_RATE_NUM; rate++) { pNetTxRxStats->rxBytesRcvd += gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd; pNetTxRxStats->rxPacketsRcvd += gDsTrafficStats.rxStats[staIdx][rate].rxPacketsRcvd; pNetTxRxStats->rxTimeTotal += gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd*DTS_11BRATE_TPUT_MULTIPLIER(rate); } for(rate = WDTS_MAX_11B_RATE_NUM; rate < WDTS_MAX_RATE_NUM; rate++) { pNetTxRxStats->rxBytesRcvd += gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd; pNetTxRxStats->rxPacketsRcvd += gDsTrafficStats.rxStats[staIdx][rate].rxPacketsRcvd; pNetTxRxStats->rxTimeTotal += gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd/DTS_RATE_TPUT(rate); } pNetTxRxStats->rxTimeTotal = pNetTxRxStats->rxTimeTotal/1000; } *pStats = gDsTrafficStats.netTxRxStats; *len = sizeof(gDsTrafficStats.netTxRxStats); } else { *pStats = NULL; *len = 0; } }
/** @brief WDI_STATableStop - clears the sta table @param pWDICtx: pointer to the WLAN DAL context @see @return Result of the function call */ WDI_Status WDI_STATableStop ( WDI_ControlBlockType* pWDICtx ) { wpt_uint8 ucMaxStations; /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ #ifndef HAL_SELF_STA_PER_BSS /* Clean up the Self STAID */ pWDICtx->ucSelfStaId = WDI_STA_INVALID_IDX; #endif ucMaxStations = pWDICtx->ucMaxStations; wpalMemoryZero( (void *) pWDICtx->staTable, ucMaxStations * sizeof( WDI_StaStruct )); return WDI_STATUS_SUCCESS; }/*WDI_STATableStop*/
WDI_Status WDI_STATableDelSta ( WDI_ControlBlockType* pWDICtx, wpt_uint8 ucSTAIdx ) { WDI_StaStruct* pSTATable = (WDI_StaStruct*) pWDICtx->staTable; if(( ucSTAIdx == WDI_STA_INVALID_IDX )|| ( ucSTAIdx >= pWDICtx->ucMaxStations )) { WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, "STA Id invalid on Del STA - internal failure"); WDI_ASSERT(0); return WDI_STATUS_E_FAILURE; } wpalMemoryZero(&pSTATable[ucSTAIdx], sizeof(pSTATable[ucSTAIdx])); pSTATable->valid = 0; return WDI_STATUS_SUCCESS; }
/** @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*/ wpalMemoryZero(buffer, bytes_read); wpalMemoryFree(buffer); } } /*WCTS_PALReadCallback*/
/* WDTS_ClearTrafficStats * This function should be invoked to clear traffic stats * Parameters: None * Return Status: None */ void WDTS_ClearTrafficStats(void) { wpalMemoryZero(gDsTrafficStats.rxStats, sizeof(gDsTrafficStats.rxStats)); wpalMemoryZero(gDsTrafficStats.txStats, sizeof(gDsTrafficStats.txStats)); }
/** @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*/
/** @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 */ wpalMemoryZero(pBuffer, len); 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*/
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; }
/** @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); return eWLAN_PAL_STATUS_E_FAILURE; } else if (written == len) { /* Message sent! No deferred state, free the buffer*/ wpalMemoryZero(pMsg, 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; if (eWLAN_PAL_STATUS_E_FAILURE == wpal_list_insert_back(&pWCTSCb->wctsPendingQueue, &pBufferQueue->node)) { WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR, "pBufferQueue wpal_list_insert_back failed"); wpalMemoryFree(pMsg); wpalMemoryFree(pBufferQueue); WPAL_ASSERT(0); return eWLAN_PAL_STATUS_E_NOMEM; } /* 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 */ vos_spin_lock_acquire(&pWCTSCb->wctsStateLock); if ((WCTS_STATE_DEFERRED != pWCTSCb->wctsState) && (WCTS_STATE_REM_CLOSED != pWCTSCb->wctsState)) { /* Mark the state as deferred.*/ pWCTSCb->wctsState = WCTS_STATE_DEFERRED; smd_enable_read_intr(pWCTSCb->wctsChannel); } vos_spin_lock_release(&pWCTSCb->wctsStateLock); /*indicate to client that message was placed in deferred queue*/ return eWLAN_PAL_STATUS_E_RESOURCES; } return eWLAN_PAL_STATUS_SUCCESS; }/*WCTS_SendMessage*/