/** @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); }
/** @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*/
/** @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*/
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; }