diff options
Diffstat (limited to 'drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c')
-rw-r--r-- | drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c | 1700 |
1 files changed, 1700 insertions, 0 deletions
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c new file mode 100644 index 000000000000..c5fc7f5085c7 --- /dev/null +++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlan/mlan_shim.c @@ -0,0 +1,1700 @@ +/** @file mlan_shim.c + * + * @brief This file contains APIs to MOAL module. + * + * + * Copyright 2014-2020 NXP + * + * This software file (the File) is distributed by NXP + * under the terms of the GNU General Public License Version 2, June 1991 + * (the License). You may use, redistribute and/or modify the File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/13/2008: initial version +********************************************************/ + +#include "mlan.h" +#ifdef STA_SUPPORT +#include "mlan_join.h" +#endif +#include "mlan_util.h" +#include "mlan_fw.h" +#include "mlan_main.h" +#include "mlan_wmm.h" +#ifdef SDIO +#include "mlan_sdio.h" +#endif /* SDIO */ +#ifdef PCIE +#include "mlan_pcie.h" +#endif /* PCIE */ +#ifdef UAP_SUPPORT +#include "mlan_uap.h" +#endif +#include "mlan_11h.h" +#include "mlan_11n_rxreorder.h" +#ifdef DRV_EMBEDDED_AUTHENTICATOR +#include "authenticator_api.h" +#endif + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ +#ifdef STA_SUPPORT +mlan_operations mlan_sta_ops = { + /* init cmd handler */ + wlan_ops_sta_init_cmd, + /* ioctl handler */ + wlan_ops_sta_ioctl, + /* cmd handler */ + wlan_ops_sta_prepare_cmd, + /* cmdresp handler */ + wlan_ops_sta_process_cmdresp, + /* rx handler */ + wlan_ops_sta_process_rx_packet, + /* Event handler */ + wlan_ops_sta_process_event, + /* txpd handler */ + wlan_ops_sta_process_txpd, + /* BSS role: STA */ + MLAN_BSS_ROLE_STA, +}; +#endif +#ifdef UAP_SUPPORT +mlan_operations mlan_uap_ops = { + /* init cmd handler */ + wlan_ops_uap_init_cmd, + /* ioctl handler */ + wlan_ops_uap_ioctl, + /* cmd handler */ + wlan_ops_uap_prepare_cmd, + /* cmdresp handler */ + wlan_ops_uap_process_cmdresp, + /* rx handler */ + wlan_ops_uap_process_rx_packet, + /* Event handler */ + wlan_ops_uap_process_event, + /* txpd handler */ + wlan_ops_uap_process_txpd, + /* BSS role: uAP */ + MLAN_BSS_ROLE_UAP, +}; +#endif + +/** mlan function table */ +mlan_operations *mlan_ops[] = { +#ifdef STA_SUPPORT + &mlan_sta_ops, +#endif +#ifdef UAP_SUPPORT + &mlan_uap_ops, +#endif + MNULL, +}; + +/** Global moal_assert callback */ +t_void (*assert_callback)(t_pvoid pmoal_handle, t_u32 cond) = MNULL; +#ifdef DEBUG_LEVEL1 +#ifdef DEBUG_LEVEL2 +#define DEFAULT_DEBUG_MASK (0xffffffff) +#else +#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR) +#endif + +/** Global moal_print callback */ +t_void (*print_callback)(t_pvoid pmoal_handle, t_u32 level, char *pformat, + IN...) = MNULL; + +/** Global moal_get_system_time callback */ +mlan_status (*get_sys_time_callback)(t_pvoid pmoal_handle, t_pu32 psec, + t_pu32 pusec) = MNULL; + +/** Global driver debug mit masks */ +t_u32 mlan_drvdbg = DEFAULT_DEBUG_MASK; +#endif + +#ifdef USB +extern mlan_status wlan_get_usb_device(pmlan_adapter pmadapter); +#endif +/******************************************************** + Local Functions +*******************************************************/ +/** + * @brief This function process pending ioctl + * + * @param pmadapter A pointer to mlan_adapter structure + * + */ +void wlan_process_pending_ioctl(mlan_adapter *pmadapter) +{ + pmlan_ioctl_req pioctl_buf; + mlan_status status = MLAN_STATUS_SUCCESS; + pmlan_callbacks pcb; +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + pmlan_ds_bss bss = MNULL; +#endif +#ifdef STA_SUPPORT + pmlan_ds_misc_cfg misc = MNULL; +#endif + ENTER(); + + pcb = &pmadapter->callbacks; + + while ((pioctl_buf = (pmlan_ioctl_req)util_dequeue_list( + pmadapter->pmoal_handle, &pmadapter->ioctl_pending_q, + pcb->moal_spin_lock, pcb->moal_spin_unlock))) { + switch (pioctl_buf->req_id) { +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + case MLAN_IOCTL_BSS: + bss = (mlan_ds_bss *)pioctl_buf->pbuf; + if (bss->sub_command == MLAN_OID_BSS_ROLE) { + PRINTM(MCMND, "Role switch ioctl: %d\n", + bss->param.bss_role); + status = wlan_bss_ioctl_bss_role(pmadapter, + pioctl_buf); + } + break; +#endif +#ifdef STA_SUPPORT + case MLAN_IOCTL_MISC_CFG: + misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; + if (misc->sub_command == MLAN_OID_MISC_WARM_RESET) { + PRINTM(MCMND, "Warm Reset ioctl\n"); + status = wlan_misc_ioctl_warm_reset(pmadapter, + pioctl_buf); + } + break; +#endif + default: + break; + } + if (status != MLAN_STATUS_PENDING) + pcb->moal_ioctl_complete(pmadapter->pmoal_handle, + pioctl_buf, status); + } + LEAVE(); +} +/******************************************************** + Global Functions +********************************************************/ +#ifdef USB +extern mlan_adapter_operations mlan_usb_ops; +#endif +#ifdef PCIE +extern mlan_adapter_operations mlan_pcie_ops; +#endif +#ifdef SDIO +extern mlan_adapter_operations mlan_sdio_ops; +#endif + +/** + * @brief This function registers MOAL to MLAN module. + * + * @param pmdevice A pointer to a mlan_device structure + * allocated in MOAL + * @param ppmlan_adapter A pointer to a t_void pointer to store + * mlan_adapter structure pointer as the context + * + * @return MLAN_STATUS_SUCCESS + * The registration succeeded. + * MLAN_STATUS_FAILURE + * The registration failed. + * + * mlan_status mlan_register( + * pmlan_device pmdevice, + * t_void **ppmlan_adapter + * ); + * + * Comments + * MOAL constructs mlan_device data structure to pass moal_handle and + * mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to + * the ppmlan_adapter buffer provided by MOAL. + * Headers: + * declared in mlan_decl.h + * See Also + * mlan_unregister + */ +mlan_status mlan_register(pmlan_device pmdevice, t_void **ppmlan_adapter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + pmlan_adapter pmadapter = MNULL; + pmlan_callbacks pcb = MNULL; + t_u8 i = 0; + t_u32 j = 0; + + if (!pmdevice || !ppmlan_adapter) { + return MLAN_STATUS_FAILURE; + } + MASSERT(ppmlan_adapter); + MASSERT(pmdevice->callbacks.moal_print); +#ifdef DEBUG_LEVEL1 + print_callback = pmdevice->callbacks.moal_print; + get_sys_time_callback = pmdevice->callbacks.moal_get_system_time; +#endif + assert_callback = pmdevice->callbacks.moal_assert; + + ENTER(); + + MASSERT(pmdevice->callbacks.moal_malloc); + MASSERT(pmdevice->callbacks.moal_mfree); + MASSERT(pmdevice->callbacks.moal_memset); + MASSERT(pmdevice->callbacks.moal_memmove); + MASSERT(pmdevice->callbacks.moal_udelay); + MASSERT(pmdevice->callbacks.moal_usleep_range); + + if (!pmdevice->callbacks.moal_malloc || + !pmdevice->callbacks.moal_mfree || + !pmdevice->callbacks.moal_memset || + !pmdevice->callbacks.moal_udelay || + !pmdevice->callbacks.moal_usleep_range || + !pmdevice->callbacks.moal_memmove) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* Allocate memory for adapter structure */ + if (pmdevice->callbacks.moal_vmalloc && pmdevice->callbacks.moal_vfree) + ret = pmdevice->callbacks.moal_vmalloc(pmdevice->pmoal_handle, + sizeof(mlan_adapter), + (t_u8 **)&pmadapter); + else + ret = pmdevice->callbacks.moal_malloc(pmdevice->pmoal_handle, + sizeof(mlan_adapter), + MLAN_MEM_DEF, + (t_u8 **)&pmadapter); + if ((ret != MLAN_STATUS_SUCCESS) || !pmadapter) { + ret = MLAN_STATUS_FAILURE; + goto exit_register; + } + + pmdevice->callbacks.moal_memset(pmdevice->pmoal_handle, pmadapter, 0, + sizeof(mlan_adapter)); + + pcb = &pmadapter->callbacks; + + /* Save callback functions */ + pmdevice->callbacks.moal_memmove(pmadapter->pmoal_handle, pcb, + &pmdevice->callbacks, + sizeof(mlan_callbacks)); + + /* Assertion for all callback functions */ + MASSERT(pcb->moal_get_hw_spec_complete); + MASSERT(pcb->moal_init_fw_complete); + MASSERT(pcb->moal_shutdown_fw_complete); + MASSERT(pcb->moal_send_packet_complete); + MASSERT(pcb->moal_recv_packet); + MASSERT(pcb->moal_recv_event); + MASSERT(pcb->moal_ioctl_complete); + +#if defined(SDIO) || defined(PCIE) + if (!IS_USB(pmadapter->card_type)) { + MASSERT(pcb->moal_write_reg); + MASSERT(pcb->moal_read_reg); + MASSERT(pcb->moal_alloc_mlan_buffer); + MASSERT(pcb->moal_free_mlan_buffer); + } +#endif + MASSERT(pcb->moal_get_vdll_data); + MASSERT(pcb->moal_write_data_sync); + MASSERT(pcb->moal_read_data_sync); + MASSERT(pcb->moal_mfree); + MASSERT(pcb->moal_memcpy); + MASSERT(pcb->moal_memcpy_ext); + MASSERT(pcb->moal_memcmp); + MASSERT(pcb->moal_get_system_time); + MASSERT(pcb->moal_init_timer); + MASSERT(pcb->moal_free_timer); + MASSERT(pcb->moal_get_boot_ktime); + MASSERT(pcb->moal_start_timer); + MASSERT(pcb->moal_stop_timer); + MASSERT(pcb->moal_init_lock); + MASSERT(pcb->moal_free_lock); + MASSERT(pcb->moal_spin_lock); + MASSERT(pcb->moal_spin_unlock); + MASSERT(pcb->moal_hist_data_add); + /* Save pmoal_handle */ + pmadapter->pmoal_handle = pmdevice->pmoal_handle; + + pmadapter->feature_control = pmdevice->feature_control; + + pmadapter->card_type = pmdevice->card_type; + pmadapter->card_rev = pmdevice->card_rev; + pmadapter->init_para.uap_max_sta = pmdevice->uap_max_sta; + +#ifdef SDIO + if (IS_SD(pmadapter->card_type)) { + PRINTM(MMSG, + "Attach mlan adapter operations.card_type is 0x%x.\n", + pmdevice->card_type); + memcpy_ext(pmadapter, &pmadapter->ops, &mlan_sdio_ops, + sizeof(mlan_adapter_operations), + sizeof(mlan_adapter_operations)); + ret = wlan_get_sdio_device(pmadapter); + if (MLAN_STATUS_SUCCESS != ret) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + if ((pmdevice->int_mode == INT_MODE_GPIO) && + (pmdevice->gpio_pin == 0)) { + PRINTM(MERROR, + "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n"); + ret = MLAN_STATUS_FAILURE; + goto error; + } + pmadapter->init_para.int_mode = pmdevice->int_mode; + pmadapter->init_para.gpio_pin = pmdevice->gpio_pin; + /* card specific probing has been deferred until now .. */ + ret = wlan_sdio_probe(pmadapter); + if (MLAN_STATUS_SUCCESS != ret) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + pmadapter->pcard_sd->max_segs = pmdevice->max_segs; + pmadapter->pcard_sd->max_seg_size = pmdevice->max_seg_size; + + pmadapter->init_para.mpa_tx_cfg = pmdevice->mpa_tx_cfg; + pmadapter->init_para.mpa_rx_cfg = pmdevice->mpa_rx_cfg; + pmadapter->pcard_sd->sdio_rx_aggr_enable = + pmdevice->sdio_rx_aggr_enable; + } +#endif + +#ifdef PCIE + if (IS_PCIE(pmadapter->card_type)) { + MASSERT(pcb->moal_malloc_consistent); + MASSERT(pcb->moal_mfree_consistent); + MASSERT(pcb->moal_map_memory); + MASSERT(pcb->moal_unmap_memory); + PRINTM(MMSG, + "Attach mlan adapter operations.card_type is 0x%x.\n", + pmdevice->card_type); + memcpy_ext(pmadapter, &pmadapter->ops, &mlan_pcie_ops, + sizeof(mlan_adapter_operations), + sizeof(mlan_adapter_operations)); + ret = wlan_get_pcie_device(pmadapter); + if (MLAN_STATUS_SUCCESS != ret) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + } +#endif + +#ifdef USB + if (IS_USB(pmadapter->card_type)) { + MASSERT(pcb->moal_write_data_async); + MASSERT(pcb->moal_recv_complete); + PRINTM(MMSG, + "Attach mlan adapter operations.card_type is 0x%x.\n", + pmdevice->card_type); + memcpy_ext(pmadapter, &pmadapter->ops, &mlan_usb_ops, + sizeof(mlan_adapter_operations), + sizeof(mlan_adapter_operations)); + ret = wlan_get_usb_device(pmadapter); + if (MLAN_STATUS_SUCCESS != ret) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + } +#endif + +#ifdef DEBUG_LEVEL1 + mlan_drvdbg = pmdevice->drvdbg; +#endif + +#ifdef MFG_CMD_SUPPORT + pmadapter->init_para.mfg_mode = pmdevice->mfg_mode; +#endif + pmadapter->init_para.auto_ds = pmdevice->auto_ds; + pmadapter->init_para.ps_mode = pmdevice->ps_mode; + if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K || + pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K || + pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_12K || + pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_8K) + pmadapter->init_para.max_tx_buf = pmdevice->max_tx_buf; +#ifdef STA_SUPPORT + pmadapter->init_para.cfg_11d = pmdevice->cfg_11d; +#else + pmadapter->init_para.cfg_11d = 0; +#endif + if (IS_DFS_SUPPORT(pmadapter->feature_control)) + pmadapter->init_para.dfs_master_radar_det_en = + DFS_MASTER_RADAR_DETECT_EN; + pmadapter->init_para.dfs_slave_radar_det_en = DFS_SLAVE_RADAR_DETECT_EN; + pmadapter->init_para.dev_cap_mask = pmdevice->dev_cap_mask; + pmadapter->init_para.indrstcfg = pmdevice->indrstcfg; + pmadapter->rx_work_flag = pmdevice->rx_work; + pmadapter->init_para.passive_to_active_scan = + pmdevice->passive_to_active_scan; + pmadapter->fixed_beacon_buffer = pmdevice->fixed_beacon_buffer; + + pmadapter->multiple_dtim = pmdevice->multi_dtim; + pmadapter->inact_tmo = pmdevice->inact_tmo; + pmadapter->init_para.fw_region = pmdevice->fw_region; + pmadapter->hs_wake_interval = pmdevice->hs_wake_interval; + if (pmdevice->indication_gpio != 0xff) { + pmadapter->ind_gpio = pmdevice->indication_gpio & 0x0f; + pmadapter->level = (pmdevice->indication_gpio & 0xf0) >> 4; + if (pmadapter->level != 0 && pmadapter->level != 1) { + PRINTM(MERROR, + "Indication GPIO level is wrong and will use default value 0.\n"); + pmadapter->level = 0; + } + } + pmadapter->hs_mimo_switch = pmdevice->hs_mimo_switch; +#ifdef USB + if (IS_USB(pmadapter->card_type)) { + pmadapter->tx_cmd_ep = pmdevice->tx_cmd_ep; + pmadapter->rx_cmd_ep = pmdevice->rx_cmd_ep; + pmadapter->tx_data_ep = pmdevice->tx_data_ep; + pmadapter->rx_data_ep = pmdevice->rx_data_ep; + } +#endif + pmadapter->init_para.dfs53cfg = pmdevice->dfs53cfg; + pmadapter->priv_num = 0; + pmadapter->priv[0] = MNULL; + + if (pcb->moal_vmalloc && pcb->moal_vfree) + ret = pcb->moal_vmalloc(pmadapter->pmoal_handle, + sizeof(mlan_private), + (t_u8 **)&pmadapter->priv[0]); + else + ret = pcb->moal_malloc(pmadapter->pmoal_handle, + sizeof(mlan_private), MLAN_MEM_DEF, + (t_u8 **)&pmadapter->priv[0]); + if (ret != MLAN_STATUS_SUCCESS || !pmadapter->priv[0]) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + + pmadapter->priv_num++; + memset(pmadapter, pmadapter->priv[0], 0, sizeof(mlan_private)); + + pmadapter->priv[0]->adapter = pmadapter; + pmadapter->priv[0]->bss_type = (t_u8)pmdevice->bss_attr[0].bss_type; + pmadapter->priv[0]->frame_type = (t_u8)pmdevice->bss_attr[0].frame_type; + pmadapter->priv[0]->bss_priority = + (t_u8)pmdevice->bss_attr[0].bss_priority; + if (pmdevice->bss_attr[0].bss_type == MLAN_BSS_TYPE_STA) + pmadapter->priv[0]->bss_role = MLAN_BSS_ROLE_STA; + else if (pmdevice->bss_attr[0].bss_type == MLAN_BSS_TYPE_UAP) + pmadapter->priv[0]->bss_role = MLAN_BSS_ROLE_UAP; +#ifdef WIFI_DIRECT_SUPPORT + else if (pmdevice->bss_attr[0].bss_type == MLAN_BSS_TYPE_WIFIDIRECT) { + pmadapter->priv[0]->bss_role = MLAN_BSS_ROLE_STA; + if (pmdevice->bss_attr[0].bss_virtual) + pmadapter->priv[0]->bss_virtual = MTRUE; + } +#endif + /* Save bss_index and bss_num */ + pmadapter->priv[0]->bss_index = 0; + pmadapter->priv[0]->bss_num = (t_u8)pmdevice->bss_attr[0].bss_num; + + /* init function table */ + for (j = 0; mlan_ops[j]; j++) { + if (mlan_ops[j]->bss_role == GET_BSS_ROLE(pmadapter->priv[0])) { + memcpy_ext(pmadapter, &pmadapter->priv[0]->ops, + mlan_ops[j], sizeof(mlan_operations), + sizeof(mlan_operations)); + break; + } + } + /** back up bss_attr table */ + memcpy_ext(pmadapter, pmadapter->bss_attr, pmdevice->bss_attr, + sizeof(pmadapter->bss_attr), sizeof(pmadapter->bss_attr)); + + /* Initialize lock variables */ + if (wlan_init_lock_list(pmadapter) != MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + + /** init lock varible for first priv */ + if (wlan_init_priv_lock_list(pmadapter, 0) != MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + + /* Allocate memory for member of adapter structure */ + if (wlan_allocate_adapter(pmadapter)) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + + /* Initialize timers */ + if (wlan_init_timer(pmadapter) != MLAN_STATUS_SUCCESS) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + /* Return pointer of mlan_adapter to MOAL */ + *ppmlan_adapter = pmadapter; + + goto exit_register; + +error: + PRINTM(MINFO, "Leave mlan_register with error\n"); + /* Free adapter structure */ + wlan_free_adapter(pmadapter); + + for (i = 0; i < MLAN_MAX_BSS_NUM; i++) { + if (pmadapter->priv[i]) { + if (pcb->moal_vmalloc && pcb->moal_vfree) + pcb->moal_vfree(pmadapter->pmoal_handle, + (t_u8 *)pmadapter->priv[i]); + else if (pcb->moal_mfree) + pcb->moal_mfree(pmadapter->pmoal_handle, + (t_u8 *)pmadapter->priv[i]); + } + } + if (pcb->moal_vmalloc && pcb->moal_vfree) + pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter); + else if (pcb->moal_mfree) + pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter); + +exit_register: + LEAVE(); + return ret; +} + +/** + * @brief This function unregisters MOAL from MLAN module. + * + * @param pmlan_adapter A pointer to a mlan_device structure + * allocated in MOAL + * + * @return MLAN_STATUS_SUCCESS + * The deregistration succeeded. + */ +mlan_status mlan_unregister(t_void *pmlan_adapter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + pmlan_callbacks pcb; + t_s32 i = 0; + + MASSERT(pmlan_adapter); + + ENTER(); + + pcb = &pmadapter->callbacks; + + /* Free adapter structure */ + wlan_free_adapter(pmadapter); + + /* Free private structures */ + for (i = 0; i < pmadapter->priv_num; i++) { + if (pmadapter->priv[i]) { + if (pcb->moal_vmalloc && pcb->moal_vfree) + pcb->moal_vfree(pmadapter->pmoal_handle, + (t_u8 *)pmadapter->priv[i]); + else if (pcb->moal_mfree) + pcb->moal_mfree(pmadapter->pmoal_handle, + (t_u8 *)pmadapter->priv[i]); + } + } + + /* Free mlan_adapter */ + if (pcb->moal_vmalloc && pcb->moal_vfree) + pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter); + else if (pcb->moal_mfree) + pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter); + + LEAVE(); + return ret; +} + +/** + * @brief This function downloads the firmware + * + * @param pmlan_adapter A pointer to a t_void pointer to store + * mlan_adapter structure pointer + * @param pmfw A pointer to firmware image + * + * @return MLAN_STATUS_SUCCESS + * The firmware download succeeded. + * MLAN_STATUS_FAILURE + * The firmware download failed. + */ +mlan_status mlan_dnld_fw(t_void *pmlan_adapter, pmlan_fw_image pmfw) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + + ENTER(); + MASSERT(pmlan_adapter); + + /* Download helper/firmware */ + if (pmfw) { + ret = pmadapter->ops.dnld_fw(pmadapter, pmfw); + if (ret != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret); + LEAVE(); + return ret; + } + } + + LEAVE(); + return ret; +} + +/** + * @brief This function pass init param to MLAN + * + * @param pmlan_adapter A pointer to a t_void pointer to store + * mlan_adapter structure pointer + * @param pparam A pointer to mlan_init_param structure + * + * @return MLAN_STATUS_SUCCESS + * + */ +mlan_status mlan_set_init_param(t_void *pmlan_adapter, pmlan_init_param pparam) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + + ENTER(); + MASSERT(pmlan_adapter); + + /** Save DPD data in MLAN */ + if ((pparam->pdpd_data_buf) || (pparam->dpd_data_len > 0)) { + pmadapter->pdpd_data = pparam->pdpd_data_buf; + pmadapter->dpd_data_len = pparam->dpd_data_len; + } + if (pparam->ptxpwr_data_buf && (pparam->txpwr_data_len > 0)) { + pmadapter->ptxpwr_data = pparam->ptxpwr_data_buf; + pmadapter->txpwr_data_len = pparam->txpwr_data_len; + } + /** Save cal data in MLAN */ + if ((pparam->pcal_data_buf) && (pparam->cal_data_len > 0)) { + pmadapter->pcal_data = pparam->pcal_data_buf; + pmadapter->cal_data_len = pparam->cal_data_len; + } + + LEAVE(); + return ret; +} + +/** + * @brief This function initializes the firmware + * + * @param pmlan_adapter A pointer to a t_void pointer to store + * mlan_adapter structure pointer + * + * @return MLAN_STATUS_SUCCESS + * The firmware initialization succeeded. + * MLAN_STATUS_PENDING + * The firmware initialization is pending. + * MLAN_STATUS_FAILURE + * The firmware initialization failed. + */ +mlan_status mlan_init_fw(t_void *pmlan_adapter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + + ENTER(); + MASSERT(pmlan_adapter); + + pmadapter->hw_status = WlanHardwareStatusGetHwSpec; + + /* Initialize firmware, may return PENDING */ + ret = wlan_init_fw(pmadapter); + PRINTM(MINFO, "wlan_init_fw returned ret=0x%x\n", ret); + + LEAVE(); + return ret; +} + +/** + * @brief Shutdown firmware + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * + * @return MLAN_STATUS_SUCCESS + * The firmware shutdown call succeeded. + * MLAN_STATUS_PENDING + * The firmware shutdown call is pending. + * MLAN_STATUS_FAILURE + * The firmware shutdown call failed. + */ +mlan_status mlan_shutdown_fw(t_void *pmlan_adapter) +{ + mlan_status ret = MLAN_STATUS_PENDING; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + pmlan_buffer pmbuf; + pmlan_ioctl_req pioctl_buf; + pmlan_callbacks pcb; + t_s32 i = 0; + + ENTER(); + + MASSERT(pmlan_adapter); + /* MLAN already shutdown */ + if (pmadapter->hw_status == WlanHardwareStatusNotReady) { + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + + pmadapter->hw_status = WlanHardwareStatusClosing; + /* Wait for mlan_process to complete */ + if (pmadapter->mlan_processing) { + PRINTM(MWARN, "MLAN main processing is still running\n"); + LEAVE(); + return ret; + } + + /* Shut down MLAN */ + PRINTM(MINFO, "Shutdown MLAN...\n"); + + /* Cancel all pending commands and complete ioctls */ + wlan_cancel_all_pending_cmd(pmadapter, MTRUE); + + /* Clean up priv structures */ + for (i = 0; i < pmadapter->priv_num; i++) { + if (pmadapter->priv[i]) + wlan_free_priv(pmadapter->priv[i]); + } + + pcb = &pmadapter->callbacks; + /** cancel pending ioctl */ + while ((pioctl_buf = (pmlan_ioctl_req)util_dequeue_list( + pmadapter->pmoal_handle, &pmadapter->ioctl_pending_q, + pcb->moal_spin_lock, pcb->moal_spin_unlock))) { + pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; + pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, + MLAN_STATUS_FAILURE); + } + + while ((pmbuf = (pmlan_buffer)util_dequeue_list( + pmadapter->pmoal_handle, &pmadapter->rx_data_queue, + pcb->moal_spin_lock, pcb->moal_spin_unlock))) { +#ifdef USB + if (IS_USB(pmadapter->card_type)) + pcb->moal_recv_complete(pmadapter->pmoal_handle, pmbuf, + pmadapter->rx_data_ep, + MLAN_STATUS_FAILURE); +#endif +#if defined(SDIO) || defined(PCIE) + if (!IS_USB(pmadapter->card_type)) + wlan_free_mlan_buffer(pmadapter, pmbuf); +#endif + } + pmadapter->rx_pkts_queued = 0; +#ifdef PCIE + if (IS_PCIE(pmadapter->card_type) && + wlan_set_drv_ready_reg(pmadapter, 0)) { + PRINTM(MERROR, "Failed to write driver not-ready signature\n"); + } +#endif + + /* Notify completion */ + ret = wlan_shutdown_fw_complete(pmadapter); + + LEAVE(); + return ret; +} + +/** + * @brief queue main work + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return N/A + */ +static t_void mlan_queue_main_work(mlan_adapter *pmadapter) +{ + pmlan_callbacks pcb = &pmadapter->callbacks; + ENTER(); + pcb->moal_spin_lock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + + /* Check if already processing */ + if (pmadapter->mlan_processing) { + pmadapter->more_task_flag = MTRUE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + } else { + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), + MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL); + } + LEAVE(); + return; +} + +/** + * @brief queue rx_work + * + * @param pmadapter A pointer to mlan_adapter structure + * + * @return N/A + */ +static t_void mlan_queue_rx_work(mlan_adapter *pmadapter) +{ + pmlan_callbacks pcb = &pmadapter->callbacks; + ENTER(); + + pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock); + + /* Check if already processing */ + if (pmadapter->mlan_rx_processing) { + pmadapter->more_rx_task_flag = MTRUE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + } else { + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), + MLAN_EVENT_ID_DRV_DEFER_RX_WORK, MNULL); + } + LEAVE(); + return; +} + +/** + * @brief block main process + * + * @param pmadapter A pointer to mlan_adapter structure + * @param block MTRUE/MFALSE + * + * @return N/A + */ +void mlan_block_main_process(mlan_adapter *pmadapter, t_u8 block) +{ + pmlan_callbacks pcb = &pmadapter->callbacks; + pcb->moal_spin_lock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + if (!block) { + pmadapter->main_lock_flag = MFALSE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + } else { + pmadapter->main_lock_flag = MTRUE; + if (pmadapter->mlan_processing) { + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + PRINTM(MEVENT, "wlan: wait main work done...\n"); + wlan_recv_event( + wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), + MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK, MNULL); + } else { + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + } + } +} + +/** + * @brief block rx process + * + * @param pmadapter A pointer to mlan_adapter structure + * @param block MTRUE/MFALSE; + * + * @return N/A + */ +void mlan_block_rx_process(mlan_adapter *pmadapter, t_u8 block) +{ + pmlan_callbacks pcb = &pmadapter->callbacks; + pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock); + if (!block) { + pmadapter->rx_lock_flag = MFALSE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + } else { + pmadapter->rx_lock_flag = MTRUE; + if (pmadapter->mlan_rx_processing) { + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + PRINTM(MEVENT, "wlan: wait rx work done...\n"); + wlan_recv_event(wlan_get_priv(pmadapter, + MLAN_BSS_ROLE_ANY), + MLAN_EVENT_ID_DRV_FLUSH_RX_WORK, MNULL); + } else { + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + } + } +} + +/** + * @brief The receive process + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * @param rx_pkts A pointer to save receive pkts number + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status mlan_rx_process(t_void *pmlan_adapter, t_u8 *rx_pkts) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + pmlan_callbacks pcb; + pmlan_buffer pmbuf; + t_u8 limit = 0; + t_u8 rx_num = 0; + + ENTER(); + + MASSERT(pmlan_adapter); + pcb = &pmadapter->callbacks; + pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock); + if (pmadapter->mlan_rx_processing || pmadapter->rx_lock_flag) { + pmadapter->more_rx_task_flag = MTRUE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + goto exit_rx_proc; + } else { + pmadapter->mlan_rx_processing = MTRUE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + } + if (rx_pkts) + limit = *rx_pkts; + +rx_process_start: + /* Check for Rx data */ + while (MTRUE) { +#ifdef DRV_EMBEDDED_AUTHENTICATOR + if (pmadapter->authenticator_priv) { + if (IsAuthenticatorEnabled( + pmadapter->authenticator_priv->psapriv)) { + AuthenticatorKeyMgmtInit( + pmadapter->authenticator_priv->psapriv, + pmadapter->authenticator_priv + ->curr_addr); + pmadapter->authenticator_priv = MNULL; + } + } +#endif + if (pmadapter->flush_data) { + pmadapter->flush_data = MFALSE; + wlan_flush_rxreorder_tbl(pmadapter); + } + pmadapter->callbacks.moal_spin_lock( + pmadapter->pmoal_handle, + pmadapter->rx_data_queue.plock); + pmbuf = (pmlan_buffer)util_dequeue_list( + pmadapter->pmoal_handle, &pmadapter->rx_data_queue, + MNULL, MNULL); + if (!pmbuf) { + pmadapter->callbacks.moal_spin_unlock( + pmadapter->pmoal_handle, + pmadapter->rx_data_queue.plock); + break; + } + pmadapter->rx_pkts_queued--; + rx_num++; + pmadapter->callbacks.moal_spin_unlock( + pmadapter->pmoal_handle, + pmadapter->rx_data_queue.plock); + + // rx_trace 6 + if (pmadapter->tp_state_on) + pmadapter->callbacks.moal_tp_accounting( + pmadapter->pmoal_handle, pmbuf, + 6 /*RX_DROP_P2*/); + if (pmadapter->tp_state_drop_point == 6 /*RX_DROP_P2*/) { + pmadapter->ops.data_complete(pmadapter, pmbuf, ret); + goto rx_process_start; + } + + if (pmadapter->delay_task_flag && + (pmadapter->rx_pkts_queued < LOW_RX_PENDING)) { + PRINTM(MEVENT, "Run\n"); + pmadapter->delay_task_flag = MFALSE; + mlan_queue_main_work(pmadapter); + } + pmadapter->ops.handle_rx_packet(pmadapter, pmbuf); + if (limit && rx_num >= limit) + break; + } + if (rx_pkts) + *rx_pkts = rx_num; + pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock); + if (pmadapter->more_rx_task_flag) { + pmadapter->more_rx_task_flag = MFALSE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); + goto rx_process_start; + } + pmadapter->mlan_rx_processing = MFALSE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->prx_proc_lock); +exit_rx_proc: + LEAVE(); + return ret; +} + +/** + * @brief The main process + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status mlan_main_process(t_void *pmlan_adapter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + pmlan_callbacks pcb; + + ENTER(); + + MASSERT(pmlan_adapter); + + pcb = &pmadapter->callbacks; + + pcb->moal_spin_lock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + + /* Check if already processing */ + if (pmadapter->mlan_processing || pmadapter->main_lock_flag) { + pmadapter->more_task_flag = MTRUE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + goto exit_main_proc; + } else { + pmadapter->mlan_processing = MTRUE; + pmadapter->main_process_cnt++; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + } +process_start: + do { + /* Is MLAN shutting down or not ready? */ + if ((pmadapter->hw_status == WlanHardwareStatusClosing) || + (pmadapter->hw_status == WlanHardwareStatusNotReady)) + break; + if (pmadapter->pending_ioctl) { + wlan_process_pending_ioctl(pmadapter); + pmadapter->pending_ioctl = MFALSE; + } + if (pmadapter->pending_disconnect_priv) { + PRINTM(MEVENT, "Reset connect state\n"); + wlan_reset_connect_state( + pmadapter->pending_disconnect_priv, MTRUE); + pmadapter->pending_disconnect_priv = MNULL; + } +#if defined(SDIO) || defined(PCIE) + if (!IS_USB(pmadapter->card_type)) { + if (pmadapter->rx_pkts_queued > HIGH_RX_PENDING) { + pcb->moal_tp_accounting_rx_param( + pmadapter->pmoal_handle, 2, 0); + PRINTM(MEVENT, "Pause\n"); + pmadapter->delay_task_flag = MTRUE; + mlan_queue_rx_work(pmadapter); + break; + } + /* Handle pending interrupts if any */ + if (pmadapter->ireg) { + if (pmadapter->hs_activated == MTRUE) + wlan_process_hs_config(pmadapter); + pmadapter->ops.process_int_status(pmadapter); + if (pmadapter->data_received) + mlan_queue_rx_work(pmadapter); + } + } +#endif + + /* Need to wake up the card ? */ + if ((pmadapter->ps_state == PS_STATE_SLEEP) && + (pmadapter->pm_wakeup_card_req && + !pmadapter->pm_wakeup_fw_try) && + (wlan_is_cmd_pending(pmadapter) || + !wlan_bypass_tx_list_empty(pmadapter) || + !wlan_wmm_lists_empty(pmadapter))) { + pmadapter->ops.wakeup_card(pmadapter, MTRUE); + pmadapter->pm_wakeup_fw_try = MTRUE; + continue; + } + if (IS_CARD_RX_RCVD(pmadapter) || + (!pmadapter->cmd_sent && + pmadapter->vdll_ctrl.pending_block)) { + pmadapter->data_received = MFALSE; + if (pmadapter->hs_activated == MTRUE) { + pmadapter->is_hs_configured = MFALSE; + wlan_host_sleep_activated_event( + wlan_get_priv(pmadapter, + MLAN_BSS_ROLE_ANY), + MFALSE); + } + pmadapter->pm_wakeup_fw_try = MFALSE; + if (pmadapter->ps_state == PS_STATE_SLEEP) + pmadapter->ps_state = PS_STATE_AWAKE; + if (pmadapter->wakeup_fw_timer_is_set) { + pcb->moal_stop_timer( + pmadapter->pmoal_handle, + pmadapter->pwakeup_fw_timer); + pmadapter->wakeup_fw_timer_is_set = MFALSE; + } + } else { + /* We have tried to wakeup the card already */ + if (pmadapter->pm_wakeup_fw_try) + break; + /* Check if we need to confirm Sleep Request received + * previously */ + if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) + if (!pmadapter->cmd_sent && + !pmadapter->curr_cmd && + !pmadapter->vdll_ctrl.pending_block) + wlan_check_ps_cond(pmadapter); + if (pmadapter->ps_state != PS_STATE_AWAKE || + (pmadapter->tx_lock_flag == MTRUE)) + break; + + if (pmadapter->data_sent || + (wlan_bypass_tx_list_empty(pmadapter) && + wlan_wmm_lists_empty(pmadapter)) || + wlan_11h_radar_detected_tx_blocked(pmadapter)) { + if (pmadapter->cmd_sent || + pmadapter->curr_cmd || + !wlan_is_cmd_pending(pmadapter)) { + break; + } + } + } + + /* Check for Cmd Resp */ + if (pmadapter->cmd_resp_received) { + pmadapter->cmd_resp_received = MFALSE; + wlan_process_cmdresp(pmadapter); + + /* call moal back when init_fw is done */ + if (pmadapter->hw_status == + WlanHardwareStatusInitdone) { + pmadapter->hw_status = WlanHardwareStatusReady; + wlan_init_fw_complete(pmadapter); + } else if (pmadapter->hw_status == + WlanHardwareStatusGetHwSpecdone) { + pmadapter->hw_status = + WlanHardwareStatusInitializing; + wlan_get_hw_spec_complete(pmadapter); + } + } + + /* Check for event */ + if (pmadapter->event_received) { + pmadapter->event_received = MFALSE; + wlan_process_event(pmadapter); + } + + /* Check if we need to confirm Sleep Request received previously + */ + if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) + if (!pmadapter->cmd_sent && !pmadapter->curr_cmd && + !pmadapter->vdll_ctrl.pending_block) + wlan_check_ps_cond(pmadapter); + + /* + * The ps_state may have been changed during processing of + * Sleep Request event. + */ + if ((pmadapter->ps_state == PS_STATE_SLEEP) || + (pmadapter->ps_state == PS_STATE_PRE_SLEEP) || + (pmadapter->ps_state == PS_STATE_SLEEP_CFM) || + (pmadapter->tx_lock_flag == MTRUE)) { + continue; + } + + /* in a case of race condition, download the VDLL block here */ + if (!pmadapter->cmd_sent && + pmadapter->vdll_ctrl.pending_block) { + wlan_download_vdll_block( + pmadapter, pmadapter->vdll_ctrl.pending_block, + pmadapter->vdll_ctrl.pending_block_len); + pmadapter->vdll_ctrl.pending_block = MNULL; + } + if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) { + if (wlan_exec_next_cmd(pmadapter) == + MLAN_STATUS_FAILURE) { + ret = MLAN_STATUS_FAILURE; + break; + } + } + + if (!pmadapter->data_sent && + !wlan_11h_radar_detected_tx_blocked(pmadapter) && + !wlan_bypass_tx_list_empty(pmadapter)) { + PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n"); + wlan_process_bypass_tx(pmadapter); + if (pmadapter->hs_activated == MTRUE) { + pmadapter->is_hs_configured = MFALSE; + wlan_host_sleep_activated_event( + wlan_get_priv(pmadapter, + MLAN_BSS_ROLE_ANY), + MFALSE); + } + } + + if (!pmadapter->data_sent && !wlan_wmm_lists_empty(pmadapter) && + !wlan_11h_radar_detected_tx_blocked(pmadapter)) { + wlan_wmm_process_tx(pmadapter); + if (pmadapter->hs_activated == MTRUE) { + pmadapter->is_hs_configured = MFALSE; + wlan_host_sleep_activated_event( + wlan_get_priv(pmadapter, + MLAN_BSS_ROLE_ANY), + MFALSE); + } + } + +#ifdef STA_SUPPORT + if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent && + !pmadapter->curr_cmd && !wlan_is_cmd_pending(pmadapter) && + wlan_bypass_tx_list_empty(pmadapter) && + wlan_wmm_lists_empty(pmadapter)) { + if (wlan_send_null_packet( + wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA), + MRVDRV_TxPD_POWER_MGMT_NULL_PACKET | + MRVDRV_TxPD_POWER_MGMT_LAST_PACKET) == + MLAN_STATUS_SUCCESS) { + pmadapter->delay_null_pkt = MFALSE; + } + break; + } +#endif + + } while (MTRUE); + + pcb->moal_spin_lock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + if (pmadapter->more_task_flag == MTRUE) { + pmadapter->more_task_flag = MFALSE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + goto process_start; + } + pmadapter->mlan_processing = MFALSE; + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + +exit_main_proc: + if (pmadapter->hw_status == WlanHardwareStatusClosing) + mlan_shutdown_fw(pmadapter); + LEAVE(); + return ret; +} + +/** + * @brief Function to send packet + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * @param pmbuf A pointer to mlan_buffer structure + * + * @return MLAN_STATUS_PENDING + */ +mlan_status mlan_send_packet(t_void *pmlan_adapter, pmlan_buffer pmbuf) +{ + mlan_status ret = MLAN_STATUS_PENDING; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + mlan_private *pmpriv; + t_u16 eth_type = 0; + + ENTER(); + MASSERT(pmlan_adapter && pmbuf); + + if (!pmlan_adapter || !pmbuf) { + return MLAN_STATUS_FAILURE; + } + + MASSERT(pmbuf->bss_index < pmadapter->priv_num); + pmbuf->flags |= MLAN_BUF_FLAG_MOAL_TX_BUF; + pmpriv = pmadapter->priv[pmbuf->bss_index]; + + eth_type = + mlan_ntohs(*(t_u16 *)&pmbuf->pbuf[pmbuf->data_offset + + MLAN_ETHER_PKT_TYPE_OFFSET]); + if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) && + ((eth_type == MLAN_ETHER_PKT_TYPE_EAPOL) || + (eth_type == MLAN_ETHER_PKT_TYPE_ARP) || + (eth_type == MLAN_ETHER_PKT_TYPE_WAPI))) || + (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) + + ) { + if (eth_type == MLAN_ETHER_PKT_TYPE_EAPOL) { + PRINTM_NETINTF(MMSG, pmpriv); + PRINTM(MMSG, "wlan: Send EAPOL pkt to " MACSTR "\n", + MAC2STR(pmbuf->pbuf + pmbuf->data_offset)); + } + if (pmadapter->tp_state_on) + pmadapter->callbacks.moal_tp_accounting( + pmadapter->pmoal_handle, pmbuf->pdesc, 2); + if (pmadapter->tp_state_drop_point == 2) + return 0; + else + wlan_add_buf_bypass_txqueue(pmadapter, pmbuf); + } else { + if (pmadapter->tp_state_on) + pmadapter->callbacks.moal_tp_accounting( + pmadapter->pmoal_handle, pmbuf->pdesc, 2); + if (pmadapter->tp_state_drop_point == 2) + return 0; + else + /* Transmit the packet*/ + wlan_wmm_add_buf_txqueue(pmadapter, pmbuf); + } + + LEAVE(); + return ret; +} + +/** + * @brief MLAN ioctl handler + * + * @param adapter A pointer to mlan_adapter structure + * @param pioctl_req A pointer to ioctl request buffer + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, + * otherwise fail + */ +mlan_status mlan_ioctl(t_void *adapter, pmlan_ioctl_req pioctl_req) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + pmlan_adapter pmadapter = (pmlan_adapter)adapter; + pmlan_private pmpriv = MNULL; + + ENTER(); + + if (pioctl_req == MNULL) { + PRINTM(MMSG, "Cancel all pending cmd!\n"); + wlan_cancel_all_pending_cmd(pmadapter, MFALSE); + goto exit; + } + if (pioctl_req->action == MLAN_ACT_CANCEL) { + wlan_cancel_pending_ioctl(pmadapter, pioctl_req); + ret = MLAN_STATUS_SUCCESS; + goto exit; + } + pmpriv = pmadapter->priv[pioctl_req->bss_index]; + ret = pmpriv->ops.ioctl(adapter, pioctl_req); +exit: + LEAVE(); + return ret; +} + +#ifdef USB +/** + * @brief Packet send completion callback + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * @param pmbuf A pointer to mlan_buffer structure + * @param port Data port + * @param status Callback status + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status mlan_write_data_async_complete(t_void *pmlan_adapter, + pmlan_buffer pmbuf, t_u32 port, + mlan_status status) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + + ENTER(); + + if (port == pmadapter->tx_cmd_ep) { + pmadapter->cmd_sent = MFALSE; + PRINTM(MCMND, "mlan_write_data_async_complete: CMD\n"); + /* pmbuf was allocated by MLAN */ + wlan_free_mlan_buffer(pmadapter, pmbuf); + } else { + pmadapter->data_sent = MFALSE; + ret = wlan_write_data_complete(pmadapter, pmbuf, status); + } + + LEAVE(); + return ret; +} + +/** + * @brief Packet receive handler + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * @param pmbuf A pointer to mlan_buffer structure + * @param port Data port + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or + * MLAN_STATUS_PENDING + */ +mlan_status mlan_recv(t_void *pmlan_adapter, pmlan_buffer pmbuf, t_u32 port) +{ + mlan_status ret = MLAN_STATUS_PENDING; + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + t_u8 *pbuf; + t_u32 len, recv_type; + t_u32 event_cause; +#ifdef DEBUG_LEVEL1 + t_u32 sec, usec; +#endif + t_u32 max_rx_data_size = MLAN_RX_DATA_BUF_SIZE; + + ENTER(); + + MASSERT(pmlan_adapter && pmbuf); + + if (pmadapter->hs_activated == MTRUE) + wlan_process_hs_config(pmadapter); + pbuf = pmbuf->pbuf + pmbuf->data_offset; + len = pmbuf->data_len; + + MASSERT(len >= MLAN_TYPE_LEN); + recv_type = *(t_u32 *)pbuf; + recv_type = wlan_le32_to_cpu(recv_type); + pbuf += MLAN_TYPE_LEN; + len -= MLAN_TYPE_LEN; + + if (port == pmadapter->rx_cmd_ep) { + switch (recv_type) { + case MLAN_USB_TYPE_CMD: + PRINTM_GET_SYS_TIME(MCMND, &sec, &usec); + PRINTM(MCMND, "mlan_recv: CMD (%lu.%06lu)\n", sec, + usec); + if (len > MRVDRV_SIZE_OF_CMD_BUFFER) { + pmbuf->status_code = MLAN_ERROR_CMD_RESP_FAIL; + ret = MLAN_STATUS_FAILURE; + PRINTM(MERROR, "mlan_recv: CMD too large\n"); + } else if (!pmadapter->curr_cmd) { + if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) { + pmbuf->data_offset += MLAN_TYPE_LEN; + pmbuf->data_len -= MLAN_TYPE_LEN; + wlan_process_sleep_confirm_resp( + pmadapter, + pmbuf->pbuf + + pmbuf->data_offset, + pmbuf->data_len); + pmbuf->flags |= + MLAN_BUF_FLAG_SLEEPCFM_RESP; + ret = MLAN_STATUS_SUCCESS; + + } else { + pmbuf->status_code = + MLAN_ERROR_CMD_RESP_FAIL; + ret = MLAN_STATUS_FAILURE; + } + PRINTM(MINFO, "mlan_recv: no curr_cmd\n"); + } else { + pmadapter->upld_len = len; + pmbuf->data_offset += MLAN_TYPE_LEN; + pmbuf->data_len -= MLAN_TYPE_LEN; + pmadapter->curr_cmd->respbuf = pmbuf; + pmadapter->cmd_resp_received = MTRUE; + } + break; + case MLAN_USB_TYPE_EVENT: + MASSERT(len >= sizeof(t_u32)); + memmove(pmadapter, &event_cause, pbuf, sizeof(t_u32)); + pmadapter->event_cause = wlan_le32_to_cpu(event_cause); + PRINTM_GET_SYS_TIME(MEVENT, &sec, &usec); + PRINTM(MEVENT, "mlan_recv: EVENT 0x%x (%lu.%06lu)\n", + pmadapter->event_cause, sec, usec); + pbuf += sizeof(t_u32); + len -= sizeof(t_u32); + if ((len > 0) && (len < MAX_EVENT_SIZE)) + memmove(pmadapter, pmadapter->event_body, pbuf, + len); + pmadapter->event_received = MTRUE; + pmadapter->pmlan_buffer_event = pmbuf; + /* remove 4 byte recv_type */ + pmbuf->data_offset += MLAN_TYPE_LEN; + pmbuf->data_len -= MLAN_TYPE_LEN; + /* MOAL to call mlan_main_process for processing */ + break; + default: + pmbuf->status_code = MLAN_ERROR_PKT_INVALID; + ret = MLAN_STATUS_FAILURE; + PRINTM(MERROR, "mlan_recv: unknown recv_type 0x%x\n", + recv_type); + break; + } + } else if (port == pmadapter->rx_data_ep) { + PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); + PRINTM(MDATA, "mlan_recv: DATA (%lu.%06lu)\n", sec, usec); +#if defined(USB) + if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl.enable) { + max_rx_data_size = pmadapter->pcard_usb->usb_rx_deaggr + .aggr_ctrl.aggr_max; + if (pmadapter->pcard_usb->usb_rx_deaggr.aggr_ctrl + .aggr_mode == MLAN_USB_AGGR_MODE_NUM) { + max_rx_data_size *= + MAX(MLAN_USB_MAX_PKT_SIZE, + pmadapter->pcard_usb->usb_rx_deaggr + .aggr_ctrl.aggr_align); + max_rx_data_size = MAX(max_rx_data_size, + MLAN_RX_DATA_BUF_SIZE); + } + } +#endif + if (len > max_rx_data_size) { + pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID; + ret = MLAN_STATUS_FAILURE; + PRINTM(MERROR, "mlan_recv: DATA too large\n"); + } else { + pmadapter->upld_len = len; + pmadapter->callbacks.moal_get_system_time( + pmadapter->pmoal_handle, &pmbuf->in_ts_sec, + &pmbuf->in_ts_usec); + pmadapter->callbacks.moal_spin_lock( + pmadapter->pmoal_handle, + pmadapter->rx_data_queue.plock); + util_enqueue_list_tail(pmadapter->pmoal_handle, + &pmadapter->rx_data_queue, + (pmlan_linked_list)pmbuf, MNULL, + MNULL); + pmadapter->rx_pkts_queued++; + pmadapter->callbacks.moal_spin_unlock( + pmadapter->pmoal_handle, + pmadapter->rx_data_queue.plock); + pmadapter->data_received = MTRUE; + mlan_queue_rx_work(pmadapter); + } + } else { + pmbuf->status_code = MLAN_ERROR_PKT_INVALID; + ret = MLAN_STATUS_FAILURE; + PRINTM(MERROR, "mlan_recv: unknown port number 0x%x\n", port); + } + + LEAVE(); + return ret; +} +#endif /* USB */ + +/** + * @brief Packet receive completion callback handler + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * @param pmbuf A pointer to mlan_buffer structure + * @param status Callback status + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status mlan_recv_packet_complete(t_void *pmlan_adapter, pmlan_buffer pmbuf, + mlan_status status) +{ + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + + ENTER(); + wlan_recv_packet_complete(pmadapter, pmbuf, status); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief select wmm queue + * + * @param pmlan_adapter A pointer to mlan_adapter structure + * @param bss_num BSS number + * @param tid TID + * + * @return wmm queue priority (0 - 3) + */ +t_u8 mlan_select_wmm_queue(t_void *pmlan_adapter, t_u8 bss_num, t_u8 tid) +{ + mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter; + pmlan_private pmpriv = pmadapter->priv[bss_num]; + t_u8 ret; + ENTER(); + ret = wlan_wmm_select_queue(pmpriv, tid); + LEAVE(); + return ret; +} + +#if defined(SDIO) || defined(PCIE) +/** + * @brief This function gets interrupt status. + * @param msg_id only used for PCIE + */ +/** + * @param msg_id A message id + * @param adapter A pointer to mlan_adapter structure + * @return MLAN_STATUS_FAILURE -- if the intererupt is not for us + */ +mlan_status mlan_interrupt(t_u16 msg_id, t_void *adapter) +{ + mlan_adapter *pmadapter = (mlan_adapter *)adapter; + mlan_status ret; + + ENTER(); + ret = pmadapter->ops.interrupt(msg_id, pmadapter); + LEAVE(); + return ret; +} +#endif + +/** + * @brief This function wakeup firmware. + * + * @param adapter A pointer to mlan_adapter structure + * @param keep_wakeup keep wake up flag + * @return N/A + */ +t_void mlan_pm_wakeup_card(t_void *adapter, t_u8 keep_wakeup) +{ + mlan_adapter *pmadapter = (mlan_adapter *)adapter; + + ENTER(); + if (keep_wakeup) + pmadapter->ops.wakeup_card(pmadapter, MFALSE); + pmadapter->keep_wakeup = keep_wakeup; + + LEAVE(); +} + +/** + * @brief This function check main_process status. + * + * @param adapter A pointer to mlan_adapter structure + * @return MTRUE/MFALSE + */ +t_u8 mlan_is_main_process_running(t_void *adapter) +{ + mlan_adapter *pmadapter = (mlan_adapter *)adapter; + pmlan_callbacks pcb = &pmadapter->callbacks; + t_u8 ret = MFALSE; + ENTER(); + pcb->moal_spin_lock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + + /* Check if already processing */ + if (pmadapter->mlan_processing) { + pmadapter->more_task_flag = MTRUE; + ret = MTRUE; + } + pcb->moal_spin_unlock(pmadapter->pmoal_handle, + pmadapter->pmain_proc_lock); + LEAVE(); + return ret; +} + +#ifdef PCIE +/** + * @brief This function sets the PCIE interrupt mode. + * + * @param adapter A pointer to mlan_adapter structure + * @param int_mode PCIE interrupt type active + * @param func_num PCIE function num + * @return N/A + */ +t_void mlan_set_int_mode(t_void *adapter, t_u32 int_mode, t_u8 func_num) +{ + mlan_adapter *pmadapter = (mlan_adapter *)adapter; + ENTER(); + pmadapter->pcard_pcie->pcie_int_mode = int_mode; + pmadapter->pcard_pcie->func_num = func_num; + LEAVE(); +} +#endif |