/**
 *  @brief This function frees the structure of adapter
 *
 *  @param pmadapter      A pointer to mlan_adapter structure
 *
 *  @return             N/A
 */
t_void
wlan_free_adapter(pmlan_adapter pmadapter)
{
    mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;

    ENTER();

    if (!pmadapter) {
        PRINTM(MERROR, "The adapter is NULL\n");
        LEAVE();
        return;
    }

    wlan_cancel_all_pending_cmd(pmadapter);
    /* Free command buffer */
    PRINTM(MINFO, "Free Command buffer\n");
    wlan_free_cmd_buffer(pmadapter);

    if (pmadapter->cmd_timer_is_set) {
        /* Cancel command timeout timer */
        pcb->moal_stop_timer(pmadapter->pmoal_handle,
                             pmadapter->pmlan_cmd_timer);
        pmadapter->cmd_timer_is_set = MFALSE;
    }
#ifdef STA_SUPPORT
    PRINTM(MINFO, "Free ScanTable\n");
    if (pmadapter->pscan_table) {
        pcb->moal_mfree(pmadapter->pmoal_handle,
                        (t_u8 *) pmadapter->pscan_table);
        pmadapter->pscan_table = MNULL;
    }
    if (pmadapter->bcn_buf) {
        pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter->bcn_buf);
        pmadapter->bcn_buf = MNULL;
    }
#endif

    wlan_11h_cleanup(pmadapter);

    if (pmadapter->mp_regs_buf) {
        pcb->moal_mfree(pmadapter->pmoal_handle,
                        (t_u8 *) pmadapter->mp_regs_buf);
        pmadapter->mp_regs_buf = MNULL;
        pmadapter->mp_regs = MNULL;
    }
#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
    wlan_free_sdio_mpa_buffers(pmadapter);
#endif
    wlan_free_mlan_buffer(pmadapter, pmadapter->psleep_cfm);
    pmadapter->psleep_cfm = MNULL;

    LEAVE();
    return;
}
/** 
 *  @brief This function frees the structure of adapter
 *    
 *  @param pmadapter      A pointer to mlan_adapter structure
 *
 *  @return             N/A
 */
t_void
wlan_free_adapter(pmlan_adapter pmadapter)
{
    mlan_callbacks *pcb = (mlan_callbacks *) & pmadapter->callbacks;

    ENTER();

    if (!pmadapter) {
        PRINTM(MERROR, "The adapter is MNULL.\n");
        LEAVE();
        return;
    }

    wlan_cancel_all_pending_cmd(pmadapter);
    /* Free command buffer */
    PRINTM(MINFO, "Free Command buffer\n");
    wlan_free_cmd_buffer(pmadapter);

    util_free_list_head(&pmadapter->cmd_free_q,
                        pmadapter->callbacks.moal_free_lock);

    util_free_list_head(&pmadapter->cmd_pending_q,
                        pmadapter->callbacks.moal_free_lock);

    util_free_list_head(&pmadapter->scan_pending_q,
                        pmadapter->callbacks.moal_free_lock);

    if (pmadapter->cmd_timer_is_set) {
        /* Cancel command timeout timer */
        pcb->moal_stop_timer(pmadapter->pmlan_cmd_timer);
        pmadapter->cmd_timer_is_set = MFALSE;
    }

    PRINTM(MINFO, "Free ScanTable\n");
    if (pmadapter->pscan_table) {
        pcb->moal_mfree((t_u8 *) pmadapter->pscan_table);
        pmadapter->pscan_table = MNULL;
    }

    if (pmadapter->mp_regs_buf) {
        pcb->moal_mfree((t_u8 *) pmadapter->mp_regs_buf);
        pmadapter->mp_regs_buf = MNULL;
        pmadapter->mp_regs = MNULL;
    }
#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
    wlan_free_sdio_mpa_buffers(pmadapter);
#endif
    wlan_free_mlan_buffer(&pmadapter->callbacks, pmadapter->psleep_cfm);
    LEAVE();
    return;
}
/**
 *  @brief This function allocates buffer for the SDIO aggregation buffer
 *  		related members of adapter structure
 *
 *  @param pmadapter       A pointer to mlan_adapter structure
 *  @param mpa_tx_buf_size Tx buffer size to allocate
 *  @param mpa_rx_buf_size Rx buffer size to allocate
 *
 *  @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
 */
mlan_status
wlan_alloc_sdio_mpa_buffers(IN mlan_adapter * pmadapter,
			    t_u32 mpa_tx_buf_size, t_u32 mpa_rx_buf_size)
{
	mlan_status ret = MLAN_STATUS_SUCCESS;
	pmlan_callbacks pcb = &pmadapter->callbacks;

	ENTER();

#ifdef SDIO_MULTI_PORT_TX_AGGR
	ret = pcb->moal_malloc(pmadapter->pmoal_handle,
			       mpa_tx_buf_size + DMA_ALIGNMENT,
			       MLAN_MEM_DEF | MLAN_MEM_DMA,
			       (t_u8 **) & pmadapter->mpa_tx.head_ptr);
	if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_tx.head_ptr) {
		PRINTM(MERROR,
		       "Could not allocate buffer for SDIO MP TX aggr\n");
		ret = MLAN_STATUS_FAILURE;
		goto error;
	}
	pmadapter->mpa_tx.buf =
		(t_u8 *) ALIGN_ADDR(pmadapter->mpa_tx.head_ptr, DMA_ALIGNMENT);
	pmadapter->mpa_tx.buf_size = mpa_tx_buf_size;
#endif /* SDIO_MULTI_PORT_TX_AGGR */

#ifdef SDIO_MULTI_PORT_RX_AGGR
	ret = pcb->moal_malloc(pmadapter->pmoal_handle,
			       mpa_rx_buf_size + DMA_ALIGNMENT,
			       MLAN_MEM_DEF | MLAN_MEM_DMA,
			       (t_u8 **) & pmadapter->mpa_rx.head_ptr);
	if (ret != MLAN_STATUS_SUCCESS || !pmadapter->mpa_rx.head_ptr) {
		PRINTM(MERROR,
		       "Could not allocate buffer for SDIO MP RX aggr\n");
		ret = MLAN_STATUS_FAILURE;
		goto error;
	}
	pmadapter->mpa_rx.buf =
		(t_u8 *) ALIGN_ADDR(pmadapter->mpa_rx.head_ptr, DMA_ALIGNMENT);
	pmadapter->mpa_rx.buf_size = mpa_rx_buf_size;
#endif /* SDIO_MULTI_PORT_RX_AGGR */
error:
	if (ret != MLAN_STATUS_SUCCESS) {
		wlan_free_sdio_mpa_buffers(pmadapter);
	}

	LEAVE();
	return ret;
}