/** * @file mlan_cmdevt.c * * @brief This file contains the handling of CMD/EVENT in MLAN * * * Copyright 2009-2023 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: 05/12/2009: initial version ************************************************************/ #include "mlan.h" #include "mlan_util.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" #include "mlan_11n.h" #include "mlan_11ac.h" #include "mlan_11ax.h" #include "mlan_11h.h" #ifdef SDIO #include "mlan_sdio.h" #endif /* SDIO */ #ifdef PCIE #include "mlan_pcie.h" #endif /* PCIE */ #include "mlan_init.h" /******************************************************** Local Variables ********************************************************/ #ifdef DEBUG_LEVEL1 #define ENUM_ELEMENT(_name, _id) \ { \ .id = _id, .name = #_name \ } #define ENUM_ELEMENT_LAST(name) \ { \ 0xFFFF, 0 \ } static const struct reflective_enum_element host_cmd_id_names[] = { #include "mlan_hostcmd_ids.h" }; static const struct reflective_enum_element host_fw_event_names[] = { #include "mlan_event_ids.h" }; #undef ENUM_ELEMENT #undef ENUM_ELEMENT_LAST #endif /* DEBUG_LEVEL1 */ /******************************************************* Global Variables ********************************************************/ /******************************************************** Local Functions ********************************************************/ static const char *wlan_hostcmd_get_name(enum host_cmd_id id) { #ifdef DEBUG_LEVEL1 const char *name = reflective_enum_lookup_name(host_cmd_id_names, id); if (name) { return wlan_str_skip_prefix(name, "HostCmd_CMD_"); } #endif return "???"; } static const char *wlan_event_get_name(enum host_fw_event_id id) { #ifdef DEBUG_LEVEL1 const char *name = reflective_enum_lookup_name(host_fw_event_names, id); if (name) { return wlan_str_skip_prefix(name, "EVENT_"); } #endif return "???"; } #ifdef STA_SUPPORT /** * @brief This function check if the command was cancel scan command * * @param pcmd A pointer to HostCmd_DS_COMMAND structure * @return N/A */ static t_u8 wlan_is_cancel_scan_cmd(HostCmd_DS_COMMAND *pcmd) { HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &pcmd->params.ext_scan; if (pext_scan_cmd->ext_scan_type == EXT_SCAN_CANCEL) return MTRUE; else return MFALSE; } /** * @brief This function inserts scan command node to scan_pending_q. * * @param pmpriv A pointer to mlan_private structure * @param pcmd_node A pointer to cmd_ctrl_node structure * @return N/A */ static t_void wlan_queue_scan_cmd(mlan_private *pmpriv, cmd_ctrl_node *pcmd_node) { mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); if (pcmd_node == MNULL) goto done; pcmd_node->cmd_flag |= CMD_F_SCAN; util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->scan_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); done: LEAVE(); } /** * @brief This function check if cmd allowed to send to firmware * during scan * * @param cmd_id cmd id * * @return MTRUE/MFALSE */ static t_u8 wlan_is_cmd_allowed_during_scan(t_u16 cmd_id) { t_u8 ret = MTRUE; ENTER(); switch (cmd_id) { case HostCmd_CMD_FUNC_INIT: case HostCmd_CMD_CFG_DATA: case HostCmd_CMD_REGION_POWER_CFG: case HostCmd_CMD_CHANNEL_TRPC_CONFIG: case HostCmd_CMD_FUNC_SHUTDOWN: case HostCmd_CMD_802_11_ASSOCIATE: case HostCmd_CMD_802_11_DEAUTHENTICATE: case HostCmd_CMD_802_11_DISASSOCIATE: case HostCmd_CMD_802_11_AD_HOC_START: case HostCmd_CMD_802_11_AD_HOC_JOIN: case HostCmd_CMD_802_11_AD_HOC_STOP: case HostCmd_CMD_11N_ADDBA_REQ: case HostCmd_CMD_11N_ADDBA_RSP: case HostCmd_CMD_11N_DELBA: case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL: case HostCmd_CMD_TDLS_CONFIG: case HostCmd_CMD_TDLS_OPERATION: case HostCmd_CMD_SOFT_RESET: #ifdef UAP_SUPPORT case HostCmd_CMD_APCMD_SYS_RESET: case HostCmd_CMD_APCMD_BSS_START: case HostCmd_CMD_APCMD_BSS_STOP: case HostCmd_CMD_APCMD_STA_DEAUTH: #endif case HostCmd_CMD_802_11_BG_SCAN_CONFIG: case HostCmd_CMD_APCMD_ACS_SCAN: ret = MFALSE; break; default: break; } LEAVE(); return ret; } /** * @brief This function move the cmd from ext_cmd_pending_q to * cmd_pending_q * * @param cmd_id cmd id * * @return MTRUE/MFALSE */ t_void wlan_move_cmd_to_cmd_pending_q(pmlan_adapter pmadapter) { cmd_ctrl_node *pcmd_node = MNULL; ENTER(); wlan_request_cmd_lock(pmadapter); while ((pcmd_node = (cmd_ctrl_node *)util_peek_list( pmadapter->pmoal_handle, &pmadapter->ext_cmd_pending_q, MNULL, MNULL))) { util_unlink_list(pmadapter->pmoal_handle, &pmadapter->ext_cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MTRUE); } wlan_release_cmd_lock(pmadapter); LEAVE(); } /** * @brief This function inserts scan command node to scan_cmd_pending_q. * * @param pmpriv A pointer to mlan_private structure * @param pcmd_node A pointer to cmd_ctrl_node structure * @return N/A */ static t_void wlan_queue_cmd_to_ext_cmd_pending_queue(mlan_private *pmpriv, cmd_ctrl_node *pcmd_node) { mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); if (pcmd_node == MNULL) goto done; util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->ext_cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); done: LEAVE(); } /** * @brief Internal function used to flush the scan cmd pending queue * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ t_void wlan_flush_ext_cmd_pending_queue(pmlan_adapter pmadapter) { cmd_ctrl_node *pcmd_node = MNULL; HostCmd_DS_COMMAND *pcmd = MNULL; mlan_ioctl_req *pioctl_buf = MNULL; pmlan_callbacks pcb = &pmadapter->callbacks; ENTER(); wlan_request_cmd_lock(pmadapter); while ((pcmd_node = (cmd_ctrl_node *)util_peek_list( pmadapter->pmoal_handle, &pmadapter->ext_cmd_pending_q, MNULL, MNULL))) { util_unlink_list(pmadapter->pmoal_handle, &pmadapter->ext_cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); PRINTM(MCMND, "flush ext_cmd_pending_queue: cmd 0x%02x\n", wlan_le16_to_cpu(pcmd->command)); if (pcmd_node->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pcmd_node->pioctl_buf = MNULL; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } wlan_release_cmd_lock(pmadapter); LEAVE(); } /** * @brief This function inserts command node to scan_pending_q or * cmd_pending_q * * @param pmpriv A pointer to mlan_private structure * @param pcmd_node A pointer to cmd_ctrl_node structure * @return N/A */ static t_void wlan_queue_cmd(mlan_private *pmpriv, cmd_ctrl_node *pcmd_node, t_u16 cmd_no) { ENTER(); if (pmpriv->adapter->scan_processing && pmpriv->adapter->ext_scan_type == EXT_SCAN_ENHANCE) { if (MFALSE == wlan_is_cmd_allowed_during_scan(cmd_no)) { PRINTM(MCMND, "QUEUE_CMD: %s [0x%x] ext_cmd_pending_q\n", wlan_hostcmd_get_name(cmd_no), cmd_no); wlan_queue_cmd_to_ext_cmd_pending_queue(pmpriv, pcmd_node); return; } } wlan_insert_cmd_to_pending_q(pmpriv->adapter, pcmd_node, MTRUE); LEAVE(); } /** * @brief Internal function used to flush the scan pending queue * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ static void wlan_check_scan_queue(pmlan_adapter pmadapter) { cmd_ctrl_node *pcmd_node = MNULL; t_u16 num = 0; pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, &pmadapter->scan_pending_q, MNULL, MNULL); if (!pcmd_node) { PRINTM(MERROR, "No pending scan command\n"); return; } while (pcmd_node != (cmd_ctrl_node *)&pmadapter->scan_pending_q) { num++; pcmd_node = pcmd_node->pnext; } PRINTM(MERROR, "num_pending_scan=%d\n", num); } #endif /** * @brief This function will dump the pending commands id * * @param pmadapter A pointer to mlan_adapter * * @return N/A */ static void wlan_dump_pending_commands(pmlan_adapter pmadapter) { cmd_ctrl_node *pcmd_node = MNULL; HostCmd_DS_COMMAND *pcmd; ENTER(); wlan_request_cmd_lock(pmadapter); pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, MNULL, MNULL); if (!pcmd_node) { wlan_release_cmd_lock(pmadapter); LEAVE(); return; } while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) { pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); PRINTM(MERROR, "pending command id: 0x%x ioctl_buf=%p\n", wlan_le16_to_cpu(pcmd->command), pcmd_node->pioctl_buf); pcmd_node = pcmd_node->pnext; } #ifdef STA_SUPPORT wlan_check_scan_queue(pmadapter); #endif wlan_release_cmd_lock(pmadapter); LEAVE(); return; } #define REASON_CODE_NO_CMD_NODE 1 #define REASON_CODE_CMD_TIMEOUT 2 #define REASON_CODE_CMD_TO_CARD_FAILURE 3 #define REASON_CODE_EXT_SCAN_TIMEOUT 4 /** * @brief This function dump debug info * * @return N/A */ static t_void wlan_dump_info(mlan_adapter *pmadapter, t_u8 reason) { cmd_ctrl_node *pcmd_node = MNULL; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif t_u16 i; #ifdef SDIO t_u8 j; t_u8 mp_aggr_pkt_limit; #endif t_u16 cmd_id, cmd_act; mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); ENTER(); PRINTM(MERROR, "------------Dump info-----------\n", reason); switch (reason) { case REASON_CODE_NO_CMD_NODE: pmadapter->dbg.num_no_cmd_node++; PRINTM(MERROR, "No Free command node\n"); break; case REASON_CODE_CMD_TIMEOUT: PRINTM(MERROR, "Commmand Timeout\n"); break; case REASON_CODE_CMD_TO_CARD_FAILURE: PRINTM(MERROR, "Command to card failure\n"); break; case REASON_CODE_EXT_SCAN_TIMEOUT: PRINTM(MERROR, "EXT_SCAN_STATUS event Timeout\n"); break; default: break; } if ((reason == REASON_CODE_NO_CMD_NODE) && (pmadapter->dbg.num_no_cmd_node > 1)) { if (pmadapter->dbg.num_no_cmd_node >= 5) { if (pmpriv) wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL); } LEAVE(); return; } wlan_dump_pending_commands(pmadapter); if (reason != REASON_CODE_CMD_TIMEOUT) { if (!pmadapter->curr_cmd) { PRINTM(MERROR, "CurCmd Empty\n"); } else { pcmd_node = pmadapter->curr_cmd; cmd_id = pmadapter->dbg.last_cmd_id [pmadapter->dbg.last_cmd_index]; cmd_act = pmadapter->dbg.last_cmd_act [pmadapter->dbg.last_cmd_index]; PRINTM_GET_SYS_TIME(MERROR, &sec, &usec); PRINTM(MERROR, "Current cmd id (%lu.%06lu) %s [0x%x], act = 0x%x\n", sec, usec, wlan_hostcmd_get_name(cmd_id), cmd_id, cmd_act); #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type) && pcmd_node->cmdbuf) { t_u8 *pcmd_buf; pcmd_buf = pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset + pmadapter->ops.intf_header_len; if ((pmadapter->ops.intf_header_len + 16) > pcmd_node->cmdbuf->data_len) { for (i = 0; i < 16; i++) PRINTM(MERROR, "%02x ", *pcmd_buf++); PRINTM(MERROR, "\n"); } } #endif pmpriv = pcmd_node->priv; if (pmpriv) PRINTM(MERROR, "BSS type = %d BSS role= %d\n", pmpriv->bss_type, pmpriv->bss_role); } } PRINTM(MERROR, "mlan_processing =%d\n", pmadapter->mlan_processing); PRINTM(MERROR, "main_lock_flag =%d\n", pmadapter->main_lock_flag); PRINTM(MERROR, "main_process_cnt =%d\n", pmadapter->main_process_cnt); PRINTM(MERROR, "delay_task_flag =%d\n", pmadapter->delay_task_flag); PRINTM(MERROR, "mlan_rx_processing =%d\n", pmadapter->mlan_rx_processing); PRINTM(MERROR, "rx_pkts_queued=%d\n", pmadapter->rx_pkts_queued); PRINTM(MERROR, "more_task_flag = %d\n", pmadapter->more_task_flag); PRINTM(MERROR, "num_cmd_timeout = %d\n", pmadapter->num_cmd_timeout); PRINTM(MERROR, "last_cmd_index = %d\n", pmadapter->dbg.last_cmd_index); PRINTM(MERROR, "last_cmd_id = "); for (i = 0; i < DBG_CMD_NUM; i++) PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_id[i]); PRINTM(MERROR, "\n"); PRINTM(MERROR, "last_cmd_act = "); for (i = 0; i < DBG_CMD_NUM; i++) PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_act[i]); PRINTM(MERROR, "\n"); PRINTM(MERROR, "last_cmd_resp_index = %d\n", pmadapter->dbg.last_cmd_resp_index); PRINTM(MERROR, "last_cmd_resp_id = "); for (i = 0; i < DBG_CMD_NUM; i++) PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_cmd_resp_id[i]); PRINTM(MERROR, "\n"); PRINTM(MERROR, "last_event_index = %d\n", pmadapter->dbg.last_event_index); PRINTM(MERROR, "last_event = "); for (i = 0; i < DBG_CMD_NUM; i++) PRINTM(MERROR, "0x%x ", pmadapter->dbg.last_event[i]); PRINTM(MERROR, "\n"); PRINTM(MERROR, "num_data_h2c_failure = %d\n", pmadapter->dbg.num_tx_host_to_card_failure); PRINTM(MERROR, "num_cmd_h2c_failure = %d\n", pmadapter->dbg.num_cmd_host_to_card_failure); #ifdef SDIO if (IS_SD(pmadapter->card_type)) { PRINTM(MERROR, "num_data_c2h_failure = %d\n", pmadapter->dbg.num_rx_card_to_host_failure); PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n", pmadapter->dbg.num_cmdevt_card_to_host_failure); PRINTM(MERROR, "num_int_read_failure = %d\n", pmadapter->dbg.num_int_read_failure); PRINTM(MERROR, "last_int_status = %d\n", pmadapter->dbg.last_int_status); } #endif PRINTM(MERROR, "num_alloc_buffer_failure = %d\n", pmadapter->dbg.num_alloc_buffer_failure); PRINTM(MERROR, "num_pkt_dropped = %d\n", pmadapter->dbg.num_pkt_dropped); PRINTM(MERROR, "num_no_cmd_node = %d\n", pmadapter->dbg.num_no_cmd_node); PRINTM(MERROR, "num_event_deauth = %d\n", pmadapter->dbg.num_event_deauth); PRINTM(MERROR, "num_event_disassoc = %d\n", pmadapter->dbg.num_event_disassoc); PRINTM(MERROR, "num_event_link_lost = %d\n", pmadapter->dbg.num_event_link_lost); PRINTM(MERROR, "num_cmd_deauth = %d\n", pmadapter->dbg.num_cmd_deauth); PRINTM(MERROR, "num_cmd_assoc_success = %d\n", pmadapter->dbg.num_cmd_assoc_success); PRINTM(MERROR, "num_cmd_assoc_failure = %d\n", pmadapter->dbg.num_cmd_assoc_failure); PRINTM(MERROR, "num_cons_assoc_failure = %d\n", pmadapter->dbg.num_cons_assoc_failure); PRINTM(MERROR, "cmd_resp_received=%d\n", pmadapter->cmd_resp_received); PRINTM(MERROR, "event_received=%d\n", pmadapter->event_received); PRINTM(MERROR, "max_tx_buf_size=%d\n", pmadapter->max_tx_buf_size); PRINTM(MERROR, "tx_buf_size=%d\n", pmadapter->tx_buf_size); PRINTM(MERROR, "curr_tx_buf_size=%d\n", pmadapter->curr_tx_buf_size); PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", pmadapter->data_sent, pmadapter->cmd_sent); PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", pmadapter->ps_mode, pmadapter->ps_state); PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d wakeup_timeout=%d\n", pmadapter->pm_wakeup_card_req, pmadapter->pm_wakeup_fw_try, pmadapter->pm_wakeup_timeout); PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n", pmadapter->is_hs_configured, pmadapter->hs_activated); PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n", pmadapter->pps_uapsd_mode, pmadapter->sleep_period.period); PRINTM(MERROR, "tx_lock_flag = %d\n", pmadapter->tx_lock_flag); PRINTM(MERROR, "scan_processing = %d\n", pmadapter->scan_processing); PRINTM(MERROR, "scan_state = 0x%x\n", pmadapter->scan_state); PRINTM(MERROR, "bypass_pkt_count=%d\n", pmadapter->bypass_pkt_count); #ifdef SDIO if (IS_SD(pmadapter->card_type)) { mp_aggr_pkt_limit = pmadapter->pcard_sd->mp_aggr_pkt_limit; PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n", pmadapter->pcard_sd->mp_rd_bitmap, pmadapter->pcard_sd->curr_rd_port); PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n", pmadapter->pcard_sd->mp_wr_bitmap, pmadapter->pcard_sd->curr_wr_port); PRINTM(MMSG, "mp_data_port_mask = 0x%x\n", pmadapter->pcard_sd->mp_data_port_mask); PRINTM(MERROR, "last_recv_rd_bitmap=0x%x mp_invalid_update=%d\n", pmadapter->pcard_sd->last_recv_rd_bitmap, pmadapter->pcard_sd->mp_invalid_update); PRINTM(MERROR, "last_recv_wr_bitmap=0x%x last_mp_index=%d\n", pmadapter->pcard_sd->last_recv_wr_bitmap, pmadapter->pcard_sd->last_mp_index); for (i = 0; i < SDIO_MP_DBG_NUM; i++) { PRINTM(MERROR, "mp_wr_bitmap: 0x%x mp_wr_ports=0x%x len=%d curr_wr_port=0x%x\n", pmadapter->pcard_sd->last_mp_wr_bitmap[i], pmadapter->pcard_sd->last_mp_wr_ports[i], pmadapter->pcard_sd->last_mp_wr_len[i], pmadapter->pcard_sd->last_curr_wr_port[i]); for (j = 0; j < mp_aggr_pkt_limit; j++) { PRINTM(MERROR, "0x%02x ", pmadapter->pcard_sd->last_mp_wr_info [i * mp_aggr_pkt_limit + j]); } PRINTM(MERROR, "\n"); } } #endif #ifdef PCIE if (IS_PCIE(pmadapter->card_type)) { PRINTM(MERROR, "txbd_rdptr=0x%x txbd_wrptr=0x%x\n", pmadapter->pcard_pcie->txbd_rdptr, pmadapter->pcard_pcie->txbd_wrptr); PRINTM(MERROR, "rxbd_rdptr=0x%x rxbd_wrptr=0x%x\n", pmadapter->pcard_pcie->rxbd_rdptr, pmadapter->pcard_pcie->rxbd_wrptr); PRINTM(MERROR, "evtbd_rdptr=0x%x evt_wrptr=0x%x\n", pmadapter->pcard_pcie->evtbd_rdptr, pmadapter->pcard_pcie->evtbd_wrptr); PRINTM(MERROR, "last_wr_index:%d\n", pmadapter->pcard_pcie->txbd_wrptr & (pmadapter->pcard_pcie->txrx_bd_size - 1)); PRINTM(MERROR, " txrx_bd_size = %d\n", pmadapter->pcard_pcie->txrx_bd_size); PRINTM(MERROR, "Tx pkt size:\n"); for (i = 0; i < pmadapter->pcard_pcie->txrx_bd_size; i++) { PRINTM(MERROR, "%04d ", pmadapter->pcard_pcie->last_tx_pkt_size[i]); if (((i + 1) % 16) == 0) PRINTM(MERROR, "\n"); } } #endif for (i = 0; i < pmadapter->priv_num; ++i) { if (pmadapter->priv[i]) wlan_dump_ralist(pmadapter->priv[i]); } if (reason != REASON_CODE_CMD_TIMEOUT) { if ((pmadapter->dbg.num_no_cmd_node >= 5) || (pmadapter->pm_wakeup_card_req && pmadapter->pm_wakeup_fw_try) || (reason == REASON_CODE_EXT_SCAN_TIMEOUT)) { if (pmpriv) wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL); else { pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); if (pmpriv) wlan_recv_event( pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL); } } } PRINTM(MERROR, "-------- Dump info End---------\n", reason); LEAVE(); return; } /** * @brief This function convert a given character to hex * * @param chr Character to be converted * * @return The converted hex if chr is a valid hex, else 0 */ static t_u32 wlan_hexval(t_u8 chr) { if (chr >= '0' && chr <= '9') return chr - '0'; if (chr >= 'A' && chr <= 'F') return chr - 'A' + 10; if (chr >= 'a' && chr <= 'f') return chr - 'a' + 10; return 0; } /** * @brief This function convert a given string to hex * * @param a A pointer to string to be converted * * @return The converted hex value if param a is a valid hex, else * 0 */ static int wlan_atox(t_u8 *a) { int i = 0; ENTER(); while (wlan_isxdigit(*a)) i = i * 16 + wlan_hexval(*a++); LEAVE(); return i; } /** * @brief This function parse cal data from ASCII to hex * * @param src A pointer to source data * @param len Source data length * @param dst A pointer to a buf to store the parsed data * * @return The parsed hex data length */ static t_u32 wlan_parse_cal_cfg(t_u8 *src, t_size len, t_u8 *dst) { t_u8 *ptr; t_u8 *dptr; ENTER(); ptr = src; dptr = dst; while (ptr - src < len) { if (*ptr && (wlan_isspace(*ptr) || *ptr == '\t')) { ptr++; continue; } if (wlan_isxdigit(*ptr)) { *dptr++ = wlan_atox(ptr); ptr += 2; } else { ptr++; } } LEAVE(); return dptr - dst; } /** * @brief This function finds first occurrence of a char in a string * * @param s A pointer to the string to be searched * @param c The character to search for * * @return Location of the first occurrence of the char * if found, else NULL */ static t_u8 *wlan_strchr(t_u8 *s, int c) { t_u8 *pos = s; while (*pos != '\0') { if (*pos == (t_u8)c) return pos; pos++; } return MNULL; } #define CFG_TYPE_HOSTCMD 0 #define CFG_TYPE_DPDFILE 1 /** * @brief WOAL parse ASCII format raw data to hex format * * @param pmpriv MOAL handle * @param cfg_type Conf file type * @param data Source data * @param size data length * @return MLAN_STATUS_SUCCESS--success, otherwise--fail */ static t_u32 wlan_process_hostcmd_cfg(pmlan_private pmpriv, t_u16 cfg_type, t_u8 *data, t_size size) { mlan_status ret = MLAN_STATUS_SUCCESS; t_u8 *pos = data; t_u8 *intf_s, *intf_e; t_u8 *buf = MNULL; t_u8 *ptr = MNULL; t_u32 cmd_len = 0; t_u8 start_raw = MFALSE; mlan_ds_misc_cmd *hostcmd; HostCmd_DS_GEN *pcmd = MNULL; HostCmd_DS_802_11_CFG_DATA *pcfg_cmd = MNULL; mlan_adapter *pmadapter = MNULL; mlan_callbacks *pcb = MNULL; t_u8 hostcmd_flag = MFALSE; ENTER(); if (!pmpriv) { PRINTM(MERROR, "pmpriv is NULL\n"); LEAVE(); return MLAN_STATUS_FAILURE; } pmadapter = pmpriv->adapter; pcb = (mlan_callbacks *)&pmadapter->callbacks; ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_ds_misc_cmd), MLAN_MEM_DEF, (t_u8 **)&hostcmd); if (ret || !hostcmd) { PRINTM(MERROR, "Could not allocate buffer space!\n"); LEAVE(); return ret; } buf = hostcmd->cmd; ptr = buf; while ((pos - data) < size) { while (*pos == ' ' || *pos == '\t') pos++; if (*pos == '#') { /* Line comment */ while (*pos != '\n') pos++; pos++; } if ((*pos == '\r' && *(pos + 1) == '\n') || *pos == '\n' || *pos == '\0') { pos++; continue; /* Needn't process this line */ } if (*pos == '}') { if (cfg_type == CFG_TYPE_DPDFILE && pcmd) { /* Fill command head for DPD RAW data conf */ hostcmd->len = ptr - buf; pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_CFG_DATA); pcmd->size = wlan_cpu_to_le16(hostcmd->len); pcfg_cmd = (HostCmd_DS_802_11_CFG_DATA *)((t_u8 *)pcmd + S_DS_GEN); pcfg_cmd->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); pcfg_cmd->type = wlan_cpu_to_le16(OID_TYPE_DPD); pcfg_cmd->data_len = wlan_cpu_to_le16( hostcmd->len - S_DS_GEN - sizeof(HostCmd_DS_802_11_CFG_DATA)); pcmd = MNULL; pcfg_cmd = MNULL; } else { /* For hostcmd data conf */ cmd_len = *((t_u16 *)(buf + sizeof(t_u16))); hostcmd->len = cmd_len; } ret = wlan_prepare_cmd(pmpriv, 0, 0, 0, MNULL, (t_void *)hostcmd); memset(pmadapter, buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); ptr = buf; start_raw = MFALSE; pos++; continue; } if (start_raw == MFALSE) { intf_s = wlan_strchr(pos, '='); if (intf_s) { if (*(intf_s + 1) == '=') hostcmd_flag = MTRUE; intf_e = wlan_strchr(intf_s, '{'); } else intf_e = MNULL; if (intf_s && intf_e) { start_raw = MTRUE; pos = intf_e + 1; /* Reserve command head for DPD RAW data conf */ if (cfg_type == CFG_TYPE_DPDFILE && !hostcmd_flag) { pcmd = (HostCmd_DS_GEN *)ptr; ptr += S_DS_GEN + sizeof(HostCmd_DS_802_11_CFG_DATA); } continue; } } if (start_raw) { /* Raw data block exists */ while (*pos != '\n') { if ((*pos <= 'f' && *pos >= 'a') || (*pos <= 'F' && *pos >= 'A') || (*pos <= '9' && *pos >= '0')) { *ptr++ = wlan_atox(pos); pos += 2; } else pos++; } } } pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)hostcmd); LEAVE(); return ret; } /** * @brief This function initializes the command node. * * @param pmpriv A pointer to mlan_private structure * @param pcmd_node A pointer to cmd_ctrl_node structure * @param cmd_no cmd id * @param pioctl_buf A pointer to MLAN IOCTL Request buffer * @param pdata_buf A pointer to information buffer * * @return N/A */ static void wlan_init_cmd_node(pmlan_private pmpriv, cmd_ctrl_node *pcmd_node, t_u32 cmd_no, t_void *pioctl_buf, t_void *pdata_buf) { mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); if (pcmd_node == MNULL) { LEAVE(); return; } pcmd_node->priv = pmpriv; pcmd_node->cmd_no = cmd_no; pcmd_node->pioctl_buf = pioctl_buf; pcmd_node->pdata_buf = pdata_buf; #ifdef USB if (IS_USB(pmadapter->card_type)) { pcmd_node->cmdbuf = wlan_alloc_mlan_buffer(pmadapter, MRVDRV_SIZE_OF_CMD_BUFFER, 0, MOAL_MALLOC_BUFFER); if (!pcmd_node->cmdbuf) { PRINTM(MERROR, "Failed to allocate cmd_buffer\n"); LEAVE(); return; } } #endif /* USB */ #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) pcmd_node->cmdbuf = pcmd_node->pmbuf; #endif /* Make sure head_ptr for cmd buf is Align */ pcmd_node->cmdbuf->data_offset = 0; memset(pmadapter, pcmd_node->cmdbuf->pbuf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); /* Prepare mlan_buffer for command sending */ pcmd_node->cmdbuf->buf_type = MLAN_BUF_TYPE_CMD; #ifdef USB if (IS_USB(pmadapter->card_type)) pcmd_node->cmdbuf->data_offset += MLAN_TYPE_LEN; #endif #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) pcmd_node->cmdbuf->data_offset += pmadapter->ops.intf_header_len; #endif LEAVE(); } /** * @brief This function gets a free command node if available in * command free queue. * * @param pmadapter A pointer to mlan_adapter structure * * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or MNULL */ static cmd_ctrl_node *wlan_get_cmd_node(mlan_adapter *pmadapter) { cmd_ctrl_node *pcmd_node; ENTER(); if (pmadapter == MNULL) { LEAVE(); return MNULL; } wlan_request_cmd_lock(pmadapter); if (util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_free_q, MNULL, MNULL)) { pcmd_node = (cmd_ctrl_node *)util_dequeue_list( pmadapter->pmoal_handle, &pmadapter->cmd_free_q, MNULL, MNULL); } else { PRINTM(MERROR, "GET_CMD_NODE: cmd_ctrl_node is not available\n"); pcmd_node = MNULL; } wlan_release_cmd_lock(pmadapter); LEAVE(); return pcmd_node; } /** * @brief This function cleans command node. * * @param pmadapter A pointer to mlan_adapter structure * @param pcmd_node A pointer to cmd_ctrl_node structure * * @return N/A */ static t_void wlan_clean_cmd_node(pmlan_adapter pmadapter, cmd_ctrl_node *pcmd_node) { ENTER(); if (pcmd_node == MNULL) { LEAVE(); return; } pcmd_node->cmd_no = 0; pcmd_node->cmd_flag = 0; pcmd_node->pioctl_buf = MNULL; pcmd_node->pdata_buf = MNULL; #ifdef USB if (IS_USB(pmadapter->card_type) && pcmd_node->cmdbuf) { wlan_free_mlan_buffer(pmadapter, pcmd_node->cmdbuf); pcmd_node->cmdbuf = MNULL; } #endif if (pcmd_node->respbuf) { pmadapter->ops.cmdrsp_complete(pmadapter, pcmd_node->respbuf, MLAN_STATUS_SUCCESS); pcmd_node->respbuf = MNULL; } LEAVE(); return; } #ifdef STA_SUPPORT /** * @brief This function will return the pointer to the first entry in * pending cmd which is scan command * * @param pmadapter A pointer to mlan_adapter * * @return A pointer to first entry match pioctl_req */ static cmd_ctrl_node *wlan_get_pending_scan_cmd(pmlan_adapter pmadapter) { cmd_ctrl_node *pcmd_node = MNULL; ENTER(); pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, MNULL, MNULL); if (!pcmd_node) { LEAVE(); return MNULL; } while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) { if (pcmd_node->cmd_flag & CMD_F_SCAN) { LEAVE(); return pcmd_node; } pcmd_node = pcmd_node->pnext; } LEAVE(); return MNULL; } #endif /** * @brief This function will return the pointer to the first entry in * pending cmd which matches the given pioctl_req * * @param pmadapter A pointer to mlan_adapter * @param pioctl_req A pointer to mlan_ioctl_req buf * * @return A pointer to first entry match pioctl_req */ static cmd_ctrl_node *wlan_get_pending_ioctl_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) { cmd_ctrl_node *pcmd_node = MNULL; ENTER(); pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, MNULL, MNULL); if (!pcmd_node) { LEAVE(); return MNULL; } while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) { if (pcmd_node->pioctl_buf && (pcmd_node->pioctl_buf == pioctl_req)) { LEAVE(); return pcmd_node; } pcmd_node = pcmd_node->pnext; } LEAVE(); return MNULL; } /** * @brief This function will return the pointer to the first entry in * pending cmd which matches the given bss_index * * @param pmadapter A pointer to mlan_adapter * @param bss_index bss_index * * @return A pointer to first entry match pioctl_req */ static cmd_ctrl_node *wlan_get_bss_pending_ioctl_cmd(pmlan_adapter pmadapter, t_u32 bss_index) { cmd_ctrl_node *pcmd_node = MNULL; mlan_ioctl_req *pioctl_buf = MNULL; ENTER(); pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, MNULL, MNULL); if (!pcmd_node) { LEAVE(); return MNULL; } while (pcmd_node != (cmd_ctrl_node *)&pmadapter->cmd_pending_q) { if (pcmd_node->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; if (pioctl_buf->bss_index == bss_index) { LEAVE(); return pcmd_node; } } pcmd_node = pcmd_node->pnext; } LEAVE(); return MNULL; } /** * @brief This function handles the command response of host_cmd * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ static mlan_status wlan_ret_host_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc; t_u16 size = wlan_le16_to_cpu(resp->size); ENTER(); PRINTM(MINFO, "host command response size = %d\n", size); size = MIN(size, MRVDRV_SIZE_OF_CMD_BUFFER); if (pioctl_buf) { misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc->param.hostcmd.len = size; memcpy_ext(pmpriv->adapter, misc->param.hostcmd.cmd, (void *)resp, size, MRVDRV_SIZE_OF_CMD_BUFFER); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function sends host command to firmware. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param pdata_buf A pointer to data buffer * @param cmd_no A pointer to cmd_no * @return MLAN_STATUS_SUCCESS */ static mlan_status wlan_cmd_host_cmd(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_void *pdata_buf, t_u16 *cmd_no) { mlan_ds_misc_cmd *pcmd_ptr = (mlan_ds_misc_cmd *)pdata_buf; ENTER(); /* Copy the HOST command to command buffer */ memcpy_ext(pmpriv->adapter, (void *)cmd, pcmd_ptr->cmd, pcmd_ptr->len, MRVDRV_SIZE_OF_CMD_BUFFER); *cmd_no = wlan_le16_to_cpu(cmd->command); PRINTM(MCMND, "Prepare Host command: 0x%x size = %d\n", *cmd_no, pcmd_ptr->len); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function get the cmd timeout value * * @param cmd_id cmd id * * @return timeout value for this command */ static t_u32 wlan_get_cmd_timeout(t_u16 cmd_id) { t_u32 timeout; ENTER(); switch (cmd_id) { case HostCmd_CMD_802_11_SCAN: case HostCmd_CMD_802_11_SCAN_EXT: timeout = MRVDRV_TIMER_10S * 2; break; case HostCmd_CMD_FUNC_INIT: case HostCmd_CMD_FUNC_SHUTDOWN: case HostCmd_CMD_802_11_ASSOCIATE: case HostCmd_CMD_802_11_DEAUTHENTICATE: case HostCmd_CMD_802_11_DISASSOCIATE: case HostCmd_CMD_802_11_AD_HOC_START: case HostCmd_CMD_802_11_AD_HOC_JOIN: case HostCmd_CMD_802_11_AD_HOC_STOP: case HostCmd_CMD_11N_ADDBA_REQ: case HostCmd_CMD_11N_ADDBA_RSP: case HostCmd_CMD_11N_DELBA: case HostCmd_CMD_802_11_REMAIN_ON_CHANNEL: case HostCmd_CMD_TDLS_CONFIG: case HostCmd_CMD_TDLS_OPERATION: case HostCmd_CMD_SUPPLICANT_PMK: case HostCmd_CMD_SUPPLICANT_PROFILE: case HostCmd_CMD_SOFT_RESET: #ifdef UAP_SUPPORT case HostCmd_CMD_APCMD_SYS_RESET: case HostCmd_CMD_APCMD_BSS_START: case HostCmd_CMD_APCMD_BSS_STOP: case HostCmd_CMD_APCMD_STA_DEAUTH: #endif case HostCmd_CMD_APCMD_ACS_SCAN: timeout = MRVDRV_TIMER_5S; break; default: #ifdef IMX_SUPPORT /* * During the roaming test and the 5AP connection test, cmd * timeout are observed for commands like 0x5e, 0x16, 0xd1. * Observed that response has come just after default timeout of * 2 seconds for these commands. This random timeout is not * observed when the default timeout is increased to 5 seconds * (As an work around, Increase the default timeout to 5 * seconds. Need to further debug exact reason for delay in cmd * responses) * */ timeout = MRVDRV_TIMER_1S * 5; #else timeout = MRVDRV_TIMER_1S * 5; #endif break; } LEAVE(); return timeout; } /** * @brief This function downloads a command to firmware. * * @param pmpriv A pointer to mlan_private structure * @param pcmd_node A pointer to cmd_ctrl_node structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status wlan_dnld_cmd_to_fw(mlan_private *pmpriv, cmd_ctrl_node *pcmd_node) { mlan_adapter *pmadapter = pmpriv->adapter; mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; mlan_status ret = MLAN_STATUS_SUCCESS; HostCmd_DS_COMMAND *pcmd; mlan_ioctl_req *pioctl_buf = MNULL; t_u16 cmd_code; t_u16 cmd_size; t_u32 age_ts_usec; #ifdef USB t_u32 tmp; #endif #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif t_u32 timeout = 0; ENTER(); if (pcmd_node) if (pcmd_node->pioctl_buf != MNULL) pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; if (!pmadapter || !pcmd_node) { if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL; ret = MLAN_STATUS_FAILURE; goto done; } pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); /* Sanity test */ if (pcmd == MNULL || pcmd->size == 0) { PRINTM(MERROR, "DNLD_CMD: pcmd is null or command size is zero, " "Not sending\n"); if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL; wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); wlan_release_cmd_lock(pmadapter); ret = MLAN_STATUS_FAILURE; goto done; } /* Set command sequence number */ pmadapter->seq_num++; pcmd->seq_num = wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO( pmadapter->seq_num, pcmd_node->priv->bss_num, pcmd_node->priv->bss_type)); cmd_code = wlan_le16_to_cpu(pcmd->command); pcmd_node->cmd_no = cmd_code; timeout = wlan_get_cmd_timeout(cmd_code); cmd_size = wlan_le16_to_cpu(pcmd->size); pcmd_node->cmdbuf->data_len = cmd_size; wlan_request_cmd_lock(pmadapter); pmadapter->curr_cmd = pcmd_node; wlan_release_cmd_lock(pmadapter); /* Save the last command id and action to debug log */ pmadapter->dbg.last_cmd_index = (pmadapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM; pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index] = cmd_code; pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index] = wlan_le16_to_cpu(*(t_u16 *)((t_u8 *)pcmd + S_DS_GEN)); pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &pmadapter->dnld_cmd_in_secs, &age_ts_usec); #ifdef USB if (IS_USB(pmadapter->card_type)) { /* Add extra header for USB */ if (pcmd_node->cmdbuf->data_offset < MLAN_TYPE_LEN) { PRINTM(MERROR, "DNLD_CMD: data_offset is too small=%d\n", pcmd_node->cmdbuf->data_offset); if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL; wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); pmadapter->curr_cmd = MNULL; wlan_release_cmd_lock(pmadapter); if (pmadapter->dbg.last_cmd_index) pmadapter->dbg.last_cmd_index--; else pmadapter->dbg.last_cmd_index = DBG_CMD_NUM - 1; ret = MLAN_STATUS_FAILURE; goto done; } tmp = wlan_cpu_to_le32(MLAN_USB_TYPE_CMD); memcpy_ext(pmadapter, (t_u8 *)pcmd - MLAN_TYPE_LEN, (t_u8 *)&tmp, MLAN_TYPE_LEN, MLAN_TYPE_LEN); pcmd_node->cmdbuf->data_offset -= MLAN_TYPE_LEN; pcmd_node->cmdbuf->data_len += MLAN_TYPE_LEN; } #endif if (pcmd->command == HostCmd_CMD_802_11_SCAN_EXT) pmadapter->scan_state |= wlan_get_ext_scan_state(pcmd); PRINTM_GET_SYS_TIME(MCMND, &sec, &usec); PRINTM_NETINTF(MCMND, pmpriv); PRINTM(MCMND, "DNLD_CMD (%lu.%06lu): %s [0x%x], act 0x%x, len %d, seqno 0x%x timeout %d\n", sec, usec, wlan_hostcmd_get_name(cmd_code), cmd_code, wlan_le16_to_cpu(*(t_u16 *)((t_u8 *)pcmd + S_DS_GEN)), cmd_size, wlan_le16_to_cpu(pcmd->seq_num), timeout); DBG_HEXDUMP(MCMD_D, "DNLD_CMD", (t_u8 *)pcmd, cmd_size); #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) { pcmd_node->cmdbuf->data_offset -= pmadapter->ops.intf_header_len; pcmd_node->cmdbuf->data_len += pmadapter->ops.intf_header_len; } #endif /* Send the command to lower layer */ ret = pmadapter->ops.host_to_card(pmpriv, MLAN_TYPE_CMD, pcmd_node->cmdbuf, MNULL); #ifdef USB if (IS_USB(pmadapter->card_type) && (ret == MLAN_STATUS_PENDING)) pcmd_node->cmdbuf = MNULL; #endif if (ret == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "DNLD_CMD: Host to Card Failed\n"); if (pcmd_node->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pioctl_buf->status_code = MLAN_ERROR_CMD_DNLD_FAIL; } wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd); pmadapter->curr_cmd = MNULL; wlan_release_cmd_lock(pmadapter); if (pmadapter->dbg.last_cmd_index) pmadapter->dbg.last_cmd_index--; else pmadapter->dbg.last_cmd_index = DBG_CMD_NUM - 1; pmadapter->dbg.num_cmd_host_to_card_failure++; wlan_dump_info(pmadapter, REASON_CODE_CMD_TO_CARD_FAILURE); ret = MLAN_STATUS_FAILURE; goto done; } /* Clear BSS_NO_BITS from HostCmd */ cmd_code &= HostCmd_CMD_ID_MASK; /* For the command who has no command response, we should return here */ if (cmd_code == HostCmd_CMD_FW_DUMP_EVENT || cmd_code == HostCmd_CMD_SOFT_RESET) { if (pcmd_node->pioctl_buf) { PRINTM(MMSG, "CMD(0x%x) has no cmd resp: free curr_cmd and do ioctl_complete\n", cmd_code); pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd); pmadapter->curr_cmd = MNULL; wlan_release_cmd_lock(pmadapter); } goto done; } /* Setup the timer after transmit command */ pcb->moal_start_timer(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_timer, MFALSE, timeout); pmadapter->cmd_timer_is_set = MTRUE; ret = MLAN_STATUS_SUCCESS; done: LEAVE(); return ret; } /** * @brief This function sends sleep confirm command to firmware. * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status wlan_dnld_sleep_confirm_cmd(mlan_adapter *pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; static t_u32 i; #if defined(SDIO) || defined(PCIE) t_u16 cmd_len = 0; #endif opt_sleep_confirm_buffer *sleep_cfm_buf = (opt_sleep_confirm_buffer *)(pmadapter->psleep_cfm->pbuf + pmadapter->psleep_cfm->data_offset); mlan_buffer *pmbuf = MNULL; mlan_private *pmpriv = MNULL; ENTER(); pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); if (!pmpriv) { LEAVE(); return MLAN_STATUS_FAILURE; } #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) { cmd_len = sizeof(OPT_Confirm_Sleep); pmbuf = pmadapter->psleep_cfm; } #endif pmadapter->seq_num++; sleep_cfm_buf->ps_cfm_sleep.seq_num = wlan_cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO( pmadapter->seq_num, pmpriv->bss_num, pmpriv->bss_type)); DBG_HEXDUMP(MCMD_D, "SLEEP_CFM", &sleep_cfm_buf->ps_cfm_sleep, sizeof(OPT_Confirm_Sleep)); /* Send sleep confirm command to firmware */ #ifdef USB if (IS_USB(pmadapter->card_type)) { pmbuf = wlan_alloc_mlan_buffer(pmadapter, sizeof(opt_sleep_confirm_buffer), 0, MOAL_MALLOC_BUFFER); if (!pmbuf) { PRINTM(MERROR, "Failed to allocate sleep confirm buffers\n"); LEAVE(); return MLAN_STATUS_FAILURE; } pmbuf->buf_type = MLAN_BUF_TYPE_CMD; pmbuf->data_len = pmadapter->psleep_cfm->data_len; memcpy_ext(pmadapter, pmbuf->pbuf + pmbuf->data_offset, pmadapter->psleep_cfm->pbuf + pmadapter->psleep_cfm->data_offset, pmadapter->psleep_cfm->data_len, pmbuf->data_len); } #endif /* USB */ #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) pmadapter->psleep_cfm->data_len = cmd_len + pmadapter->ops.intf_header_len; #endif if (pmbuf) ret = pmadapter->ops.host_to_card(pmpriv, MLAN_TYPE_CMD, pmbuf, MNULL); #ifdef USB if (IS_USB(pmadapter->card_type) && (ret != MLAN_STATUS_PENDING)) wlan_free_mlan_buffer(pmadapter, pmbuf); #endif if (ret == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "SLEEP_CFM: failed\n"); pmadapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++; goto done; } else { if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) pmadapter->ps_state = PS_STATE_SLEEP_CFM; #ifdef STA_SUPPORT if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) { if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl) { /* Response is not needed for sleep confirm * command */ pmadapter->ps_state = PS_STATE_SLEEP; } else { pmadapter->ps_state = PS_STATE_SLEEP_CFM; } if (!sleep_cfm_buf->ps_cfm_sleep.sleep_cfm.resp_ctrl && (pmadapter->is_hs_configured && !pmadapter->sleep_period.period)) { pmadapter->pm_wakeup_card_req = MTRUE; wlan_host_sleep_activated_event( wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA), MTRUE); } } #endif /* STA_SUPPORT */ #define NUM_SC_PER_LINE 16 if (++i % NUM_SC_PER_LINE == 0) { if (pmadapter->second_mac) PRINTM(MEVENT, "++\n"); else PRINTM(MEVENT, "+\n"); } else { if (pmadapter->second_mac) PRINTM(MEVENT, "++"); else PRINTM(MEVENT, "+"); } } done: LEAVE(); return ret; } /** * @brief Fetch bitmap rate index * * @param rate_scope A pointer to MrvlRateScope_t * * @return bitmap rate index */ static t_u16 wlan_get_bitmap_index(MrvlRateScope_t *rate_scope) { t_u16 index = 0; if (rate_scope != MNULL) { index += NELEMENTS(rate_scope->ht_mcs_rate_bitmap); index += NELEMENTS(rate_scope->vht_mcs_rate_bitmap); } return index; } /******************************************************** Global Functions ********************************************************/ /** * @brief Event handler * * @param priv A pointer to mlan_private structure * @param event_id Event ID * @param pmevent Event buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_recv_event(pmlan_private priv, mlan_event_id event_id, t_void *pmevent) { pmlan_callbacks pcb = MNULL; ENTER(); if (!priv) { LEAVE(); return MLAN_STATUS_FAILURE; } pcb = &priv->adapter->callbacks; if (pmevent) /* The caller has provided the event. */ pcb->moal_recv_event(priv->adapter->pmoal_handle, (pmlan_event)pmevent); else { mlan_event mevent; memset(priv->adapter, &mevent, 0, sizeof(mlan_event)); mevent.bss_index = priv->bss_index; mevent.event_id = event_id; mevent.event_len = 0; pcb->moal_recv_event(priv->adapter->pmoal_handle, &mevent); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function allocates the command buffer and links * it to command free queue. * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_alloc_cmd_buffer(mlan_adapter *pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; cmd_ctrl_node *pcmd_array = MNULL; t_u32 buf_size; t_u32 i; ENTER(); /* Allocate and initialize cmd_ctrl_node */ buf_size = sizeof(cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF | MLAN_MEM_DMA, (t_u8 **)&pcmd_array); if (ret != MLAN_STATUS_SUCCESS || !pcmd_array) { PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate pcmd_array\n"); ret = MLAN_STATUS_FAILURE; goto done; } pmadapter->cmd_pool = pcmd_array; #if defined(PCIE) || defined(SDIO) if (!IS_USB(pmadapter->card_type)) { /* Allocate and initialize command buffers */ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { pcmd_array[i].pmbuf = wlan_alloc_mlan_buffer( pmadapter, MRVDRV_SIZE_OF_CMD_BUFFER, 0, MOAL_MALLOC_BUFFER); if (!pcmd_array[i].pmbuf) { PRINTM(MERROR, "ALLOC_CMD_BUF: Failed to allocate command buffer\n"); ret = MLAN_STATUS_FAILURE; goto done; } } } #endif wlan_request_cmd_lock(pmadapter); for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) wlan_insert_cmd_to_free_q(pmadapter, &pcmd_array[i]); wlan_release_cmd_lock(pmadapter); ret = MLAN_STATUS_SUCCESS; done: LEAVE(); return ret; } /** * @brief This function frees the command buffer. * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_free_cmd_buffer(mlan_adapter *pmadapter) { mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; cmd_ctrl_node *pcmd_array; t_u32 i; ENTER(); /* Need to check if cmd pool is allocated or not */ if (pmadapter->cmd_pool == MNULL) { PRINTM(MINFO, "FREE_CMD_BUF: cmd_pool is Null\n"); goto done; } pcmd_array = pmadapter->cmd_pool; /* Release shared memory buffers */ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { #ifdef USB if (IS_USB(pmadapter->card_type) && pcmd_array[i].cmdbuf) { PRINTM(MINFO, "Free all the USB command buffer.\n"); wlan_free_mlan_buffer(pmadapter, pcmd_array[i].cmdbuf); pcmd_array[i].cmdbuf = MNULL; } #endif #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type) && pcmd_array[i].pmbuf) { PRINTM(MINFO, "Free all the command buffer.\n"); wlan_free_mlan_buffer(pmadapter, pcmd_array[i].pmbuf); pcmd_array[i].pmbuf = MNULL; } #endif if (pcmd_array[i].respbuf) { #ifdef USB if (IS_USB(pmadapter->card_type)) pmadapter->callbacks.moal_recv_complete( pmadapter->pmoal_handle, pcmd_array[i].respbuf, pmadapter->rx_cmd_ep, MLAN_STATUS_SUCCESS); #endif #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) wlan_free_mlan_buffer(pmadapter, pcmd_array[i].respbuf); #endif pcmd_array[i].respbuf = MNULL; } } /* Release cmd_ctrl_node */ if (pmadapter->cmd_pool) { PRINTM(MINFO, "Free command pool.\n"); pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter->cmd_pool); pmadapter->cmd_pool = MNULL; } done: LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles events generated by firmware * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_process_event(pmlan_adapter pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event; t_u32 eventcause = pmadapter->event_cause; #ifdef DEBUG_LEVEL1 t_u32 in_ts_sec = 0, in_ts_usec = 0; #endif ENTER(); /* Save the last event to debug log */ pmadapter->dbg.last_event_index = (pmadapter->dbg.last_event_index + 1) % DBG_CMD_NUM; pmadapter->dbg.last_event[pmadapter->dbg.last_event_index] = (t_u16)eventcause; if ((eventcause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) { priv = wlan_get_priv_by_id(pmadapter, EVENT_GET_BSS_NUM(eventcause), EVENT_GET_BSS_TYPE(eventcause)); if (priv && priv->bss_type != MLAN_BSS_TYPE_DFS) { if (wlan_11h_dfs_event_preprocessing(pmadapter) == MLAN_STATUS_SUCCESS) { memcpy_ext(pmadapter, (t_u8 *)&eventcause, pmbuf->pbuf + pmbuf->data_offset, sizeof(eventcause), sizeof(eventcause)); } else { priv = wlan_get_priv_by_id( pmadapter, EVENT_GET_BSS_NUM(eventcause), EVENT_GET_BSS_TYPE(eventcause)); if (priv) PRINTM_NETINTF(MEVENT, priv); PRINTM(MERROR, "Error processing DFS Event: %s [0x%x]\n", wlan_event_get_name(eventcause & EVENT_ID_MASK), eventcause); goto done; } } } /* Get BSS number and corresponding priv */ priv = wlan_get_priv_by_id(pmadapter, EVENT_GET_BSS_NUM(eventcause), EVENT_GET_BSS_TYPE(eventcause)); if (!priv) priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); if (!priv) { ret = MLAN_STATUS_FAILURE; goto done; } /* Clear BSS_NO_BITS from event */ eventcause &= EVENT_ID_MASK; pmadapter->event_cause = eventcause; if (pmbuf) { pmbuf->bss_index = priv->bss_index; memcpy_ext(pmadapter, pmbuf->pbuf + pmbuf->data_offset, (t_u8 *)&eventcause, sizeof(eventcause), sizeof(eventcause)); } if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE && eventcause != EVENT_FW_DUMP_INFO) { PRINTM_GET_SYS_TIME(MEVENT, &in_ts_sec, &in_ts_usec); PRINTM_NETINTF(MEVENT, priv); PRINTM(MEVENT, "%lu.%06lu : Event: %s [0x%x]\n", in_ts_sec, in_ts_usec, wlan_event_get_name(eventcause), eventcause); } ret = priv->ops.process_event(priv); done: pmadapter->ops.event_complete(pmadapter, pmbuf, MLAN_STATUS_SUCCESS); LEAVE(); return ret; } /** * @brief This function requests a lock on command queue. * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ t_void wlan_request_cmd_lock(mlan_adapter *pmadapter) { mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; ENTER(); /* Call MOAL spin lock callback function */ pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock); LEAVE(); return; } /** * @brief This function releases a lock on command queue. * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ t_void wlan_release_cmd_lock(mlan_adapter *pmadapter) { mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; ENTER(); /* Call MOAL spin unlock callback function */ pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_lock); LEAVE(); return; } /** * @brief This function prepare the command before sending to firmware. * * @param pmpriv A pointer to mlan_private structure * @param cmd_no Command number * @param cmd_action Command action: GET or SET * @param cmd_oid Cmd oid: treated as sub command * @param pioctl_buf A pointer to MLAN IOCTL Request buffer * @param pdata_buf A pointer to information buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_prepare_cmd(mlan_private *pmpriv, t_u16 cmd_no, t_u16 cmd_action, t_u32 cmd_oid, t_void *pioctl_buf, t_void *pdata_buf) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = MNULL; cmd_ctrl_node *pcmd_node = MNULL; HostCmd_DS_COMMAND *cmd_ptr = MNULL; pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf; ENTER(); if (!pmpriv) { LEAVE(); return MLAN_STATUS_FAILURE; } pmadapter = pmpriv->adapter; /* Sanity test */ if (!pmadapter || pmadapter->surprise_removed) { PRINTM(MERROR, "PREP_CMD: Card is Removed\n"); if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY; ret = MLAN_STATUS_FAILURE; goto done; } if (pmadapter->hw_status == WlanHardwareStatusReset) { if ((cmd_no != HostCmd_CMD_FUNC_INIT) #ifdef PCIE && (cmd_no != HostCmd_CMD_PCIE_HOST_BUF_DETAILS) #endif ) { PRINTM(MERROR, "PREP_CMD: FW is in reset state\n"); if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_FW_NOT_READY; ret = MLAN_STATUS_FAILURE; goto done; } } /* Get a new command node */ pcmd_node = wlan_get_cmd_node(pmadapter); if (pcmd_node == MNULL) { PRINTM(MERROR, "PREP_CMD: No free cmd node\n"); wlan_dump_info(pmadapter, REASON_CODE_NO_CMD_NODE); if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_NO_MEM; ret = MLAN_STATUS_FAILURE; goto done; } /** reset num no cmd node */ pmadapter->dbg.num_no_cmd_node = 0; /* Initialize the command node */ wlan_init_cmd_node(pmpriv, pcmd_node, cmd_no, pioctl_buf, pdata_buf); if (pcmd_node->cmdbuf == MNULL) { PRINTM(MERROR, "PREP_CMD: No free cmd buf\n"); if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_NO_MEM; ret = MLAN_STATUS_FAILURE; goto done; } cmd_ptr = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); cmd_ptr->command = cmd_no; cmd_ptr->result = 0; /* Prepare command */ if (cmd_no) ret = pmpriv->ops.prepare_cmd(pmpriv, cmd_no, cmd_action, cmd_oid, pioctl_buf, pdata_buf, cmd_ptr); else { ret = wlan_cmd_host_cmd(pmpriv, cmd_ptr, pdata_buf, &cmd_no); pcmd_node->cmd_flag |= CMD_F_HOSTCMD; } /* Return error, since the command preparation failed */ if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no); pcmd_node->pioctl_buf = MNULL; if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_CMD_DNLD_FAIL; wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); wlan_release_cmd_lock(pmadapter); ret = MLAN_STATUS_FAILURE; goto done; } wlan_request_cmd_lock(pmadapter); /* Send command */ #ifdef STA_SUPPORT if (cmd_no == HostCmd_CMD_802_11_SCAN || cmd_no == HostCmd_CMD_802_11_SCAN_EXT) { if (cmd_no == HostCmd_CMD_802_11_SCAN_EXT && pmadapter->ext_scan && pmadapter->ext_scan_enh && pmadapter->ext_scan_type == EXT_SCAN_ENHANCE && wlan_is_cancel_scan_cmd(cmd_ptr)) { wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MFALSE); } else wlan_queue_scan_cmd(pmpriv, pcmd_node); } else { #endif if ((cmd_no == HostCmd_CMD_802_11_HS_CFG_ENH) && (cmd_action == HostCmd_ACT_GEN_SET) && (pmadapter->hs_cfg.conditions == HOST_SLEEP_CFG_CANCEL)) wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MFALSE); else wlan_queue_cmd(pmpriv, pcmd_node, cmd_no); #ifdef STA_SUPPORT } #endif wlan_release_cmd_lock(pmadapter); done: LEAVE(); return ret; } /** * @brief This function inserts command node to cmd_free_q * after cleaning it. * * @param pmadapter A pointer to mlan_adapter structure * @param pcmd_node A pointer to cmd_ctrl_node structure * * @return N/A */ t_void wlan_insert_cmd_to_free_q(mlan_adapter *pmadapter, cmd_ctrl_node *pcmd_node) { mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; mlan_ioctl_req *pioctl_req = MNULL; ENTER(); if (pcmd_node == MNULL) goto done; if (pcmd_node->pioctl_buf) { pioctl_req = (mlan_ioctl_req *)pcmd_node->pioctl_buf; if (pioctl_req->status_code != MLAN_ERROR_NO_ERROR) pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req, MLAN_STATUS_FAILURE); else pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req, MLAN_STATUS_SUCCESS); } /* Clean the node */ wlan_clean_cmd_node(pmadapter, pcmd_node); /* Insert node into cmd_free_q */ util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->cmd_free_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); done: LEAVE(); } /** * @brief This function queues the command to cmd list. * * @param pmadapter A pointer to mlan_adapter structure * @param pcmd_node A pointer to cmd_ctrl_node structure * @param add_tail Specify if the cmd needs to be queued in the header or * tail * * @return N/A */ t_void wlan_insert_cmd_to_pending_q(mlan_adapter *pmadapter, cmd_ctrl_node *pcmd_node, t_u32 add_tail) { HostCmd_DS_COMMAND *pcmd = MNULL; t_u16 command; ENTER(); if (pcmd_node == MNULL) { PRINTM(MERROR, "QUEUE_CMD: pcmd_node is MNULL\n"); goto done; } pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); command = wlan_le16_to_cpu(pcmd->command); /* Exit_PS command needs to be queued in the header always. */ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) { HostCmd_DS_802_11_PS_MODE_ENH *pm = &pcmd->params.psmode_enh; if (wlan_le16_to_cpu(pm->action) == DIS_AUTO_PS) { if (pmadapter->ps_state != PS_STATE_AWAKE) add_tail = MFALSE; } } if (add_tail) { util_enqueue_list_tail(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); } else { util_enqueue_list_head(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); } PRINTM_NETINTF(MCMND, pcmd_node->priv); PRINTM(MCMND, "QUEUE_CMD: %s [0x%x] is queued\n", wlan_hostcmd_get_name(command), command); done: LEAVE(); return; } /** * @brief This function executes next command in command * pending queue. It will put firmware back to PS mode * if applicable. * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_exec_next_cmd(mlan_adapter *pmadapter) { mlan_private *priv = MNULL; cmd_ctrl_node *pcmd_node = MNULL; mlan_status ret = MLAN_STATUS_SUCCESS; HostCmd_DS_COMMAND *pcmd; ENTER(); /* Sanity test */ if (pmadapter == MNULL) { PRINTM(MERROR, "EXEC_NEXT_CMD: pmadapter is MNULL\n"); ret = MLAN_STATUS_FAILURE; goto done; } /* Check if already in processing */ if (pmadapter->curr_cmd) { PRINTM(MERROR, "EXEC_NEXT_CMD: there is command in processing!\n"); ret = MLAN_STATUS_FAILURE; goto done; } wlan_request_cmd_lock(pmadapter); /* Check if any command is pending */ pcmd_node = (cmd_ctrl_node *)util_peek_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, MNULL, MNULL); if (pcmd_node) { pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); priv = pcmd_node->priv; if (pmadapter->ps_state != PS_STATE_AWAKE) { PRINTM(MERROR, "Cannot send command in sleep state, this should not happen\n"); wlan_release_cmd_lock(pmadapter); goto done; } util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); wlan_release_cmd_lock(pmadapter); ret = wlan_dnld_cmd_to_fw(priv, pcmd_node); priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); /* Any command sent to the firmware when host is in sleep mode, * should de-configure host sleep */ /* We should skip the host sleep configuration command itself * though */ if (priv && (pcmd->command != wlan_cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) { if (pmadapter->hs_activated == MTRUE) { pmadapter->is_hs_configured = MFALSE; wlan_host_sleep_activated_event(priv, MFALSE); } } goto done; } else { wlan_release_cmd_lock(pmadapter); } ret = MLAN_STATUS_SUCCESS; done: LEAVE(); return ret; } /** * @brief This function handles the command error in pre_asleep state * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ void wlan_handle_cmd_error_in_pre_aleep(mlan_adapter *pmadapter, t_u16 cmd_no) { cmd_ctrl_node *pcmd_node = MNULL; ENTER(); PRINTM(MERROR, "CMD_RESP: 0x%x block in pre_asleep!\n", cmd_no); wlan_request_cmd_lock(pmadapter); pcmd_node = pmadapter->curr_cmd; pmadapter->curr_cmd = MNULL; if (pcmd_node) { #ifdef USB if (IS_USB(pmadapter->card_type)) { pcmd_node->cmdbuf->data_offset += MLAN_TYPE_LEN; pcmd_node->cmdbuf->data_len -= MLAN_TYPE_LEN; } #endif #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) { pcmd_node->cmdbuf->data_offset += pmadapter->ops.intf_header_len; pcmd_node->cmdbuf->data_len -= pmadapter->ops.intf_header_len; } #endif if (pcmd_node->respbuf) { pmadapter->ops.cmdrsp_complete(pmadapter, pcmd_node->respbuf, MLAN_STATUS_SUCCESS); pcmd_node->respbuf = MNULL; } wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node, MFALSE); } wlan_release_cmd_lock(pmadapter); LEAVE(); } /** * @brief This function handles the command response * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_process_cmdresp(mlan_adapter *pmadapter) { HostCmd_DS_COMMAND *resp = MNULL; mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); mlan_private *pmpriv_next = MNULL; mlan_status ret = MLAN_STATUS_SUCCESS; t_u16 orig_cmdresp_no; t_u16 cmdresp_no; t_u16 cmdresp_result; mlan_ioctl_req *pioctl_buf = MNULL; mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif t_u32 i; ENTER(); if (pmadapter->curr_cmd) if (pmadapter->curr_cmd->pioctl_buf != MNULL) { pioctl_buf = (mlan_ioctl_req *) pmadapter->curr_cmd->pioctl_buf; } if (!pmadapter->curr_cmd || !pmadapter->curr_cmd->respbuf) { resp = (HostCmd_DS_COMMAND *)pmadapter->upld_buf; resp->command = wlan_le16_to_cpu(resp->command); PRINTM(MERROR, "CMD_RESP: No curr_cmd, 0x%x\n", resp->command); if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL; ret = MLAN_STATUS_FAILURE; goto done; } DBG_HEXDUMP(MCMD_D, "CMD_RESP", pmadapter->curr_cmd->respbuf->pbuf + pmadapter->curr_cmd->respbuf->data_offset, pmadapter->curr_cmd->respbuf->data_len); resp = (HostCmd_DS_COMMAND *)(pmadapter->curr_cmd->respbuf->pbuf + pmadapter->curr_cmd->respbuf->data_offset); orig_cmdresp_no = wlan_le16_to_cpu(resp->command); cmdresp_no = (orig_cmdresp_no & HostCmd_CMD_ID_MASK); if (pmadapter->curr_cmd->cmd_no != cmdresp_no) { PRINTM(MERROR, "cmdresp error: cmd=0x%x cmd_resp=0x%x\n", pmadapter->curr_cmd->cmd_no, cmdresp_no); ret = MLAN_STATUS_FAILURE; goto done; } pmadapter->dnld_cmd_in_secs = 0; /* Now we got response from FW, cancel the command timer */ if (pmadapter->cmd_timer_is_set) { /* Cancel command timeout timer */ pcb->moal_stop_timer(pmadapter->pmoal_handle, pmadapter->pmlan_cmd_timer); /* Cancel command timeout timer */ pmadapter->cmd_timer_is_set = MFALSE; } pmadapter->num_cmd_timeout = 0; wlan_request_cmd_lock(pmadapter); if (pmadapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { cmd_ctrl_node *free_cmd = pmadapter->curr_cmd; pmadapter->curr_cmd = MNULL; PRINTM(MCMND, "CMD_RESP: 0x%x been canceled!\n", wlan_le16_to_cpu(resp->command)); if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; wlan_insert_cmd_to_free_q(pmadapter, free_cmd); wlan_release_cmd_lock(pmadapter); ret = MLAN_STATUS_FAILURE; goto done; } else { wlan_release_cmd_lock(pmadapter); } if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { /* Copy original response back to response buffer */ if (pmpriv) wlan_ret_host_cmd(pmpriv, resp, pioctl_buf); } resp->size = wlan_le16_to_cpu(resp->size); resp->seq_num = wlan_le16_to_cpu(resp->seq_num); resp->result = wlan_le16_to_cpu(resp->result); /* Get BSS number and corresponding priv */ pmpriv = wlan_get_priv_by_id(pmadapter, HostCmd_GET_BSS_NO(resp->seq_num), HostCmd_GET_BSS_TYPE(resp->seq_num)); if (!pmpriv) pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); /* Clear RET_BIT from HostCmd */ resp->command = (orig_cmdresp_no & HostCmd_CMD_ID_MASK); if (!pmpriv) { ret = MLAN_STATUS_FAILURE; goto done; } cmdresp_no = resp->command; cmdresp_result = resp->result; /* Save the last command response to debug log */ pmadapter->dbg.last_cmd_resp_index = (pmadapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM; pmadapter->dbg.last_cmd_resp_id[pmadapter->dbg.last_cmd_resp_index] = orig_cmdresp_no; PRINTM_GET_SYS_TIME(MCMND, &sec, &usec); PRINTM_NETINTF(MCMND, pmadapter->curr_cmd->priv); PRINTM(MCMND, "CMD_RESP (%lu.%06lu): %s [0x%x], result %d, len %d, seqno 0x%x\n", sec, usec, wlan_hostcmd_get_name(orig_cmdresp_no & ~HostCmd_RET_BIT), orig_cmdresp_no, cmdresp_result, resp->size, resp->seq_num); if (!(orig_cmdresp_no & HostCmd_RET_BIT)) { PRINTM(MERROR, "CMD_RESP: Invalid response to command!\n"); if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_FW_CMDRESP; wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd); pmadapter->curr_cmd = MNULL; wlan_release_cmd_lock(pmadapter); ret = MLAN_STATUS_FAILURE; goto done; } if (pmadapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { if (pmadapter->curr_cmd && cmdresp_result == HostCmd_RESULT_PRE_ASLEEP) { wlan_handle_cmd_error_in_pre_aleep(pmadapter, cmdresp_no); ret = MLAN_STATUS_FAILURE; goto done; } pmadapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD; if ((cmdresp_result == HostCmd_RESULT_OK) && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH)) ret = wlan_ret_802_11_hs_cfg(pmpriv, resp, pioctl_buf); } else { if (pmadapter->curr_cmd && cmdresp_result == HostCmd_RESULT_PRE_ASLEEP) { wlan_handle_cmd_error_in_pre_aleep(pmadapter, cmdresp_no); ret = MLAN_STATUS_FAILURE; goto done; } /* handle response */ ret = pmpriv->ops.process_cmdresp(pmpriv, cmdresp_no, resp, pioctl_buf); } /* Check init command response */ if (pmadapter->hw_status == WlanHardwareStatusInitializing || pmadapter->hw_status == WlanHardwareStatusGetHwSpec) { if (ret == MLAN_STATUS_FAILURE) { #if 0 //ignore command error for WARM RESET if (pmadapter->pwarm_reset_ioctl_req) { /* warm reset failure */ pmadapter->pwarm_reset_ioctl_req->status_code = MLAN_ERROR_CMD_RESP_FAIL; pcb->moal_ioctl_complete( pmadapter->pmoal_handle, pmadapter->pwarm_reset_ioctl_req, MLAN_STATUS_FAILURE); pmadapter->pwarm_reset_ioctl_req = MNULL; goto done; } #endif PRINTM(MERROR, "cmd 0x%02x failed during initialization\n", cmdresp_no); wlan_init_fw_complete(pmadapter); goto done; } #ifdef STA_SUPPORT #ifdef PCIE /* init adma write pointer */ if (IS_PCIE(pmadapter->card_type) && cmdresp_no == HostCmd_CMD_FUNC_SHUTDOWN && pmadapter->pwarm_reset_ioctl_req) { if (pmadapter->pcard_pcie->reg->use_adma) wlan_pcie_init_fw(pmadapter); } #endif #endif } wlan_request_cmd_lock(pmadapter); if (pmadapter->curr_cmd) { cmd_ctrl_node *free_cmd = pmadapter->curr_cmd; pioctl_buf = (mlan_ioctl_req *)pmadapter->curr_cmd->pioctl_buf; pmadapter->curr_cmd = MNULL; if (pioctl_buf && (ret == MLAN_STATUS_SUCCESS)) pioctl_buf->status_code = MLAN_ERROR_NO_ERROR; else if (pioctl_buf && (ret == MLAN_STATUS_FAILURE) && !pioctl_buf->status_code) pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL; /* Clean up and put current command back to cmd_free_q */ wlan_insert_cmd_to_free_q(pmadapter, free_cmd); } wlan_release_cmd_lock(pmadapter); if ((pmadapter->hw_status == WlanHardwareStatusInitializing) && (pmadapter->last_init_cmd == cmdresp_no)) { i = pmpriv->bss_index + 1; while (i < pmadapter->priv_num && (!(pmpriv_next = pmadapter->priv[i]) || pmpriv_next->bss_virtual || pmpriv_next->bss_type == MLAN_BSS_TYPE_DFS)) i++; if (!pmpriv_next || i >= pmadapter->priv_num) { #ifdef STA_SUPPORT if (pmadapter->pwarm_reset_ioctl_req) { for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]->curr_addr[0] == 0xff) memmove(pmadapter, pmadapter->priv[i] ->curr_addr, pmadapter->permanent_addr, MLAN_MAC_ADDR_LENGTH); } /* warm reset complete */ PRINTM(MMSG, "wlan: warm reset complete\n"); pmadapter->hw_status = WlanHardwareStatusReady; pcb->moal_ioctl_complete( pmadapter->pmoal_handle, pmadapter->pwarm_reset_ioctl_req, MLAN_STATUS_SUCCESS); pmadapter->pwarm_reset_ioctl_req = MNULL; goto done; } #endif pmadapter->hw_status = WlanHardwareStatusInitdone; } else { /* Issue init commands for the next interface */ ret = pmpriv_next->ops.init_cmd(pmpriv_next, MFALSE); } } else if ((pmadapter->hw_status == WlanHardwareStatusGetHwSpec) && (HostCmd_CMD_GET_HW_SPEC == cmdresp_no)) { pmadapter->hw_status = WlanHardwareStatusGetHwSpecdone; } done: LEAVE(); return ret; } /** * @brief This function handles the timeout of command sending. * It will re-send the same command again. * * @param function_context A pointer to function_context * @return N/A */ t_void wlan_cmd_timeout_func(t_void *function_context) { mlan_adapter *pmadapter = (mlan_adapter *)function_context; cmd_ctrl_node *pcmd_node = MNULL; mlan_ioctl_req *pioctl_buf = MNULL; #ifdef DEBUG_LEVEL1 t_u32 sec = 0, usec = 0; #endif #if defined(SDIO) || defined(PCIE) t_u8 i; #endif mlan_private *pmpriv = MNULL; ENTER(); pmadapter->cmd_timer_is_set = MFALSE; if (!pmadapter->curr_cmd) { if (pmadapter->ext_scan && pmadapter->ext_scan_enh && pmadapter->scan_processing) { PRINTM(MMSG, "Ext scan enh timeout\n"); pmadapter->ext_scan_timeout = MTRUE; wlan_dump_info(pmadapter, REASON_CODE_EXT_SCAN_TIMEOUT); goto exit; } PRINTM(MWARN, "CurCmd Empty\n"); goto exit; } pmadapter->num_cmd_timeout++; pcmd_node = pmadapter->curr_cmd; if (pcmd_node->pioctl_buf != MNULL) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pioctl_buf->status_code = MLAN_ERROR_CMD_TIMEOUT; } pmadapter->dbg.timeout_cmd_id = pmadapter->dbg.last_cmd_id[pmadapter->dbg.last_cmd_index]; pmadapter->dbg.timeout_cmd_act = pmadapter->dbg.last_cmd_act[pmadapter->dbg.last_cmd_index]; PRINTM_GET_SYS_TIME(MERROR, &sec, &usec); PRINTM(MERROR, "Timeout cmd id (%lu.%06lu) %s [0x%x], act = 0x%x\n", sec, usec, wlan_hostcmd_get_name(pmadapter->dbg.timeout_cmd_id), pmadapter->dbg.timeout_cmd_id, pmadapter->dbg.timeout_cmd_act); #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type) && pcmd_node->cmdbuf) { t_u8 *pcmd_buf; pcmd_buf = pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset + pmadapter->ops.intf_header_len; if ((pmadapter->ops.intf_header_len + 16) < pcmd_node->cmdbuf->data_len) { for (i = 0; i < 16; i++) PRINTM(MERROR, "%02x ", *pcmd_buf++); PRINTM(MERROR, "\n"); } } #endif #ifdef PCIE if (IS_PCIE(pmadapter->card_type)) pmadapter->ops.debug_dump(pmadapter); #endif pmpriv = pcmd_node->priv; if (pmpriv) PRINTM(MERROR, "BSS type = %d BSS role= %d\n", pmpriv->bss_type, pmpriv->bss_role); wlan_dump_info(pmadapter, REASON_CODE_CMD_TIMEOUT); if (pmadapter->hw_status == WlanHardwareStatusInitializing || pmadapter->hw_status == WlanHardwareStatusGetHwSpec) wlan_init_fw_complete(pmadapter); else { /* Signal MOAL to perform extra handling for debugging */ if (pmpriv) { wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL); } else { wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), MLAN_EVENT_ID_DRV_DBG_DUMP, MNULL); } } exit: LEAVE(); return; } #ifdef STA_SUPPORT /** * @brief Internal function used to flush the scan pending queue * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ t_void wlan_flush_scan_queue(pmlan_adapter pmadapter) { cmd_ctrl_node *pcmd_node = MNULL; mlan_ioctl_req *pioctl_buf = MNULL; HostCmd_DS_COMMAND *pcmd = MNULL; t_u16 cmd_no = 0; pmlan_callbacks pcb = &pmadapter->callbacks; ENTER(); wlan_request_cmd_lock(pmadapter); while ((pcmd_node = (cmd_ctrl_node *)util_peek_list( pmadapter->pmoal_handle, &pmadapter->scan_pending_q, MNULL, MNULL))) { util_unlink_list(pmadapter->pmoal_handle, &pmadapter->scan_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); pcmd = (HostCmd_DS_COMMAND *)(pcmd_node->cmdbuf->pbuf + pcmd_node->cmdbuf->data_offset); cmd_no = wlan_le16_to_cpu(pcmd->command); PRINTM(MCMND, "flush scan queue: cmd 0x%02x\n", cmd_no); if (pcmd_node->pioctl_buf && cmd_no != HostCmd_CMD_802_11_SCAN && cmd_no != HostCmd_CMD_802_11_SCAN_EXT) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pcmd_node->pioctl_buf = MNULL; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } pmadapter->scan_processing = MFALSE; wlan_release_cmd_lock(pmadapter); LEAVE(); } /** * @brief Cancel pending SCAN ioctl cmd. * * @param pmadapter A pointer to mlan_adapter * @param pioctl_req A pointer to pmlan_ioctl_req * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING */ mlan_status wlan_cancel_pending_scan_cmd(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) { pmlan_callbacks pcb = &pmadapter->callbacks; cmd_ctrl_node *pcmd_node = MNULL; mlan_ioctl_req *pioctl_buf = MNULL; pmlan_private priv = MNULL; mlan_status status = MLAN_STATUS_SUCCESS; ENTER(); PRINTM(MIOCTL, "Cancel scan command\n"); wlan_request_cmd_lock(pmadapter); /* IOCTL will be completed, avoid calling IOCTL complete again from * EVENT/CMDRESP */ if (pmadapter->pscan_ioctl_req) { pioctl_buf = pmadapter->pscan_ioctl_req; priv = pmadapter->priv[pioctl_buf->bss_index]; pmadapter->pscan_ioctl_req = MNULL; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } if (pmadapter->curr_cmd && pmadapter->curr_cmd->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pmadapter->curr_cmd->pioctl_buf; if (pioctl_buf->req_id == MLAN_IOCTL_SCAN) { PRINTM(MIOCTL, "wlan_cancel_scan: current command\n"); pcmd_node = pmadapter->curr_cmd; pcmd_node->pioctl_buf = MNULL; pcmd_node->cmd_flag |= CMD_F_CANCELED; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } } while ((pcmd_node = wlan_get_pending_scan_cmd(pmadapter)) != MNULL) { PRINTM(MIOCTL, "wlan_cancel_scan: find scan command in cmd_pending_q\n"); util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } wlan_release_cmd_lock(pmadapter); if (pmadapter->scan_processing && pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) { if (priv) { if (MLAN_STATUS_SUCCESS == wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN_EXT, HostCmd_ACT_GEN_SET, 0, pioctl_req, MNULL)) { wlan_recv_event( priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL); status = MLAN_STATUS_PENDING; } } } /* Cancel all pending scan command */ wlan_flush_scan_queue(pmadapter); LEAVE(); return status; } #endif /** * @brief Cancel all pending cmd. * * @param pmadapter A pointer to mlan_adapter * @param flag MTRUE/MFALSE * * @return N/A */ t_void wlan_cancel_all_pending_cmd(pmlan_adapter pmadapter, t_u8 flag) { cmd_ctrl_node *pcmd_node = MNULL; pmlan_callbacks pcb = &pmadapter->callbacks; mlan_ioctl_req *pioctl_buf = MNULL; #ifdef STA_SUPPORT pmlan_private priv = MNULL; #endif ENTER(); /* Cancel current cmd */ wlan_request_cmd_lock(pmadapter); #ifdef STA_SUPPORT /* IOCTL will be completed, avoid calling IOCTL complete again from * EVENT/CMDRESP */ if (pmadapter->pscan_ioctl_req) { pioctl_buf = pmadapter->pscan_ioctl_req; priv = pmadapter->priv[pioctl_buf->bss_index]; pmadapter->pscan_ioctl_req = MNULL; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } #endif if (pmadapter->curr_cmd) { pcmd_node = pmadapter->curr_cmd; if (pcmd_node->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pcmd_node->pioctl_buf = MNULL; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } if (flag) { pmadapter->curr_cmd = MNULL; wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } } /* Cancel all pending command */ while ((pcmd_node = (cmd_ctrl_node *)util_peek_list( pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, MNULL, MNULL))) { util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); if (pcmd_node->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); pcmd_node->pioctl_buf = MNULL; } wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } wlan_release_cmd_lock(pmadapter); /* Cancel all pending scan command */ wlan_flush_scan_queue(pmadapter); /* Cancel all pending command in scan_cmd_pending_q command */ wlan_flush_ext_cmd_pending_queue(pmadapter); LEAVE(); } /** * @brief Cancel specific bss's pending ioctl cmd. * * @param pmadapter A pointer to mlan_adapter * @param bss_index BSS index * * @return N/A */ t_void wlan_cancel_bss_pending_cmd(pmlan_adapter pmadapter, t_u32 bss_index) { pmlan_callbacks pcb = &pmadapter->callbacks; cmd_ctrl_node *pcmd_node = MNULL; mlan_ioctl_req *pioctl_buf = MNULL; #ifdef STA_SUPPORT t_u8 flash_scan = MFALSE; #endif #ifdef STA_SUPPORT pmlan_private priv = MNULL; #endif ENTER(); PRINTM(MIOCTL, "MOAL Cancel BSS IOCTL: bss_index=%d\n", (int)bss_index); wlan_request_cmd_lock(pmadapter); #ifdef STA_SUPPORT if (pmadapter->pscan_ioctl_req && (pmadapter->pscan_ioctl_req->bss_index == bss_index)) { /* IOCTL will be completed, avoid calling IOCTL complete again * from EVENT/CMDRESP */ flash_scan = MTRUE; pioctl_buf = pmadapter->pscan_ioctl_req; priv = pmadapter->priv[pioctl_buf->bss_index]; pmadapter->pscan_ioctl_req = MNULL; pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } #endif if (pmadapter->curr_cmd && pmadapter->curr_cmd->pioctl_buf) { pioctl_buf = (mlan_ioctl_req *)pmadapter->curr_cmd->pioctl_buf; if (pioctl_buf->bss_index == bss_index) { pcmd_node = pmadapter->curr_cmd; pcmd_node->pioctl_buf = MNULL; pcmd_node->cmd_flag |= CMD_F_CANCELED; #ifdef STA_SUPPORT if (pioctl_buf->req_id == MLAN_IOCTL_SCAN) flash_scan = MTRUE; #endif pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); } } while ((pcmd_node = wlan_get_bss_pending_ioctl_cmd( pmadapter, bss_index)) != MNULL) { util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); pioctl_buf = (mlan_ioctl_req *)pcmd_node->pioctl_buf; pcmd_node->pioctl_buf = MNULL; #ifdef STA_SUPPORT if (pioctl_buf->req_id == MLAN_IOCTL_SCAN) flash_scan = MTRUE; #endif pioctl_buf->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_buf, MLAN_STATUS_FAILURE); wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } wlan_release_cmd_lock(pmadapter); #ifdef STA_SUPPORT if (flash_scan) { if (pmadapter->scan_processing && pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) { if (priv) { if (MLAN_STATUS_FAILURE == wlan_prepare_cmd( priv, HostCmd_CMD_802_11_SCAN_EXT, HostCmd_ACT_GEN_SET, 0, MNULL, MNULL)) PRINTM(MERROR, "failed to prepare command"); wlan_recv_event( priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL); } } /* Cancel all pending scan command */ wlan_flush_scan_queue(pmadapter); } #endif LEAVE(); return; } /** * @brief Cancel pending ioctl cmd. * * @param pmadapter A pointer to mlan_adapter * @param pioctl_req A pointer to mlan_ioctl_req buf * * @return N/A */ t_void wlan_cancel_pending_ioctl(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req) { pmlan_callbacks pcb = &pmadapter->callbacks; cmd_ctrl_node *pcmd_node = MNULL; t_u8 find = MFALSE; #ifdef STA_SUPPORT pmlan_private priv = MNULL; #endif ENTER(); PRINTM(MIOCTL, "MOAL Cancel IOCTL: 0x%x sub_id=0x%x action=%d\n", pioctl_req->req_id, *((t_u32 *)pioctl_req->pbuf), (int)pioctl_req->action); wlan_request_cmd_lock(pmadapter); #ifdef STA_SUPPORT /* IOCTL will be completed, avoid calling IOCTL complete again from * EVENT/CMDRESP */ if (pmadapter->pscan_ioctl_req == pioctl_req) { priv = pmadapter->priv[pioctl_req->bss_index]; pmadapter->pscan_ioctl_req = MNULL; find = MTRUE; } #endif if ((pmadapter->curr_cmd) && (pmadapter->curr_cmd->pioctl_buf == pioctl_req)) { pcmd_node = pmadapter->curr_cmd; pcmd_node->pioctl_buf = MNULL; pcmd_node->cmd_flag |= CMD_F_CANCELED; find = MTRUE; } while ((pcmd_node = wlan_get_pending_ioctl_cmd(pmadapter, pioctl_req)) != MNULL) { util_unlink_list(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, (pmlan_linked_list)pcmd_node, MNULL, MNULL); pcmd_node->pioctl_buf = MNULL; find = MTRUE; wlan_insert_cmd_to_free_q(pmadapter, pcmd_node); } wlan_release_cmd_lock(pmadapter); #ifdef STA_SUPPORT if (pioctl_req->req_id == MLAN_IOCTL_SCAN) { if (pmadapter->scan_processing && pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) { if (priv) { if (MLAN_STATUS_FAILURE == wlan_prepare_cmd( priv, HostCmd_CMD_802_11_SCAN_EXT, HostCmd_ACT_GEN_SET, 0, MNULL, MNULL)) PRINTM(MERROR, "Failed to prepare command"); wlan_recv_event( priv, MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL); } } /* Cancel all pending scan command */ wlan_flush_scan_queue(pmadapter); } #endif if (find) { pioctl_req->status_code = MLAN_ERROR_CMD_CANCEL; pcb->moal_ioctl_complete(pmadapter->pmoal_handle, pioctl_req, MLAN_STATUS_FAILURE); } LEAVE(); return; } /** * @brief This function convert mlan_wifi_rate to wifi_rate. * * @param pmpriv A pointer to mlan_private structure * @param pmlan_rate A pointer to mlan_wifi_rate structure * @param prate A pointer to wifi_rate * * @return N/A */ t_void wlan_fill_hal_wifi_rate(pmlan_private pmpriv, mlan_wifi_rate *pmlan_rate, wifi_rate *prate) { t_u8 index = 0; t_u8 rate_info = 0; ENTER(); prate->preamble = pmlan_rate->preamble; prate->nss = pmlan_rate->nss; prate->bw = pmlan_rate->bw; prate->rateMcsIdx = pmlan_rate->rateMcsIdx; prate->reserved = 0; prate->bitrate = wlan_le32_to_cpu(pmlan_rate->bitrate); if (!prate->bitrate) { index = prate->rateMcsIdx; index |= prate->nss << 4; if (prate->preamble == WIFI_PREAMBLE_HT) rate_info = MLAN_RATE_FORMAT_HT; else if (prate->preamble == WIFI_PREAMBLE_VHT) rate_info = MLAN_RATE_FORMAT_VHT; else rate_info = MLAN_RATE_FORMAT_LG; rate_info |= prate->bw << 2; PRINTM(MCMND, "index=0x%x rate_info=0x%x\n", index, rate_info); /** For rateMcsIdx, OFDM/CCK rate code would be as per ieee std * in the units of 0.5mbps. HT/VHT it would be mcs index */ /** For bitrate, in 100kbps */ if (rate_info == MLAN_RATE_FORMAT_LG) prate->bitrate = prate->rateMcsIdx * 5; else prate->bitrate = wlan_index_to_data_rate(pmpriv->adapter, index, rate_info, 0) * 5; PRINTM(MCMND, "bitrate(in 100kbps)=%d\n", prate->bitrate); } LEAVE(); } /** * @brief This function prepares command of ftm config session params. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param cmd_oid OID: CONFIG or CANCEL * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_802_11_ftm_config_session_params(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u32 cmd_oid, t_void *pdata_buf) { HostCmd_DS_FTM_CONFIG_SESSION_PARAMS *ftm_config = &cmd->params.ftm_config; t_u8 *tlv = MNULL; mlan_rtt_config_params *rtt_params = MNULL; MrvlIEtypes_RTTRangeRequest_t *tlv_rtt_rr = MNULL; mlan_rtt_cancel_params *rtt_cancel = MNULL; MrvlIEtypes_RTTRangeCancel_t *tlv_rtt_rc = MNULL; t_u32 i = 0; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_FTM_CONFIG_SESSION_PARAMS); cmd->size = S_DS_GEN + sizeof(HostCmd_DS_FTM_CONFIG_SESSION_PARAMS); ftm_config->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); tlv = ftm_config->tlv_buffer; if (cmd_oid == OID_RTT_REQUEST) { rtt_params = (mlan_rtt_config_params *)pdata_buf; for (i = 0; i < rtt_params->rtt_config_num; i++) { tlv_rtt_rr = (MrvlIEtypes_RTTRangeRequest_t *)tlv; tlv_rtt_rr->header.type = wlan_cpu_to_le16(TLV_TYPE_RTT_RANGE_REQUEST); tlv_rtt_rr->header.len = wlan_cpu_to_le16((sizeof(*tlv_rtt_rr) - sizeof(MrvlIEtypesHeader_t))); memcpy_ext(pmpriv->adapter, tlv_rtt_rr->addr, rtt_params->rtt_config[i].addr, sizeof(rtt_params->rtt_config[i].addr), sizeof(tlv_rtt_rr->addr)); tlv_rtt_rr->type = rtt_params->rtt_config[i].type; tlv_rtt_rr->peer = rtt_params->rtt_config[i].peer; tlv_rtt_rr->channel = rtt_params->rtt_config[i].channel; tlv_rtt_rr->bandcfg = rtt_params->rtt_config[i].bandcfg; tlv_rtt_rr->burst_period = rtt_params->rtt_config[i].burst_period; tlv_rtt_rr->num_burst = rtt_params->rtt_config[i].num_burst; tlv_rtt_rr->num_frames_per_burst = rtt_params->rtt_config[i].num_frames_per_burst; tlv_rtt_rr->num_retries_per_rtt_frame = rtt_params->rtt_config[i] .num_retries_per_rtt_frame; tlv_rtt_rr->num_retries_per_ftmr = rtt_params->rtt_config[i].num_retries_per_ftmr; tlv_rtt_rr->LCI_request = rtt_params->rtt_config[i].LCI_request; tlv_rtt_rr->LCR_request = rtt_params->rtt_config[i].LCR_request; tlv_rtt_rr->burst_duration = rtt_params->rtt_config[i].burst_duration; tlv_rtt_rr->preamble = rtt_params->rtt_config[i].preamble; tlv_rtt_rr->bw = rtt_params->rtt_config[i].bw; cmd->size += sizeof(*tlv_rtt_rr); tlv += sizeof(*tlv_rtt_rr); } } else if (cmd_oid == OID_RTT_CANCEL) { rtt_cancel = (mlan_rtt_cancel_params *)pdata_buf; for (i = 0; i < rtt_cancel->rtt_cancel_num; i++) { tlv_rtt_rc = (MrvlIEtypes_RTTRangeCancel_t *)tlv; tlv_rtt_rc->header.type = wlan_cpu_to_le16(TLV_TYPE_RTT_RANGE_CANCEL); tlv_rtt_rc->header.len = wlan_cpu_to_le16(sizeof(*tlv_rtt_rc) - sizeof(MrvlIEtypesHeader_t)); memcpy_ext(pmpriv->adapter, tlv_rtt_rc->addr, rtt_cancel->rtt_cancel[i], sizeof(rtt_cancel->rtt_cancel[i]), sizeof(tlv_rtt_rc->addr)); cmd->size += sizeof(*tlv_rtt_rc); tlv += sizeof(*tlv_rtt_rc); } } else { LEAVE(); return MLAN_STATUS_FAILURE; } cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of ftm config session * params. * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_ftm_config_session_params(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { ENTER(); PRINTM(MCMND, "ftm config successfully\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function transform Event_WLS_FTM_t to wifi_rtt_result in * mlan_event. * * @param pmpriv A pointer to mlan_private structure * @param event_ftm A pointer to Event_WLS_FTM_t * @param event_ftm_len length of event_ftm * @param pevent A pointer to mlan_event * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_fill_hal_rtt_results(pmlan_private pmpriv, Event_WLS_FTM_t *event_ftm, t_u32 event_ftm_len, mlan_event *pevent) { /** For input buffer Event_WLS_FTM_t */ t_u8 *tlv = event_ftm->u.rtt_results.tlv_buffer; int event_left_len = event_ftm_len - (tlv - (t_u8 *)event_ftm); MrvlIEtypes_RTTResult_t *tlv_rtt_result = MNULL; t_u16 tlv_rtt_result_len = 0; IEEEtypes_Header_t *tlv_ie = MNULL; int tlv_ie_len = 0; int tlv_left_len = 0; t_u8 *tlv_pos = MNULL; /** For output buffer mlan_event */ t_u8 *pos = pevent->event_buf; wifi_rtt_result_element *rtt_result_elem = MNULL; wifi_rtt_result *rtt_result = MNULL; t_u32 i = 0; ENTER(); PRINTM(MCMND, "wlan_fill_hal_rtt_results event_ftm_len=%d event_left_len=%d event_ftm=%p tlv=%p\n", event_ftm_len, event_left_len, event_ftm, tlv); pevent->event_id = MLAN_EVENT_ID_DRV_RTT_RESULT; /** Event format for moal is: [complete(u8)] + [multiple number of rtt * result(len(u16) + body)] */ /** [complete(u8)] */ *pos = event_ftm->u.rtt_results.complete; pos += sizeof(event_ftm->u.rtt_results.complete); /** multiple number of rtt result(wifi_rtt_result_element) */ /** Fill rtt results, 1 tlv at least contain 1 MrvlIEtypes_RTTResult_t */ while (event_left_len >= sizeof(MrvlIEtypes_RTTResult_t)) { PRINTM(MCMND, "[%d] event_left_len=%d tlv=%p\n", i, event_left_len, tlv); tlv_rtt_result = (MrvlIEtypes_RTTResult_t *)tlv; tlv_rtt_result_len = wlan_le16_to_cpu(tlv_rtt_result->header.len); rtt_result_elem = (wifi_rtt_result_element *)pos; pos += sizeof(*rtt_result_elem); rtt_result = (wifi_rtt_result *)(rtt_result_elem->data); memcpy_ext(pmpriv->adapter, rtt_result->addr, tlv_rtt_result->addr, sizeof(tlv_rtt_result->addr), sizeof(rtt_result->addr)); rtt_result->burst_num = wlan_le32_to_cpu(tlv_rtt_result->burst_num); rtt_result->measurement_number = wlan_le32_to_cpu(tlv_rtt_result->measurement_number); rtt_result->success_number = wlan_le32_to_cpu(tlv_rtt_result->success_number); rtt_result->number_per_burst_peer = tlv_rtt_result->number_per_burst_peer; rtt_result->status = tlv_rtt_result->status; rtt_result->retry_after_duration = tlv_rtt_result->retry_after_duration; rtt_result->type = tlv_rtt_result->type; rtt_result->rssi = wlan_le32_to_cpu(tlv_rtt_result->rssi); rtt_result->rssi_spread = wlan_le32_to_cpu(tlv_rtt_result->rssi_spread); wlan_fill_hal_wifi_rate(pmpriv, &tlv_rtt_result->tx_rate, &rtt_result->tx_rate); wlan_fill_hal_wifi_rate(pmpriv, &tlv_rtt_result->rx_rate, &rtt_result->rx_rate); rtt_result->rtt = wlan_le64_to_cpu(tlv_rtt_result->rtt); rtt_result->rtt_sd = wlan_le64_to_cpu(tlv_rtt_result->rtt_sd); rtt_result->rtt_spread = wlan_le64_to_cpu(tlv_rtt_result->rtt_spread); rtt_result->distance_mm = wlan_le32_to_cpu(tlv_rtt_result->distance_mm); rtt_result->distance_sd_mm = wlan_le32_to_cpu(tlv_rtt_result->distance_sd_mm); rtt_result->distance_spread_mm = wlan_le32_to_cpu(tlv_rtt_result->distance_spread_mm); rtt_result->ts = wlan_le64_to_cpu(tlv_rtt_result->ts); rtt_result->burst_duration = wlan_le32_to_cpu(tlv_rtt_result->burst_duration); rtt_result->negotiated_burst_num = wlan_le32_to_cpu(tlv_rtt_result->negotiated_burst_num); pos += sizeof(*rtt_result); tlv_ie = (IEEEtypes_Header_t *)(tlv_rtt_result->tlv_buffer); tlv_pos = (t_u8 *)tlv_ie; tlv_left_len = tlv_rtt_result_len - (sizeof(*tlv_rtt_result) - sizeof(tlv_rtt_result->header)); PRINTM(MCMND, "tlv_ie=%p tlv_left_len=%d\n", tlv_ie, tlv_left_len); /** Get the standard IEEEIE: MEASUREMENT_REPORT for LCI/LCR*/ while ((tlv_left_len > 0) && (tlv_left_len > sizeof(*tlv_ie))) { tlv_ie_len = tlv_ie->len; PRINTM(MCMND, "[-] tlv_ie=%p tlv_ie_len=%d tlv_left_len=%d jump=%d\n", tlv_ie, tlv_ie_len, tlv_left_len, sizeof(*tlv_ie) + tlv_ie_len); if ((tlv_ie_len > 0) && (tlv_ie->element_id == MEASUREMENT_REPORT)) { PRINTM(MCMND, "LCI/LCR IE: id=%d len=%d\n", tlv_ie->element_id, tlv_ie->len); memcpy_ext(pmpriv->adapter, pos, (t_u8 *)tlv_ie, sizeof(*tlv_ie) + tlv_ie_len, sizeof(*tlv_ie) + tlv_ie_len); pos += sizeof(*tlv_ie) + tlv_ie_len; } tlv_left_len -= sizeof(*tlv_ie) + tlv_ie_len; tlv_pos += sizeof(*tlv_ie) + tlv_ie_len; tlv_ie = (IEEEtypes_Header_t *)tlv_pos; PRINTM(MCMND, "[+] tlv_ie=%p tlv_ie_len=%d tlv_left_len=%d \n", tlv_ie, tlv_ie_len, tlv_left_len); } rtt_result_elem->len = pos - rtt_result_elem->data; tlv += tlv_rtt_result_len + sizeof(tlv_rtt_result->header); event_left_len -= tlv_rtt_result_len + sizeof(tlv_rtt_result->header); i++; } /** event_len include the mlan_event header and payload */ pevent->event_len = pos - pevent->event_buf; PRINTM(MCMND, "pevent->event_len=%d \n", pevent->event_len); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of ftm config responder. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_802_11_ftm_config_responder(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u32 cmd_oid, t_void *pdata_buf) { mlan_rtt_responder *rtt_rsp_cfg = (mlan_rtt_responder *)pdata_buf; HostCmd_DS_FTM_CONFIG_RESPONDER *responder = &cmd->params.ftm_rtt_responder; t_u8 *tlv = responder->tlv_buffer; MrvlIEtypes_RTTResponderEnCfg_t *tlv_rsp_en = MNULL; MrvlIEtypes_RTTLCICfg_t *tlv_lci = MNULL; MrvlIEtypes_RTTLCRCfg_t *tlv_lcr = MNULL; mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_FTM_CONFIG_RESPONDER); cmd->size = S_DS_GEN + sizeof(HostCmd_DS_FTM_CONFIG_RESPONDER); switch (rtt_rsp_cfg->action) { case RTT_GET_RESPONDER_INFO: responder->action = wlan_cpu_to_le16(HostCmd_ACT_RTT_GET_RSP_INFO); break; case RTT_SET_RESPONDER_ENABLE: tlv_rsp_en = (MrvlIEtypes_RTTResponderEnCfg_t *)tlv; responder->action = wlan_cpu_to_le16(HostCmd_ACT_RTT_SET_RSP_EN); tlv_rsp_en->header.type = wlan_cpu_to_le16(TLV_TYPE_RTT_RESPONDER_EN_CFG); tlv_rsp_en->header.len = wlan_cpu_to_le16( sizeof(*tlv_rsp_en) - sizeof(MrvlIEtypesHeader_t)); tlv_rsp_en->channel = rtt_rsp_cfg->u.encfg.channel; tlv_rsp_en->bandcfg = rtt_rsp_cfg->u.encfg.bandcfg; tlv_rsp_en->max_duration_seconds = wlan_cpu_to_le32(rtt_rsp_cfg->u.encfg.max_dur_sec); cmd->size += sizeof(*tlv_rsp_en); break; case RTT_SET_RESPONDER_DISABLE: responder->action = wlan_cpu_to_le16(HostCmd_ACT_RTT_SET_RSP_DIS); break; case RTT_SET_RESPONDER_LCI: tlv_lci = (MrvlIEtypes_RTTLCICfg_t *)tlv; responder->action = wlan_cpu_to_le16(HostCmd_ACT_RTT_SET_RSP_LCI); tlv_lci->header.type = wlan_cpu_to_le16(TLV_TYPE_RTT_LCI_CFG); tlv_lci->header.len = wlan_cpu_to_le16( sizeof(*tlv_lci) - sizeof(MrvlIEtypesHeader_t)); tlv_lci->latitude = wlan_cpu_to_le64(rtt_rsp_cfg->u.lci.latitude); tlv_lci->longitude = wlan_cpu_to_le64(rtt_rsp_cfg->u.lci.longitude); tlv_lci->altitude = wlan_cpu_to_le32(rtt_rsp_cfg->u.lci.altitude); tlv_lci->latitude_unc = rtt_rsp_cfg->u.lci.latitude_unc; tlv_lci->longitude_unc = rtt_rsp_cfg->u.lci.longitude_unc; tlv_lci->altitude_unc = rtt_rsp_cfg->u.lci.altitude_unc; tlv_lci->motion_pattern = rtt_rsp_cfg->u.lci.motion_pattern; tlv_lci->floor = wlan_cpu_to_le32(rtt_rsp_cfg->u.lci.floor); tlv_lci->height_above_floor = wlan_cpu_to_le32(rtt_rsp_cfg->u.lci.height_above_floor); tlv_lci->height_unc = wlan_cpu_to_le32(rtt_rsp_cfg->u.lci.height_unc); cmd->size += sizeof(*tlv_lci); break; case RTT_SET_RESPONDER_LCR: tlv_lcr = (MrvlIEtypes_RTTLCRCfg_t *)tlv; responder->action = wlan_cpu_to_le16(HostCmd_ACT_RTT_SET_RSP_LCR); tlv_lcr->header.type = wlan_cpu_to_le16(TLV_TYPE_RTT_LCR_CFG); tlv_lcr->header.len = wlan_cpu_to_le16( sizeof(*tlv_lcr) - sizeof(MrvlIEtypesHeader_t)); memcpy_ext(pmpriv->adapter, tlv_lcr->country_code, rtt_rsp_cfg->u.lcr.country_code, sizeof(rtt_rsp_cfg->u.lcr.country_code), sizeof(tlv_lcr->country_code)); tlv_lcr->length = wlan_cpu_to_le32(rtt_rsp_cfg->u.lcr.length); memcpy_ext(pmpriv->adapter, tlv_lcr->civic_info, rtt_rsp_cfg->u.lcr.civic_info, sizeof(rtt_rsp_cfg->u.lcr.civic_info), sizeof(tlv_lcr->civic_info)); cmd->size += sizeof(*tlv_lcr); break; default: PRINTM(MERROR, "wlan_cmd_802_11_ftm_config_responder: action not found\n"); ret = MLAN_STATUS_FAILURE; goto done; break; } cmd->size = wlan_cpu_to_le16(cmd->size); done: LEAVE(); return ret; } /** * @brief This function handles the command response of ftm config responder * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_ftm_config_responder(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)(pioctl_buf->pbuf); mlan_rtt_responder *rtt_rsp_cfg = &(misc->param.rtt_rsp_cfg); HostCmd_DS_FTM_CONFIG_RESPONDER *responder = MNULL; t_u32 cmdrsp_len = wlan_le16_to_cpu(resp->size); int left_len = 0; t_u8 *tlv = MNULL; MrvlIEtypes_RTTResponderInfo_t *tlv_rsp_info = MNULL; ENTER(); PRINTM(MCMND, "ftm config responder successfully cmdrsp_len=%d\n", cmdrsp_len); if ((cmdrsp_len < S_DS_GEN) || (cmdrsp_len - S_DS_GEN < sizeof(HostCmd_DS_FTM_CONFIG_RESPONDER))) goto done; responder = &resp->params.ftm_rtt_responder; left_len = cmdrsp_len - (S_DS_GEN + sizeof(*responder)); PRINTM(MCMND, "left_len=%d\n", left_len); tlv = responder->tlv_buffer; while ((left_len > 0) && (left_len > sizeof(MrvlIEtypesHeader_t))) { PRINTM(MCMND, "left_len=%d tlv: type=0x%x len=%d\n", left_len, ((MrvlIEtypesHeader_t *)tlv)->type, ((MrvlIEtypesHeader_t *)tlv)->len); if (((MrvlIEtypesHeader_t *)tlv)->type == TLV_TYPE_RTT_RESPONDER_INFO) { if (((MrvlIEtypesHeader_t *)tlv)->len >= (sizeof(MrvlIEtypes_RTTResponderInfo_t) - sizeof(MrvlIEtypesHeader_t))) { tlv_rsp_info = (MrvlIEtypes_RTTResponderInfo_t *)tlv; PRINTM(MCMND, "rtt_rsp_cfg->action=0x%x\n", rtt_rsp_cfg->action); if (rtt_rsp_cfg->action == RTT_GET_RESPONDER_INFO || rtt_rsp_cfg->action == RTT_SET_RESPONDER_ENABLE) { rtt_rsp_cfg->u.info.channel = tlv_rsp_info->channel; rtt_rsp_cfg->u.info.bandcfg = tlv_rsp_info->bandcfg; rtt_rsp_cfg->u.info.preamble = tlv_rsp_info->preamble; PRINTM(MCMND, "set to rtt_rsp_cfg channel=%d bandcfg=%d %d %d %d preamble=%d\n", rtt_rsp_cfg->u.info.channel, rtt_rsp_cfg->u.info.bandcfg .chanBand, rtt_rsp_cfg->u.info.bandcfg .chanWidth, rtt_rsp_cfg->u.info.bandcfg .chan2Offset, rtt_rsp_cfg->u.info.bandcfg .chan2Offset, rtt_rsp_cfg->u.info.preamble); break; } } } left_len -= ((MrvlIEtypesHeader_t *)tlv)->len + sizeof(MrvlIEtypesHeader_t); tlv += ((MrvlIEtypesHeader_t *)tlv)->len + sizeof(MrvlIEtypesHeader_t); } done: LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief Handle the version_ext resp * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_ver_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_VERSION_EXT *ver_ext = &resp->params.verext; mlan_ds_get_info *info; ENTER(); if (pioctl_buf) { info = (mlan_ds_get_info *)pioctl_buf->pbuf; info->param.ver_ext.version_str_sel = ver_ext->version_str_sel; memcpy_ext(pmpriv->adapter, info->param.ver_ext.version_str, ver_ext->version_str, sizeof(char) * 128, sizeof(char) * MLAN_MAX_VER_STR_LEN); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief Handle the rx mgmt forward registration resp * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_rx_mgmt_ind(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc = MNULL; ENTER(); if (pioctl_buf) { misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc->param.mgmt_subtype_mask = wlan_le32_to_cpu( resp->params.rx_mgmt_ind.mgmt_subtype_mask); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function checks conditions and prepares to * send sleep confirm command to firmware if OK. * * @param pmadapter A pointer to mlan_adapter structure * * @return N/A */ t_void wlan_check_ps_cond(mlan_adapter *pmadapter) { ENTER(); if (!pmadapter->cmd_sent && !pmadapter->curr_cmd && !pmadapter->keep_wakeup && !wlan_is_tx_pending(pmadapter) && !pmadapter->event_cause && !IS_CARD_RX_RCVD(pmadapter)) { wlan_dnld_sleep_confirm_cmd(pmadapter); } else { PRINTM(MCMND, "Delay Sleep Confirm (%s%s%s%s)\n", (pmadapter->cmd_sent) ? "D" : "", (pmadapter->curr_cmd) ? "C" : "", (pmadapter->event_cause) ? "V" : "", (wlan_is_tx_pending(pmadapter)) ? "T" : "", (IS_CARD_RX_RCVD(pmadapter)) ? "R" : ""); } LEAVE(); } /** * @brief This function sends the HS_ACTIVATED event to the application * * @param priv A pointer to mlan_private structure * @param activated MTRUE if activated, MFALSE if de-activated * * @return N/A */ t_void wlan_host_sleep_activated_event(pmlan_private priv, t_u8 activated) { ENTER(); if (!priv) { LEAVE(); return; } if (activated) { if (priv->adapter->is_hs_configured) { priv->adapter->hs_activated = MTRUE; wlan_update_rxreorder_tbl(priv->adapter, MTRUE); PRINTM(MEVENT, "hs_activated\n"); wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_ACTIVATED, MNULL); } else PRINTM(MWARN, "hs_activated: HS not configured !!!\n"); } else { PRINTM(MEVENT, "hs_deactived\n"); priv->adapter->hs_activated = MFALSE; wlan_recv_event(priv, MLAN_EVENT_ID_DRV_HS_DEACTIVATED, MNULL); } LEAVE(); return; } /** * @brief This function sends the HS_WAKEUP event to the application * * @param priv A pointer to mlan_private structure * * @return N/A */ t_void wlan_host_sleep_wakeup_event(pmlan_private priv) { ENTER(); if (priv->adapter->is_hs_configured) wlan_recv_event(priv, MLAN_EVENT_ID_FW_HS_WAKEUP, MNULL); else PRINTM(MWARN, "hs_wakeup: Host Sleep not configured !!!\n"); LEAVE(); } /** * @brief This function handles the command response of hs_cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_hs_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { pmlan_adapter pmadapter = pmpriv->adapter; HostCmd_DS_802_11_HS_CFG_ENH *phs_cfg = &resp->params.opt_hs_cfg; ENTER(); phs_cfg->params.hs_config.conditions = wlan_le32_to_cpu(phs_cfg->params.hs_config.conditions); phs_cfg->action = wlan_le16_to_cpu(phs_cfg->action); PRINTM(MCMND, "CMD_RESP: HS_CFG cmd reply result=%#x," " action=0x%x conditions=0x%x gpio=0x%x gap=0x%x\n", resp->result, phs_cfg->action, phs_cfg->params.hs_config.conditions, phs_cfg->params.hs_config.gpio, phs_cfg->params.hs_config.gap); if ((phs_cfg->action == HS_ACTIVATE && !pmadapter->pcard_info->supp_ps_handshake) || pmadapter->pcard_info->supp_ps_handshake) { /* clean up curr_cmd to allow suspend */ if (pioctl_buf) pioctl_buf->status_code = MLAN_ERROR_NO_ERROR; /* Clean up and put current command back to cmd_free_q */ wlan_request_cmd_lock(pmadapter); wlan_insert_cmd_to_free_q(pmadapter, pmadapter->curr_cmd); pmadapter->curr_cmd = MNULL; wlan_release_cmd_lock(pmadapter); if (!pmadapter->pcard_info->supp_ps_handshake) { wlan_host_sleep_activated_event(pmpriv, MTRUE); goto done; } } if (phs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) { pmadapter->is_hs_configured = MTRUE; if (pmadapter->pcard_info->supp_ps_handshake) wlan_host_sleep_activated_event(pmpriv, MTRUE); } else { pmadapter->is_hs_configured = MFALSE; if (pmadapter->hs_activated) wlan_host_sleep_activated_event(pmpriv, MFALSE); } done: LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief Perform hs related activities on receiving the power up interrupt * * @param pmadapter A pointer to the adapter structure * @return N/A */ t_void wlan_process_hs_config(pmlan_adapter pmadapter) { ENTER(); PRINTM(MINFO, "Recevie interrupt/data in HS mode\n"); if (pmadapter->hs_cfg.gap == HOST_SLEEP_CFG_GAP_FF) pmadapter->ops.wakeup_card(pmadapter, MTRUE); LEAVE(); return; } /** * @brief Check sleep confirm command response and set the state to ASLEEP * * @param pmadapter A pointer to the adapter structure * @param pbuf A pointer to the command response buffer * @param upld_len Command response buffer length * @return N/A */ void wlan_process_sleep_confirm_resp(pmlan_adapter pmadapter, t_u8 *pbuf, t_u32 upld_len) { HostCmd_DS_COMMAND *cmd; pmlan_private pmpriv; ENTER(); if (!upld_len) { PRINTM(MERROR, "Command size is 0\n"); LEAVE(); return; } cmd = (HostCmd_DS_COMMAND *)pbuf; cmd->result = wlan_le16_to_cpu(cmd->result); cmd->command = wlan_le16_to_cpu(cmd->command); cmd->seq_num = wlan_le16_to_cpu(cmd->seq_num); pmpriv = wlan_get_priv_by_id(pmadapter, HostCmd_GET_BSS_NO(cmd->seq_num), HostCmd_GET_BSS_TYPE(cmd->seq_num)); /* Update sequence number */ cmd->seq_num = HostCmd_GET_SEQ_NO(cmd->seq_num); /* Clear RET_BIT from HostCmd */ cmd->command &= HostCmd_CMD_ID_MASK; if (!pmpriv) pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); if (cmd->command != HostCmd_CMD_802_11_PS_MODE_ENH) { PRINTM(MERROR, "Received unexpected response for command %x, result = %x\n", cmd->command, cmd->result); LEAVE(); return; } if (pmadapter->second_mac) PRINTM(MEVENT, "##\n"); else PRINTM(MEVENT, "#\n"); if (cmd->result != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "Sleep confirm command failed\n"); pmadapter->pm_wakeup_card_req = MFALSE; pmadapter->ps_state = PS_STATE_AWAKE; LEAVE(); return; } pmadapter->pm_wakeup_card_req = MTRUE; if (pmadapter->is_hs_configured) { wlan_host_sleep_activated_event( wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY), MTRUE); } pmadapter->ps_state = PS_STATE_SLEEP; LEAVE(); } /** * @brief This function prepares command of power mode * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param ps_bitmap PS bitmap * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_enh_power_mode(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u16 ps_bitmap, t_void *pdata_buf) { HostCmd_DS_802_11_PS_MODE_ENH *psmode_enh = &cmd->params.psmode_enh; t_u8 *tlv = MNULL; t_u16 cmd_size = 0; ENTER(); PRINTM(MCMND, "PS Command: action = 0x%x, bitmap = 0x%x\n", cmd_action, ps_bitmap); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); if (cmd_action == DIS_AUTO_PS) { psmode_enh->action = wlan_cpu_to_le16(DIS_AUTO_PS); psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap); cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE); } else if (cmd_action == GET_PS) { psmode_enh->action = wlan_cpu_to_le16(GET_PS); psmode_enh->params.ps_bitmap = wlan_cpu_to_le16(ps_bitmap); cmd->size = wlan_cpu_to_le16(S_DS_GEN + AUTO_PS_FIX_SIZE); } else if (cmd_action == EXT_PS_PARAM) { psmode_enh->action = wlan_cpu_to_le16(EXT_PS_PARAM); psmode_enh->params.ext_param.reserved = 0; cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(t_u16) + sizeof(ext_ps_param)); psmode_enh->params.ext_param.param.header.type = wlan_cpu_to_le16(TLV_TYPE_PS_EXT_PARAM); psmode_enh->params.ext_param.param.header.len = sizeof(t_u32); psmode_enh->params.ext_param.param.mode = wlan_cpu_to_le32(*((t_u32 *)pdata_buf)); } else if (cmd_action == EN_AUTO_PS) { psmode_enh->action = wlan_cpu_to_le16(EN_AUTO_PS); psmode_enh->params.auto_ps.ps_bitmap = wlan_cpu_to_le16(ps_bitmap); cmd_size = S_DS_GEN + AUTO_PS_FIX_SIZE; tlv = (t_u8 *)cmd + cmd_size; if (ps_bitmap & BITMAP_STA_PS) { pmlan_adapter pmadapter = pmpriv->adapter; MrvlIEtypes_ps_param_t *ps_tlv = (MrvlIEtypes_ps_param_t *)tlv; ps_param *ps_mode = &ps_tlv->param; ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PS_PARAM); ps_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_ps_param_t) - sizeof(MrvlIEtypesHeader_t)); cmd_size += sizeof(MrvlIEtypes_ps_param_t); tlv += sizeof(MrvlIEtypes_ps_param_t); ps_mode->null_pkt_interval = wlan_cpu_to_le16(pmadapter->null_pkt_interval); ps_mode->multiple_dtims = wlan_cpu_to_le16(pmadapter->multiple_dtim); ps_mode->bcn_miss_timeout = wlan_cpu_to_le16(pmadapter->bcn_miss_time_out); ps_mode->local_listen_interval = wlan_cpu_to_le16( pmadapter->local_listen_interval); ps_mode->delay_to_ps = wlan_cpu_to_le16(pmadapter->delay_to_ps); ps_mode->mode = wlan_cpu_to_le16(pmadapter->enhanced_ps_mode); } if (ps_bitmap & BITMAP_BCN_TMO) { MrvlIEtypes_bcn_timeout_t *bcn_tmo_tlv = (MrvlIEtypes_bcn_timeout_t *)tlv; mlan_ds_bcn_timeout *bcn_tmo = (mlan_ds_bcn_timeout *)pdata_buf; bcn_tmo_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_BCN_TIMEOUT); bcn_tmo_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_bcn_timeout_t) - sizeof(MrvlIEtypesHeader_t)); bcn_tmo_tlv->bcn_miss_tmo_window = wlan_cpu_to_le16(bcn_tmo->bcn_miss_tmo_window); bcn_tmo_tlv->bcn_miss_tmo_period = wlan_cpu_to_le16(bcn_tmo->bcn_miss_tmo_period); bcn_tmo_tlv->bcn_rq_tmo_window = wlan_cpu_to_le16(bcn_tmo->bcn_rq_tmo_window); bcn_tmo_tlv->bcn_rq_tmo_period = wlan_cpu_to_le16(bcn_tmo->bcn_rq_tmo_period); cmd_size += sizeof(MrvlIEtypes_bcn_timeout_t); tlv += sizeof(MrvlIEtypes_bcn_timeout_t); psmode_enh->params.auto_ps.ps_bitmap = wlan_cpu_to_le16( (ps_bitmap & (~BITMAP_BCN_TMO)) | BITMAP_STA_PS); } if (ps_bitmap & BITMAP_AUTO_DS) { MrvlIEtypes_auto_ds_param_t *auto_ps_tlv = (MrvlIEtypes_auto_ds_param_t *)tlv; auto_ds_param *auto_ds = &auto_ps_tlv->param; t_u16 idletime = 0; auto_ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM); auto_ps_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_auto_ds_param_t) - sizeof(MrvlIEtypesHeader_t)); cmd_size += sizeof(MrvlIEtypes_auto_ds_param_t); tlv += sizeof(MrvlIEtypes_auto_ds_param_t); if (pdata_buf) idletime = ((mlan_ds_auto_ds *)pdata_buf)->idletime; auto_ds->deep_sleep_timeout = wlan_cpu_to_le16(idletime); } #if defined(UAP_SUPPORT) if (pdata_buf && (ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS))) { mlan_ds_ps_mgmt *ps_mgmt = (mlan_ds_ps_mgmt *)pdata_buf; MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL; MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL; if (ps_mgmt->flags & PS_FLAG_SLEEP_PARAM) { sleep_tlv = (MrvlIEtypes_sleep_param_t *)tlv; sleep_tlv->header.type = wlan_cpu_to_le16( TLV_TYPE_AP_SLEEP_PARAM); sleep_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_sleep_param_t) - sizeof(MrvlIEtypesHeader_t)); sleep_tlv->ctrl_bitmap = wlan_cpu_to_le32( ps_mgmt->sleep_param.ctrl_bitmap); sleep_tlv->min_sleep = wlan_cpu_to_le32( ps_mgmt->sleep_param.min_sleep); sleep_tlv->max_sleep = wlan_cpu_to_le32( ps_mgmt->sleep_param.max_sleep); cmd_size += sizeof(MrvlIEtypes_sleep_param_t); tlv += sizeof(MrvlIEtypes_sleep_param_t); } if (ps_mgmt->flags & PS_FLAG_INACT_SLEEP_PARAM) { inact_tlv = (MrvlIEtypes_inact_sleep_param_t *)tlv; inact_tlv->header.type = wlan_cpu_to_le16( TLV_TYPE_AP_INACT_SLEEP_PARAM); inact_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_inact_sleep_param_t) - sizeof(MrvlIEtypesHeader_t)); inact_tlv->inactivity_to = wlan_cpu_to_le32( ps_mgmt->inact_param.inactivity_to); inact_tlv->min_awake = wlan_cpu_to_le32( ps_mgmt->inact_param.min_awake); inact_tlv->max_awake = wlan_cpu_to_le32( ps_mgmt->inact_param.max_awake); cmd_size += sizeof(MrvlIEtypes_inact_sleep_param_t); tlv += sizeof(MrvlIEtypes_inact_sleep_param_t); } } #endif cmd->size = wlan_cpu_to_le16(cmd_size); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of ps_mode_enh * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_enh_power_mode(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { pmlan_adapter pmadapter = pmpriv->adapter; MrvlIEtypesHeader_t *mrvl_tlv = MNULL; MrvlIEtypes_auto_ds_param_t *auto_ds_tlv = MNULL; HostCmd_DS_802_11_PS_MODE_ENH *ps_mode = &resp->params.psmode_enh; ENTER(); ps_mode->action = wlan_le16_to_cpu(ps_mode->action); PRINTM(MINFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", resp->result, ps_mode->action); if (ps_mode->action == EN_AUTO_PS) { ps_mode->params.auto_ps.ps_bitmap = wlan_le16_to_cpu(ps_mode->params.auto_ps.ps_bitmap); if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_AUTO_DS) { PRINTM(MCMND, "Enabled auto deep sleep\n"); pmpriv->adapter->is_deep_sleep = MTRUE; mrvl_tlv = (MrvlIEtypesHeader_t *)((t_u8 *)ps_mode + AUTO_PS_FIX_SIZE); while (wlan_le16_to_cpu(mrvl_tlv->type) != TLV_TYPE_AUTO_DS_PARAM) { mrvl_tlv = (MrvlIEtypesHeader_t *)((t_u8 *)mrvl_tlv + wlan_le16_to_cpu( mrvl_tlv->len) + sizeof(MrvlIEtypesHeader_t)); } auto_ds_tlv = (MrvlIEtypes_auto_ds_param_t *)mrvl_tlv; pmpriv->adapter->idle_time = wlan_le16_to_cpu( auto_ds_tlv->param.deep_sleep_timeout); } if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) { PRINTM(MCMND, "Enabled STA power save\n"); if (pmadapter->sleep_period.period) { PRINTM(MCMND, "Setting uapsd/pps mode to TRUE\n"); } } #if defined(UAP_SUPPORT) if (ps_mode->params.auto_ps.ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) { pmadapter->ps_mode = Wlan802_11PowerModePSP; PRINTM(MCMND, "Enabled uAP power save\n"); } #endif } else if (ps_mode->action == DIS_AUTO_PS) { ps_mode->params.ps_bitmap = wlan_cpu_to_le16(ps_mode->params.ps_bitmap); if (ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) { pmpriv->adapter->is_deep_sleep = MFALSE; PRINTM(MCMND, "Disabled auto deep sleep\n"); } if (ps_mode->params.ps_bitmap & BITMAP_STA_PS) { PRINTM(MCMND, "Disabled STA power save\n"); if (pmadapter->sleep_period.period) { pmadapter->delay_null_pkt = MFALSE; pmadapter->tx_lock_flag = MFALSE; pmadapter->pps_uapsd_mode = MFALSE; } } #if defined(UAP_SUPPORT) if (ps_mode->params.ps_bitmap & (BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) { pmadapter->ps_mode = Wlan802_11PowerModeCAM; PRINTM(MCMND, "Disabled uAP power save\n"); } #endif } else if (ps_mode->action == GET_PS) { ps_mode->params.ps_bitmap = wlan_le16_to_cpu(ps_mode->params.ps_bitmap); if (ps_mode->params.auto_ps.ps_bitmap & (BITMAP_STA_PS | BITMAP_UAP_INACT_PS | BITMAP_UAP_DTIM_PS)) pmadapter->ps_mode = Wlan802_11PowerModePSP; else pmadapter->ps_mode = Wlan802_11PowerModeCAM; PRINTM(MCMND, "ps_bitmap=0x%x\n", ps_mode->params.ps_bitmap); if (pioctl_buf) { mlan_ds_pm_cfg *pm_cfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf; if (pm_cfg->sub_command == MLAN_OID_PM_CFG_IEEE_PS) { if (ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) pm_cfg->param.ps_mode = 1; else pm_cfg->param.ps_mode = 0; } #if defined(UAP_SUPPORT) if (pm_cfg->sub_command == MLAN_OID_PM_CFG_PS_MODE) { MrvlIEtypes_sleep_param_t *sleep_tlv = MNULL; MrvlIEtypes_inact_sleep_param_t *inact_tlv = MNULL; MrvlIEtypesHeader_t *tlv = MNULL; t_u16 tlv_type = 0; t_u16 tlv_len = 0; t_u16 tlv_buf_left = 0; pm_cfg->param.ps_mgmt.flags = PS_FLAG_PS_MODE; if (ps_mode->params.ps_bitmap & BITMAP_UAP_INACT_PS) pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_INACTIVITY; else if (ps_mode->params.ps_bitmap & BITMAP_UAP_DTIM_PS) pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_PERIODIC_DTIM; else pm_cfg->param.ps_mgmt.ps_mode = PS_MODE_DISABLE; tlv_buf_left = resp->size - (S_DS_GEN + AUTO_PS_FIX_SIZE); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)ps_mode + AUTO_PS_FIX_SIZE); while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); switch (tlv_type) { case TLV_TYPE_AP_SLEEP_PARAM: sleep_tlv = (MrvlIEtypes_sleep_param_t *)tlv; pm_cfg->param.ps_mgmt.flags |= PS_FLAG_SLEEP_PARAM; pm_cfg->param.ps_mgmt .sleep_param .ctrl_bitmap = wlan_le32_to_cpu( sleep_tlv->ctrl_bitmap); pm_cfg->param.ps_mgmt .sleep_param .min_sleep = wlan_le32_to_cpu( sleep_tlv->min_sleep); pm_cfg->param.ps_mgmt .sleep_param .max_sleep = wlan_le32_to_cpu( sleep_tlv->max_sleep); break; case TLV_TYPE_AP_INACT_SLEEP_PARAM: inact_tlv = (MrvlIEtypes_inact_sleep_param_t *)tlv; pm_cfg->param.ps_mgmt.flags |= PS_FLAG_INACT_SLEEP_PARAM; pm_cfg->param.ps_mgmt .inact_param .inactivity_to = wlan_le32_to_cpu( inact_tlv->inactivity_to); pm_cfg->param.ps_mgmt .inact_param .min_awake = wlan_le32_to_cpu( inact_tlv->min_awake); pm_cfg->param.ps_mgmt .inact_param .max_awake = wlan_le32_to_cpu( inact_tlv->max_awake); break; } tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } } #endif } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of tx rate query * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_tx_rate_query(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_adapter *pmadapter = pmpriv->adapter; mlan_ds_rate *rate = MNULL; ENTER(); pmpriv->tx_rate = resp->params.tx_rate.tx_rate; pmpriv->tx_rate_info = resp->params.tx_rate.tx_rate_info; if (pmpriv->adapter->pcard_info->v14_fw_api) { pmpriv->tx_rate_info = wlan_convert_v14_tx_rate_info( pmpriv, pmpriv->tx_rate_info); PRINTM(MINFO, "%s: v14_fw_api=%d tx_rate=%d tx_rate_info=0x%x->0x%x\n", __func__, pmpriv->adapter->pcard_info->v14_fw_api, pmpriv->tx_rate, resp->params.tx_rate.tx_rate_info, pmpriv->tx_rate_info); } if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) pmpriv->ext_tx_rate_info = resp->params.tx_rate.ext_tx_rate_info; else pmpriv->ext_tx_rate_info = 0; if (!pmpriv->is_data_rate_auto) { pmpriv->data_rate = wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate, pmpriv->tx_rate_info, pmpriv->ext_tx_rate_info); } if (pioctl_buf) { rate = (mlan_ds_rate *)pioctl_buf->pbuf; if (rate->sub_command == MLAN_OID_RATE_CFG) { if (rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) { if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_VHT || ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE)) /* VHT rate */ rate->param.rate_cfg.rate = (pmpriv->tx_rate) & 0xF; else if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HT) /* HT rate */ rate->param.rate_cfg.rate = pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0; else /* LG rate */ /* For HostCmd_CMD_802_11_TX_RATE_QUERY, * there is a hole (0x4) in rate table * between HR/DSSS and OFDM rates, * so minus 1 for OFDM rate index */ rate->param.rate_cfg.rate = (pmpriv->tx_rate > MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate - 1 : pmpriv->tx_rate; } else { /* rate_type = MLAN_RATE_VALUE */ rate->param.rate_cfg.rate = wlan_index_to_data_rate( pmadapter, pmpriv->tx_rate, pmpriv->tx_rate_info, pmpriv->ext_tx_rate_info); } } else if (rate->sub_command == MLAN_OID_GET_DATA_RATE) { /* Tx rate info */ if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_VHT || (pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) { /* AX/VHT rate */ rate->param.data_rate.tx_rate_format = pmpriv->tx_rate_info & 0x3; rate->param.data_rate.tx_ht_bw = (pmpriv->tx_rate_info & 0xC) >> 2; if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) rate->param.data_rate.tx_ht_gi = (pmpriv->tx_rate_info & 0x10) >> 4 | (pmpriv->tx_rate_info & 0x80) >> 6; else rate->param.data_rate.tx_ht_gi = (pmpriv->tx_rate_info & 0x10) >> 4; rate->param.data_rate.tx_nss = ((pmpriv->tx_rate) >> 4) & 0x03; rate->param.data_rate.tx_mcs_index = (pmpriv->tx_rate) & 0xF; if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_VHT || (pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) rate->param.data_rate.tx_data_rate = wlan_index_to_data_rate( pmadapter, pmpriv->tx_rate, pmpriv->tx_rate_info, pmpriv->ext_tx_rate_info); } else if ((pmpriv->tx_rate_info & 0x3) == MLAN_RATE_FORMAT_HT) { /* HT rate */ rate->param.data_rate.tx_rate_format = MLAN_RATE_FORMAT_HT; rate->param.data_rate.tx_ht_bw = (pmpriv->tx_rate_info & 0xC) >> 2; rate->param.data_rate.tx_ht_gi = (pmpriv->tx_rate_info & 0x10) >> 4; rate->param.data_rate.tx_mcs_index = pmpriv->tx_rate; rate->param.data_rate.tx_data_rate = wlan_index_to_data_rate( pmadapter, pmpriv->tx_rate, pmpriv->tx_rate_info, pmpriv->ext_tx_rate_info); } else { /* LG rate */ rate->param.data_rate.tx_rate_format = MLAN_RATE_FORMAT_LG; /* For HostCmd_CMD_802_11_TX_RATE_QUERY, * there is a hole in rate table * between HR/DSSS and OFDM rates, * so minus 1 for OFDM rate index */ rate->param.data_rate.tx_data_rate = (pmpriv->tx_rate > MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate - 1 : pmpriv->tx_rate; } /* Rx rate info */ if ((pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_VHT || (pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) { /* VHT rate */ rate->param.data_rate.rx_rate_format = pmpriv->rxpd_rate_info & 0x3; rate->param.data_rate.rx_ht_bw = (pmpriv->rxpd_rate_info & 0xC) >> 2; if ((pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) rate->param.data_rate.rx_ht_gi = (pmpriv->rxpd_rate_info & 0x10) >> 4 | (pmpriv->rxpd_rate_info & 0x80) >> 6; else rate->param.data_rate.rx_ht_gi = (pmpriv->rxpd_rate_info & 0x10) >> 4; rate->param.data_rate.rx_nss = ((pmpriv->rxpd_rate) >> 4) & 0x3; rate->param.data_rate.rx_mcs_index = (pmpriv->rxpd_rate) & 0xF; if ((pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_VHT || (pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_HE) rate->param.data_rate.rx_data_rate = wlan_index_to_data_rate( pmadapter, pmpriv->rxpd_rate, pmpriv->rxpd_rate_info, pmpriv->rxpd_rx_info); } else if ((pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_HT) { /* HT rate */ rate->param.data_rate.rx_rate_format = MLAN_RATE_FORMAT_HT; rate->param.data_rate.rx_ht_bw = (pmpriv->rxpd_rate_info & 0xC) >> 2; rate->param.data_rate.rx_ht_gi = (pmpriv->rxpd_rate_info & 0x10) >> 4; rate->param.data_rate.rx_mcs_index = pmpriv->rxpd_rate; rate->param.data_rate.rx_data_rate = wlan_index_to_data_rate( pmadapter, pmpriv->rxpd_rate, pmpriv->rxpd_rate_info, 0); } else { /* LG rate */ rate->param.data_rate.rx_rate_format = MLAN_RATE_FORMAT_LG; /* For rate index in RxPD, * there is a hole in rate table * between HR/DSSS and OFDM rates, * so minus 1 for OFDM rate index */ rate->param.data_rate.rx_data_rate = (pmpriv->rxpd_rate > MLAN_RATE_INDEX_OFDM0) ? pmpriv->rxpd_rate - 1 : pmpriv->rxpd_rate; } } pioctl_buf->data_read_written = sizeof(mlan_data_rate) + MLAN_SUB_COMMAND_SIZE; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of robustcoex. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_robustcoex(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u16 *pdata_buf) { HostCmd_DS_802_11_ROBUSTCOEX *rbstcx = &cmd->params.robustcoexparams; mlan_ds_misc_robustcoex_params *robustcoex_params = MNULL; MrvlIEtypes_RobustcoexSourceGPIO_t *tlv = (MrvlIEtypes_RobustcoexSourceGPIO_t *)(rbstcx->tlv_buf); ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ROBUSTCOEX); cmd->size = sizeof(HostCmd_DS_802_11_ROBUSTCOEX) + S_DS_GEN; rbstcx->action = wlan_cpu_to_le16(cmd_action); switch (cmd_action) { case HostCmd_ACT_GEN_SET: robustcoex_params = (mlan_ds_misc_robustcoex_params *)pdata_buf; if (robustcoex_params->method == ROBUSTCOEX_GPIO_CFG) { cmd->size += sizeof(MrvlIEtypes_RobustcoexSourceGPIO_t); tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_ROBUSTCOEX); tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_RobustcoexSourceGPIO_t) - sizeof(MrvlIEtypesHeader_t)); tlv->enable = (t_u8)robustcoex_params->enable; tlv->gpio_num = (t_u8)robustcoex_params->gpio_num; tlv->gpio_polarity = (t_u8)robustcoex_params->gpio_polarity; } break; case HostCmd_ACT_GEN_GET: default: break; } cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } #if defined(PCIE) /** * @brief This function enables SSU support. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_ssu(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u16 *pdata_buf) { HostCmd_DS_SSU_CFG *ssu_cfg_cmd = &cmd->params.ssu_params; mlan_ds_ssu_params *ssu_params = MNULL; mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SSU); cmd->size = sizeof(HostCmd_DS_SSU_CFG) + S_DS_GEN; ssu_cfg_cmd->action = wlan_cpu_to_le16(cmd_action); switch (cmd_action) { case HostCmd_ACT_GEN_SET: case HostCmd_ACT_GEN_SET_DEFAULT: ssu_params = (mlan_ds_ssu_params *)pdata_buf; ssu_cfg_cmd->nskip = wlan_cpu_to_le32(ssu_params->nskip); ssu_cfg_cmd->nsel = wlan_cpu_to_le32(ssu_params->nsel); ssu_cfg_cmd->adcdownsample = wlan_cpu_to_le32(ssu_params->adcdownsample); ssu_cfg_cmd->mask_adc_pkt = wlan_cpu_to_le32(ssu_params->mask_adc_pkt); ssu_cfg_cmd->out_16bits = wlan_cpu_to_le32(ssu_params->out_16bits); ssu_cfg_cmd->spec_pwr_enable = wlan_cpu_to_le32(ssu_params->spec_pwr_enable); ssu_cfg_cmd->rate_deduction = wlan_cpu_to_le32(ssu_params->rate_deduction); ssu_cfg_cmd->n_pkt_avg = wlan_cpu_to_le32(ssu_params->n_pkt_avg); /* Initialize PCIE ring buffer */ ret = wlan_alloc_ssu_pcie_buf(pmadapter); if (MLAN_STATUS_SUCCESS != ret) { PRINTM(MERROR, "Failed to allocate PCIE host buffers for SSU\n"); LEAVE(); return MLAN_STATUS_FAILURE; } ssu_cfg_cmd->buffer_base_addr[0] = wlan_cpu_to_le32((t_u32)pmadapter->ssu_buf->buf_pa); ssu_cfg_cmd->buffer_base_addr[1] = wlan_cpu_to_le32( (t_u32)((t_u64)(pmadapter->ssu_buf->buf_pa >> 32))); ssu_cfg_cmd->buffer_pool_size = wlan_cpu_to_le32(MLAN_SSU_BUF_SIZE); break; case HostCmd_ACT_GEN_GET: default: break; } cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } #endif /** * @brief This function prepares command of dmcs config. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_dmcs_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_DMCS_CFG *dmcs = &cmd->params.dmcs; mlan_ds_misc_mapping_policy *dmcs_params = MNULL; t_u8 *mapping_policy = (t_u8 *)dmcs->tlv_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DMCS_CONFIG); cmd->size = sizeof(HostCmd_DS_DMCS_CFG) + S_DS_GEN; dmcs->action = wlan_cpu_to_le16(cmd_action); dmcs_params = (mlan_ds_misc_mapping_policy *)pdata_buf; dmcs->subcmd = wlan_cpu_to_le16(dmcs_params->subcmd); switch (dmcs->subcmd) { case 0: cmd->size += sizeof(t_u8); *mapping_policy = dmcs_params->mapping_policy; break; case 1: default: break; } cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of dmcs config * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_ret_dmcs_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_status ret = MLAN_STATUS_SUCCESS; HostCmd_DS_DMCS_CFG *dmcs = &resp->params.dmcs; MrvlIEtypes_DmcsStatus_t *dmcs_status; mlan_ds_misc_cfg *cfg = MNULL; t_u16 tlv_buf_left = 0; t_u16 tlv_type = 0, tlv_len = 0; MrvlIEtypesHeader_t *tlv = MNULL; int i = 0; ENTER(); if (pioctl_buf) { cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; tlv = (MrvlIEtypesHeader_t *)((t_u8 *)dmcs + sizeof(HostCmd_DS_DMCS_CFG)); tlv_buf_left = resp->size - (sizeof(HostCmd_DS_DMCS_CFG) + S_DS_GEN); while (tlv_buf_left > sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) { PRINTM(MERROR, "Error while processing DMCS status tlv, bytes_left < TLV len\n"); ret = MLAN_STATUS_FAILURE; break; } switch (tlv_type) { case TLV_TYPE_DMCS_STATUS: dmcs_status = (MrvlIEtypes_DmcsStatus_t *)tlv; cfg->param.dmcs_status.mapping_policy = dmcs_status->mapping_policy; memset(pmpriv->adapter, &cfg->param.dmcs_status.radio_status, 0, sizeof(dmcsStatus_t)); for (i = 0; i < MAX_NUM_MAC; i++) { memcpy_ext( pmpriv->adapter, &cfg->param.dmcs_status .radio_status[i], &dmcs_status->radio_status[i], sizeof(dmcsStatus_t), sizeof(dmcsStatus_t)); } break; default: break; } tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } pioctl_buf->data_read_written = sizeof(mlan_ds_misc_dmcs_status); } LEAVE(); return ret; } /** * @brief This function prepares command of tx_rate_cfg. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * @param pioctl_buf A pointer to ioctl buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_TX_RATE_CFG *rate_cfg = (HostCmd_DS_TX_RATE_CFG *)&(cmd->params.tx_rate_cfg); MrvlRateScope_t *rate_scope; MrvlRateDropPattern_t *rate_drop; MrvlIETypes_rate_setting_t *rate_setting_tlv; mlan_ds_rate *ds_rate = MNULL; t_u16 *pbitmap_rates = (t_u16 *)pdata_buf; t_u32 i; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); rate_cfg->action = wlan_cpu_to_le16(cmd_action); rate_cfg->cfg_index = 0; rate_scope = (MrvlRateScope_t *)rate_cfg->tlv_buf; rate_scope->type = wlan_cpu_to_le16(TLV_TYPE_RATE_SCOPE); rate_scope->length = wlan_cpu_to_le16(sizeof(MrvlRateScope_t) - sizeof(MrvlIEtypesHeader_t)); if (pbitmap_rates != MNULL) { rate_scope->hr_dsss_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[0]); rate_scope->ofdm_rate_bitmap = wlan_cpu_to_le16(pbitmap_rates[1]); for (i = 0; i < NELEMENTS(rate_scope->ht_mcs_rate_bitmap); i++) rate_scope->ht_mcs_rate_bitmap[i] = wlan_cpu_to_le16(pbitmap_rates[2 + i]); for (i = 0; i < NELEMENTS(rate_scope->vht_mcs_rate_bitmap); i++) rate_scope->vht_mcs_rate_bitmap[i] = wlan_cpu_to_le16( pbitmap_rates [2 + NELEMENTS( rate_scope->ht_mcs_rate_bitmap) + i]); if (IS_FW_SUPPORT_11AX(pmpriv->adapter)) { for (i = 0; i < NELEMENTS(rate_scope->he_mcs_rate_bitmap); i++) rate_scope->he_mcs_rate_bitmap [i] = wlan_cpu_to_le16( pbitmap_rates[2 + wlan_get_bitmap_index( rate_scope) + i]); } else { rate_scope->length = wlan_cpu_to_le16( sizeof(MrvlRateScope_t) - sizeof(rate_scope->he_mcs_rate_bitmap) - sizeof(MrvlIEtypesHeader_t)); } } else { rate_scope->hr_dsss_rate_bitmap = wlan_cpu_to_le16(pmpriv->bitmap_rates[0]); rate_scope->ofdm_rate_bitmap = wlan_cpu_to_le16(pmpriv->bitmap_rates[1]); for (i = 0; i < NELEMENTS(rate_scope->ht_mcs_rate_bitmap); i++) rate_scope->ht_mcs_rate_bitmap[i] = wlan_cpu_to_le16(pmpriv->bitmap_rates[2 + i]); for (i = 0; i < NELEMENTS(rate_scope->vht_mcs_rate_bitmap); i++) rate_scope->vht_mcs_rate_bitmap[i] = wlan_cpu_to_le16( pmpriv->bitmap_rates [2 + NELEMENTS( rate_scope->ht_mcs_rate_bitmap) + i]); if (IS_FW_SUPPORT_11AX(pmpriv->adapter)) { for (i = 0; i < NELEMENTS(rate_scope->vht_mcs_rate_bitmap); i++) rate_scope->he_mcs_rate_bitmap[i] = wlan_cpu_to_le16( pmpriv->bitmap_rates [2 + wlan_get_bitmap_index( rate_scope) + i]); } else { rate_scope->length = wlan_cpu_to_le16( sizeof(MrvlRateScope_t) - sizeof(rate_scope->he_mcs_rate_bitmap) - sizeof(MrvlIEtypesHeader_t)); } } rate_drop = (MrvlRateDropPattern_t *)((t_u8 *)rate_scope + wlan_le16_to_cpu(rate_scope->length) + sizeof(MrvlIEtypesHeader_t)); rate_drop->type = wlan_cpu_to_le16(TLV_TYPE_RATE_DROP_PATTERN); rate_drop->length = wlan_cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); rate_drop->rate_drop_mode = 0; cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) + wlan_le16_to_cpu(rate_scope->length) + sizeof(MrvlIEtypesHeader_t) + sizeof(MrvlRateDropPattern_t)); if (pioctl_buf && pmpriv->adapter->pcard_info->v17_fw_api) { ds_rate = (mlan_ds_rate *)pioctl_buf->pbuf; rate_setting_tlv = (MrvlIETypes_rate_setting_t *)((t_u8 *)rate_drop + sizeof(MrvlRateDropPattern_t)); rate_setting_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_TX_RATE_CFG); rate_setting_tlv->header.len = wlan_cpu_to_le16( sizeof(rate_setting_tlv->rate_setting)); rate_setting_tlv->rate_setting = wlan_cpu_to_le16(ds_rate->param.rate_cfg.rate_setting); PRINTM(MCMND, "he rate setting = %d\n", rate_setting_tlv->rate_setting); cmd->size = wlan_cpu_to_le16( S_DS_GEN + sizeof(HostCmd_DS_TX_RATE_CFG) + wlan_le16_to_cpu(rate_scope->length) + sizeof(MrvlIEtypesHeader_t) + sizeof(MrvlRateDropPattern_t) + sizeof(MrvlIETypes_rate_setting_t)); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of tx_rate_cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_ret_tx_rate_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_adapter *pmadapter = pmpriv->adapter; mlan_ds_rate *ds_rate = MNULL; HostCmd_DS_TX_RATE_CFG *prate_cfg = MNULL; MrvlRateScope_t *prate_scope; MrvlIEtypesHeader_t *head = MNULL; t_u16 tlv, tlv_buf_len = 0; t_u8 *tlv_buf; t_u32 i; t_s32 index; mlan_status ret = MLAN_STATUS_SUCCESS; MrvlIETypes_rate_setting_t *rate_setting_tlv = MNULL; t_u16 rate_setting = 0xffff; ENTER(); if (resp == MNULL) { LEAVE(); return MLAN_STATUS_FAILURE; } prate_cfg = (HostCmd_DS_TX_RATE_CFG *)&(resp->params.tx_rate_cfg); tlv_buf = (t_u8 *)prate_cfg->tlv_buf; tlv_buf_len = resp->size - (sizeof(HostCmd_DS_TX_RATE_CFG) + S_DS_GEN); while (tlv_buf && tlv_buf_len > 0) { tlv = (*tlv_buf); tlv = tlv | (*(tlv_buf + 1) << 8); switch (tlv) { case TLV_TYPE_RATE_SCOPE: prate_scope = (MrvlRateScope_t *)tlv_buf; pmpriv->bitmap_rates[0] = wlan_le16_to_cpu( prate_scope->hr_dsss_rate_bitmap); pmpriv->bitmap_rates[1] = wlan_le16_to_cpu(prate_scope->ofdm_rate_bitmap); for (i = 0; i < NELEMENTS(prate_scope->ht_mcs_rate_bitmap); i++) pmpriv->bitmap_rates[2 + i] = wlan_le16_to_cpu( prate_scope->ht_mcs_rate_bitmap[i]); for (i = 0; i < NELEMENTS(prate_scope->vht_mcs_rate_bitmap); i++) pmpriv->bitmap_rates [2 + sizeof(prate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16) + i] = wlan_le16_to_cpu( prate_scope ->vht_mcs_rate_bitmap[i]); if (IS_FW_SUPPORT_11AX(pmadapter)) { for (i = 0; i < NELEMENTS(prate_scope->he_mcs_rate_bitmap); i++) pmpriv->bitmap_rates [2 + sizeof(prate_scope ->ht_mcs_rate_bitmap) / sizeof(t_u16) + sizeof(prate_scope ->vht_mcs_rate_bitmap) / sizeof(t_u16) + i] = wlan_le16_to_cpu( prate_scope ->he_mcs_rate_bitmap [i]); } break; case TLV_TYPE_TX_RATE_CFG: rate_setting_tlv = (MrvlIETypes_rate_setting_t *)tlv_buf; rate_setting = rate_setting_tlv->rate_setting; break; /* Add RATE_DROP tlv here */ } head = (MrvlIEtypesHeader_t *)tlv_buf; head->len = wlan_le16_to_cpu(head->len); tlv_buf += head->len + sizeof(MrvlIEtypesHeader_t); tlv_buf_len -= (head->len + sizeof(MrvlIEtypesHeader_t)); } pmpriv->is_data_rate_auto = wlan_is_rate_auto(pmpriv); if (pmpriv->is_data_rate_auto) { pmpriv->data_rate = 0; } else { ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_TX_RATE_QUERY, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); } if (pioctl_buf) { ds_rate = (mlan_ds_rate *)pioctl_buf->pbuf; if (ds_rate == MNULL) { PRINTM(MERROR, "Request buffer not found!\n"); LEAVE(); return MLAN_STATUS_FAILURE; } if (pmpriv->is_data_rate_auto) { ds_rate->param.rate_cfg.is_rate_auto = MTRUE; ds_rate->param.rate_cfg.rate_format = MLAN_RATE_FORMAT_AUTO; } else { ds_rate->param.rate_cfg.is_rate_auto = MFALSE; /* check the LG rate */ index = wlan_get_rate_index( pmadapter, &pmpriv->bitmap_rates[0], 4); if (index != -1) { if ((index >= MLAN_RATE_BITMAP_OFDM0) && (index <= MLAN_RATE_BITMAP_OFDM7)) index -= (MLAN_RATE_BITMAP_OFDM0 - MLAN_RATE_INDEX_OFDM0); ds_rate->param.rate_cfg.rate_format = MLAN_RATE_FORMAT_LG; ds_rate->param.rate_cfg.rate = index; } /* check the HT rate */ index = wlan_get_rate_index( pmadapter, &pmpriv->bitmap_rates[2], 16); if (index != -1) { ds_rate->param.rate_cfg.rate_format = MLAN_RATE_FORMAT_HT; ds_rate->param.rate_cfg.rate = index; } /* check the VHT rate */ index = wlan_get_rate_index( pmadapter, &pmpriv->bitmap_rates[10], 16); if (index != -1) { ds_rate->param.rate_cfg.rate_format = MLAN_RATE_FORMAT_VHT; ds_rate->param.rate_cfg.rate = index % 16; ds_rate->param.rate_cfg.nss = index / 16; ds_rate->param.rate_cfg.nss += MLAN_RATE_NSS1; } /* check the HE rate */ if (IS_FW_SUPPORT_11AX(pmadapter)) { index = wlan_get_rate_index( pmadapter, &pmpriv->bitmap_rates[18], 16); if (index != -1) { ds_rate->param.rate_cfg.rate_format = MLAN_RATE_FORMAT_HE; ds_rate->param.rate_cfg.rate = index % 16; ds_rate->param.rate_cfg.nss = index / 16; ds_rate->param.rate_cfg.nss += MLAN_RATE_NSS1; } } ds_rate->param.rate_cfg.rate_setting = rate_setting; PRINTM(MINFO, "Rate index is %d\n", ds_rate->param.rate_cfg.rate); } for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) { ds_rate->param.rate_cfg.bitmap_rates[i] = pmpriv->bitmap_rates[i]; } } LEAVE(); return ret; } /** * @brief This function issues adapter specific commands * to initialize firmware * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE */ mlan_status wlan_adapter_get_hw_spec(pmlan_adapter pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_private priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); ENTER(); #if defined(SDIO) /* * This should be issued in the very first to config * SDIO_GPIO interrupt mode. */ if (IS_SD(pmadapter->card_type) && (wlan_set_sdio_gpio_int(priv) != MLAN_STATUS_SUCCESS)) { ret = MLAN_STATUS_FAILURE; goto done; } #endif #ifdef PCIE if (IS_PCIE(pmadapter->card_type) && (MLAN_STATUS_SUCCESS != wlan_set_pcie_buf_config(priv))) { ret = MLAN_STATUS_FAILURE; goto done; } #endif ret = wlan_prepare_cmd(priv, HostCmd_CMD_FUNC_INIT, HostCmd_ACT_GEN_SET, 0, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } /** DPD data dnld cmd prepare */ if ((pmadapter->pdpd_data) && (pmadapter->dpd_data_len > 0)) { ret = wlan_process_hostcmd_cfg(priv, CFG_TYPE_DPDFILE, pmadapter->pdpd_data, pmadapter->dpd_data_len); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } pmadapter->pdpd_data = MNULL; pmadapter->dpd_data_len = 0; } if ((pmadapter->ptxpwr_data) && (pmadapter->txpwr_data_len > 0)) { ret = wlan_process_hostcmd_cfg(priv, CFG_TYPE_HOSTCMD, pmadapter->ptxpwr_data, pmadapter->txpwr_data_len); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } pmadapter->ptxpwr_data = MNULL; pmadapter->txpwr_data_len = 0; } if (!pmadapter->pdpd_data && (pmadapter->dpd_data_len == UNKNOW_DPD_LENGTH)) { ret = wlan_prepare_cmd(priv, HostCmd_CMD_CFG_DATA, HostCmd_ACT_GEN_GET, OID_TYPE_DPD, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } /** Cal data dnld cmd prepare */ if ((pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) { ret = wlan_prepare_cmd(priv, HostCmd_CMD_CFG_DATA, HostCmd_ACT_GEN_SET, OID_TYPE_CAL, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } pmadapter->pcal_data = MNULL; pmadapter->cal_data_len = 0; } /* Get FW region and cfp tables */ ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REGION_CFG, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } /* * Get HW spec */ ret = wlan_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } ret = MLAN_STATUS_PENDING; done: LEAVE(); return ret; } /** * @brief This function issues adapter specific commands * to initialize firmware * * @param pmadapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_PENDING or MLAN_STATUS_FAILURE */ mlan_status wlan_adapter_init_cmd(pmlan_adapter pmadapter) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_private pmpriv = MNULL; #ifdef STA_SUPPORT pmlan_private pmpriv_sta = MNULL; #endif t_u32 mode = BLOCK_CMD_IN_PRE_ASLEEP; ENTER(); pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); #ifdef STA_SUPPORT pmpriv_sta = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA); #endif #ifdef SDIO #endif ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_RECONFIGURE_TX_BUFF, HostCmd_ACT_GEN_SET, 0, MNULL, &pmadapter->max_tx_buf_size); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } #if defined(STA_SUPPORT) if (pmpriv_sta && (pmpriv_sta->state_11d.user_enable_11d == ENABLE_11D)) { /* Send command to FW to enable 11d */ ret = wlan_prepare_cmd(pmpriv_sta, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, Dot11D_i, MNULL, &pmpriv_sta->state_11d.user_enable_11d); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } #endif #ifdef STA_SUPPORT if (pmpriv_sta && (pmadapter->ps_mode == Wlan802_11PowerModePSP)) { ret = wlan_prepare_cmd(pmpriv_sta, HostCmd_CMD_802_11_PS_MODE_ENH, EN_AUTO_PS, BITMAP_STA_PS, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } #endif if (pmadapter->init_auto_ds) { mlan_ds_auto_ds auto_ds; /* Enable auto deep sleep */ auto_ds.idletime = pmadapter->idle_time; ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH, EN_AUTO_PS, BITMAP_AUTO_DS, MNULL, &auto_ds); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_MODE_ENH, EXT_PS_PARAM, HostCmd_ACT_GEN_SET, MNULL, &mode); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } #define DEF_AUTO_NULL_PKT_PERIOD 30 if (pmpriv_sta) { t_u32 value = DEF_AUTO_NULL_PKT_PERIOD; ret = wlan_prepare_cmd(pmpriv_sta, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, NullPktPeriod_i, MNULL, &value); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } if (pmadapter->init_para.indrstcfg != 0xffffffff) { mlan_ds_ind_rst_cfg ind_rst_cfg; ind_rst_cfg.ir_mode = pmadapter->init_para.indrstcfg & 0xff; ind_rst_cfg.gpio_pin = (pmadapter->init_para.indrstcfg & 0xff00) >> 8; ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_INDEPENDENT_RESET_CFG, HostCmd_ACT_GEN_SET, 0, MNULL, (t_void *)&ind_rst_cfg); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } if (pmadapter->inact_tmo) { ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT, HostCmd_ACT_GEN_SET, 0, MNULL, &pmadapter->inact_tmo); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } if (pmadapter->init_para.drcs_chantime_mode) { mlan_ds_drcs_cfg drcs_init_cfg[2]; drcs_init_cfg[0].chan_idx = 0x1; drcs_init_cfg[0].chantime = (t_u8)(pmadapter->init_para.drcs_chantime_mode >> 8); /* switchtime use default value in fw*/ drcs_init_cfg[0].switchtime = 10; drcs_init_cfg[0].undozetime = 5; drcs_init_cfg[0].mode = (t_u8)(pmadapter->init_para.drcs_chantime_mode); drcs_init_cfg[1].chan_idx = 0x2; drcs_init_cfg[1].chantime = (t_u8)(pmadapter->init_para.drcs_chantime_mode >> 24); /* switchtime use default value in fw*/ drcs_init_cfg[1].switchtime = 10; drcs_init_cfg[1].undozetime = 5; drcs_init_cfg[1].mode = (t_u8)(pmadapter->init_para.drcs_chantime_mode >> 16); ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_DRCS_CONFIG, HostCmd_ACT_GEN_SET, 0, MNULL, (t_void *)drcs_init_cfg); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } /* Send request to firmware */ ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_RF_ANTENNA, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } ret = MLAN_STATUS_PENDING; done: LEAVE(); return ret; } /** * @brief This function download the vdll block. * * @param pmadapter A pointer to mlan_adapter structure * @param block A pointer to VDLL block * @param block_len The VDLL block length * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_download_vdll_block(mlan_adapter *pmadapter, t_u8 *block, t_u16 block_len) { mlan_status status = MLAN_STATUS_FAILURE; mlan_status ret = MLAN_STATUS_PENDING; #if defined(SDIO) || defined(PCIE) pvdll_dnld_ctrl ctrl = &pmadapter->vdll_ctrl; #endif mlan_buffer *pmbuf = MNULL; mlan_private *pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY); HostCmd_DS_GEN *cmd_hdr = MNULL; t_u16 msg_len = block_len + sizeof(HostCmd_DS_GEN); #ifdef USB t_u32 tmp; #endif ENTER(); #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) { pmbuf = ctrl->cmd_buf; if (pmbuf) pmbuf->data_offset += pmadapter->ops.intf_header_len; } #endif #ifdef USB if (IS_USB(pmadapter->card_type)) { pmbuf = wlan_alloc_mlan_buffer(pmadapter, MRVDRV_SIZE_OF_CMD_BUFFER, 0, MOAL_MALLOC_BUFFER); if (pmbuf) { tmp = wlan_cpu_to_le32(MLAN_USB_TYPE_VDLL); memcpy_ext(pmadapter, (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset), (t_u8 *)&tmp, MLAN_TYPE_LEN, MLAN_TYPE_LEN); pmbuf->data_offset += MLAN_TYPE_LEN; } } #endif if (!pmbuf) { PRINTM(MERROR, "dnld vdll: Fail to alloc vdll buf"); goto done; } if (!pmpriv) { PRINTM(MERROR, "dnld vdll: Fail to get pmpriv"); goto done; } cmd_hdr = (HostCmd_DS_GEN *)(pmbuf->pbuf + pmbuf->data_offset); cmd_hdr->command = wlan_cpu_to_le16(HostCmd_CMD_VDLL); cmd_hdr->seq_num = wlan_cpu_to_le16(0xFF00); cmd_hdr->size = wlan_cpu_to_le16(msg_len); pmadapter->callbacks.moal_memcpy_ext(pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset + sizeof(HostCmd_DS_GEN), block, block_len, block_len); pmbuf->data_len = msg_len; #if defined(SDIO) || defined(PCIE) if (!IS_USB(pmadapter->card_type)) { pmbuf->data_offset -= pmadapter->ops.intf_header_len; pmbuf->data_len += pmadapter->ops.intf_header_len; } #endif #ifdef USB if (IS_USB(pmadapter->card_type)) { pmbuf->data_offset -= MLAN_TYPE_LEN; pmbuf->data_len += MLAN_TYPE_LEN; } #endif PRINTM_NETINTF(MCMND, pmpriv); PRINTM(MCMND, "DNLD_VDLL : block_len=%d\n", block_len); ret = pmadapter->ops.host_to_card(pmpriv, MLAN_TYPE_VDLL, pmbuf, MNULL); if (ret == MLAN_STATUS_FAILURE) PRINTM(MERROR, "DNLD_VDLL: Host to Card Failed\n"); else status = MLAN_STATUS_SUCCESS; done: if ((ret == MLAN_STATUS_FAILURE) || (ret == MLAN_STATUS_SUCCESS)) { #ifdef USB if (IS_USB(pmadapter->card_type)) wlan_free_mlan_buffer(pmadapter, pmbuf); #endif } LEAVE(); return status; } /** * @brief The function Get the VDLL image from moal * * @param pmadapter A pointer to mlan_adapter structure * @param offset offset * * @return MLAN_STATUS_SUCCESS * */ static mlan_status wlan_get_vdll_image(pmlan_adapter pmadapter, t_u32 vdll_len) { mlan_status status = MLAN_STATUS_SUCCESS; vdll_dnld_ctrl *ctrl = &pmadapter->vdll_ctrl; pmlan_callbacks pcb = &pmadapter->callbacks; ENTER(); if (ctrl->vdll_mem) { PRINTM(MCMND, "VDLL mem is not empty: %p old_len=%d new_len=%d\n", ctrl->vdll_mem, ctrl->vdll_len, vdll_len); if (pcb->moal_vmalloc && pcb->moal_vfree) pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)ctrl->vdll_mem); else pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)ctrl->vdll_mem); ctrl->vdll_mem = MNULL; ctrl->vdll_len = 0; } if (pcb->moal_vmalloc && pcb->moal_vfree) status = pcb->moal_vmalloc(pmadapter->pmoal_handle, vdll_len, (t_u8 **)&ctrl->vdll_mem); else status = pcb->moal_malloc(pmadapter->pmoal_handle, vdll_len, MLAN_MEM_DEF, (t_u8 **)&ctrl->vdll_mem); if (status != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "VDLL: Fail to alloc vdll memory"); goto done; } if (MLAN_STATUS_SUCCESS != pcb->moal_get_vdll_data(pmadapter->pmoal_handle, vdll_len, ctrl->vdll_mem)) { PRINTM(MERROR, "VDLL: firmware image not available\n"); status = MLAN_STATUS_FAILURE; if (pcb->moal_vmalloc && pcb->moal_vfree) pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)ctrl->vdll_mem); else pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)ctrl->vdll_mem); ctrl->vdll_mem = MNULL; ctrl->vdll_len = 0; goto done; } /*allocate a memory to store all VDLL images*/ ctrl->vdll_len = vdll_len; PRINTM(MMSG, "VDLL image: len=%d\n", ctrl->vdll_len); done: LEAVE(); return status; } /** * @brief This function handle the multi_chan info event * * @param pmpriv A pointer to mlan_private structure * @param pevent A pointer to event buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_process_vdll_event(pmlan_private pmpriv, pmlan_buffer pevent) { mlan_status status = MLAN_STATUS_SUCCESS; vdll_ind *ind = MNULL; t_u32 offset = 0; t_u16 block_len = 0; mlan_adapter *pmadapter = pmpriv->adapter; vdll_dnld_ctrl *ctrl = &pmadapter->vdll_ctrl; ENTER(); ind = (vdll_ind *)(pevent->pbuf + pevent->data_offset + sizeof(mlan_event_id)); switch (wlan_le16_to_cpu(ind->type)) { case VDLL_IND_TYPE_REQ: offset = wlan_le32_to_cpu(ind->offset); block_len = wlan_le16_to_cpu(ind->block_len); PRINTM(MEVENT, "VDLL_IND: type=%d offset = 0x%x, len = %d\n", wlan_le16_to_cpu(ind->type), offset, block_len); if (offset <= ctrl->vdll_len) { block_len = MIN(block_len, ctrl->vdll_len - offset); if (!pmadapter->cmd_sent) { status = wlan_download_vdll_block( pmadapter, ctrl->vdll_mem + offset, block_len); if (status) PRINTM(MERROR, "Fail to download VDLL block\n"); } else { PRINTM(MCMND, "cmd_sent=1, delay download VDLL block\n"); ctrl->pending_block_len = block_len; ctrl->pending_block = ctrl->vdll_mem + offset; } } else { PRINTM(MERROR, "Invalid VDLL req: offset=0x%x, len=%d, vdll_len=%d\n", offset, block_len, ctrl->vdll_len); } break; case VDLL_IND_TYPE_OFFSET: offset = wlan_le32_to_cpu(ind->offset); PRINTM(MEVENT, "VDLL_IND (OFFSET): offset=0x%x\n", offset); wlan_get_vdll_image(pmadapter, offset); break; case VDLL_IND_TYPE_ERR_SIG: PRINTM(MERROR, "VDLL_IND (SIG ERR).\n"); break; case VDLL_IND_TYPE_ERR_ID: PRINTM(MERROR, "VDLL_IND (ID ERR).\n"); break; default: PRINTM(MERROR, "unknow vdll ind type=%d\n", ind->type); break; } LEAVE(); return status; } /** * @brief This function handle the csi event * * @param pmpriv A pointer to mlan_private structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_process_csi_event(pmlan_private pmpriv) { pmlan_adapter pmadapter = pmpriv->adapter; mlan_status status; t_u32 eventcause = pmadapter->event_cause; t_u8 *evt_buf = MNULL; pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event; pmlan_callbacks pcb = &pmadapter->callbacks; pmlan_event pevent; ENTER(); /* Allocate memory for event buffer */ status = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf); if ((status == MLAN_STATUS_SUCCESS) && evt_buf) { t_u16 csi_sig; pcsi_record_ds csi_record = (pcsi_record_ds)( pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause)); /* Check CSI signature */ csi_sig = csi_record->CSI_Sign; if (csi_sig != CSI_SIGNATURE) { PRINTM(MERROR, "Wrong CSI signature 0x%04x. Should be 0x%04x", csi_sig, CSI_SIGNATURE); status = MLAN_STATUS_FAILURE; } else { /* Send event to moal */ pevent = (pmlan_event)evt_buf; pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_CSI; /* Event length is the CSI record length in byte */ pevent->event_len = csi_record->Len * 4; if (pevent->event_len > pmbuf->data_len - sizeof(eventcause)) pevent->event_len = pmbuf->data_len - sizeof(eventcause); memcpy_ext(pmadapter, (t_u8 *)pevent->event_buf, csi_record, pevent->event_len, pevent->event_len); wlan_recv_event(pmpriv, pevent->event_id, pevent); } pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf); } LEAVE(); return status; } /** * @brief This function handle the multi_chan info event * * @param pmpriv A pointer to mlan_private structure * @param pevent A pointer to event buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_handle_event_multi_chan_info(pmlan_private pmpriv, pmlan_buffer pevent) { pmlan_adapter pmadapter = pmpriv->adapter; t_u32 interfaces = 0; MrvlIEtypes_multi_chan_info_t *pmulti_chan_info = MNULL; MrvlIEtypes_multi_chan_group_info_t *pmulti_chan_grp_info = MNULL; int tlv_buf_left = pevent->data_len - sizeof(mlan_event_id); t_u16 tlv_type, tlv_len; mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_private intf_priv = MNULL; int num_intf = 0, bss_type = 0, bss_num = 0; MrvlIEtypesHeader_t *tlv = MNULL; ENTER(); PRINTM(MEVENT, "multi channel event\n"); pmulti_chan_info = (MrvlIEtypes_multi_chan_info_t *)(pevent->pbuf + pevent->data_offset + sizeof(mlan_event_id)); if (tlv_buf_left < (int)(sizeof(MrvlIEtypes_multi_chan_info_t)) || wlan_le16_to_cpu(pmulti_chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) { PRINTM(MERROR, "Invalid multi channel event\n"); goto done; } pmadapter->mc_status = wlan_le16_to_cpu(pmulti_chan_info->status); PRINTM(MEVENT, "mc_status=%d\n", pmadapter->mc_status); tlv_buf_left -= sizeof(MrvlIEtypes_multi_chan_info_t); tlv = (MrvlIEtypesHeader_t *)pmulti_chan_info->tlv_buffer; while (tlv_buf_left >= (int)sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); if ((sizeof(MrvlIEtypesHeader_t) + tlv_len) > (unsigned int)tlv_buf_left) { PRINTM(MERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, tlv_buf_left); break; } if (tlv_type != TLV_TYPE_MULTI_CHAN_GROUP_INFO_TLV_ID) { PRINTM(MERROR, "wrong tlv type:0x%x\n", tlv_type); break; } pmulti_chan_grp_info = (MrvlIEtypes_multi_chan_group_info_t *)tlv; PRINTM(MEVENT, "mc_info: groupid=%d chan=%d, numintf=%d\n", pmulti_chan_grp_info->chan_group_id, pmulti_chan_grp_info->chan_band_info.chan_num, pmulti_chan_grp_info->num_intf); num_intf = pmulti_chan_grp_info->num_intf; for (interfaces = 0; interfaces < (t_u32)num_intf; interfaces++) { bss_type = pmulti_chan_grp_info ->bss_type_numlist[interfaces] >> 4; bss_num = pmulti_chan_grp_info ->bss_type_numlist[interfaces] & BSS_NUM_MASK; PRINTM(MEVENT, "intf%d: bss_type=%d bss_num=%d\n", interfaces, bss_type, bss_num); intf_priv = wlan_get_priv_by_id(pmadapter, bss_num, bss_type); if (intf_priv) { #ifdef USB if (IS_USB(pmadapter->card_type)) { if (pmulti_chan_grp_info->hid_num .usb_epnum == MLAN_USB_EP_DATA || pmulti_chan_grp_info->hid_num .usb_epnum == MLAN_USB_EP_DATA_CH2 || pmulti_chan_grp_info->hid_num .usb_epnum == MLAN_USB_EP_DATA_IF2 || pmulti_chan_grp_info->hid_num .usb_epnum == MLAN_USB_EP_DATA_CH2_IF2) { intf_priv->port = pmulti_chan_grp_info ->hid_num .usb_epnum; intf_priv->port_index = wlan_get_port_index( pmadapter, intf_priv->port); PRINTM(MEVENT, "intf%d: bss_type=%d bss_num=%d port=%d index=%d\n", interfaces, bss_type, bss_num, intf_priv->port, intf_priv->port_index); } else PRINTM(MERROR, "Invalid Endpoint num in multi_channel event\n"); } #endif } else { PRINTM(MERROR, "Invalid bss_type, bss_num in multi_channel event\n"); } } tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } #ifdef USB if (IS_USB(pmadapter->card_type)) { } #endif done: LEAVE(); return ret; } /** * @brief This function prepares the command MULTI_CHAN_CFG * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action Command action: GET or SET * @param pdata_buf A pointer to new setting buf * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_multi_chan_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { mlan_ds_multi_chan_cfg *multi_chan_cfg = (mlan_ds_multi_chan_cfg *)pdata_buf; HostCmd_DS_MULTI_CHAN_CFG *pmchan_cfg = (HostCmd_DS_MULTI_CHAN_CFG *)&cmd->params.multi_chan_cfg; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MULTI_CHAN_CONFIG); pmchan_cfg->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { pmchan_cfg->buffer_weight = multi_chan_cfg->buffer_weight; pmchan_cfg->channel_time = wlan_cpu_to_le32(multi_chan_cfg->channel_time); PRINTM(MCMND, "Set multi-channel: buffer_weight=%d channel_time=%d\n", multi_chan_cfg->buffer_weight, multi_chan_cfg->channel_time); cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_MULTI_CHAN_CFG)); } else { cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(cmd_action)); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of MULTI_CHAN_CFG * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_multi_chan_cfg(pmlan_private pmpriv, const HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *pcfg = MNULL; const HostCmd_DS_MULTI_CHAN_CFG *presp_cfg = &resp->params.multi_chan_cfg; ENTER(); if (pioctl_buf) { pcfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; pcfg->param.multi_chan_cfg.channel_time = wlan_le32_to_cpu(presp_cfg->channel_time); pcfg->param.multi_chan_cfg.buffer_weight = presp_cfg->buffer_weight; pcfg->param.multi_chan_cfg.tlv_len = resp->size - (sizeof(HostCmd_DS_GEN) + sizeof(HostCmd_DS_MULTI_CHAN_CFG)); PRINTM(MCMND, "Get multi-channel: buffer_weight=%d channel_time=%d tlv_len=%d\n", pcfg->param.multi_chan_cfg.buffer_weight, pcfg->param.multi_chan_cfg.channel_time, pcfg->param.multi_chan_cfg.tlv_len); memcpy_ext(pmpriv->adapter, pcfg->param.multi_chan_cfg.tlv_buf, presp_cfg->tlv_buf, pcfg->param.multi_chan_cfg.tlv_len, pcfg->param.multi_chan_cfg.tlv_len); pioctl_buf->buf_len = sizeof(mlan_ds_multi_chan_cfg) + pcfg->param.multi_chan_cfg.tlv_len; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares the command MULTI_CHAN_POLICY * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action Command action: GET or SET * @param pdata_buf A pointer to new setting buf * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_multi_chan_policy(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { t_u16 policy = 0; HostCmd_DS_MULTI_CHAN_POLICY *pmulti_chan_policy = (HostCmd_DS_MULTI_CHAN_POLICY *)&cmd->params.multi_chan_policy; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MULTI_CHAN_POLICY); pmulti_chan_policy->action = wlan_cpu_to_le16(cmd_action); cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_MULTI_CHAN_POLICY)); if (cmd_action == HostCmd_ACT_GEN_SET) { policy = *((t_u16 *)pdata_buf); pmulti_chan_policy->policy = wlan_cpu_to_le16(policy); PRINTM(MCMND, "Set multi-channel policy: %d\n", policy); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of MULTI_CHAN_POLICY * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_multi_chan_policy(pmlan_private pmpriv, const HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *pcfg = MNULL; const HostCmd_DS_MULTI_CHAN_POLICY *presp_cfg = &resp->params.multi_chan_policy; ENTER(); if (pioctl_buf) { pcfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; pcfg->param.multi_chan_policy = wlan_le16_to_cpu(presp_cfg->policy); if (pioctl_buf->action == HostCmd_ACT_GEN_SET) { if (pcfg->param.multi_chan_policy) pmpriv->adapter->mc_policy = MTRUE; else pmpriv->adapter->mc_policy = MFALSE; } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares the command DRCD_CFG * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action Command action: GET or SET * @param pdata_buf A pointer to new setting buf * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_drcs_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { mlan_ds_drcs_cfg *drcs_cfg = (mlan_ds_drcs_cfg *)pdata_buf; HostCmd_DS_DRCS_CFG *pdrcs_cfg = (HostCmd_DS_DRCS_CFG *)&cmd->params.drcs_cfg; MrvlTypes_DrcsTimeSlice_t *channel_time_slicing = &pdrcs_cfg->time_slicing; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DRCS_CONFIG); pdrcs_cfg->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { channel_time_slicing->header.type = wlan_cpu_to_le16(MRVL_DRCS_TIME_SLICE_TLV_ID); channel_time_slicing->header.len = wlan_cpu_to_le16(sizeof(MrvlTypes_DrcsTimeSlice_t) - sizeof(MrvlIEtypesHeader_t)); channel_time_slicing->chan_idx = wlan_cpu_to_le16(drcs_cfg->chan_idx); channel_time_slicing->chantime = drcs_cfg->chantime; channel_time_slicing->switchtime = drcs_cfg->switchtime; channel_time_slicing->undozetime = drcs_cfg->undozetime; channel_time_slicing->mode = drcs_cfg->mode; PRINTM(MCMND, "Set multi-channel: chan_idx=%d chantime=%d switchtime=%d undozetime=%d mode=%d\n", channel_time_slicing->chan_idx, channel_time_slicing->chantime, channel_time_slicing->switchtime, channel_time_slicing->undozetime, channel_time_slicing->mode); cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_DRCS_CFG)); /* Set two channels different parameters */ if (0x3 != channel_time_slicing->chan_idx) { drcs_cfg++; channel_time_slicing = pdrcs_cfg->drcs_buf; channel_time_slicing->header.type = wlan_cpu_to_le16(MRVL_DRCS_TIME_SLICE_TLV_ID); channel_time_slicing->header.len = wlan_cpu_to_le16( sizeof(MrvlTypes_DrcsTimeSlice_t) - sizeof(MrvlIEtypesHeader_t)); channel_time_slicing->chan_idx = wlan_cpu_to_le16(drcs_cfg->chan_idx); channel_time_slicing->chantime = drcs_cfg->chantime; channel_time_slicing->switchtime = drcs_cfg->switchtime; channel_time_slicing->undozetime = drcs_cfg->undozetime; channel_time_slicing->mode = drcs_cfg->mode; PRINTM(MCMND, "Set multi-channel: chan_idx=%d chantime=%d switchtime=%d undozetime=%d mode=%d\n", channel_time_slicing->chan_idx, channel_time_slicing->chantime, channel_time_slicing->switchtime, channel_time_slicing->undozetime, channel_time_slicing->mode); cmd->size += wlan_cpu_to_le16( sizeof(MrvlTypes_DrcsTimeSlice_t)); } } else { cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(cmd_action)); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of DRCS_CFG * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_drcs_cfg(pmlan_private pmpriv, const HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *pcfg = MNULL; const HostCmd_DS_DRCS_CFG *presp_cfg = &resp->params.drcs_cfg; const MrvlTypes_DrcsTimeSlice_t *channel_time_slicing = &presp_cfg->time_slicing; const MrvlTypes_DrcsTimeSlice_t *channel_time_slicing1 = MNULL; mlan_ds_drcs_cfg *drcs_cfg1 = MNULL; ENTER(); if (pioctl_buf) { pcfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; if (wlan_le16_to_cpu(channel_time_slicing->header.type) != MRVL_DRCS_TIME_SLICE_TLV_ID || wlan_le16_to_cpu(channel_time_slicing->header.len) != sizeof(MrvlTypes_DrcsTimeSlice_t) - sizeof(MrvlIEtypesHeader_t)) { LEAVE(); return MLAN_STATUS_FAILURE; } pcfg->param.drcs_cfg[0].chan_idx = wlan_le16_to_cpu(channel_time_slicing->chan_idx); pcfg->param.drcs_cfg[0].chantime = channel_time_slicing->chantime; pcfg->param.drcs_cfg[0].switchtime = channel_time_slicing->switchtime; pcfg->param.drcs_cfg[0].undozetime = channel_time_slicing->undozetime; pcfg->param.drcs_cfg[0].mode = channel_time_slicing->mode; PRINTM(MCMND, "multi-channel: chan_idx=%d chantime=%d switchtime=%d undozetime=%d mode=%d\n", pcfg->param.drcs_cfg[0].chan_idx, channel_time_slicing->chantime, channel_time_slicing->switchtime, channel_time_slicing->undozetime, channel_time_slicing->mode); pioctl_buf->buf_len = sizeof(mlan_ds_drcs_cfg); /*Channel for chan_idx 1 and 2 have different parameters*/ if (0x3 != pcfg->param.drcs_cfg[0].chan_idx) { channel_time_slicing1 = presp_cfg->drcs_buf; if (wlan_le16_to_cpu( channel_time_slicing1->header.type) != MRVL_DRCS_TIME_SLICE_TLV_ID || wlan_le16_to_cpu( channel_time_slicing1->header.len) != sizeof(MrvlTypes_DrcsTimeSlice_t) - sizeof(MrvlIEtypesHeader_t)) { LEAVE(); return MLAN_STATUS_FAILURE; } drcs_cfg1 = (mlan_ds_drcs_cfg *)&pcfg->param.drcs_cfg[1]; drcs_cfg1->chan_idx = wlan_le16_to_cpu( channel_time_slicing1->chan_idx); drcs_cfg1->chantime = channel_time_slicing1->chantime; drcs_cfg1->switchtime = channel_time_slicing1->switchtime; drcs_cfg1->undozetime = channel_time_slicing1->undozetime; drcs_cfg1->mode = channel_time_slicing1->mode; PRINTM(MCMND, "multi-channel: chan_idx=%d chantime=%d switchtime=%d undozetime=%d mode=%d\n", drcs_cfg1->chan_idx, drcs_cfg1->chantime, drcs_cfg1->switchtime, drcs_cfg1->undozetime, drcs_cfg1->mode); pioctl_buf->buf_len += sizeof(mlan_ds_drcs_cfg); } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of get_hw_spec. * * @param pmpriv A pointer to mlan_private structure * @param pcmd A pointer to HostCmd_DS_COMMAND structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd) { HostCmd_DS_GET_HW_SPEC *hw_spec = &pcmd->params.hw_spec; ENTER(); pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN); memcpy_ext(pmpriv->adapter, hw_spec->permanent_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); LEAVE(); return MLAN_STATUS_SUCCESS; } #ifdef SDIO #endif /** * @brief This function prepares command of set_cfg_data. * * @param pmpriv A pointer to mlan_private strcture * @param pcmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action Command action: GET or SET * @param pdata_buf A pointer to cal_data buf * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_cfg_data(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd, t_u16 cmd_action, t_u32 cmd_oid, t_void *pdata_buf) { mlan_status ret = MLAN_STATUS_SUCCESS; HostCmd_DS_802_11_CFG_DATA *pcfg_data = &(pcmd->params.cfg_data); pmlan_adapter pmadapter = pmpriv->adapter; t_u32 len = 0; t_u32 data_offset; t_u8 *temp_pcmd = (t_u8 *)pcmd; ENTER(); data_offset = S_DS_GEN + sizeof(HostCmd_DS_802_11_CFG_DATA); if ((cmd_oid == OID_TYPE_CAL) && (pmadapter->pcal_data) && (pmadapter->cal_data_len > 0)) { len = wlan_parse_cal_cfg((t_u8 *)pmadapter->pcal_data, pmadapter->cal_data_len, (t_u8 *)(temp_pcmd + data_offset)); } pcfg_data->action = cmd_action; pcfg_data->type = cmd_oid; pcfg_data->data_len = len; pcmd->command = HostCmd_CMD_CFG_DATA; pcmd->size = pcfg_data->data_len + data_offset; pcmd->command = wlan_cpu_to_le16(pcmd->command); pcmd->size = wlan_cpu_to_le16(pcmd->size); pcfg_data->action = wlan_cpu_to_le16(pcfg_data->action); pcfg_data->type = wlan_cpu_to_le16(pcfg_data->type); pcfg_data->data_len = wlan_cpu_to_le16(pcfg_data->data_len); LEAVE(); return ret; } /** * @brief This function handles the command response of set_cfg_data * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to A pointer to mlan_ioctl_req * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_ret_cfg_data(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND *resp, IN t_void *pioctl_buf) { mlan_status ret = MLAN_STATUS_SUCCESS; t_u8 event_buf[100]; mlan_cmdresp_event *pevent = (mlan_cmdresp_event *)event_buf; mlan_adapter *pmadapter = pmpriv->adapter; HostCmd_DS_802_11_CFG_DATA *pcfg_data = &resp->params.cfg_data; t_u16 action; t_u16 type; ENTER(); if (resp->result != HostCmd_RESULT_OK) { PRINTM(MERROR, "CFG data cmd resp failed\n"); ret = MLAN_STATUS_FAILURE; } if (!pmadapter->pdpd_data && (pmadapter->dpd_data_len == UNKNOW_DPD_LENGTH) && pmadapter->hw_status == WlanHardwareStatusGetHwSpec) { action = wlan_le16_to_cpu(pcfg_data->action); type = wlan_le16_to_cpu(pcfg_data->type); if (action == HostCmd_ACT_GEN_GET && (type == OID_TYPE_DPD)) { pcfg_data->action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_STORE_HOST_CMD_RESP; pevent->resp = (t_u8 *)resp; pevent->event_len = resp->size; wlan_recv_event(pmpriv, MLAN_EVENT_ID_STORE_HOST_CMD_RESP, (mlan_event *)pevent); } } LEAVE(); return ret; } /** * @brief This function prepares command of mac_control. * * @param pmpriv A pointer to mlan_private structure * @param pcmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action Command action * @param pdata_buf A pointer to command information buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *pcmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_MAC_CONTROL *pmac = &pcmd->params.mac_ctrl; t_u32 action = 0; ENTER(); if (cmd_action != HostCmd_ACT_GEN_SET) { PRINTM(MERROR, "wlan_cmd_mac_control(): support SET only.\n"); LEAVE(); return MLAN_STATUS_FAILURE; } pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL); pcmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN); if (pdata_buf) { action = *((t_u32 *)pdata_buf); pmac->action = wlan_cpu_to_le32(action); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of mac_control * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_mac_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { ENTER(); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of get_hw_spec * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_ret_get_hw_spec(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, t_void *pioctl_buf) { HostCmd_DS_GET_HW_SPEC *hw_spec = &resp->params.hw_spec; mlan_adapter *pmadapter = pmpriv->adapter; mlan_status ret = MLAN_STATUS_SUCCESS; t_u32 i; t_u16 left_len; t_u16 tlv_type = 0; t_u16 tlv_len = 0; MrvlIEtypes_fw_ver_info_t *api_rev = MNULL; t_u16 api_id = 0; MrvlIEtypesHeader_t *tlv = MNULL; pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf; MrvlIEtypes_Max_Conn_t *tlv_max_conn = MNULL; MrvlIEtypes_Extension_t *ext_tlv = MNULL; MrvlIEtypes_fw_cap_info_t *fw_cap_tlv = MNULL; MrvlIEtypes_Secure_Boot_Uuid_t *sb_uuid_tlv = MNULL; ENTER(); pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info); pmadapter->fw_cap_info &= pmadapter->init_para.dev_cap_mask; PRINTM(MMSG, "fw_cap_info=0x%x, dev_cap_mask=0x%x\n", wlan_le32_to_cpu(hw_spec->fw_cap_info), pmadapter->init_para.dev_cap_mask); #ifdef STA_SUPPORT if (IS_SUPPORT_MULTI_BANDS(pmadapter)) pmadapter->fw_bands = (t_u8)GET_FW_DEFAULT_BANDS(pmadapter); else pmadapter->fw_bands = BAND_B; if ((pmadapter->fw_bands & BAND_A) && (pmadapter->fw_bands & BAND_GN)) pmadapter->fw_bands |= BAND_AN; if (!(pmadapter->fw_bands & BAND_G) && (pmadapter->fw_bands & BAND_GN)) pmadapter->fw_bands &= ~BAND_GN; pmadapter->config_bands = pmadapter->fw_bands; for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) pmadapter->priv[i]->config_bands = pmadapter->fw_bands; } if (pmadapter->fw_bands & BAND_A) { if (pmadapter->fw_bands & BAND_AN) { pmadapter->config_bands |= BAND_AN; for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) pmadapter->priv[i]->config_bands |= BAND_AN; } } if (pmadapter->fw_bands & BAND_AAC) { pmadapter->config_bands |= BAND_AAC; for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) pmadapter->priv[i]->config_bands |= BAND_AAC; } } if (pmadapter->fw_bands & BAND_GAC) { pmadapter->config_bands |= BAND_GAC; for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) pmadapter->priv[i]->config_bands |= BAND_GAC; } } pmadapter->adhoc_start_band = BAND_A; pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A; } else if (pmadapter->fw_bands & BAND_G) { pmadapter->adhoc_start_band = BAND_G | BAND_B; pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; } else if (pmadapter->fw_bands & BAND_B) { pmadapter->adhoc_start_band = BAND_B; pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL; } #endif /* STA_SUPPORT */ pmadapter->fw_release_number = wlan_le32_to_cpu(hw_spec->fw_release_number); pmadapter->number_of_antenna = wlan_le16_to_cpu(hw_spec->number_of_antenna) & 0x00ff; pmadapter->antinfo = (wlan_le16_to_cpu(hw_spec->number_of_antenna) & 0xff00) >> 8; PRINTM(MCMND, "num_ant=%d, antinfo=0x%x\n", pmadapter->number_of_antenna, pmadapter->antinfo); PRINTM(MINFO, "GET_HW_SPEC: fw_release_number- 0x%X\n", pmadapter->fw_release_number); PRINTM(MINFO, "GET_HW_SPEC: Permanent addr- " MACSTR "\n", MAC2STR(hw_spec->permanent_addr)); PRINTM(MINFO, "GET_HW_SPEC: hw_if_version=0x%X version=0x%X\n", wlan_le16_to_cpu(hw_spec->hw_if_version), wlan_le16_to_cpu(hw_spec->version)); if (pmpriv->curr_addr[0] == 0xff) memmove(pmadapter, pmpriv->curr_addr, hw_spec->permanent_addr, MLAN_MAC_ADDR_LENGTH); memmove(pmadapter, pmadapter->permanent_addr, hw_spec->permanent_addr, MLAN_MAC_ADDR_LENGTH); pmadapter->hw_dot_11n_dev_cap = wlan_le32_to_cpu(hw_spec->dot_11n_dev_cap); pmadapter->hw_dev_mcs_support = hw_spec->dev_mcs_support; pmadapter->hw_mpdu_density = GET_MPDU_DENSITY(hw_spec->hw_dev_cap); PRINTM(MCMND, "GET_HW_SPEC: hw_mpdu_density=%d dev_mcs_support=0x%x\n", pmadapter->hw_mpdu_density, hw_spec->dev_mcs_support); for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) wlan_update_11n_cap(pmadapter->priv[i]); } wlan_show_dot11ndevcap(pmadapter, pmadapter->hw_dot_11n_dev_cap); wlan_show_devmcssupport(pmadapter, pmadapter->hw_dev_mcs_support); pmadapter->user_htstream = pmadapter->hw_dev_mcs_support; /** separate stream config for 2.4G and 5G, will be changed according to * antenna cfg*/ if (pmadapter->fw_bands & BAND_A) pmadapter->user_htstream |= (pmadapter->user_htstream << 8); PRINTM(MCMND, "user_htstream=0x%x\n", pmadapter->user_htstream); if (ISSUPP_BEAMFORMING(pmadapter->hw_dot_11n_dev_cap)) { PRINTM(MCMND, "Enable Beamforming\n"); for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) pmadapter->priv[i]->tx_bf_cap = pmadapter->pcard_info ->default_11n_tx_bf_cap; } } pmadapter->hw_dot_11ac_dev_cap = wlan_le32_to_cpu(hw_spec->Dot11acDevCap); pmadapter->hw_dot_11ac_mcs_support = wlan_le32_to_cpu(hw_spec->Dot11acMcsSupport); for (i = 0; i < pmadapter->priv_num; i++) { if (pmadapter->priv[i]) wlan_update_11ac_cap(pmadapter->priv[i]); } wlan_show_dot11acdevcap(pmadapter, pmadapter->hw_dot_11ac_dev_cap); wlan_show_dot11acmcssupport(pmadapter, pmadapter->hw_dot_11ac_mcs_support); #ifdef SDIO if (IS_SD(pmadapter->card_type)) { pmadapter->pcard_sd->mp_end_port = wlan_le16_to_cpu(hw_spec->mp_end_port); for (i = 1; i <= (unsigned)(pmadapter->pcard_sd->max_ports - pmadapter->pcard_sd->mp_end_port); i++) pmadapter->pcard_sd->mp_data_port_mask &= ~(1 << (pmadapter->pcard_sd->max_ports - i)); } #endif pmadapter->max_mgmt_ie_index = wlan_le16_to_cpu(hw_spec->mgmt_buf_count); PRINTM(MCMND, "GET_HW_SPEC: mgmt IE count=%d\n", pmadapter->max_mgmt_ie_index); if (!pmadapter->max_mgmt_ie_index || pmadapter->max_mgmt_ie_index > MAX_MGMT_IE_INDEX) pmadapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; pmadapter->region_code = wlan_le16_to_cpu(hw_spec->region_code); for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* Use the region code to search for the index */ if (pmadapter->region_code == region_code_index[i]) break; } /* If it's unidentified region code, use the default */ if (i >= MRVDRV_MAX_REGION_CODE) { pmadapter->region_code = MRVDRV_DEFAULT_REGION_CODE; PRINTM(MWARN, "unidentified region code, use the default (0x%02x)\n", MRVDRV_DEFAULT_REGION_CODE); } /* Synchronize CFP code with region code */ pmadapter->cfp_code_bg = pmadapter->region_code; pmadapter->cfp_code_a = pmadapter->region_code; if (pmadapter->fw_cap_info & ENHANCE_EXT_SCAN_ENABLE) pmadapter->ext_scan_enh = MTRUE; #ifdef SDIO if (IS_SD(pmadapter->card_type)) { } #endif #ifdef STA_SUPPORT if (wlan_11d_set_universaltable(pmpriv, pmadapter->fw_bands)) { if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; ret = MLAN_STATUS_FAILURE; goto done; } #endif /* STA_SUPPORT */ if (pmadapter->fw_cap_info & FW_CAPINFO_ECSA) { t_u8 ecsa_enable = MTRUE; pmadapter->ecsa_enable = MTRUE; PRINTM(MCMND, "pmadapter->ecsa_enable=%d\n", pmadapter->ecsa_enable); ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, ECSAEnable_i, MNULL, &ecsa_enable); if (ret) { ret = MLAN_STATUS_FAILURE; goto done; } } if (pmadapter->fw_cap_info & FW_CAPINFO_GET_LOG) { pmadapter->getlog_enable = MTRUE; PRINTM(MCMND, "pmadapter->getlog_enable=%d\n", pmadapter->getlog_enable); } left_len = resp->size - sizeof(HostCmd_DS_GET_HW_SPEC) - S_DS_GEN; tlv = (MrvlIEtypesHeader_t *)((t_u8 *)hw_spec + sizeof(HostCmd_DS_GET_HW_SPEC)); while (left_len > sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); switch (tlv_type) { case TLV_TYPE_FW_VER_INFO: api_rev = (MrvlIEtypes_fw_ver_info_t *)tlv; api_id = wlan_le16_to_cpu(api_rev->api_id); switch (api_id) { case FW_API_VER_ID: pmadapter->fw_ver = api_rev->major_ver; pmadapter->fw_min_ver = api_rev->minor_ver; PRINTM(MCMND, "fw ver=%d.%d\n", api_rev->major_ver, api_rev->minor_ver); break; case UAP_FW_API_VER_ID: pmadapter->uap_fw_ver = api_rev->major_ver; PRINTM(MCMND, "uap fw ver=%d.%d\n", api_rev->major_ver, api_rev->minor_ver); break; case CHANRPT_API_VER_ID: pmadapter->chanrpt_param_bandcfg = api_rev->minor_ver; PRINTM(MCMND, "chanrpt api ver=%d.%d\n", api_rev->major_ver, api_rev->minor_ver); break; case FW_HOTFIX_VER_ID: pmadapter->fw_hotfix_ver = api_rev->major_ver; PRINTM(MCMND, "fw hotfix ver=%d\n", api_rev->major_ver); break; default: break; } break; case TLV_TYPE_MAX_CONN: tlv_max_conn = (MrvlIEtypes_Max_Conn_t *)tlv; PRINTM(MMSG, "max_p2p_conn = %d, max_sta_conn = %d\n", tlv_max_conn->max_p2p_conn, tlv_max_conn->max_sta_conn); if (tlv_max_conn->max_p2p_conn && tlv_max_conn->max_sta_conn) pmadapter->max_sta_conn = MIN(tlv_max_conn->max_sta_conn, tlv_max_conn->max_p2p_conn); else if (tlv_max_conn->max_sta_conn) pmadapter->max_sta_conn = tlv_max_conn->max_sta_conn; else if (tlv_max_conn->max_p2p_conn) pmadapter->max_sta_conn = tlv_max_conn->max_p2p_conn; else pmadapter->max_sta_conn = 0; break; case TLV_TYPE_EXTENSION_ID: ext_tlv = (MrvlIEtypes_Extension_t *)tlv; if (ext_tlv->ext_id == HE_CAPABILITY) { ext_tlv->type = tlv_type; ext_tlv->len = tlv_len; wlan_update_11ax_cap( pmadapter, (MrvlIEtypes_Extension_t *)ext_tlv); } break; case TLV_TYPE_FW_CAP_INFO: fw_cap_tlv = (MrvlIEtypes_fw_cap_info_t *)tlv; pmadapter->fw_cap_info = wlan_le32_to_cpu(fw_cap_tlv->fw_cap_info); pmadapter->fw_cap_ext = wlan_le32_to_cpu(fw_cap_tlv->fw_cap_ext); PRINTM(MCMND, "fw_cap_info=0x%x fw_cap_ext=0x%x\n", pmadapter->fw_cap_info, pmadapter->fw_cap_ext); break; case TLV_TYPE_SECURE_BOOT_UUID: sb_uuid_tlv = (MrvlIEtypes_Secure_Boot_Uuid_t *)tlv; pmadapter->uuid_lo = sb_uuid_tlv->uuid_lo; pmadapter->uuid_hi = sb_uuid_tlv->uuid_hi; PRINTM(MMSG, "uuid: %016llx%016llx\n", pmadapter->uuid_lo, pmadapter->uuid_hi); break; default: break; } left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code, pmadapter->fw_bands)) { if (pioctl_req) pioctl_req->status_code = MLAN_ERROR_IOCTL_FAIL; ret = MLAN_STATUS_FAILURE; goto done; } done: LEAVE(); return ret; } /** * @brief This function prepares command of radio_control. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_802_11_radio_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_802_11_RADIO_CONTROL *pradio_control = &cmd->params.radio; t_u32 radio_ctl = 0; ENTER(); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL)) + S_DS_GEN); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL); pradio_control->action = wlan_cpu_to_le16(cmd_action); memcpy_ext(pmpriv->adapter, &radio_ctl, pdata_buf, sizeof(t_u32), sizeof(radio_ctl)); pradio_control->control = wlan_cpu_to_le16((t_u16)radio_ctl); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of radio_control * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_radio_control(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_802_11_RADIO_CONTROL *pradio_ctrl = (HostCmd_DS_802_11_RADIO_CONTROL *)&resp->params.radio; mlan_ds_radio_cfg *radio_cfg = MNULL; mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); pmadapter->radio_on = wlan_le16_to_cpu(pradio_ctrl->control); if (pioctl_buf) { radio_cfg = (mlan_ds_radio_cfg *)pioctl_buf->pbuf; radio_cfg->param.radio_on_off = (t_u32)pmadapter->radio_on; pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of remain_on_channel. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_remain_on_channel(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel = &cmd->params.remain_on_chan; mlan_ds_remain_chan *cfg = (mlan_ds_remain_chan *)pdata_buf; ENTER(); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_REMAIN_ON_CHANNEL)) + S_DS_GEN); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_REMAIN_ON_CHANNEL); remain_channel->action = cmd_action; if (cmd_action == HostCmd_ACT_GEN_SET) { if (cfg->remove) { remain_channel->action = HostCmd_ACT_GEN_REMOVE; } else { remain_channel->bandcfg = cfg->bandcfg; remain_channel->channel = cfg->channel; remain_channel->remain_period = wlan_cpu_to_le32(cfg->remain_period); } } remain_channel->action = wlan_cpu_to_le16(remain_channel->action); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of remain_on_channel * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_remain_on_channel(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_REMAIN_ON_CHANNEL *remain_channel = &resp->params.remain_on_chan; mlan_ds_radio_cfg *radio_cfg = MNULL; t_u16 action = wlan_le16_to_cpu(remain_channel->action); ENTER(); if (action == HostCmd_ACT_GEN_REMOVE) pmpriv->adapter->remain_on_channel = MFALSE; else pmpriv->adapter->remain_on_channel = MTRUE; if (pioctl_buf) { radio_cfg = (mlan_ds_radio_cfg *)pioctl_buf->pbuf; radio_cfg->param.remain_chan.status = remain_channel->status; radio_cfg->param.remain_chan.bandcfg = remain_channel->bandcfg; radio_cfg->param.remain_chan.channel = remain_channel->channel; radio_cfg->param.remain_chan.remain_period = wlan_le32_to_cpu(remain_channel->remain_period); pioctl_buf->data_read_written = sizeof(mlan_ds_radio_cfg); } LEAVE(); return MLAN_STATUS_SUCCESS; } #ifdef WIFI_DIRECT_SUPPORT /** * @brief This function prepares command of wifi direct mode. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_wifi_direct_mode(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &cmd->params.wifi_direct_mode; t_u16 mode = *((t_u16 *)pdata_buf); ENTER(); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_WIFI_DIRECT_MODE)) + S_DS_GEN); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_WIFI_DIRECT_MODE_CONFIG); wfd_mode->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) wfd_mode->mode = wlan_cpu_to_le16(mode); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of wifi direct mode * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_wifi_direct_mode(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_WIFI_DIRECT_MODE *wfd_mode = &resp->params.wifi_direct_mode; mlan_ds_bss *bss = MNULL; ENTER(); if (pioctl_buf) { bss = (mlan_ds_bss *)pioctl_buf->pbuf; bss->param.wfd_mode = wlan_le16_to_cpu(wfd_mode->mode); pioctl_buf->data_read_written = sizeof(mlan_ds_bss); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of p2p_params_config. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_p2p_params_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG *p2p_config = &cmd->params.p2p_params_config; mlan_ds_wifi_direct_config *cfg = (mlan_ds_wifi_direct_config *)pdata_buf; MrvlIEtypes_NoA_setting_t *pnoa_tlv = MNULL; MrvlIEtypes_OPP_PS_setting_t *popp_ps_tlv = MNULL; t_u8 *tlv = MNULL; ENTER(); cmd->size = sizeof(HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG) + S_DS_GEN; cmd->command = wlan_cpu_to_le16(HostCmd_CMD_P2P_PARAMS_CONFIG); p2p_config->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { tlv = (t_u8 *)p2p_config->tlv_buf; if (cfg->flags & WIFI_DIRECT_NOA) { pnoa_tlv = (MrvlIEtypes_NoA_setting_t *)tlv; pnoa_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_NOA); pnoa_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_NoA_setting_t) - sizeof(MrvlIEtypesHeader_t)); pnoa_tlv->enable = cfg->noa_enable; pnoa_tlv->index = wlan_cpu_to_le16(cfg->index); pnoa_tlv->noa_count = cfg->noa_count; pnoa_tlv->noa_duration = wlan_cpu_to_le32(cfg->noa_duration); pnoa_tlv->noa_interval = wlan_cpu_to_le32(cfg->noa_interval); cmd->size += sizeof(MrvlIEtypes_NoA_setting_t); tlv += sizeof(MrvlIEtypes_NoA_setting_t); PRINTM(MCMND, "Set NOA: enable=%d index=%d, count=%d, duration=%d interval=%d\n", cfg->noa_enable, cfg->index, cfg->noa_count, (int)cfg->noa_duration, (int)cfg->noa_interval); } if (cfg->flags & WIFI_DIRECT_OPP_PS) { popp_ps_tlv = (MrvlIEtypes_OPP_PS_setting_t *)tlv; popp_ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_OPP_PS); popp_ps_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_OPP_PS_setting_t) - sizeof(MrvlIEtypesHeader_t)); popp_ps_tlv->enable = cfg->ct_window; popp_ps_tlv->enable |= cfg->opp_ps_enable << 7; cmd->size += sizeof(MrvlIEtypes_OPP_PS_setting_t); PRINTM(MCMND, "Set OPP_PS: enable=%d ct_win=%d\n", cfg->opp_ps_enable, cfg->ct_window); } } else if (cmd_action == HostCmd_ACT_GEN_GET) { tlv = (t_u8 *)p2p_config->tlv_buf; if (cfg->flags & WIFI_DIRECT_NOA) { pnoa_tlv = (MrvlIEtypes_NoA_setting_t *)tlv; pnoa_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_NOA); pnoa_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_NoA_setting_t) - sizeof(MrvlIEtypesHeader_t)); cmd->size += sizeof(MrvlIEtypes_NoA_setting_t); tlv += sizeof(MrvlIEtypes_NoA_setting_t); } if (cfg->flags & WIFI_DIRECT_OPP_PS) { popp_ps_tlv = (MrvlIEtypes_OPP_PS_setting_t *)tlv; popp_ps_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_WIFI_DIRECT_OPP_PS); popp_ps_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_OPP_PS_setting_t) - sizeof(MrvlIEtypesHeader_t)); cmd->size += sizeof(MrvlIEtypes_OPP_PS_setting_t); } } cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of p2p_params_config * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_p2p_params_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG *p2p_config = &resp->params.p2p_params_config; mlan_ds_misc_cfg *cfg = MNULL; MrvlIEtypes_NoA_setting_t *pnoa_tlv = MNULL; MrvlIEtypes_OPP_PS_setting_t *popp_ps_tlv = MNULL; MrvlIEtypesHeader_t *tlv = MNULL; t_u16 tlv_buf_left = 0; t_u16 tlv_type = 0; t_u16 tlv_len = 0; ENTER(); if (wlan_le16_to_cpu(p2p_config->action) == HostCmd_ACT_GEN_GET) { if (pioctl_buf) { cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; tlv = (MrvlIEtypesHeader_t *)(p2p_config->tlv_buf); tlv_buf_left = resp->size - (sizeof(HostCmd_DS_WIFI_DIRECT_PARAM_CONFIG) + S_DS_GEN); while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) { PRINTM(MERROR, "Error processing p2p param config TLVs, bytes left < TLV length\n"); break; } switch (tlv_type) { case TLV_TYPE_WIFI_DIRECT_NOA: pnoa_tlv = (MrvlIEtypes_NoA_setting_t *) tlv; cfg->param.p2p_config.flags |= WIFI_DIRECT_NOA; cfg->param.p2p_config.noa_enable = pnoa_tlv->enable; cfg->param.p2p_config.index = wlan_le16_to_cpu( pnoa_tlv->index); cfg->param.p2p_config.noa_count = pnoa_tlv->noa_count; cfg->param.p2p_config.noa_duration = wlan_le32_to_cpu( pnoa_tlv->noa_duration); cfg->param.p2p_config.noa_interval = wlan_le32_to_cpu( pnoa_tlv->noa_interval); PRINTM(MCMND, "Get NOA: enable=%d index=%d, count=%d, duration=%d interval=%d\n", cfg->param.p2p_config.noa_enable, cfg->param.p2p_config.index, cfg->param.p2p_config.noa_count, (int)cfg->param.p2p_config .noa_duration, (int)cfg->param.p2p_config .noa_interval); break; case TLV_TYPE_WIFI_DIRECT_OPP_PS: popp_ps_tlv = (MrvlIEtypes_OPP_PS_setting_t *) tlv; cfg->param.p2p_config.flags |= WIFI_DIRECT_OPP_PS; cfg->param.p2p_config.opp_ps_enable = (popp_ps_tlv->enable & 0x80) >> 7; cfg->param.p2p_config.ct_window = popp_ps_tlv->enable & 0x7f; PRINTM(MCMND, "Get OPP_PS: enable=%d ct_win=%d\n", cfg->param.p2p_config .opp_ps_enable, cfg->param.p2p_config.ct_window); break; default: break; } tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } pioctl_buf->data_read_written = sizeof(mlan_ds_wifi_direct_config); } } LEAVE(); return MLAN_STATUS_SUCCESS; } #endif /** * @brief This function prepares command of GPIO TSF LATCH. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pioctl_buf A pointer to mlan_ioctl_req buf * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_gpio_tsf_latch(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, mlan_ioctl_req *pioctl_buf, t_void *pdata_buf) { HostCmd_DS_GPIO_TSF_LATCH_PARAM_CONFIG *gpio_tsf_config = &cmd->params.gpio_tsf_latch; mlan_ds_gpio_tsf_latch *cfg = (mlan_ds_gpio_tsf_latch *)pdata_buf; mlan_ds_misc_cfg *misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; mlan_ds_tsf_info *tsf_info = (mlan_ds_tsf_info *)pdata_buf; MrvlIEtypes_GPIO_TSF_LATCH_CONFIG *gpio_tsf_latch_config = MNULL; MrvlIEtypes_GPIO_TSF_LATCH_REPORT *gpio_tsf_latch_report = MNULL; t_u8 *tlv = MNULL; ENTER(); cmd->size = sizeof(HostCmd_DS_GPIO_TSF_LATCH_PARAM_CONFIG) + S_DS_GEN; cmd->command = wlan_cpu_to_le16(HostCmd_CMD_GPIO_TSF_LATCH_PARAM_CONFIG); gpio_tsf_config->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { tlv = (t_u8 *)gpio_tsf_config->tlv_buf; if (misc_cfg->sub_command == MLAN_OID_MISC_GPIO_TSF_LATCH) { gpio_tsf_latch_config = (MrvlIEtypes_GPIO_TSF_LATCH_CONFIG *)tlv; gpio_tsf_latch_config->header.type = wlan_cpu_to_le16( TLV_TYPE_GPIO_TSF_LATCH_CONFIG); gpio_tsf_latch_config->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_GPIO_TSF_LATCH_CONFIG) - sizeof(MrvlIEtypesHeader_t)); gpio_tsf_latch_config->clock_sync_mode = cfg->clock_sync_mode; gpio_tsf_latch_config->clock_sync_Role = cfg->clock_sync_Role; gpio_tsf_latch_config->clock_sync_gpio_pin_number = cfg->clock_sync_gpio_pin_number; gpio_tsf_latch_config->clock_sync_gpio_level_toggle = cfg->clock_sync_gpio_level_toggle; gpio_tsf_latch_config->clock_sync_gpio_pulse_width = wlan_cpu_to_le16( cfg->clock_sync_gpio_pulse_width); cmd->size += sizeof(MrvlIEtypes_GPIO_TSF_LATCH_CONFIG); tlv += sizeof(MrvlIEtypes_GPIO_TSF_LATCH_CONFIG); PRINTM(MCMND, "Set GPIO TSF latch config: Mode=%d Role=%d, GPIO Pin Number=%d, GPIO level/toggle=%d GPIO pulse width=%d\n", cfg->clock_sync_mode, cfg->clock_sync_Role, cfg->clock_sync_gpio_pin_number, cfg->clock_sync_gpio_level_toggle, (int)cfg->clock_sync_gpio_pulse_width); } } else if (cmd_action == HostCmd_ACT_GEN_GET) { tlv = (t_u8 *)gpio_tsf_config->tlv_buf; if (misc_cfg->sub_command == MLAN_OID_MISC_GPIO_TSF_LATCH) { gpio_tsf_latch_config = (MrvlIEtypes_GPIO_TSF_LATCH_CONFIG *)tlv; gpio_tsf_latch_config->header.type = wlan_cpu_to_le16( TLV_TYPE_GPIO_TSF_LATCH_CONFIG); gpio_tsf_latch_config->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_GPIO_TSF_LATCH_CONFIG) - sizeof(MrvlIEtypesHeader_t)); cmd->size += sizeof(MrvlIEtypes_GPIO_TSF_LATCH_CONFIG); tlv += sizeof(MrvlIEtypes_GPIO_TSF_LATCH_CONFIG); } if (misc_cfg->sub_command == MLAN_OID_MISC_GET_TSF_INFO) { gpio_tsf_latch_report = (MrvlIEtypes_GPIO_TSF_LATCH_REPORT *)tlv; gpio_tsf_latch_report->header.type = wlan_cpu_to_le16( TLV_TYPE_GPIO_TSF_LATCH_REPORT); gpio_tsf_latch_report->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_GPIO_TSF_LATCH_REPORT) - sizeof(MrvlIEtypesHeader_t)); gpio_tsf_latch_report->tsf_format = wlan_cpu_to_le16(tsf_info->tsf_format); PRINTM(MCMND, "Get TSF info: format=%d\n", tsf_info->tsf_format); cmd->size += sizeof(MrvlIEtypes_GPIO_TSF_LATCH_REPORT); } } cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of GPIO TSF Latch * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_gpio_tsf_latch(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_GPIO_TSF_LATCH_PARAM_CONFIG *gpio_tsf_config = &resp->params.gpio_tsf_latch; mlan_ds_misc_cfg *cfg = MNULL; MrvlIEtypes_GPIO_TSF_LATCH_CONFIG *gpio_tsf_latch_config = MNULL; MrvlIEtypes_GPIO_TSF_LATCH_REPORT *gpio_tsf_latch_report = MNULL; MrvlIEtypesHeader_t *tlv = MNULL; t_u16 tlv_buf_left = 0; t_u16 tlv_type = 0; t_u16 tlv_len = 0; ENTER(); if (wlan_le16_to_cpu(gpio_tsf_config->action) == HostCmd_ACT_GEN_GET) { if (pioctl_buf) { cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; tlv = (MrvlIEtypesHeader_t *)(gpio_tsf_config->tlv_buf); tlv_buf_left = resp->size - (sizeof(HostCmd_DS_GPIO_TSF_LATCH_PARAM_CONFIG) + S_DS_GEN); while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) { PRINTM(MERROR, "Error processing gpio tsf latch config TLVs, bytes left < TLV length\n"); break; } switch (tlv_type) { case TLV_TYPE_GPIO_TSF_LATCH_CONFIG: if (cfg->sub_command == MLAN_OID_MISC_GPIO_TSF_LATCH) { gpio_tsf_latch_config = (MrvlIEtypes_GPIO_TSF_LATCH_CONFIG *)tlv; cfg->param.gpio_tsf_latch_config .clock_sync_mode = gpio_tsf_latch_config ->clock_sync_mode; cfg->param.gpio_tsf_latch_config .clock_sync_Role = gpio_tsf_latch_config ->clock_sync_Role; cfg->param.gpio_tsf_latch_config .clock_sync_gpio_pin_number = gpio_tsf_latch_config ->clock_sync_gpio_pin_number; cfg->param.gpio_tsf_latch_config .clock_sync_gpio_level_toggle = gpio_tsf_latch_config ->clock_sync_gpio_level_toggle; cfg->param.gpio_tsf_latch_config .clock_sync_gpio_pulse_width = wlan_le16_to_cpu( gpio_tsf_latch_config ->clock_sync_gpio_pulse_width); PRINTM(MCMND, "Get GPIO TSF latch config: Mode=%d Role=%d, GPIO Pin Number=%d, GPIO level/toggle=%d GPIO pulse width=%d\n", cfg->param .gpio_tsf_latch_config .clock_sync_mode, cfg->param .gpio_tsf_latch_config .clock_sync_Role, cfg->param .gpio_tsf_latch_config .clock_sync_gpio_pin_number, cfg->param .gpio_tsf_latch_config .clock_sync_gpio_level_toggle, (int)cfg->param .gpio_tsf_latch_config .clock_sync_gpio_pulse_width); } break; case TLV_TYPE_GPIO_TSF_LATCH_REPORT: if (cfg->sub_command == MLAN_OID_MISC_GET_TSF_INFO) { gpio_tsf_latch_report = (MrvlIEtypes_GPIO_TSF_LATCH_REPORT *)tlv; cfg->param.tsf_info .tsf_format = wlan_le16_to_cpu( gpio_tsf_latch_report ->tsf_format); cfg->param.tsf_info .tsf_info = wlan_le16_to_cpu( gpio_tsf_latch_report ->tsf_info); cfg->param.tsf_info .tsf = wlan_le64_to_cpu( gpio_tsf_latch_report ->tsf); cfg->param.tsf_info .tsf_offset = wlan_le16_to_cpu( gpio_tsf_latch_report ->tsf_offset); PRINTM(MCMND, "Get GPIO TSF latch report : format=%d\n info=%d tsf=%llu offset=%d", cfg->param.tsf_info .tsf_format, cfg->param.tsf_info .tsf_info, cfg->param.tsf_info.tsf, cfg->param.tsf_info .tsf_offset); } break; default: break; } tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } if (cfg->sub_command == MLAN_OID_MISC_GPIO_TSF_LATCH) pioctl_buf->data_read_written = sizeof(mlan_ds_gpio_tsf_latch); else if (cfg->sub_command == MLAN_OID_MISC_GET_TSF_INFO) pioctl_buf->data_read_written = sizeof(mlan_ds_tsf_info); } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of CROSS CHIP SYNCH. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_cross_chip_synch(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CROSS_CHIP_SYNCH *cross_chip_synch = &cmd->params.cross_chip_synch; mlan_ds_cross_chip_synch *cfg = (mlan_ds_cross_chip_synch *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CROSS_CHIP_SYNCH); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CROSS_CHIP_SYNCH) + S_DS_GEN); cross_chip_synch->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cross_chip_synch->start_stop = cfg->start_stop; cross_chip_synch->role = cfg->role; cross_chip_synch->period = wlan_cpu_to_le32(cfg->period); cross_chip_synch->init_tsf_low = wlan_cpu_to_le32(cfg->init_tsf_low); cross_chip_synch->init_tsf_high = wlan_cpu_to_le32(cfg->init_tsf_high); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of CROSS CHIP SYNCH. * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND structure * @param pioctl_buf A pointer to mlan_ioctl_req buf * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_cross_chip_synch(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CROSS_CHIP_SYNCH *cross_chip_synch = &resp->params.cross_chip_synch; mlan_ds_misc_cfg *cfg = MNULL; ENTER(); if (pioctl_buf) { cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; if (wlan_le16_to_cpu(cross_chip_synch->action) == HostCmd_ACT_GEN_GET) { cfg->param.cross_chip_synch.start_stop = cross_chip_synch->start_stop; cfg->param.cross_chip_synch.role = cross_chip_synch->role; cfg->param.cross_chip_synch.period = wlan_le32_to_cpu(cross_chip_synch->period); cfg->param.cross_chip_synch.init_tsf_low = wlan_le32_to_cpu( cross_chip_synch->init_tsf_low); cfg->param.cross_chip_synch.init_tsf_high = wlan_le32_to_cpu( cross_chip_synch->init_tsf_high); } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of mimo switch configuration. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_802_11_mimo_switch(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_void *pdata_buf) { HostCmd_DS_MIMO_SWITCH *mimo_switch_cmd = &cmd->params.mimo_switch; mlan_ds_mimo_switch *pmimo_switch = (mlan_ds_mimo_switch *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MIMO_SWITCH); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_MIMO_SWITCH)) + S_DS_GEN); mimo_switch_cmd->txpath_antmode = pmimo_switch->txpath_antmode; mimo_switch_cmd->rxpath_antmode = pmimo_switch->rxpath_antmode; LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of hs wakeup reason. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_hs_wakeup_reason(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_void *pdata_buf) { ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_HS_WAKEUP_REASON); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_HS_WAKEUP_REASON)) + S_DS_GEN); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of * hs wakeup reason * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_hs_wakeup_reason(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_HS_WAKEUP_REASON *hs_wakeup_reason = (HostCmd_DS_HS_WAKEUP_REASON *)&resp->params.hs_wakeup_reason; mlan_ds_pm_cfg *pm_cfg = MNULL; ENTER(); pm_cfg = (mlan_ds_pm_cfg *)pioctl_buf->pbuf; pm_cfg->param.wakeup_reason.hs_wakeup_reason = wlan_le16_to_cpu(hs_wakeup_reason->wakeup_reason); pioctl_buf->data_read_written = sizeof(mlan_ds_pm_cfg); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of tx_rx_pkt_stats * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param pioctl_buf A pointer to mlan_ioctl_req structure * @param pdata_buf A pointer to information buffer * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_tx_rx_pkt_stats(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, pmlan_ioctl_req pioctl_buf, t_void *pdata_buf) { HostCmd_DS_TX_RX_HISTOGRAM *ptx_rx_histogram = &cmd->params.tx_rx_histogram; mlan_ds_misc_tx_rx_histogram *ptx_rx_pkt_stats = (mlan_ds_misc_tx_rx_histogram *)pdata_buf; mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); if (!ptx_rx_pkt_stats) { ret = MLAN_STATUS_FAILURE; goto done; } cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_RX_PKT_STATS); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TX_RX_HISTOGRAM) + S_DS_GEN); ptx_rx_histogram->enable = ptx_rx_pkt_stats->enable; ptx_rx_histogram->action = wlan_cpu_to_le16(ptx_rx_pkt_stats->action); done: LEAVE(); return ret; } /** * @brief This function handles the command response of tx_rx_pkt_stats * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_tx_rx_pkt_stats(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_TX_RX_HISTOGRAM *ptx_rx_histogram = &resp->params.tx_rx_histogram; mlan_ds_misc_cfg *info; t_u16 cmdsize = resp->size; t_u16 length; t_u32 *pos, count = 0; ENTER(); if (pioctl_buf) { ptx_rx_histogram->action = wlan_le16_to_cpu(ptx_rx_histogram->action); info = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; length = cmdsize - S_DS_GEN - sizeof(HostCmd_DS_TX_RX_HISTOGRAM); if (length > 0) { info->param.tx_rx_histogram.size = length; memcpy_ext(pmpriv->adapter, info->param.tx_rx_histogram.value, (t_u8 *)ptx_rx_histogram + sizeof(HostCmd_DS_TX_RX_HISTOGRAM), length, info->param.tx_rx_histogram.size); pos = (t_u32 *)info->param.tx_rx_histogram.value; while (length - 4 * count) { *pos = wlan_le32_to_cpu(*pos); pos += 4; count++; } } } LEAVE(); return MLAN_STATUS_SUCCESS; } /* * @brief This function prepares command of cwmode control. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_cw_mode_ctrl(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CW_MODE_CTRL *cwmode_ctrl = &cmd->params.cwmode; mlan_ds_cw_mode_ctrl *cw_mode = (mlan_ds_cw_mode_ctrl *)pdata_buf; ENTER(); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_CW_MODE_CTRL)) + S_DS_GEN); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CW_MODE_CTRL); cwmode_ctrl->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cwmode_ctrl->mode = cw_mode->mode; cwmode_ctrl->channel = cw_mode->channel; cwmode_ctrl->chanInfo = cw_mode->chanInfo; cwmode_ctrl->txPower = wlan_cpu_to_le16(cw_mode->txPower); cwmode_ctrl->rateInfo = wlan_cpu_to_le32(cw_mode->rateInfo); cwmode_ctrl->pktLength = wlan_cpu_to_le16(cw_mode->pktLength); } LEAVE(); return MLAN_STATUS_SUCCESS; } /* * @brief This function handles the command response of cwmode_ctrl * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_cw_mode_ctrl(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CW_MODE_CTRL *cwmode_resp = &resp->params.cwmode; mlan_ds_misc_cfg *misc = MNULL; ENTER(); if (pioctl_buf) { misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc->param.cwmode.mode = cwmode_resp->mode; misc->param.cwmode.channel = cwmode_resp->channel; misc->param.cwmode.chanInfo = cwmode_resp->chanInfo; misc->param.cwmode.txPower = wlan_le16_to_cpu(cwmode_resp->txPower); misc->param.cwmode.rateInfo = wlan_le32_to_cpu(cwmode_resp->rateInfo); ; misc->param.cwmode.pktLength = wlan_le16_to_cpu(cwmode_resp->pktLength); ; pioctl_buf->data_read_written = sizeof(mlan_ds_misc_cfg); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of rf_antenna. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_802_11_rf_antenna(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_802_11_RF_ANTENNA *pantenna = &cmd->params.antenna; mlan_ds_ant_cfg *ant_cfg = (mlan_ds_ant_cfg *)pdata_buf; typedef struct _HostCmd_DS_802_11_RF_ANTENNA_1X1 { /** Action */ t_u16 action; /** Antenna or 0xffff (diversity) */ t_u16 antenna_mode; /** Evaluate time */ t_u16 evaluate_time; /** Current antenna */ t_u16 current_antenna; } HostCmd_DS_802_11_RF_ANTENNA_1X1; HostCmd_DS_802_11_RF_ANTENNA_1X1 *pantenna_1x1 = (HostCmd_DS_802_11_RF_ANTENNA_1X1 *)&cmd->params.antenna; mlan_ds_ant_cfg_1x1 *ant_cfg_1x1 = (mlan_ds_ant_cfg_1x1 *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA); if (!IS_STREAM_2X2(pmpriv->adapter->feature_control)) cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_802_11_RF_ANTENNA_1X1) + S_DS_GEN); else cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN); if (cmd_action == HostCmd_ACT_GEN_SET) { if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) { pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_SET_TX); pantenna->tx_antenna_mode = wlan_cpu_to_le16((t_u16)ant_cfg->tx_antenna); pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_SET_RX); pantenna->rx_antenna_mode = wlan_cpu_to_le16((t_u16)ant_cfg->rx_antenna); } else { pantenna_1x1->action = wlan_cpu_to_le16(HostCmd_ACT_SET_BOTH); pantenna_1x1->antenna_mode = wlan_cpu_to_le16((t_u16)ant_cfg_1x1->antenna); pantenna_1x1->evaluate_time = wlan_cpu_to_le16( (t_u16)ant_cfg_1x1->evaluate_time); } } else { if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) { pantenna->action_tx = wlan_cpu_to_le16(HostCmd_ACT_GET_TX); pantenna->action_rx = wlan_cpu_to_le16(HostCmd_ACT_GET_RX); } else { pantenna_1x1->action = wlan_cpu_to_le16(HostCmd_ACT_GET_BOTH); } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of rf_antenna * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_rf_antenna(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_802_11_RF_ANTENNA *pantenna = &resp->params.antenna; t_u16 tx_ant_mode = wlan_le16_to_cpu(pantenna->tx_antenna_mode); t_u16 rx_ant_mode = wlan_le16_to_cpu(pantenna->rx_antenna_mode); mlan_adapter *pmadapter = pmpriv->adapter; typedef struct _HostCmd_DS_802_11_RF_ANTENNA_1X1 { /** Action */ t_u16 action; /** Antenna or 0xffff (diversity) */ t_u16 antenna_mode; /** Evaluate time */ t_u16 evaluate_time; /** Current antenna */ t_u16 current_antenna; } HostCmd_DS_802_11_RF_ANTENNA_1X1; HostCmd_DS_802_11_RF_ANTENNA_1X1 *pantenna_1x1 = (HostCmd_DS_802_11_RF_ANTENNA_1X1 *)&resp->params.antenna; t_u16 ant_mode = wlan_le16_to_cpu(pantenna_1x1->antenna_mode); t_u16 evaluate_time = wlan_le16_to_cpu(pantenna_1x1->evaluate_time); t_u16 current_antenna = wlan_le16_to_cpu(pantenna_1x1->current_antenna); mlan_ds_radio_cfg *radio = MNULL; ENTER(); if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) { PRINTM(MCMND, "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x" " Rx action = 0x%x, Rx Mode = 0x%04x\n", wlan_le16_to_cpu(pantenna->action_tx), tx_ant_mode, wlan_le16_to_cpu(pantenna->action_rx), rx_ant_mode); if (IS_CARD9098(pmadapter->card_type) || IS_CARDIW624(pmadapter->card_type) || IS_CARDAW693(pmadapter->card_type) || IS_CARD9097(pmadapter->card_type)) { tx_ant_mode &= 0x0303; rx_ant_mode &= 0x0303; /** 2G antcfg TX */ if (tx_ant_mode & 0x00FF) { pmadapter->user_htstream &= ~0xF0; pmadapter->user_htstream |= (bitcount(tx_ant_mode & 0x00FF) << 4); } /* 5G antcfg tx */ if (tx_ant_mode & 0xFF00) { pmadapter->user_htstream &= ~0xF000; pmadapter->user_htstream |= (bitcount(tx_ant_mode & 0xFF00) << 12); } /* 2G antcfg RX */ if (rx_ant_mode & 0x00FF) { pmadapter->user_htstream &= ~0xF; pmadapter->user_htstream |= bitcount(rx_ant_mode & 0x00FF); } /* 5G antcfg RX */ if (rx_ant_mode & 0xFF00) { pmadapter->user_htstream &= ~0xF00; pmadapter->user_htstream |= (bitcount(rx_ant_mode & 0xFF00) << 8); } PRINTM(MCMND, "user_htstream=0x%x, tx_antenna=0x%x rx_antenna=0x%x\n", pmadapter->user_htstream, tx_ant_mode, rx_ant_mode); } } else PRINTM(MINFO, "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x, Evaluate time = %d, Current antenna = %d\n", wlan_le16_to_cpu(pantenna_1x1->action), ant_mode, evaluate_time, current_antenna); if (pioctl_buf) { radio = (mlan_ds_radio_cfg *)pioctl_buf->pbuf; if (IS_STREAM_2X2(pmpriv->adapter->feature_control)) { radio->param.ant_cfg.tx_antenna = tx_ant_mode; radio->param.ant_cfg.rx_antenna = rx_ant_mode; } else { radio->param.ant_cfg_1x1.antenna = ant_mode; radio->param.ant_cfg_1x1.evaluate_time = evaluate_time; radio->param.ant_cfg_1x1.current_antenna = current_antenna; } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of reg_access. * * @param priv A pointer to mlan_priv register. * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_reg_access(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { mlan_ds_reg_rw *reg_rw; MrvlIEtypes_Reg_type_t *tlv; mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); reg_rw = (mlan_ds_reg_rw *)pdata_buf; switch (cmd->command) { case HostCmd_CMD_MAC_REG_ACCESS: { HostCmd_DS_MAC_REG_ACCESS *mac_reg; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN); mac_reg = (HostCmd_DS_MAC_REG_ACCESS *)&cmd->params.mac_reg; mac_reg->action = wlan_cpu_to_le16(cmd_action); mac_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset); mac_reg->value = wlan_cpu_to_le32(reg_rw->value); if ((reg_rw->type == MLAN_REG_MAC2) && (IS_CARD9098(pmadapter->card_type) || IS_CARDIW624(pmadapter->card_type) || IS_CARDAW693(pmadapter->card_type) || IS_CARD9097(pmadapter->card_type))) { tlv = (MrvlIEtypes_Reg_type_t *)((t_u8 *)cmd + sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN); tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL); tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8)); tlv->type = MLAN_REG_MAC2; cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_MAC_REG_ACCESS) + S_DS_GEN + sizeof(MrvlIEtypes_Reg_type_t)); } break; } case HostCmd_CMD_REG_ACCESS: { HostCmd_DS_REG_ACCESS *reg; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_REG_ACCESS) + S_DS_GEN); reg = (HostCmd_DS_REG_ACCESS *)&cmd->params.reg; reg->action = wlan_cpu_to_le16(cmd_action); reg->reg_type = wlan_cpu_to_le16((t_u16)reg_rw->type); reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset); reg->value = wlan_cpu_to_le32(reg_rw->value); break; } case HostCmd_CMD_BBP_REG_ACCESS: { HostCmd_DS_BBP_REG_ACCESS *bbp_reg; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN); bbp_reg = (HostCmd_DS_BBP_REG_ACCESS *)&cmd->params.bbp_reg; bbp_reg->action = wlan_cpu_to_le16(cmd_action); bbp_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset); bbp_reg->value = (t_u8)reg_rw->value; if ((reg_rw->type == MLAN_REG_BBP2) && (IS_CARD9098(pmadapter->card_type) || IS_CARDIW624(pmadapter->card_type) || IS_CARDAW693(pmadapter->card_type) || IS_CARD9097(pmadapter->card_type))) { tlv = (MrvlIEtypes_Reg_type_t *)((t_u8 *)cmd + sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN); tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL); tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8)); tlv->type = MLAN_REG_BBP2; cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_BBP_REG_ACCESS) + S_DS_GEN + sizeof(MrvlIEtypes_Reg_type_t)); } break; } case HostCmd_CMD_RF_REG_ACCESS: { HostCmd_DS_RF_REG_ACCESS *rf_reg; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN); rf_reg = (HostCmd_DS_RF_REG_ACCESS *)&cmd->params.rf_reg; rf_reg->action = wlan_cpu_to_le16(cmd_action); rf_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset); rf_reg->value = (t_u8)reg_rw->value; if ((reg_rw->type == MLAN_REG_RF2) && (IS_CARD9098(pmadapter->card_type) || IS_CARDIW624(pmadapter->card_type) || IS_CARDAW693(pmadapter->card_type) || IS_CARD9097(pmadapter->card_type))) { tlv = (MrvlIEtypes_Reg_type_t *)((t_u8 *)cmd + sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN); tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL); tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8)); tlv->type = MLAN_REG_RF2; cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN + sizeof(MrvlIEtypes_Reg_type_t)); } break; } case HostCmd_CMD_CAU_REG_ACCESS: { HostCmd_DS_RF_REG_ACCESS *cau_reg; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN); cau_reg = (HostCmd_DS_RF_REG_ACCESS *)&cmd->params.rf_reg; cau_reg->action = wlan_cpu_to_le16(cmd_action); cau_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset); cau_reg->value = (t_u8)reg_rw->value; break; } case HostCmd_CMD_TARGET_ACCESS: { HostCmd_DS_TARGET_ACCESS *target; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_TARGET_ACCESS) + S_DS_GEN); target = (HostCmd_DS_TARGET_ACCESS *)&cmd->params.target; target->action = wlan_cpu_to_le16(cmd_action); target->csu_target = wlan_cpu_to_le16(MLAN_CSU_TARGET_PSU); target->address = wlan_cpu_to_le16((t_u16)reg_rw->offset); target->data = (t_u8)reg_rw->value; break; } case HostCmd_CMD_802_11_EEPROM_ACCESS: { mlan_ds_read_eeprom *rd_eeprom = (mlan_ds_read_eeprom *)pdata_buf; HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom = (HostCmd_DS_802_11_EEPROM_ACCESS *)&cmd->params.eeprom; cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) + S_DS_GEN); cmd_eeprom->action = wlan_cpu_to_le16(cmd_action); cmd_eeprom->offset = wlan_cpu_to_le16(rd_eeprom->offset); cmd_eeprom->byte_count = wlan_cpu_to_le16(rd_eeprom->byte_count); cmd_eeprom->value = 0; break; } case HostCmd_CMD_BCA_REG_ACCESS: { HostCmd_DS_BCA_REG_ACCESS *bca_reg; cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_BCA_REG_ACCESS) + S_DS_GEN); bca_reg = (HostCmd_DS_BCA_REG_ACCESS *)&cmd->params.bca_reg; bca_reg->action = wlan_cpu_to_le16(cmd_action); bca_reg->offset = wlan_cpu_to_le16((t_u16)reg_rw->offset); bca_reg->value = wlan_cpu_to_le32(reg_rw->value); if ((reg_rw->type == MLAN_REG_BCA2) && (IS_CARD9098(pmadapter->card_type) || IS_CARDIW624(pmadapter->card_type) || IS_CARDAW693(pmadapter->card_type) || IS_CARD9097(pmadapter->card_type))) { tlv = (MrvlIEtypes_Reg_type_t *)((t_u8 *)cmd + sizeof(HostCmd_DS_BCA_REG_ACCESS) + S_DS_GEN); tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_REG_ACCESS_CTRL); tlv->header.len = wlan_cpu_to_le16(sizeof(t_u8)); tlv->type = MLAN_REG_BCA2; cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_BCA_REG_ACCESS) + S_DS_GEN + sizeof(MrvlIEtypes_Reg_type_t)); } break; } default: LEAVE(); return MLAN_STATUS_FAILURE; } cmd->command = wlan_cpu_to_le16(cmd->command); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of reg_access * * @param pmadapter A pointer to mlan_adapter structure * @param type The type of reg access (MAC, BBP or RF) * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_ret_reg_access(mlan_adapter *pmadapter, t_u16 type, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_reg_mem *reg_mem = MNULL; mlan_ds_reg_rw *reg_rw = MNULL; ENTER(); if (pioctl_buf) { reg_mem = (mlan_ds_reg_mem *)pioctl_buf->pbuf; reg_rw = ®_mem->param.reg_rw; switch (type) { case HostCmd_CMD_MAC_REG_ACCESS: { HostCmd_DS_MAC_REG_ACCESS *reg; reg = (HostCmd_DS_MAC_REG_ACCESS *)&resp->params.mac_reg; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset); reg_rw->value = wlan_le32_to_cpu(reg->value); break; } case HostCmd_CMD_REG_ACCESS: { HostCmd_DS_REG_ACCESS *reg; reg = (HostCmd_DS_REG_ACCESS *)&resp->params.reg; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset); reg_rw->value = wlan_le32_to_cpu(reg->value); break; } case HostCmd_CMD_BBP_REG_ACCESS: { HostCmd_DS_BBP_REG_ACCESS *reg; reg = (HostCmd_DS_BBP_REG_ACCESS *)&resp->params.bbp_reg; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset); reg_rw->value = (t_u32)reg->value; break; } case HostCmd_CMD_RF_REG_ACCESS: { HostCmd_DS_RF_REG_ACCESS *reg; reg = (HostCmd_DS_RF_REG_ACCESS *)&resp->params.rf_reg; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset); reg_rw->value = (t_u32)reg->value; break; } case HostCmd_CMD_CAU_REG_ACCESS: { HostCmd_DS_RF_REG_ACCESS *reg; reg = (HostCmd_DS_RF_REG_ACCESS *)&resp->params.rf_reg; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset); reg_rw->value = (t_u32)reg->value; break; } case HostCmd_CMD_TARGET_ACCESS: { HostCmd_DS_TARGET_ACCESS *reg; reg = (HostCmd_DS_TARGET_ACCESS *)&resp->params.target; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->address); reg_rw->value = (t_u32)reg->data; break; } case HostCmd_CMD_802_11_EEPROM_ACCESS: { mlan_ds_read_eeprom *eeprom = ®_mem->param.rd_eeprom; HostCmd_DS_802_11_EEPROM_ACCESS *cmd_eeprom = (HostCmd_DS_802_11_EEPROM_ACCESS *)&resp->params .eeprom; cmd_eeprom->byte_count = wlan_le16_to_cpu(cmd_eeprom->byte_count); PRINTM(MINFO, "EEPROM read len=%x\n", cmd_eeprom->byte_count); if (eeprom->byte_count < cmd_eeprom->byte_count) { eeprom->byte_count = 0; PRINTM(MINFO, "EEPROM read return length is too big\n"); pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL; LEAVE(); return MLAN_STATUS_FAILURE; } eeprom->offset = wlan_le16_to_cpu(cmd_eeprom->offset); eeprom->byte_count = cmd_eeprom->byte_count; if (eeprom->byte_count > 0) { memcpy_ext(pmadapter, &eeprom->value, &cmd_eeprom->value, eeprom->byte_count, MAX_EEPROM_DATA); HEXDUMP("EEPROM", (char *)&eeprom->value, MIN(MAX_EEPROM_DATA, eeprom->byte_count)); } break; } case HostCmd_CMD_BCA_REG_ACCESS: { HostCmd_DS_BCA_REG_ACCESS *reg; reg = (HostCmd_DS_BCA_REG_ACCESS *)&resp->params.bca_reg; reg_rw->offset = (t_u32)wlan_le16_to_cpu(reg->offset); reg_rw->value = wlan_le32_to_cpu(reg->value); break; } default: pioctl_buf->status_code = MLAN_ERROR_CMD_RESP_FAIL; LEAVE(); return MLAN_STATUS_FAILURE; } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of mem_access. * * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_mem_access(HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { mlan_ds_mem_rw *mem_rw = (mlan_ds_mem_rw *)pdata_buf; HostCmd_DS_MEM_ACCESS *mem_access = (HostCmd_DS_MEM_ACCESS *)&cmd->params.mem; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MEM_ACCESS); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MEM_ACCESS) + S_DS_GEN); mem_access->action = wlan_cpu_to_le16(cmd_action); mem_access->addr = wlan_cpu_to_le32(mem_rw->addr); mem_access->value = wlan_cpu_to_le32(mem_rw->value); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of mem_access * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_mem_access(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_reg_mem *reg_mem = MNULL; mlan_ds_mem_rw *mem_rw = MNULL; HostCmd_DS_MEM_ACCESS *mem = (HostCmd_DS_MEM_ACCESS *)&resp->params.mem; ENTER(); if (pioctl_buf) { reg_mem = (mlan_ds_reg_mem *)pioctl_buf->pbuf; mem_rw = ®_mem->param.mem_rw; mem_rw->addr = wlan_le32_to_cpu(mem->addr); mem_rw->value = wlan_le32_to_cpu(mem->value); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * * @brief This function handles coex events generated by firmware * * @param priv A pointer to mlan_private structure * @param pevent A pointer to event buf * * @return N/A */ void wlan_bt_coex_wlan_param_update_event(pmlan_private priv, pmlan_buffer pevent) { pmlan_adapter pmadapter = priv->adapter; MrvlIEtypesHeader_t *tlv = MNULL; MrvlIETypes_BtCoexAggrWinSize_t *pCoexWinsize = MNULL; MrvlIEtypes_BtCoexScanTime_t *pScantlv = MNULL; t_s32 len = pevent->data_len - sizeof(t_u32); t_u8 *pCurrent_ptr = pevent->pbuf + pevent->data_offset + sizeof(t_u32); t_u16 tlv_type, tlv_len; ENTER(); while (len >= (t_s32)sizeof(MrvlIEtypesHeader_t)) { tlv = (MrvlIEtypesHeader_t *)pCurrent_ptr; tlv_len = wlan_le16_to_cpu(tlv->len); tlv_type = wlan_le16_to_cpu(tlv->type); if ((tlv_len + (t_s32)sizeof(MrvlIEtypesHeader_t)) > len) break; switch (tlv_type) { case TLV_BTCOEX_WL_AGGR_WINSIZE: pCoexWinsize = (MrvlIETypes_BtCoexAggrWinSize_t *)tlv; pmadapter->coex_win_size = pCoexWinsize->coex_win_size; pmadapter->coex_tx_win_size = pCoexWinsize->tx_win_size; pmadapter->coex_rx_win_size = pCoexWinsize->rx_win_size; wlan_coex_ampdu_rxwinsize(pmadapter); wlan_update_ampdu_txwinsize(pmadapter); break; case TLV_BTCOEX_WL_SCANTIME: pScantlv = (MrvlIEtypes_BtCoexScanTime_t *)tlv; pmadapter->coex_scan = pScantlv->coex_scan; pmadapter->coex_min_scan_time = wlan_le16_to_cpu(pScantlv->min_scan_time); pmadapter->coex_max_scan_time = wlan_le16_to_cpu(pScantlv->max_scan_time); break; default: break; } len -= tlv_len + sizeof(MrvlIEtypesHeader_t); pCurrent_ptr += tlv_len + sizeof(MrvlIEtypesHeader_t); } PRINTM(MEVENT, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n", pmadapter->coex_scan, pmadapter->coex_min_scan_time, pmadapter->coex_win_size, pmadapter->coex_tx_win_size, pmadapter->coex_rx_win_size); LEAVE(); } /** * @brief This function prepares command of supplicant pmk * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_802_11_supplicant_pmk(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { MrvlIEtypes_PMK_t *ppmk_tlv = MNULL; MrvlIEtypes_Passphrase_t *ppassphrase_tlv = MNULL; MrvlIEtypes_SAE_Password_t *psae_password_tlv = MNULL; MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL; MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL; HostCmd_DS_802_11_SUPPLICANT_PMK *pesupplicant_psk = &cmd->params.esupplicant_psk; t_u8 *ptlv_buffer = (t_u8 *)pesupplicant_psk->tlv_buffer; mlan_ds_sec_cfg *sec = (mlan_ds_sec_cfg *)pdata_buf; mlan_ds_passphrase *psk = MNULL; t_u8 zero_mac[] = {0, 0, 0, 0, 0, 0}; t_u8 ssid_flag = 0, bssid_flag = 0, pmk_flag = 0, passphrase_flag = 0; t_u8 sae_password_flag = 0; t_u8 zero[MLAN_MAX_KEY_LENGTH] = {0}; MrvlIEtypes_fw_roam_enable_t *proam_tlv = MNULL; MrvlIEtypes_keyParams_t *key_tlv = MNULL; int length = 0; t_u8 userset_passphrase = 0; ENTER(); if (sec->multi_passphrase) psk = (mlan_ds_passphrase *)&sec->param .roam_passphrase[userset_passphrase]; else psk = (mlan_ds_passphrase *)&sec->param.passphrase; if (cmd_action == HostCmd_ACT_GEN_REMOVE) { cmd->size = sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1; proam_tlv = (MrvlIEtypes_fw_roam_enable_t *)ptlv_buffer; proam_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_ROAM); proam_tlv->header.len = sizeof(MrvlIEtypes_fw_roam_enable_t) - sizeof(MrvlIEtypesHeader_t); proam_tlv->roam_enable = MTRUE; ptlv_buffer += (proam_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (proam_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); proam_tlv->header.len = wlan_cpu_to_le16(proam_tlv->header.len); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PMK); pesupplicant_psk->action = wlan_cpu_to_le16(cmd_action); pesupplicant_psk->cache_result = 0; cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } // Parse the rest of the buf here // 1) - This will get the passphrase, AKMP // for specified ssid, if none specified then it will get all. // Eg: iwpriv passphrase 0:ssid=nxp // 2) :: // - passphrase and psk cannot be provided to // the same SSID, Takes one SSID at a time, If ssid= is present // the it should contain a passphrase or psk. If no arguments are // provided then AKMP=802.1x, and passphrase should be provided // after association. // End of each parameter should be followed by a ':'(except for the // last parameter) as the delimiter. If ':' has to be used in // an SSID then a '/' should be preceded to ':' as a escape. // Eg:iwpriv passphrase // "1:ssid=mrvl AP:psk=abcdefgh:bssid=00:50:43:ef:23:f3" // iwpriv passphrase // "1:ssid=nxp/: AP:psk=abcdefgd:bssid=00:50:43:ef:23:f3" // iwpriv passphrase "1:ssid=mrvlAP:psk=abcdefgd" // 3) - This will clear the passphrase // for specified ssid, if none specified then it will clear all. // Eg: iwpriv passphrase 2:ssid=nxp // // // -1 is for t_u8 TlvBuffer[1] as this should not be included */ cmd->size = sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1; if (psk && memcmp(pmpriv->adapter, (t_u8 *)&psk->bssid, zero_mac, sizeof(zero_mac))) { pbssid_tlv = (MrvlIEtypes_Bssid_t *)ptlv_buffer; pbssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_BSSID); pbssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH; memcpy_ext(pmpriv->adapter, pbssid_tlv->bssid, (t_u8 *)&psk->bssid, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); ptlv_buffer += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); pbssid_tlv->header.len = wlan_cpu_to_le16(pbssid_tlv->header.len); bssid_flag = 1; } if (psk && (psk->psk_type == MLAN_PSK_PMK)) { ppmk_tlv = (MrvlIEtypes_PMK_t *)ptlv_buffer; ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK); ppmk_tlv->header.len = MLAN_MAX_KEY_LENGTH; memcpy_ext(pmpriv->adapter, ppmk_tlv->pmk, psk->psk.pmk.pmk, MLAN_MAX_KEY_LENGTH, MLAN_MAX_KEY_LENGTH); ptlv_buffer += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len); pmk_flag = 1; if (memcmp(pmpriv->adapter, psk->psk.pmk.pmk_r0, zero, MLAN_MAX_KEY_LENGTH)) { ppmk_tlv = (MrvlIEtypes_PMK_t *)ptlv_buffer; ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK_R0); ppmk_tlv->header.len = MLAN_MAX_KEY_LENGTH; memcpy_ext(pmpriv->adapter, ppmk_tlv->pmk, psk->psk.pmk.pmk_r0, MLAN_MAX_KEY_LENGTH, MLAN_MAX_KEY_LENGTH); ptlv_buffer += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len); } if (memcmp(pmpriv->adapter, psk->psk.pmk.pmk_r0_name, zero, MLAN_MAX_PMKR0_NAME_LENGTH)) { ppmk_tlv = (MrvlIEtypes_PMK_t *)ptlv_buffer; ppmk_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PMK_R0_NAME); ppmk_tlv->header.len = MLAN_MAX_PMKR0_NAME_LENGTH; memcpy_ext(pmpriv->adapter, ppmk_tlv->pmk, psk->psk.pmk.pmk_r0_name, MLAN_MAX_PMKR0_NAME_LENGTH, MLAN_MAX_PMKR0_NAME_LENGTH); ptlv_buffer += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); ppmk_tlv->header.len = wlan_cpu_to_le16(ppmk_tlv->header.len); } } if (pmpriv->adapter->fw_roaming && (pmpriv->adapter->userset_passphrase || (psk && psk->psk_type == MLAN_PSK_PMK))) { proam_tlv = (MrvlIEtypes_fw_roam_enable_t *)ptlv_buffer; proam_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_ROAM); proam_tlv->header.len = sizeof(MrvlIEtypes_fw_roam_enable_t) - sizeof(MrvlIEtypesHeader_t); proam_tlv->roam_enable = MTRUE; proam_tlv->userset_passphrase = pmpriv->adapter->userset_passphrase; ptlv_buffer += (proam_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (proam_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); proam_tlv->header.len = wlan_cpu_to_le16(proam_tlv->header.len); } do { if (pmpriv->adapter->userset_passphrase && sec->multi_passphrase) { key_tlv = (MrvlIEtypes_keyParams_t *)ptlv_buffer; key_tlv->header.type = wlan_cpu_to_le16( TLV_TYPE_ROAM_OFFLOAD_USER_SET_PMK); ptlv_buffer += sizeof(MrvlIEtypesHeader_t); cmd->size += sizeof(MrvlIEtypesHeader_t); length = cmd->size; } if (psk->ssid.ssid_len) { pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *)ptlv_buffer; pssid_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SSID); pssid_tlv->header.len = (t_u16)MIN(MLAN_MAX_SSID_LENGTH, psk->ssid.ssid_len); memcpy_ext(pmpriv->adapter, (t_u8 *)pssid_tlv->ssid, (t_u8 *)psk->ssid.ssid, psk->ssid.ssid_len, MLAN_MAX_SSID_LENGTH); ptlv_buffer += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); pssid_tlv->header.len = wlan_cpu_to_le16(pssid_tlv->header.len); ssid_flag = 1; } if (psk->psk_type == MLAN_PSK_PASSPHRASE) { ppassphrase_tlv = (MrvlIEtypes_Passphrase_t *)ptlv_buffer; ppassphrase_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_PASSPHRASE); ppassphrase_tlv->header.len = (t_u16)MIN(MLAN_MAX_PASSPHRASE_LENGTH, psk->psk.passphrase.passphrase_len); memcpy_ext(pmpriv->adapter, ppassphrase_tlv->passphrase, psk->psk.passphrase.passphrase, psk->psk.passphrase.passphrase_len, MLAN_MAX_PASSPHRASE_LENGTH); ptlv_buffer += (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (ppassphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); ppassphrase_tlv->header.len = wlan_cpu_to_le16(ppassphrase_tlv->header.len); passphrase_flag = 1; } if (psk->psk_type == MLAN_PSK_SAE_PASSWORD) { psae_password_tlv = (MrvlIEtypes_SAE_Password_t *)ptlv_buffer; psae_password_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SAE_PASSWORD); psae_password_tlv->header.len = (t_u16)MIN( MLAN_MAX_SAE_PASSWORD_LENGTH, psk->psk.sae_password.sae_password_len); memcpy_ext(pmpriv->adapter, psae_password_tlv->sae_password, psk->psk.sae_password.sae_password, psk->psk.sae_password.sae_password_len, MLAN_MAX_SAE_PASSWORD_LENGTH); ptlv_buffer += (psae_password_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); cmd->size += (psae_password_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); psae_password_tlv->header.len = wlan_cpu_to_le16(psae_password_tlv->header.len); sae_password_flag = 1; } if (key_tlv) key_tlv->header.len = wlan_cpu_to_le16(cmd->size - length); userset_passphrase++; psk = (mlan_ds_passphrase *)&sec->param .roam_passphrase[userset_passphrase]; } while (psk && sec->multi_passphrase && userset_passphrase < pmpriv->adapter->userset_passphrase); pmpriv->adapter->userset_passphrase = 0; if ((cmd_action == HostCmd_ACT_GEN_SET) && ((ssid_flag || bssid_flag) && (!pmk_flag && !passphrase_flag) && (!pmk_flag && !sae_password_flag))) { PRINTM(MERROR, "Invalid case,ssid/bssid present without pmk, passphrase or sae password\n"); LEAVE(); return MLAN_STATUS_FAILURE; } cmd->command = wlan_cpu_to_le16(HostCmd_CMD_SUPPLICANT_PMK); pesupplicant_psk->action = wlan_cpu_to_le16(cmd_action); pesupplicant_psk->cache_result = 0; cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief Handle the supplicant pmk response * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS MLAN_STATUS_FAILURE */ mlan_status wlan_ret_802_11_supplicant_pmk(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_802_11_SUPPLICANT_PMK *supplicant_pmk_resp = &resp->params.esupplicant_psk; mlan_ds_sec_cfg *sec_buf = MNULL; mlan_ds_sec_cfg *sec = MNULL; mlan_adapter *pmadapter = pmpriv->adapter; pmlan_callbacks pcb = &pmadapter->callbacks; MrvlIEtypes_PMK_t *ppmk_tlv = MNULL; MrvlIEtypes_Passphrase_t *passphrase_tlv = MNULL; MrvlIEtypes_SAE_Password_t *psae_password_tlv = MNULL; MrvlIEtypes_SsIdParamSet_t *pssid_tlv = MNULL; MrvlIEtypes_Bssid_t *pbssid_tlv = MNULL; t_u8 *tlv_buf = (t_u8 *)supplicant_pmk_resp->tlv_buffer; t_u16 action = wlan_le16_to_cpu(supplicant_pmk_resp->action); int tlv_buf_len = 0; t_u16 tlv; mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); tlv_buf_len = resp->size - (sizeof(HostCmd_DS_802_11_SUPPLICANT_PMK) + S_DS_GEN - 1); if (pioctl_buf) { if (((mlan_ds_bss *)pioctl_buf->pbuf)->sub_command == MLAN_OID_BSS_FIND_BSS) { ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_ds_sec_cfg), MLAN_MEM_DEF, (t_u8 **)&sec_buf); if (ret || !sec_buf) { PRINTM(MERROR, "Could not allocate sec_buf!\n"); LEAVE(); return ret; } sec = sec_buf; } else { sec = (mlan_ds_sec_cfg *)pioctl_buf->pbuf; } if (action == HostCmd_ACT_GEN_GET) { while (tlv_buf_len > 0) { tlv = (*tlv_buf) | (*(tlv_buf + 1) << 8); if ((tlv != TLV_TYPE_SSID) && (tlv != TLV_TYPE_BSSID) && (tlv != TLV_TYPE_PASSPHRASE) && (tlv != TLV_TYPE_PMK) && (tlv != TLV_TYPE_SAE_PASSWORD)) break; switch (tlv) { case TLV_TYPE_SSID: pssid_tlv = (MrvlIEtypes_SsIdParamSet_t *) tlv_buf; pssid_tlv->header.len = wlan_le16_to_cpu( pssid_tlv->header.len); memcpy_ext( pmpriv->adapter, sec->param.passphrase.ssid.ssid, pssid_tlv->ssid, pssid_tlv->header.len, MLAN_MAX_SSID_LENGTH); sec->param.passphrase.ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, pssid_tlv->header.len); tlv_buf += pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t); tlv_buf_len -= (pssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); break; case TLV_TYPE_BSSID: pbssid_tlv = (MrvlIEtypes_Bssid_t *)tlv_buf; pbssid_tlv->header.len = wlan_le16_to_cpu( pbssid_tlv->header.len); memcpy_ext(pmpriv->adapter, &sec->param.passphrase.bssid, pbssid_tlv->bssid, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); tlv_buf += pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t); tlv_buf_len -= (pbssid_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); break; case TLV_TYPE_PASSPHRASE: passphrase_tlv = (MrvlIEtypes_Passphrase_t *) tlv_buf; passphrase_tlv->header .len = wlan_le16_to_cpu( passphrase_tlv->header.len); sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE; sec->param.passphrase.psk.passphrase .passphrase_len = passphrase_tlv->header.len; memcpy_ext( pmpriv->adapter, sec->param.passphrase.psk .passphrase.passphrase, passphrase_tlv->passphrase, passphrase_tlv->header.len, MLAN_MAX_PASSPHRASE_LENGTH); tlv_buf += passphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t); tlv_buf_len -= (passphrase_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); break; case TLV_TYPE_SAE_PASSWORD: psae_password_tlv = (MrvlIEtypes_SAE_Password_t *) tlv_buf; psae_password_tlv->header .len = wlan_le16_to_cpu( psae_password_tlv->header.len); sec->param.passphrase.psk_type = MLAN_PSK_SAE_PASSWORD; sec->param.passphrase.psk.sae_password .sae_password_len = psae_password_tlv->header.len; memcpy_ext( pmpriv->adapter, sec->param.passphrase.psk .sae_password .sae_password, psae_password_tlv->sae_password, psae_password_tlv->header.len, MLAN_MAX_SAE_PASSWORD_LENGTH); tlv_buf += psae_password_tlv->header.len + sizeof(MrvlIEtypesHeader_t); tlv_buf_len -= (psae_password_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); break; case TLV_TYPE_PMK: ppmk_tlv = (MrvlIEtypes_PMK_t *)tlv_buf; ppmk_tlv->header.len = wlan_le16_to_cpu( ppmk_tlv->header.len); sec->param.passphrase.psk_type = MLAN_PSK_PMK; memcpy_ext(pmpriv->adapter, sec->param.passphrase.psk.pmk .pmk, ppmk_tlv->pmk, ppmk_tlv->header.len, MLAN_MAX_KEY_LENGTH); tlv_buf += ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t); tlv_buf_len -= (ppmk_tlv->header.len + sizeof(MrvlIEtypesHeader_t)); break; } } #ifdef STA_SUPPORT if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA && ((mlan_ds_bss *)pioctl_buf->pbuf)->sub_command == MLAN_OID_BSS_FIND_BSS) { wlan_set_ewpa_mode(pmpriv, &sec->param.passphrase); ret = wlan_find_bss(pmpriv, pioctl_buf); } #endif } else if (action == HostCmd_ACT_GEN_SET) { PRINTM(MINFO, "Esupp PMK set: enable ewpa query\n"); pmpriv->ewpa_query = MTRUE; } if (sec_buf) pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)sec_buf); } LEAVE(); return ret; } /** * @brief This function prepares command of independent reset. * * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_ind_rst_cfg(HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { mlan_ds_ind_rst_cfg *pdata_ind_rst = (mlan_ds_ind_rst_cfg *)pdata_buf; HostCmd_DS_INDEPENDENT_RESET_CFG *ind_rst_cfg = (HostCmd_DS_INDEPENDENT_RESET_CFG *)&cmd->params.ind_rst_cfg; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_INDEPENDENT_RESET_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_INDEPENDENT_RESET_CFG) + S_DS_GEN); ind_rst_cfg->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { ind_rst_cfg->ir_mode = pdata_ind_rst->ir_mode; ind_rst_cfg->gpio_pin = pdata_ind_rst->gpio_pin; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of independent reset * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_ind_rst_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc = MNULL; const HostCmd_DS_INDEPENDENT_RESET_CFG *ind_rst_cfg = (HostCmd_DS_INDEPENDENT_RESET_CFG *)&resp->params.ind_rst_cfg; ENTER(); if (pioctl_buf) { misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; if (wlan_le16_to_cpu(ind_rst_cfg->action) == HostCmd_ACT_GEN_GET) { misc->param.ind_rst_cfg.ir_mode = ind_rst_cfg->ir_mode; misc->param.ind_rst_cfg.gpio_pin = ind_rst_cfg->gpio_pin; } } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of ps inactivity timeout. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_ps_inactivity_timeout(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { t_u16 timeout = *((t_u16 *)pdata_buf); HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT *ps_inact_tmo = (HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT *)&cmd->params .ps_inact_tmo; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_INACTIVITY_TIMEOUT); cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_802_11_PS_INACTIVITY_TIMEOUT) + S_DS_GEN); ps_inact_tmo->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) ps_inact_tmo->inact_tmo = wlan_cpu_to_le16(timeout); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of HostCmd_CMD_GET_TSF * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action) { ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_TSF); cmd->size = wlan_cpu_to_le16((sizeof(HostCmd_DS_TSF)) + S_DS_GEN); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of HostCmd_CMD_GET_TSF * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_get_tsf(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc_cfg = MNULL; HostCmd_DS_TSF *tsf_pointer = (HostCmd_DS_TSF *)&resp->params.tsf; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.misc_tsf = wlan_le64_to_cpu(tsf_pointer->tsf); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of chan_region_cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_chan_region_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_adapter *pmadapter = pmpriv->adapter; t_u16 action; HostCmd_DS_CHAN_REGION_CFG *reg = MNULL; t_u8 *tlv_buf = MNULL; t_u16 tlv_buf_left = 0; mlan_ds_misc_cfg *misc_cfg = MNULL; mlan_ds_misc_chnrgpwr_cfg *cfg = MNULL; mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); reg = (HostCmd_DS_CHAN_REGION_CFG *)&resp->params.reg_cfg; if (!reg) { ret = MLAN_STATUS_FAILURE; goto done; } action = wlan_le16_to_cpu(reg->action); if (action != HostCmd_ACT_GEN_GET) { ret = MLAN_STATUS_FAILURE; goto done; } tlv_buf = (t_u8 *)reg + sizeof(*reg); if (resp->size > (S_DS_GEN + sizeof(*reg))) { tlv_buf_left = resp->size - S_DS_GEN - sizeof(*reg); } else { PRINTM(MERROR, "Region size calculation ERROR.\n"); } /* Add FW cfp tables and region info */ wlan_add_fw_cfp_tables(pmpriv, tlv_buf, tlv_buf_left); if (pmadapter->otp_region) { if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code, pmadapter->fw_bands)) { PRINTM(MERROR, "Set region table failure!! region_code = 0x%X, fw_bands = 0x%X\n", pmadapter->region_code, pmadapter->fw_bands); } } if (!pioctl_buf) goto done; if (!pioctl_buf->pbuf) { ret = MLAN_STATUS_FAILURE; goto done; } misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; if (misc_cfg->sub_command == MLAN_OID_MISC_GET_REGIONPWR_CFG) { cfg = (mlan_ds_misc_chnrgpwr_cfg *)&( misc_cfg->param.rgchnpwr_cfg); cfg->length = resp->size; memcpy_ext(pmpriv->adapter, cfg->chnrgpwr_buf, (t_u8 *)resp, cfg->length, sizeof(cfg->chnrgpwr_buf)); } else { memset(pmpriv->adapter, &misc_cfg->param.custom_reg_domain, 0, sizeof(mlan_ds_custom_reg_domain)); if (pmadapter->otp_region) memcpy_ext(pmpriv->adapter, &misc_cfg->param.custom_reg_domain.region, pmadapter->otp_region, sizeof(otp_region_info_t), sizeof(otp_region_info_t)); if (pmadapter->cfp_otp_bg) { misc_cfg->param.custom_reg_domain.num_bg_chan = pmadapter->tx_power_table_bg_rows; memcpy_ext(pmpriv->adapter, (t_u8 *)misc_cfg->param.custom_reg_domain .cfp_tbl, (t_u8 *)pmadapter->cfp_otp_bg, pmadapter->tx_power_table_bg_rows * sizeof(chan_freq_power_t), pmadapter->tx_power_table_bg_rows * sizeof(chan_freq_power_t)); } if (pmadapter->cfp_otp_a) { misc_cfg->param.custom_reg_domain.num_a_chan = pmadapter->tx_power_table_a_rows; memcpy_ext(pmpriv->adapter, (t_u8 *)misc_cfg->param.custom_reg_domain .cfp_tbl + pmadapter->tx_power_table_bg_rows * sizeof(chan_freq_power_t), (t_u8 *)pmadapter->cfp_otp_a, pmadapter->tx_power_table_a_rows * sizeof(chan_freq_power_t), pmadapter->tx_power_table_a_rows * sizeof(chan_freq_power_t)); } } done: LEAVE(); return ret; } /** * @brief This function prepares command of packet aggragation * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_packet_aggr_ctrl(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_PACKET_AGGR_CTRL *aggr_ctrl = &cmd->params.aggr_ctrl; mlan_ds_misc_aggr_ctrl *aggr = (mlan_ds_misc_aggr_ctrl *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_PACKET_AGGR_CTRL); aggr_ctrl->action = wlan_cpu_to_le16(cmd_action); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_PACKET_AGGR_CTRL) + S_DS_GEN); aggr_ctrl->aggr_enable = 0; if (aggr->tx.enable) aggr_ctrl->aggr_enable |= MBIT(0); aggr_ctrl->aggr_enable = wlan_cpu_to_le16(aggr_ctrl->aggr_enable); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of * packet aggregation * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_packet_aggr_ctrl(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc = MNULL; HostCmd_DS_PACKET_AGGR_CTRL *aggr_ctrl = &resp->params.aggr_ctrl; mlan_ds_misc_aggr_ctrl *aggr = MNULL; #if defined(USB) mlan_adapter *pmadapter = pmpriv->adapter; t_u8 i; t_u8 change = 0; usb_tx_aggr_params *pusb_tx_aggr = MNULL; #endif ENTER(); aggr_ctrl->aggr_enable = wlan_le16_to_cpu(aggr_ctrl->aggr_enable); aggr_ctrl->tx_aggr_max_size = wlan_le16_to_cpu(aggr_ctrl->tx_aggr_max_size); aggr_ctrl->tx_aggr_max_num = wlan_le16_to_cpu(aggr_ctrl->tx_aggr_max_num); aggr_ctrl->tx_aggr_align = wlan_le16_to_cpu(aggr_ctrl->tx_aggr_align); PRINTM(MCMND, "enable=0x%x, tx_size=%d, tx_num=%d, tx_align=%d\n", aggr_ctrl->aggr_enable, aggr_ctrl->tx_aggr_max_size, aggr_ctrl->tx_aggr_max_num, aggr_ctrl->tx_aggr_align); #if defined(USB) if (IS_USB(pmadapter->card_type)) { if (aggr_ctrl->aggr_enable & MBIT(0)) { if (!pmadapter->pcard_usb->usb_tx_aggr[0] .aggr_ctrl.enable) { pmadapter->pcard_usb->usb_tx_aggr[0] .aggr_ctrl.enable = MTRUE; change = MTRUE; } } else { if (pmadapter->pcard_usb->usb_tx_aggr[0] .aggr_ctrl.enable) { pmadapter->pcard_usb->usb_tx_aggr[0] .aggr_ctrl.enable = MFALSE; change = MTRUE; } } pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_LEN_V2; pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_align = aggr_ctrl->tx_aggr_align; pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_max = aggr_ctrl->tx_aggr_max_size; pmadapter->pcard_usb->usb_tx_aggr[0].aggr_ctrl.aggr_tmo = MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000; if (change) { wlan_reset_usb_tx_aggr(pmadapter); for (i = 0; i < pmadapter->priv_num; ++i) { if (pmadapter->priv[i]) { pusb_tx_aggr = wlan_get_usb_tx_aggr_params( pmadapter, pmadapter->priv[i] ->port); if (pusb_tx_aggr && pusb_tx_aggr->aggr_ctrl.aggr_mode == MLAN_USB_AGGR_MODE_LEN_V2) pmadapter->priv[i]->intf_hr_len = MLAN_USB_TX_AGGR_HEADER; else pmadapter->priv[i]->intf_hr_len = USB_INTF_HEADER_LEN; } } } } #endif if (pioctl_buf) { misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; aggr = (mlan_ds_misc_aggr_ctrl *)&(misc->param.aggr_params); if (aggr_ctrl->aggr_enable & MBIT(0)) aggr->tx.enable = MTRUE; else aggr->tx.enable = MFALSE; aggr->tx.aggr_align = aggr_ctrl->tx_aggr_align; aggr->tx.aggr_max_size = aggr_ctrl->tx_aggr_max_size; aggr->tx.aggr_max_num = aggr_ctrl->tx_aggr_max_num; #if defined(USB) if (IS_USB(pmadapter->card_type)) aggr->tx.aggr_tmo = pmadapter->pcard_usb->usb_tx_aggr[0] .aggr_ctrl.aggr_tmo; #endif } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function sends fw dump event command to firmware. * * @param pmpriv A pointer to mlan_private structure * @param cmd Hostcmd ID * @param cmd_action Command action * @param pdata_buf A void pointer to information buffer * @return N/A */ mlan_status wlan_cmd_fw_dump_event(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_FW_DUMP_EVENT); cmd->size = S_DS_GEN; cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of get link layer statistics. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE * */ mlan_status wlan_cmd_802_11_link_statistic(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, mlan_ioctl_req *pioctl_buf) { mlan_ds_get_info *info = (mlan_ds_get_info *)(pioctl_buf->pbuf); HostCmd_DS_802_11_LINK_STATISTIC *ll_stat = &cmd->params.get_link_statistic; wifi_link_layer_params *ll_params = MNULL; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_LINK_STATS); cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_802_11_LINK_STATISTIC)); ll_stat->action = wlan_cpu_to_le16(cmd_action); switch (cmd_action) { case HostCmd_ACT_GEN_SET: ll_params = (wifi_link_layer_params *)info->param.link_statistic; ll_stat->mpdu_size_threshold = wlan_cpu_to_le32(ll_params->mpdu_size_threshold); ll_stat->aggressive_statistics_gathering = wlan_cpu_to_le32( ll_params->aggressive_statistics_gathering); break; case HostCmd_ACT_GEN_GET: /** ll_stat->stat_type = wlan_cpu_to_le16(stat_type); */ break; default: break; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function fill link layer statistic from firmware * * @param priv A pointer to * mlan_private structure * @param link_statistic_ioctl_buf, A pointer to fill ioctl buffer * @param resp A pointer to * HostCmd_DS_COMMAND * * @return MLAN_STATUS_SUCCESS */ static void wlan_fill_link_statistic(mlan_private *priv, char *link_statistic_ioctl_buf, HostCmd_DS_COMMAND *resp) { char *link_statistic = link_statistic_ioctl_buf; wifi_radio_stat *radio_stat = MNULL; wifi_iface_stat *iface_stat = MNULL; mlan_wifi_iface_stat *fw_ifaceStat = MNULL; mlan_wifi_radio_stat *fw_radioStat = MNULL; t_u32 num_radio = 0; int i = 0, chan_idx = 0, peerIdx = 0, rate_idx = 0; t_u16 left_len = 0, tlv_type = 0, tlv_len = 0; MrvlIEtypesHeader_t *tlv = MNULL; HostCmd_DS_802_11_LINK_STATISTIC *plink_stat = (HostCmd_DS_802_11_LINK_STATISTIC *)&resp->params .get_link_statistic; /* TLV parse */ if (resp->size > (sizeof(HostCmd_DS_802_11_LINK_STATISTIC) - S_DS_GEN)) left_len = resp->size - sizeof(HostCmd_DS_802_11_LINK_STATISTIC) - S_DS_GEN; tlv = (MrvlIEtypesHeader_t *)(plink_stat->value); DBG_HEXDUMP(MDAT_D, "tlv:", (void *)tlv, 1024); while (left_len > sizeof(MrvlIEtypesHeader_t)) { tlv_type = wlan_le16_to_cpu(tlv->type); tlv_len = wlan_le16_to_cpu(tlv->len); switch (tlv_type) { case TLV_TYPE_LL_STAT_IFACE: fw_ifaceStat = (mlan_wifi_iface_stat *)((t_u8 *)tlv + sizeof(MrvlIEtypesHeader_t)); break; case TLV_TYPE_LL_STAT_RADIO: fw_radioStat = (mlan_wifi_radio_stat *)((t_u8 *)tlv + sizeof(MrvlIEtypesHeader_t)); num_radio = MAX_RADIO; break; default: break; } left_len -= (sizeof(MrvlIEtypesHeader_t) + tlv_len); tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t)); } if (!fw_ifaceStat || !fw_radioStat) { PRINTM(MERROR, "!fw_ifaceStat || !fw_radioStat\n"); return; } *((t_u32 *)link_statistic) = num_radio; link_statistic += sizeof(num_radio); /* Fill radio stats array*/ for (i = 0; i < num_radio; i++) { radio_stat = (wifi_radio_stat *)link_statistic; link_statistic += sizeof(wifi_radio_stat); radio_stat->radio = wlan_le32_to_cpu(fw_radioStat[i].radio); radio_stat->on_time = wlan_le32_to_cpu(fw_radioStat[i].on_time); radio_stat->tx_time = wlan_le32_to_cpu(fw_radioStat[i].tx_time); radio_stat->reserved0 = wlan_le32_to_cpu(fw_radioStat[i].reserved0); radio_stat->rx_time = wlan_le32_to_cpu(fw_radioStat[i].rx_time); radio_stat->on_time_scan = wlan_le32_to_cpu(fw_radioStat[i].on_time_scan); radio_stat->on_time_nbd = wlan_le32_to_cpu(fw_radioStat[i].on_time_nbd); radio_stat->on_time_gscan = wlan_le32_to_cpu(fw_radioStat[i].on_time_gscan); radio_stat->on_time_roam_scan = wlan_le32_to_cpu(fw_radioStat[i].on_time_roam_scan); radio_stat->on_time_pno_scan = wlan_le32_to_cpu(fw_radioStat[i].on_time_pno_scan); radio_stat->on_time_hs20 = wlan_le32_to_cpu(fw_radioStat[i].on_time_hs20); radio_stat->num_channels = wlan_le32_to_cpu(fw_radioStat[i].num_channels); for (chan_idx = 0; chan_idx < radio_stat->num_channels; chan_idx++) { if (radio_stat->num_channels > MAX_NUM_CHAN) { radio_stat->num_channels = wlan_le32_to_cpu(MAX_NUM_CHAN); PRINTM(MERROR, "%s : radio_stat->num_channels=%d\n", __func__, radio_stat->num_channels); break; } radio_stat->channels[chan_idx].channel.width = wlan_le32_to_cpu(fw_radioStat[i] .channels[chan_idx] .channel.width); radio_stat->channels[chan_idx].channel.center_freq = wlan_le32_to_cpu(fw_radioStat[i] .channels[chan_idx] .channel.center_freq); radio_stat->channels[chan_idx].channel.center_freq0 = wlan_le32_to_cpu(fw_radioStat[i] .channels[chan_idx] .channel.center_freq0); radio_stat->channels[chan_idx].channel.center_freq1 = wlan_le32_to_cpu(fw_radioStat[i] .channels[chan_idx] .channel.center_freq1); radio_stat->channels[chan_idx] .on_time = wlan_le32_to_cpu( fw_radioStat[i].channels[chan_idx].on_time); radio_stat->channels[chan_idx].cca_busy_time = wlan_le32_to_cpu(fw_radioStat[i] .channels[chan_idx] .cca_busy_time); } } /* Fill iface stats*/ iface_stat = (wifi_iface_stat *)link_statistic; /* get wifi_interface_link_layer_info in driver, not in firmware */ if (priv->bss_role == MLAN_BSS_ROLE_STA) { iface_stat->info.mode = MLAN_INTERFACE_STA; if (priv->media_connected) iface_stat->info.state = MLAN_ASSOCIATING; else iface_stat->info.state = MLAN_DISCONNECTED; iface_stat->info.roaming = MLAN_ROAMING_IDLE; iface_stat->info.capabilities = MLAN_CAPABILITY_QOS; memcpy_ext(priv->adapter, iface_stat->info.ssid, priv->curr_bss_params.bss_descriptor.ssid.ssid, MLAN_MAX_SSID_LENGTH, MLAN_MAX_SSID_LENGTH); memcpy_ext(priv->adapter, iface_stat->info.bssid, priv->curr_bss_params.bss_descriptor.mac_address, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); } else { iface_stat->info.mode = MLAN_INTERFACE_SOFTAP; iface_stat->info.capabilities = MLAN_CAPABILITY_QOS; } memcpy_ext(priv->adapter, iface_stat->info.mac_addr, priv->curr_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); memcpy_ext(priv->adapter, iface_stat->info.ap_country_str, priv->adapter->country_code, COUNTRY_CODE_LEN, COUNTRY_CODE_LEN); memcpy_ext(priv->adapter, iface_stat->info.country_str, priv->adapter->country_code, COUNTRY_CODE_LEN, COUNTRY_CODE_LEN); iface_stat->beacon_rx = wlan_le32_to_cpu(fw_ifaceStat->beacon_rx); iface_stat->average_tsf_offset = wlan_le64_to_cpu(fw_ifaceStat->average_tsf_offset); iface_stat->leaky_ap_detected = wlan_le32_to_cpu(fw_ifaceStat->leaky_ap_detected); iface_stat->leaky_ap_avg_num_frames_leaked = wlan_le32_to_cpu(fw_ifaceStat->leaky_ap_avg_num_frames_leaked); iface_stat->leaky_ap_guard_time = wlan_le32_to_cpu(fw_ifaceStat->leaky_ap_guard_time); /* Value of iface_stat should be Reaccumulate by each peer */ iface_stat->mgmt_rx = wlan_le32_to_cpu(fw_ifaceStat->mgmt_rx); iface_stat->mgmt_action_rx = wlan_le32_to_cpu(fw_ifaceStat->mgmt_action_rx); iface_stat->mgmt_action_tx = wlan_le32_to_cpu(fw_ifaceStat->mgmt_action_tx); iface_stat->rssi_mgmt = wlan_le32_to_cpu(fw_ifaceStat->rssi_mgmt); iface_stat->rssi_data = wlan_le32_to_cpu(fw_ifaceStat->rssi_data); iface_stat->rssi_ack = wlan_le32_to_cpu(fw_ifaceStat->rssi_ack); for (i = WMM_AC_BK; i <= WMM_AC_VO; i++) { iface_stat->ac[i].ac = i; iface_stat->ac[i].tx_mpdu = wlan_le32_to_cpu(fw_ifaceStat->ac[i].tx_mpdu); iface_stat->ac[i].rx_mpdu = wlan_le32_to_cpu(fw_ifaceStat->ac[i].rx_mpdu); iface_stat->ac[i].tx_mcast = wlan_le32_to_cpu(fw_ifaceStat->ac[i].tx_mcast); iface_stat->ac[i].rx_mcast = wlan_le32_to_cpu(fw_ifaceStat->ac[i].rx_mcast); iface_stat->ac[i].rx_ampdu = wlan_le32_to_cpu(fw_ifaceStat->ac[i].rx_ampdu); iface_stat->ac[i].tx_ampdu = wlan_le32_to_cpu(fw_ifaceStat->ac[i].tx_ampdu); iface_stat->ac[i].mpdu_lost = wlan_le32_to_cpu(fw_ifaceStat->ac[i].mpdu_lost); iface_stat->ac[i].retries = wlan_le32_to_cpu(fw_ifaceStat->ac[i].retries); iface_stat->ac[i].retries_short = wlan_le32_to_cpu(fw_ifaceStat->ac[i].retries_short); iface_stat->ac[i].retries_long = wlan_le32_to_cpu(fw_ifaceStat->ac[i].retries_long); iface_stat->ac[i].contention_time_min = wlan_le32_to_cpu( fw_ifaceStat->ac[i].contention_time_min); iface_stat->ac[i].contention_time_max = wlan_le32_to_cpu( fw_ifaceStat->ac[i].contention_time_max); iface_stat->ac[i].contention_time_avg = wlan_le32_to_cpu( fw_ifaceStat->ac[i].contention_time_avg); iface_stat->ac[i].contention_num_samples = wlan_le32_to_cpu( fw_ifaceStat->ac[i].contention_num_samples); } /* LL_STAT V3: STA-solution: support maxium 1 peers for AP*/ iface_stat->num_peers = wlan_le32_to_cpu(fw_ifaceStat->num_peers); for (peerIdx = 0; peerIdx < iface_stat->num_peers; peerIdx++) { iface_stat->peer_info[peerIdx].type = fw_ifaceStat->peer_info[peerIdx].type; memcpy_ext(priv->adapter, iface_stat->peer_info[peerIdx].peer_mac_address, fw_ifaceStat->peer_info[peerIdx].peer_mac_address, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); iface_stat->peer_info[peerIdx].capabilities = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx].capabilities); iface_stat->peer_info[peerIdx].num_rate = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx].num_rate); PRINTM(MINFO, "bitrate tx_mpdu rx_mpdu mpdu_lost retries retries_short retries_long\n"); for (rate_idx = 0; rate_idx < iface_stat->peer_info[peerIdx].num_rate; rate_idx++) { wlan_fill_hal_wifi_rate(priv, &fw_ifaceStat ->peer_info[peerIdx] .rate_stats[rate_idx] .rate, &iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .rate); iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .tx_mpdu = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx] .rate_stats[rate_idx] .tx_mpdu); iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .rx_mpdu = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx] .rate_stats[rate_idx] .rx_mpdu); iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .mpdu_lost = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx] .rate_stats[rate_idx] .mpdu_lost); iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .retries = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx] .rate_stats[rate_idx] .retries); iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .retries_short = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx] .rate_stats[rate_idx] .retries_short); iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .retries_long = wlan_le32_to_cpu( fw_ifaceStat->peer_info[peerIdx] .rate_stats[rate_idx] .retries_long); PRINTM(MDAT_D, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .rate.bitrate, iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .tx_mpdu, iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .rx_mpdu, iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .mpdu_lost, iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .retries, iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .retries_short, iface_stat->peer_info[peerIdx] .rate_stats[rate_idx] .retries_long); } } } /** * @brief This function handles the command response of get_link_statistic * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_get_link_statistic(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_get_info *info; t_u8 *link_statistic = MNULL; t_u16 action = wlan_le16_to_cpu(resp->params.get_link_statistic.action); ENTER(); if (pioctl_buf) { info = (mlan_ds_get_info *)pioctl_buf->pbuf; link_statistic = info->param.link_statistic; switch (action) { case HostCmd_ACT_GEN_GET: wlan_fill_link_statistic(pmpriv, link_statistic, resp); break; case HostCmd_ACT_GEN_SET: case HostCmd_ACT_GEN_REMOVE: /* nothing to do */ break; default: break; } /* Indicate ioctl complete */ pioctl_buf->data_read_written = BUF_MAXLEN + MLAN_SUB_COMMAND_SIZE; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function sends boot sleep configure command to firmware. * * @param pmpriv A pointer to mlan_private structure * @param cmd Hostcmd ID * @param cmd_action Command action * @param pdata_buf A void pointer to information buffer * @return MLAN_STATUS_SUCCESS/ MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_boot_sleep(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_BOOT_SLEEP *boot_sleep = MNULL; t_u16 enable = *(t_u16 *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_BOOT_SLEEP); boot_sleep = &cmd->params.boot_sleep; boot_sleep->action = wlan_cpu_to_le16(cmd_action); boot_sleep->enable = wlan_cpu_to_le16(enable); cmd->size = wlan_cpu_to_le16(S_DS_GEN + sizeof(HostCmd_DS_BOOT_SLEEP)); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of boot sleep cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_boot_sleep(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_BOOT_SLEEP *boot_sleep = &resp->params.boot_sleep; mlan_ds_misc_cfg *cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; ENTER(); cfg->param.boot_sleep = wlan_le16_to_cpu(boot_sleep->enable); PRINTM(MCMND, "boot sleep cfg status %u", cfg->param.boot_sleep); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of mac_address. * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_802_11_mac_address(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action) { ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) + S_DS_GEN); cmd->result = 0; cmd->params.mac_addr.action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { memcpy_ext(pmpriv->adapter, cmd->params.mac_addr.mac_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); /* HEXDUMP("SET_CMD: MAC ADDRESS-", priv->CurrentAddr, 6); */ } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of mac_address * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_802_11_mac_address(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_802_11_MAC_ADDRESS *pmac_addr = &resp->params.mac_addr; mlan_ds_bss *bss = MNULL; ENTER(); memcpy_ext(pmpriv->adapter, pmpriv->curr_addr, pmac_addr->mac_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); PRINTM(MINFO, "MAC address: " MACSTR "\n", MAC2STR(pmpriv->curr_addr)); if (pioctl_buf) { bss = (mlan_ds_bss *)pioctl_buf->pbuf; memcpy_ext(pmpriv->adapter, &bss->param.mac_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); pioctl_buf->data_read_written = MLAN_MAC_ADDR_LENGTH + MLAN_SUB_COMMAND_SIZE; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of Rx abort cfg * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_rxabortcfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_RX_ABORT_CFG *cfg_cmd = (HostCmd_DS_CMD_RX_ABORT_CFG *)&cmd->params.rx_abort_cfg; mlan_ds_misc_rx_abort_cfg *cfg = (mlan_ds_misc_rx_abort_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RX_ABORT_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_RX_ABORT_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->enable = (t_u8)cfg->enable; cfg_cmd->rssi_threshold = (t_s8)cfg->rssi_threshold; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of OFDM DESENSE cfg * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_ofdmdesense_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_OFDM_DESENSE_CFG *cfg_cmd = (HostCmd_DS_CMD_OFDM_DESENSE_CFG *)&cmd->params.ofdm_desense_cfg; mlan_ds_misc_ofdm_desense_cfg *cfg = (mlan_ds_misc_ofdm_desense_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_OFDM_DESENSE_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_OFDM_DESENSE_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->enable = (t_u8)cfg->enable; cfg_cmd->cca_threshold = (t_s8)cfg->cca_threshold; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of Rx Abort Cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_rxabortcfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_RX_ABORT_CFG *cfg_cmd = (HostCmd_DS_CMD_RX_ABORT_CFG *)&resp->params.rx_abort_cfg; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.rx_abort_cfg.enable = (t_u8)cfg_cmd->enable; misc_cfg->param.rx_abort_cfg.rssi_threshold = (t_s8)cfg_cmd->rssi_threshold; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of OFDM DESENSE CFG * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_ofdmdesense_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_OFDM_DESENSE_CFG *cfg_cmd = (HostCmd_DS_CMD_OFDM_DESENSE_CFG *)&resp->params .ofdm_desense_cfg; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.ofdm_desense_cfg.enable = (t_u8)cfg_cmd->enable; misc_cfg->param.ofdm_desense_cfg.cca_threshold = (t_s8)cfg_cmd->cca_threshold; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of Rx abort cfg ext * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_rxabortcfg_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_RX_ABORT_CFG_EXT *cfg_cmd = (HostCmd_DS_CMD_RX_ABORT_CFG_EXT *)&cmd->params.rx_abort_cfg_ext; mlan_ds_misc_rx_abort_cfg_ext *cfg = (mlan_ds_misc_rx_abort_cfg_ext *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RX_ABORT_CFG_EXT); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_RX_ABORT_CFG_EXT) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->enable = (t_u8)cfg->enable; cfg_cmd->rssi_margin = (t_s8)cfg->rssi_margin; cfg_cmd->ceil_rssi_threshold = (t_s8)cfg->ceil_rssi_threshold; cfg_cmd->floor_rssi_threshold = (t_s8)cfg->floor_rssi_threshold; cfg_cmd->current_dynamic_rssi_threshold = (t_s8)cfg->current_dynamic_rssi_threshold; cfg_cmd->rssi_default_config = (t_u8)cfg->rssi_default_config; cfg_cmd->edmac_enable = (t_u8)cfg->edmac_enable; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of nav mitigation * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_nav_mitigation(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_NAV_MITIGATION_CFG *cfg_cmd = (HostCmd_DS_CMD_NAV_MITIGATION_CFG *)&cmd->params.nav_mitigation; mlan_ds_misc_nav_mitigation *cfg = (mlan_ds_misc_nav_mitigation *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_NAV_MITIGATION_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_NAV_MITIGATION_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->start_nav_mitigation = wlan_cpu_to_le16(cfg->start_nav_mitigation); cfg_cmd->threshold = wlan_cpu_to_le16(cfg->threshold); cfg_cmd->detect_cnt = wlan_cpu_to_le16(cfg->detect_cnt); cfg_cmd->stop_cnt = wlan_cpu_to_le16(cfg->stop_cnt); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of LED config parameter * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_led_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { int count = 0; HostCmd_DS_CMD_LED_CFG *cfg_cmd = &cmd->params.ledcntrcfg; t_u8 *tlv = MNULL; t_u16 cmd_size = 0; int i = 0; mlan_ds_misc_led_cfg *cfg = (mlan_ds_misc_led_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_LED_CONTROL); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); cmd_size = S_DS_GEN + sizeof(HostCmd_DS_CMD_LED_CFG); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->enable = wlan_cpu_to_le16(cfg->enable); count = cfg->led_cfg_len; if (count != 0) { tlv = (t_u8 *)cmd + cmd_size; while (i < count) { MrvlIEtypes_led_behavior_t *led_tlv = (MrvlIEtypes_led_behavior_t *)tlv; led_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_LEDBEHAVIOR); led_tlv->header.len = wlan_cpu_to_le16( sizeof(MrvlIEtypes_led_behavior_t) - sizeof(MrvlIEtypesHeader_t)); led_tlv->firmwarestate = wlan_cpu_to_le16( cfg->misc_led_behvr[i].firmwarestate); led_tlv->ledstate = wlan_cpu_to_le16( cfg->misc_led_behvr[i].ledstate); led_tlv->ledargs = wlan_cpu_to_le16( cfg->misc_led_behvr[i].ledargs); cmd_size += sizeof(MrvlIEtypes_led_behavior_t); i++; if (i != count) { tlv += sizeof( MrvlIEtypes_led_behavior_t); } } } } cmd->size = wlan_cpu_to_le16(cmd_size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of led config * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_led_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc = (mlan_ds_misc_cfg *)(pioctl_buf->pbuf); mlan_ds_misc_led_cfg *mlan_led_cfg = &(misc->param.led_config); t_u8 *tlv = MNULL; int left_len = 0, i = 0; t_u32 cmdrsp_len = wlan_le16_to_cpu(resp->size); ENTER(); if ((cmdrsp_len < S_DS_GEN) || (cmdrsp_len - S_DS_GEN < sizeof(HostCmd_DS_CMD_LED_CFG))) return MLAN_STATUS_SUCCESS; mlan_led_cfg->enable = resp->params.ledcntrcfg.enable; left_len = cmdrsp_len - (S_DS_GEN + sizeof(HostCmd_DS_CMD_LED_CFG)); tlv = (t_u8 *)resp + (S_DS_GEN + sizeof(HostCmd_DS_CMD_LED_CFG)); for (i = 0; i < MAX_FW_STATES; i++) { mlan_led_cfg->misc_led_behvr[i].firmwarestate = *tlv; tlv++; tlv++; // to skip reserved byte mlan_led_cfg->misc_led_behvr[i].ledstate = *tlv; tlv++; mlan_led_cfg->misc_led_behvr[i].ledargs = *tlv; tlv++; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of Rx Abort Cfg ext * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_rxabortcfg_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_RX_ABORT_CFG_EXT *cfg_cmd = (HostCmd_DS_CMD_RX_ABORT_CFG_EXT *)&resp->params .rx_abort_cfg_ext; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.rx_abort_cfg_ext.enable = cfg_cmd->enable; misc_cfg->param.rx_abort_cfg_ext.rssi_margin = cfg_cmd->rssi_margin; misc_cfg->param.rx_abort_cfg_ext.ceil_rssi_threshold = cfg_cmd->ceil_rssi_threshold; misc_cfg->param.rx_abort_cfg_ext.floor_rssi_threshold = cfg_cmd->floor_rssi_threshold; misc_cfg->param.rx_abort_cfg_ext.current_dynamic_rssi_threshold = cfg_cmd->current_dynamic_rssi_threshold; misc_cfg->param.rx_abort_cfg_ext.rssi_default_config = cfg_cmd->rssi_default_config; misc_cfg->param.rx_abort_cfg_ext.edmac_enable = cfg_cmd->edmac_enable; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of nav mitigation * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_nav_mitigation(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_NAV_MITIGATION_CFG *cfg_cmd = (HostCmd_DS_CMD_NAV_MITIGATION_CFG *)&resp->params .nav_mitigation; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.nav_mitigation.start_nav_mitigation = wlan_le16_to_cpu(cfg_cmd->start_nav_mitigation); misc_cfg->param.nav_mitigation.threshold = wlan_le16_to_cpu(cfg_cmd->threshold); misc_cfg->param.nav_mitigation.detect_cnt = wlan_le16_to_cpu(cfg_cmd->detect_cnt); misc_cfg->param.nav_mitigation.stop_cnt = wlan_le16_to_cpu(cfg_cmd->stop_cnt); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function sets the hal/phy cfg params * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action The action: GET or SET * @param pdata_buf A pointer to data buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_hal_phy_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_u16 *pdata_buf) { HostCmd_DS_HAL_PHY_CFG *hal_phy_cfg_cmd = &cmd->params.hal_phy_cfg_params; mlan_ds_hal_phy_cfg_params *hal_phy_cfg_params = MNULL; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_HAL_PHY_CFG); cmd->size = sizeof(HostCmd_DS_HAL_PHY_CFG) + S_DS_GEN; hal_phy_cfg_cmd->action = wlan_cpu_to_le16(cmd_action); hal_phy_cfg_params = (mlan_ds_hal_phy_cfg_params *)pdata_buf; hal_phy_cfg_cmd->dot11b_psd_mask_cfg = hal_phy_cfg_params->dot11b_psd_mask_cfg; cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of hal_phy_cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_hal_phy_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_HAL_PHY_CFG *cfg_cmd = (HostCmd_DS_HAL_PHY_CFG *)&resp->params.hal_phy_cfg_params; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.hal_phy_cfg_params.dot11b_psd_mask_cfg = cfg_cmd->dot11b_psd_mask_cfg; } LEAVE(); return MLAN_STATUS_SUCCESS; } mlan_status wlan_cmd_ips_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_IPS_CONFIG *ips_cfg = MNULL; t_u32 enable = *(t_u32 *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_IPS_CONFIG); ips_cfg = &cmd->params.ips_cfg; ips_cfg->enable = wlan_cpu_to_le32(enable); cmd->size = S_DS_GEN + sizeof(HostCmd_DS_IPS_CONFIG); LEAVE(); return MLAN_STATUS_SUCCESS; } mlan_status wlan_ret_ips_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { ENTER(); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of Dot11mc unassoc ftm cfg * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_dot11mc_unassoc_ftm_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *cfg_cmd = (HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *)&cmd->params .dot11mc_unassoc_ftm_cfg; mlan_ds_misc_dot11mc_unassoc_ftm_cfg *cfg = (mlan_ds_misc_dot11mc_unassoc_ftm_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DOT11MC_UNASSOC_FTM_CFG); cmd->size = wlan_cpu_to_le16( sizeof(HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->state = wlan_cpu_to_le16(cfg->state); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of Dot11mc unassoc ftm cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_dot11mc_unassoc_ftm_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *cfg_cmd = (HostCmd_DS_CMD_DOT11MC_UNASSOC_FTM_CFG *)&resp->params .dot11mc_unassoc_ftm_cfg; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.dot11mc_unassoc_ftm_cfg.state = wlan_le16_to_cpu(cfg_cmd->state); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of Tx ampdu prot mode * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_tx_ampdu_prot_mode(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *cfg_cmd = (HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *)&cmd->params .tx_ampdu_prot_mode; mlan_ds_misc_tx_ampdu_prot_mode *cfg = (mlan_ds_misc_tx_ampdu_prot_mode *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_TX_AMPDU_PROT_MODE); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_TX_AMPDU_PROT_MODE) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->mode = wlan_cpu_to_le16(cfg->mode); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of Tx ampdu prot mode * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_tx_ampdu_prot_mode(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *cfg_cmd = (HostCmd_DS_CMD_TX_AMPDU_PROT_MODE *)&resp->params .tx_ampdu_prot_mode; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.tx_ampdu_prot_mode.mode = wlan_le16_to_cpu(cfg_cmd->mode); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of Rate Adapt cfg * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_rate_adapt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_RATE_ADAPT_CFG *cfg_cmd = (HostCmd_DS_CMD_RATE_ADAPT_CFG *)&cmd->params.rate_adapt_cfg; mlan_ds_misc_rate_adapt_cfg *cfg = (mlan_ds_misc_rate_adapt_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RATE_ADAPT_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_RATE_ADAPT_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->sr_rateadapt = (t_u8)cfg->sr_rateadapt; cfg_cmd->ra_low_thresh = (t_u8)cfg->ra_low_thresh; cfg_cmd->ra_high_thresh = (t_u8)cfg->ra_high_thresh; cfg_cmd->ra_interval = wlan_cpu_to_le16(cfg->ra_interval); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of Rate Adapt Cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_rate_adapt_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_RATE_ADAPT_CFG *cfg_cmd = (HostCmd_DS_CMD_RATE_ADAPT_CFG *)&resp->params.rate_adapt_cfg; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.rate_adapt_cfg.sr_rateadapt = (t_u8)cfg_cmd->sr_rateadapt; misc_cfg->param.rate_adapt_cfg.ra_low_thresh = (t_u8)cfg_cmd->ra_low_thresh; misc_cfg->param.rate_adapt_cfg.ra_high_thresh = (t_u8)cfg_cmd->ra_high_thresh; misc_cfg->param.rate_adapt_cfg.ra_interval = wlan_le16_to_cpu(cfg_cmd->ra_interval); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of CCK Desense cfg * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_cck_desense_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CMD_CCK_DESENSE_CFG *cfg_cmd = (HostCmd_DS_CMD_CCK_DESENSE_CFG *)&cmd->params.cck_desense_cfg; mlan_ds_misc_cck_desense_cfg *cfg = (mlan_ds_misc_cck_desense_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CCK_DESENSE_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CMD_CCK_DESENSE_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) { cfg_cmd->mode = wlan_cpu_to_le16(cfg->mode); cfg_cmd->margin = (t_s8)cfg->margin; cfg_cmd->ceil_thresh = (t_s8)cfg->ceil_thresh; cfg_cmd->num_on_intervals = (t_u8)cfg->num_on_intervals; cfg_cmd->num_off_intervals = (t_u8)cfg->num_off_intervals; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of CCK Desense Cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_cck_desense_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_CMD_CCK_DESENSE_CFG *cfg_cmd = (HostCmd_DS_CMD_CCK_DESENSE_CFG *)&resp->params.cck_desense_cfg; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.cck_desense_cfg.mode = wlan_le16_to_cpu(cfg_cmd->mode); misc_cfg->param.cck_desense_cfg.margin = (t_s8)cfg_cmd->margin; misc_cfg->param.cck_desense_cfg.ceil_thresh = (t_s8)cfg_cmd->ceil_thresh; misc_cfg->param.cck_desense_cfg.num_on_intervals = (t_u8)cfg_cmd->num_on_intervals; misc_cfg->param.cck_desense_cfg.num_off_intervals = (t_u8)cfg_cmd->num_off_intervals; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function sends dynamic bandwidth command to firmware. * * @param pmpriv A pointer to mlan_private structure * @param cmd Hostcmd ID * @param cmd_action Command action * @param pdata_buf A void pointer to information buffer * @return N/A */ mlan_status wlan_cmd_config_dyn_bw(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_DYN_BW *dyn_bw_cmd = &cmd->params.dyn_bw; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DYN_BW); cmd->size = S_DS_GEN + sizeof(HostCmd_DS_DYN_BW); dyn_bw_cmd->action = wlan_cpu_to_le16(cmd_action); dyn_bw_cmd->dyn_bw = wlan_cpu_to_le16(*(t_u16 *)pdata_buf); cmd->size = wlan_cpu_to_le16(cmd->size); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of dyn_bw * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_dyn_bw(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *cfg = MNULL; HostCmd_DS_DYN_BW *dyn_bw = &resp->params.dyn_bw; ENTER(); if (pioctl_buf && (wlan_le16_to_cpu(dyn_bw->action) == HostCmd_ACT_GEN_GET)) { cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; cfg->param.dyn_bw = wlan_le16_to_cpu(dyn_bw->dyn_bw); PRINTM(MCMND, "Get dynamic bandwidth 0x%x\n", cfg->param.dyn_bw); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of CHAN_TRPC_CONFIG * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_get_chan_trpc_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_CHANNEL_TRPC_CONFIG *trpc_cfg = &cmd->params.ch_trpc_config; mlan_ds_misc_chan_trpc_cfg *cfg = (mlan_ds_misc_chan_trpc_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_CHANNEL_TRPC_CONFIG); trpc_cfg->action = wlan_cpu_to_le16(cmd_action); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_CHANNEL_TRPC_CONFIG) + S_DS_GEN); trpc_cfg->sub_band = wlan_cpu_to_le16(cfg->sub_band); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of LOW_POWER_MODE_CFG * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_set_get_low_power_mode_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_LOW_POWER_MODE_CFG *lpm_cfg = &cmd->params.lpm_cfg; t_u16 lpm = *(t_u16 *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_LOW_POWER_MODE_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_LOW_POWER_MODE_CFG) + S_DS_GEN); lpm_cfg->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) lpm_cfg->lpm = wlan_cpu_to_le16(lpm); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of low power mode * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_set_get_low_power_mode_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_power_cfg *cfg = MNULL; HostCmd_DS_LOW_POWER_MODE_CFG *lpm_cfg = &resp->params.lpm_cfg; ENTER(); if (pioctl_buf && (wlan_le16_to_cpu(lpm_cfg->action) == HostCmd_ACT_GEN_GET)) { cfg = (mlan_ds_power_cfg *)pioctl_buf->pbuf; cfg->param.lpm = wlan_le16_to_cpu(lpm_cfg->lpm); PRINTM(MCMND, "Get low power mode %d\n", cfg->param.lpm); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of * packet aggregation * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_get_chan_trpc_config(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc = MNULL; HostCmd_DS_CHANNEL_TRPC_CONFIG *trpc_cfg = &resp->params.ch_trpc_config; mlan_ds_misc_chan_trpc_cfg *cfg = MNULL; mlan_adapter *pmadapter = pmpriv->adapter; ENTER(); if (pioctl_buf) { misc = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; cfg = (mlan_ds_misc_chan_trpc_cfg *)&(misc->param.trpc_cfg); cfg->sub_band = wlan_le16_to_cpu(trpc_cfg->sub_band); cfg->length = resp->size; memcpy_ext(pmadapter, cfg->trpc_buf, (t_u8 *)resp, cfg->length, sizeof(cfg->trpc_buf)); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of mc_aggr_cfg * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_mc_aggr_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_MC_AGGR_CFG *cfg_cmd = (HostCmd_DS_MC_AGGR_CFG *)&cmd->params.mc_aggr_cfg; mlan_ds_mc_aggr_cfg *cfg = (mlan_ds_mc_aggr_cfg *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_MC_AGGR_CFG); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MC_AGGR_CFG) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); cfg_cmd->enable_bitmap = (t_u8)cfg->enable_bitmap; cfg_cmd->mask_bitmap = (t_u8)cfg->mask_bitmap; cfg_cmd->cts2self_offset = wlan_cpu_to_le16(cfg->cts2self_offset); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of mc_aggr_cfg * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_mc_aggr_cfg(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { HostCmd_DS_MC_AGGR_CFG *cfg_cmd = (HostCmd_DS_MC_AGGR_CFG *)&resp->params.mc_aggr_cfg; mlan_ds_misc_cfg *misc_cfg = MNULL; ENTER(); if (pioctl_buf) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.mc_aggr_cfg.enable_bitmap = (t_u8)cfg_cmd->enable_bitmap; misc_cfg->param.mc_aggr_cfg.mask_bitmap = (t_u8)cfg_cmd->mask_bitmap; misc_cfg->param.mc_aggr_cfg.cts2self_offset = (t_u8)cfg_cmd->cts2self_offset; } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of ch_load * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_get_ch_load(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_GET_CH_LOAD *cfg_cmd = (HostCmd_DS_GET_CH_LOAD *)&cmd->params.ch_load; mlan_ds_ch_load *cfg = (mlan_ds_ch_load *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_GET_CH_LOAD); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_CH_LOAD) + S_DS_GEN); cfg_cmd->action = wlan_cpu_to_le16(cmd_action); cfg_cmd->ch_load = wlan_cpu_to_le16(cfg->ch_load_param); cfg_cmd->noise = wlan_cpu_to_le16(cfg->noise); cfg_cmd->rx_quality = wlan_cpu_to_le16(cfg->rx_quality); cfg_cmd->duration = wlan_cpu_to_le16(cfg->duration); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of ch_load * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_ch_load(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { ENTER(); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of RANGE_EXT * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_cmd_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf) { HostCmd_DS_RANGE_EXT *range_ext = &cmd->params.range_ext; t_u8 mode = *(t_u8 *)pdata_buf; ENTER(); cmd->command = wlan_cpu_to_le16(HostCmd_CMD_RANGE_EXT); cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_RANGE_EXT) + S_DS_GEN); range_ext->action = wlan_cpu_to_le16(cmd_action); if (cmd_action == HostCmd_ACT_GEN_SET) range_ext->mode = mode; LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of RANGE_EXT * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to command buffer * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_range_ext(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *misc_cfg = MNULL; HostCmd_DS_RANGE_EXT *range_ext = &resp->params.range_ext; ENTER(); if (pioctl_buf && (wlan_le16_to_cpu(range_ext->action) == HostCmd_ACT_GEN_GET)) { misc_cfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; misc_cfg->param.range_ext_mode = range_ext->mode; PRINTM(MCMND, "Get range ext mode %d\n", misc_cfg->param.range_ext_mode); } LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function prepares command of get_sensor_temp * * @param pmpriv A pointer to mlan_private structure * @param cmd A pointer to HostCmd_DS_COMMAND structure * @param cmd_action the action: GET or SET * @param pdata_buf A pointer to data buffer * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_cmd_get_sensor_temp(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action) { ENTER(); if (cmd_action != HostCmd_ACT_GEN_GET) { PRINTM(MERROR, "wlan_cmd_get_sensor_temp: support GET only.\n"); LEAVE(); return MLAN_STATUS_FAILURE; } cmd->command = wlan_cpu_to_le16(HostCmd_CMD_DS_GET_SENSOR_TEMP); cmd->size = wlan_cpu_to_le16(S_DS_GEN + 4); LEAVE(); return MLAN_STATUS_SUCCESS; } /** * @brief This function handles the command response of get_sensor_temp * * @param pmpriv A pointer to mlan_private structure * @param resp A pointer to HostCmd_DS_COMMAND * @param pioctl_buf A pointer to mlan_ioctl_req structure * * @return MLAN_STATUS_SUCCESS */ mlan_status wlan_ret_get_sensor_temp(pmlan_private pmpriv, HostCmd_DS_COMMAND *resp, mlan_ioctl_req *pioctl_buf) { mlan_ds_misc_cfg *pcfg = MNULL; const HostCmd_DS_SENSOR_TEMP *pSensorT = &resp->params.temp_sensor; ENTER(); if (pioctl_buf) { pcfg = (mlan_ds_misc_cfg *)pioctl_buf->pbuf; pcfg->param.sensor_temp.temperature = wlan_le32_to_cpu(pSensorT->temperature); PRINTM(MCMND, "get SOC temperature %u C \n", pSensorT->temperature); } LEAVE(); return MLAN_STATUS_SUCCESS; }