MCUXpresso_MIMXRT1021xxxxx/middleware/wifi_nxp/wifidriver/mlan_cmdevt.c
Yilin Sun 763d32be90
Updated SDK to v2.15.000
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-03-15 22:23:36 +08:00

1815 lines
70 KiB
C

/** @file mlan_cmdevt.c
*
* @brief This file provides the handling of CMD/EVENT in MLAN
*
* Copyright 2008-2023 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/*************************************************************
Change Log:
05/12/2009: initial version
************************************************************/
#include <mlan_api.h>
/* Additional WMSDK header files */
#include <wmerrno.h>
#include <wm_os.h>
/* Always keep this include at the end of all include files */
#include <mlan_remap_mem_operations.h>
/********************************************************
Local Variables
********************************************************/
/*******************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
/**
* @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(IN mlan_private *pmpriv,
IN t_u16 cmd_no,
IN t_u16 cmd_action,
IN t_u32 cmd_oid,
IN t_void *pioctl_buf,
IN t_void *pdata_buf)
{
/* Note: We send only one command at a time and do not need the linked
list based implementation used here. So we will call our own
implementation here.
*/
return wifi_prepare_and_send_cmd(pmpriv, cmd_no, cmd_action, cmd_oid, pioctl_buf, pdata_buf, pmpriv->bss_type,
NULL);
}
#ifdef CONFIG_11AX
/**
* @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;
}
#endif
/**
* @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,
IN HostCmd_DS_COMMAND *cmd,
IN ENH_PS_MODES cmd_action,
IN t_u16 ps_bitmap,
IN 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 = (ENH_PS_MODES)(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 = (ENH_PS_MODES)(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 = (ENH_PS_MODES)(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) != 0U)
{
pmlan_adapter pmadapter = pmpriv->adapter;
MrvlIEtypes_ps_param_t *ps_tlv = (MrvlIEtypes_ps_param_t *)(void *)tlv;
ps_param *ps_mode = (ps_param *)&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 += (t_u16)sizeof(MrvlIEtypes_ps_param_t);
tlv += (t_u8)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->adhoc_wake_period = wlan_cpu_to_le16(pmadapter->adhoc_awake_period);
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_AUTO_DS) != 0U)
{
MrvlIEtypes_auto_ds_param_t *auto_ps_tlv = (MrvlIEtypes_auto_ds_param_t *)(void *)tlv;
auto_ds_param *auto_ds = (auto_ds_param *)&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 += (t_u16)sizeof(MrvlIEtypes_auto_ds_param_t);
tlv += (t_u8)sizeof(MrvlIEtypes_auto_ds_param_t);
if (pdata_buf != NULL)
{
idletime = ((mlan_ds_auto_ds *)pdata_buf)->idletime;
}
auto_ds->deep_sleep_timeout = wlan_cpu_to_le16(idletime);
}
/* fixme :
* This macro is not defined as if now
* once full fledged support is added in the SDK
* for UAP this macro will be defined and
* line below will be uncommented*/
/* #if defined(UAP_SUPPORT)*/
if ((pdata_buf != MNULL) && (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) != 0U)
{
sleep_tlv = (MrvlIEtypes_sleep_param_t *)(void *)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 += (t_u16)sizeof(MrvlIEtypes_sleep_param_t);
tlv += (t_u8)sizeof(MrvlIEtypes_sleep_param_t);
}
if ((ps_mgmt->flags & PS_FLAG_INACT_SLEEP_PARAM) != 0U)
{
inact_tlv = (MrvlIEtypes_inact_sleep_param_t *)(void *)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 += (t_u16)sizeof(MrvlIEtypes_inact_sleep_param_t);
tlv += (t_u8)sizeof(MrvlIEtypes_inact_sleep_param_t);
}
}
/*#endif*/
cmd->size = wlan_cpu_to_le16(cmd_size);
}
else
{ /* Do Nothing */
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#ifdef SD8801
mlan_status wlan_ret_802_11_tx_rate_query(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND *resp, IN void *pioctl)
{
mlan_adapter *pmadapter = pmpriv->adapter;
wifi_ds_rate *rate = MNULL;
ENTER();
pmpriv->tx_rate = resp->params.tx_rate.tx_rate;
pmpriv->tx_htinfo = resp->params.tx_rate.ht_info;
if (!pmpriv->is_data_rate_auto)
{
pmpriv->data_rate = wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate, pmpriv->tx_htinfo);
}
if (pioctl)
{
rate = (wifi_ds_rate *)pioctl;
if (rate->sub_command == WIFI_DS_RATE_CFG)
{
#if 0
if(rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) {
#endif
if (pmpriv->tx_htinfo & MBIT(0))
rate->param.rate_cfg.rate = pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
else
/* 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.rate_cfg.rate =
(pmpriv->tx_rate > MLAN_RATE_INDEX_OFDM0) ? pmpriv->tx_rate - 1 : pmpriv->tx_rate;
#if 0
}
else {
rate->param.rate_cfg.rate = wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate,
pmpriv->tx_htinfo);
}
#endif
}
else if (rate->sub_command == WIFI_DS_GET_DATA_RATE)
{
if (pmpriv->tx_htinfo & MBIT(0))
{
rate->param.data_rate.tx_data_rate = pmpriv->tx_rate + MLAN_RATE_INDEX_MCS0;
if (pmpriv->tx_htinfo & MBIT(1))
rate->param.data_rate.tx_bw = MLAN_HT_BW40;
else
rate->param.data_rate.tx_bw = MLAN_HT_BW20;
if (pmpriv->tx_htinfo & MBIT(2))
rate->param.data_rate.tx_gi = MLAN_HT_SGI;
else
rate->param.data_rate.tx_gi = MLAN_HT_LGI;
}
else
/* 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;
if (pmpriv->rxpd_htinfo & MBIT(0))
{
rate->param.data_rate.rx_data_rate = pmpriv->rxpd_rate + MLAN_RATE_INDEX_MCS0;
if (pmpriv->rxpd_htinfo & MBIT(1))
rate->param.data_rate.rx_bw = MLAN_HT_BW40;
else
rate->param.data_rate.rx_bw = MLAN_HT_BW20;
if (pmpriv->rxpd_htinfo & MBIT(2))
rate->param.data_rate.rx_gi = MLAN_HT_SGI;
else
rate->param.data_rate.rx_gi = MLAN_HT_LGI;
}
else
/* 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;
}
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#else
/**
* @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(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND *resp, IN void *pioctl)
{
mlan_adapter *pmadapter = pmpriv->adapter;
wifi_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;
#ifdef CONFIG_11AX
if ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_HE)
pmpriv->ext_tx_rate_info = resp->params.tx_rate.ext_tx_rate_info;
#endif
if (!pmpriv->is_data_rate_auto)
{
pmpriv->data_rate = wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate, pmpriv->tx_rate_info
#ifdef CONFIG_11AX
,
pmpriv->ext_tx_rate_info
#endif
);
}
if (pioctl != NULL)
{
rate = (wifi_ds_rate *)pioctl;
if (rate->sub_command == WIFI_DS_RATE_CFG)
{
#if 0
if(rate->param.rate_cfg.rate_type == MLAN_RATE_INDEX) {
#endif
#ifdef CONFIG_11AC
if ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_VHT
#ifdef CONFIG_11AX
|| ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_HE)
#endif
)
{
/* VHT rate */
rate->param.rate_cfg.rate = (t_u32)((pmpriv->tx_rate) & 0xF);
}
else
#endif
if ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == 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 - 1U : pmpriv->tx_rate;
}
#if 0
}
else {
/* rate_type = MLAN_RATE_VALUE */
rate->param.rate_cfg.rate = wlan_index_to_data_rate(pmadapter,
pmpriv->tx_rate,
pmpriv->tx_rate_info);
}
#endif
}
else if (rate->sub_command == WIFI_DS_GET_DATA_RATE)
{
/* Tx rate info */
#ifdef CONFIG_11AC
if ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_VHT
#ifdef CONFIG_11AX
|| (mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_HE
#endif
)
{
/* VHT/HE rate */
rate->param.data_rate.tx_rate_format = (mlan_rate_format)(pmpriv->tx_rate_info & 0x3U);
rate->param.data_rate.tx_bw = (t_u32)((pmpriv->tx_rate_info & 0xC) >> 2);
#ifdef CONFIG_11AX
if ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_HE)
rate->param.data_rate.tx_gi =
(pmpriv->tx_rate_info & 0x10) >> 4 | (pmpriv->tx_rate_info & 0x80) >> 6;
else
#endif
rate->param.data_rate.tx_gi = (t_u32)((pmpriv->tx_rate_info & 0x10) >> 4);
rate->param.data_rate.tx_nss = ((pmpriv->tx_rate) >> 4) & 0x03;
rate->param.data_rate.tx_mcs_index = (t_u32)((pmpriv->tx_rate) & 0xF);
rate->param.data_rate.tx_data_rate =
wlan_index_to_data_rate(pmadapter, pmpriv->tx_rate, pmpriv->tx_rate_info
#ifdef CONFIG_11AX
,
pmpriv->ext_tx_rate_info
#endif
);
}
else
#endif
if ((mlan_rate_format)(pmpriv->tx_rate_info & 0x3U) == MLAN_RATE_FORMAT_HT)
{
/* HT rate */
rate->param.data_rate.tx_rate_format = MLAN_RATE_FORMAT_HT;
rate->param.data_rate.tx_bw = (pmpriv->tx_rate_info & 0xCU) >> 2U;
rate->param.data_rate.tx_gi = (pmpriv->tx_rate_info & 0x10U) >> 4U;
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
#ifdef CONFIG_11AX
,
pmpriv->ext_tx_rate_info
#endif
);
}
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 - 1U : pmpriv->tx_rate;
}
/* Rx rate info */
#ifdef CONFIG_11AC
if ((mlan_rate_format)(pmpriv->rxpd_rate_info & 0x3U) == MLAN_RATE_FORMAT_VHT
#ifdef CONFIG_11AX
|| (pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_HE
#endif
)
{
/* VHT/HE rate */
rate->param.data_rate.rx_rate_format = (mlan_rate_format)(pmpriv->rxpd_rate_info & 0x3);
rate->param.data_rate.rx_bw = (t_u32)((pmpriv->rxpd_rate_info & 0xC) >> 2);
#ifdef CONFIG_11AX
if ((pmpriv->rxpd_rate_info & 0x3) == MLAN_RATE_FORMAT_HE)
rate->param.data_rate.rx_gi =
(pmpriv->rxpd_rate_info & 0x10) >> 4 | (pmpriv->rxpd_rate_info & 0x80) >> 6;
else
#endif
rate->param.data_rate.rx_gi = (t_u32)((pmpriv->rxpd_rate_info & 0x10) >> 4);
rate->param.data_rate.rx_nss = ((pmpriv->rxpd_rate) >> 4) & 0x3;
rate->param.data_rate.rx_mcs_index = (t_u32)((pmpriv->rxpd_rate) & 0xF);
rate->param.data_rate.rx_data_rate =
wlan_index_to_data_rate(pmadapter, pmpriv->rxpd_rate, pmpriv->rxpd_rate_info
#ifdef CONFIG_11AX
,
pmpriv->ext_tx_rate_info
#endif
);
}
else
#endif
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_bw = (pmpriv->rxpd_rate_info & 0xCU) >> 2U;
rate->param.data_rate.rx_gi = (pmpriv->rxpd_rate_info & 0x10U) >> 4U;
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
#ifdef CONFIG_11AX
,
pmpriv->ext_tx_rate_info
#endif
);
}
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 =
(t_u32)((pmpriv->rxpd_rate > MLAN_RATE_INDEX_OFDM0) ? pmpriv->rxpd_rate - 1 : pmpriv->rxpd_rate);
}
}
else
{ /* Do Nothing */
}
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#endif
/**
* @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
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status wlan_cmd_tx_rate_cfg(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND *cmd,
IN t_u16 cmd_action,
IN t_void *pdata_buf,
IN 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 *)(void *)((t_u8 *)rate_cfg + sizeof(HostCmd_DS_TX_RATE_CFG));
// coverity[overrun-local:SUPPRESS]
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[2U + i]);
}
#ifdef CONFIG_11AC
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[2U + NELEMENTS(rate_scope->ht_mcs_rate_bitmap) + i]);
}
#endif
#ifdef CONFIG_11AX
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[2U + 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));
}
#endif
}
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[2U + i]);
}
#ifdef CONFIG_11AC
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[2U + NELEMENTS(rate_scope->ht_mcs_rate_bitmap) + i]);
}
#endif
#ifdef CONFIG_11AX
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(pmpriv->bitmap_rates[2U + 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));
}
#endif
}
rate_drop = (MrvlRateDropPattern_t *)(void *)((t_u8 *)rate_scope + sizeof(MrvlRateScope_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) + sizeof(MrvlRateScope_t) +
sizeof(MrvlRateDropPattern_t));
if (pioctl_buf)
{
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) + sizeof(MrvlRateScope_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(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND *resp, IN void *pioctl)
{
mlan_adapter *pmadapter = pmpriv->adapter;
wifi_ds_rate *ds_rate = MNULL;
HostCmd_DS_TX_RATE_CFG *prate_cfg = MNULL;
MrvlRateScope_t *prate_scope;
MrvlIEtypesHeader_t *head = MNULL;
t_u16 tlv;
t_u16 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 *)((t_u8 *)prate_cfg) + sizeof(HostCmd_DS_TX_RATE_CFG);
if (tlv_buf != NULL)
{
tlv_buf_len = resp->size - (sizeof(HostCmd_DS_TX_RATE_CFG) + S_DS_GEN);
tlv_buf_len = wlan_le16_to_cpu(tlv_buf_len);
}
while (tlv_buf_len > 0U)
{
// coverity[overrun-local:SUPPRESS]
tlv = (t_u16)(*tlv_buf);
tlv = tlv | (*(tlv_buf + 1) << 8);
switch (tlv)
{
case TLV_TYPE_RATE_SCOPE:
prate_scope = (MrvlRateScope_t *)(void *)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 < sizeof(prate_scope->ht_mcs_rate_bitmap) / sizeof(t_u16); i++)
{
pmpriv->bitmap_rates[2U + i] = wlan_le16_to_cpu(prate_scope->ht_mcs_rate_bitmap[i]);
}
#ifdef CONFIG_11AC
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]);
}
#endif
#ifdef CONFIG_11AX
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]);
}
}
#endif
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 */
default:
PRINTM(MINFO, "Unexpected TLV for rate cfg \n");
break;
}
head = (MrvlIEtypesHeader_t *)(void *)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 != 0U)
{
pmpriv->data_rate = 0;
PRINTM(MINFO, "Rate is Auto\r\n");
}
if (pioctl != NULL)
{
ds_rate = (wifi_ds_rate *)pioctl;
if (ds_rate == MNULL)
{
PRINTM(MERROR, "Request buffer not found!\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
if (pmpriv->is_data_rate_auto != 0U)
{
// ds_rate->param.rate_cfg.is_rate_auto = MTRUE;
ds_rate->param.rate_cfg.rate_format = MLAN_RATE_FORMAT_AUTO;
}
else
{
/* 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 = (t_u32)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 = (t_u32)index;
}
#ifdef CONFIG_11AC
/* 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 = (t_u32)(index % 16);
ds_rate->param.rate_cfg.nss = (t_u32)(index / 16);
ds_rate->param.rate_cfg.nss += MLAN_RATE_NSS1;
}
#endif
#ifdef CONFIG_11AX
/* 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;
}
}
#endif
ds_rate->param.rate_cfg.rate_setting = rate_setting;
PRINTM(MINFO, "Rate index is %d\n", ds_rate->param.rate_cfg.rate);
ds_rate->param.rate_cfg.rate_index = ds_rate->param.rate_cfg.rate;
}
}
LEAVE();
return ret;
}
/**
* @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(IN pmlan_private pmpriv, IN 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);
(void)__memcpy(pmpriv->adapter, hw_spec->permanent_addr, pmpriv->curr_addr, MLAN_MAC_ADDR_LENGTH);
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, IN HostCmd_DS_COMMAND *cmd, IN 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 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(IN pmlan_private pmpriv, IN HostCmd_DS_COMMAND *resp, IN 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;
pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
t_u16 left_len;
t_u16 tlv_type = 0;
t_u16 tlv_len = 0;
MrvlIEtypesHeader_t *tlv = MNULL;
#ifdef CONFIG_11AX
MrvlIEtypes_Extension_t *ext_tlv = MNULL;
#endif
MrvlIEtypes_fw_cap_info_t *fw_cap_tlv = MNULL;
ENTER();
pmadapter->fw_cap_info = wlan_le32_to_cpu(hw_spec->fw_cap_info);
if ((IS_SUPPORT_MULTI_BANDS(pmadapter)) != 0U)
{
pmadapter->fw_bands = (t_u16)GET_FW_DEFAULT_BANDS(pmadapter);
#ifndef CONFIG_5GHz_SUPPORT
/* fixme: Re-check if this is the correct way to disable 5 GHz. */
pmadapter->fw_bands &= ~(BAND_A | BAND_AN | BAND_AAC);
#endif /* CONFIG_5GHz_SUPPORT */
}
else
{
pmadapter->fw_bands = BAND_B;
}
pmadapter->config_bands = pmadapter->fw_bands;
for (i = 0; i < pmadapter->priv_num; i++)
{
if (pmadapter->priv[i] != MNULL)
{
pmadapter->priv[i]->config_bands = pmadapter->fw_bands;
}
}
if ((pmadapter->fw_bands & BAND_A) != 0U)
{
if ((pmadapter->fw_bands & BAND_GN) != 0U)
{
pmadapter->config_bands |= BAND_AN;
for (i = 0; i < pmadapter->priv_num; i++)
{
if (pmadapter->priv[i] != MNULL)
{
pmadapter->priv[i]->config_bands |= BAND_AN;
}
}
pmadapter->fw_bands |= BAND_AN;
}
if ((pmadapter->fw_bands & BAND_AAC) != 0U)
{
pmadapter->config_bands |= BAND_AAC;
for (i = 0; i < pmadapter->priv_num; i++)
{
if (pmadapter->priv[i] != MNULL)
{
pmadapter->priv[i]->config_bands |= BAND_AAC;
}
}
}
if ((pmadapter->fw_bands & BAND_AN) != 0U)
{
pmadapter->adhoc_start_band = (BAND_A | BAND_AN);
pmadapter->adhoc_11n_enabled = MTRUE;
}
else
{
pmadapter->adhoc_start_band = BAND_A;
}
pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
}
else if ((pmadapter->fw_bands & BAND_GN) != 0U)
{
pmadapter->adhoc_start_band = (BAND_G | BAND_B | BAND_GN);
pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
pmadapter->adhoc_11n_enabled = MTRUE;
}
else if ((pmadapter->fw_bands & BAND_G) != 0U)
{
pmadapter->adhoc_start_band = (BAND_G | BAND_B);
pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
}
else if ((pmadapter->fw_bands & BAND_B) != 0U)
{
pmadapter->adhoc_start_band = BAND_B;
pmpriv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
}
else
{
/* Do nothing */
}
pmadapter->fw_release_number = hw_spec->fw_release_number;
pmadapter->number_of_antenna = wlan_le16_to_cpu(hw_spec->number_of_antenna);
PRINTM(MINFO, "GET_HW_SPEC: fw_release_number- 0x%X\n", wlan_le32_to_cpu(pmadapter->fw_release_number));
PRINTM(MINFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", hw_spec->permanent_addr[0],
hw_spec->permanent_addr[1], hw_spec->permanent_addr[2], hw_spec->permanent_addr[3],
hw_spec->permanent_addr[4], hw_spec->permanent_addr[5]);
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] == 0xffU)
{
(void)__memmove(pmadapter, pmpriv->curr_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->usr_dot_11n_dev_cap_bg = pmadapter->hw_dot_11n_dev_cap & DEFAULT_11N_CAP_MASK_BG;
pmadapter->usr_dot_11n_dev_cap_a = pmadapter->hw_dot_11n_dev_cap & DEFAULT_11N_CAP_MASK_A;
pmadapter->usr_dev_mcs_support = 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);
wlan_show_dot11ndevcap(pmadapter, pmadapter->hw_dot_11n_dev_cap);
wlan_show_devmcssupport(pmadapter, pmadapter->hw_dev_mcs_support);
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);
pmadapter->usr_dot_11ac_mcs_support = pmadapter->hw_dot_11ac_mcs_support;
pmadapter->usr_dot_11ac_dev_cap_bg = pmadapter->hw_dot_11ac_dev_cap & ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
#ifdef CONFIG_5GHz_SUPPORT
pmadapter->usr_dot_11ac_dev_cap_a = pmadapter->hw_dot_11ac_dev_cap & ~DEFALUT_11AC_CAP_BEAMFORMING_RESET_MASK;
#endif
pmadapter->usr_dot_11ac_bw = BW_FOLLOW_VHTCAP;
pmadapter->mp_end_port = wlan_le16_to_cpu(hw_spec->mp_end_port);
for (i = 1; i <= (unsigned)(MAX_PORT - pmadapter->mp_end_port); i++)
{
pmadapter->mp_data_port_mask &= ~(1U << (MAX_PORT - i));
}
#ifdef OTP_CHANINFO
if ((pmadapter->otp_region != MNULL) && (pmadapter->otp_region->force_reg == 0U))
{
#endif
/* Set the region code to WWSM by default */
pmadapter->region_code = MRVDRV_DEFAULT_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 = (t_u8)pmadapter->region_code;
pmadapter->cfp_code_a = (t_u8)pmadapter->region_code;
#ifdef OTP_CHANINFO
}
#endif
if (wlan_set_regiontable(pmpriv, (t_u8)pmadapter->region_code, pmadapter->fw_bands) != MLAN_STATUS_SUCCESS)
{
if (pioctl_req != MNULL)
{
pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
}
ret = MLAN_STATUS_FAILURE;
goto done;
}
if (wlan_11d_set_universaltable(pmpriv, pmadapter->fw_bands) != MLAN_STATUS_SUCCESS)
{
if (pioctl_req != MNULL)
{
pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
}
ret = MLAN_STATUS_FAILURE;
goto done;
}
left_len = resp->size - (t_u16)sizeof(HostCmd_DS_GET_HW_SPEC) - (t_u16)S_DS_GEN;
tlv = (MrvlIEtypesHeader_t *)(void *)((t_u8 *)(&resp->params) + 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)
{
#ifdef CONFIG_11AX
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;
#endif
case TLV_TYPE_FW_CAP_INFO:
fw_cap_tlv = (MrvlIEtypes_fw_cap_info_t *)(void *)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;
default:
PRINTM(MINFO, "Unexpected TLV hw spec \n");
break;
}
left_len -= (t_u16)(sizeof(MrvlIEtypesHeader_t) + tlv_len);
tlv = (MrvlIEtypesHeader_t *)(void *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t));
}
pmadapter->cmd_tx_data = IS_FW_SUPPORT_CMD_TX_DATA(pmadapter) ? 0x01 : 0x00;
done:
LEAVE();
return ret;
}
/**
* @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(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND *cmd,
IN t_u16 cmd_action,
IN 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 != 0U)
{
remain_channel->action = HostCmd_ACT_GEN_REMOVE;
}
else
{
remain_channel->status = 0;
remain_channel->reserved = 0;
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;
}
#ifdef OTP_CHANINFO
/**
* @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(IN pmlan_private pmpriv,
IN HostCmd_DS_COMMAND *resp,
IN 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;
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 *)(void *)&resp->params;
if (reg == MNULL)
{
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);
tlv_buf_left = (t_u16)(wlan_le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*reg));
/* Add FW cfp tables and region info */
wlan_add_fw_cfp_tables(pmpriv, tlv_buf, tlv_buf_left);
if (pioctl_buf == MNULL)
{
goto done;
}
if (pioctl_buf->pbuf == MNULL)
{
ret = MLAN_STATUS_FAILURE;
goto done;
}
misc_cfg = (mlan_ds_misc_cfg *)(void *)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 = wlan_le16_to_cpu(resp->size);
(void)__memcpy(pmpriv->adapter, cfg->chnrgpwr_buf, (t_u8 *)resp, cfg->length);
}
else
{
(void)__memset(pmpriv->adapter, &misc_cfg->param.custom_reg_domain, 0, sizeof(mlan_ds_custom_reg_domain));
if (pmadapter->otp_region != MNULL)
{
(void)__memcpy(pmpriv->adapter, &misc_cfg->param.custom_reg_domain.region, pmadapter->otp_region,
sizeof(otp_region_info_t));
}
if (pmadapter->cfp_otp_bg != MNULL)
{
misc_cfg->param.custom_reg_domain.num_bg_chan = pmadapter->tx_power_table_bg_rows;
(void)__memcpy(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));
}
#ifdef CONFIG_5GHz_SUPPORT
if (pmadapter->cfp_otp_a != MNULL)
{
misc_cfg->param.custom_reg_domain.num_a_chan = pmadapter->tx_power_table_a_rows;
(void)__memcpy(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));
}
#endif
}
done:
LEAVE();
return ret;
}
#endif
#ifdef CONFIG_COMPRESS_TX_PWTBL
mlan_status wlan_cmd_region_power_cfg(pmlan_private pmpriv,
HostCmd_DS_COMMAND *cmd,
t_u16 cmd_action,
t_void *pdata_buf)
{
t_u16 buf_len;
ENTER();
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_REGION_POWER_CFG);
if (cmd_action == HostCmd_ACT_GEN_SET)
{
buf_len = cmd->size - S_DS_GEN;
__memcpy(pmpriv->adapter, (t_u8 *)cmd + S_DS_GEN, pdata_buf, buf_len);
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#endif
#ifdef CONFIG_WIFI_CLOCKSYNC
/**
* @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_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 == (t_u32)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: \r\nMode=%d Role=%d, \r\nGPIO Pin Number=%d, \r\nGPIO level/toggle=%d GPIO "
"pulse "
"width=%d\n\r",
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 == (t_u32)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 == (t_u32)MLAN_OID_MISC_GET_TSF_INFO)
{
gpio_tsf_latch_report = (MrvlIEtypes_GPIO_TSF_LATCH_REPORT *)tlv;
(void)memset(gpio_tsf_latch_report, 0, sizeof(MrvlIEtypes_GPIO_TSF_LATCH_REPORT));
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\r", 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(MCMND, "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 == (t_u32)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\r",
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 == (t_u32)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\r\n",
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:
wifi_d("gpio tsf latch: Unknown tlv type");
break;
}
tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len + sizeof(MrvlIEtypesHeader_t));
}
if (cfg->sub_command == (t_u32)MLAN_OID_MISC_GPIO_TSF_LATCH)
pioctl_buf->data_read_written = sizeof(mlan_ds_gpio_tsf_latch);
else if (cfg->sub_command == (t_u32)MLAN_OID_MISC_GET_TSF_INFO)
pioctl_buf->data_read_written = sizeof(mlan_ds_tsf_info);
}
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
#endif /* CONFIG_WIFI_CLOCKSYNC */
#ifdef CONFIG_FW_VDLL
extern const unsigned char wlan_fw_bin[];
extern unsigned int wlan_fw_bin_len;
/**
* @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;
int ret = -WM_FAIL;
pvdll_dnld_ctrl ctrl = &pmadapter->vdll_ctrl;
t_u16 msg_len = block_len + sizeof(HostCmd_DS_GEN);
HostCmd_DS_GEN *cmd_hdr;
ENTER();
if ((msg_len > WIFI_FW_CMDBUF_SIZE) || (ctrl == NULL))
{
wevt_d("VDLL block mem greater than cmd buf/vdll struct not inited");
goto done;
}
cmd_hdr = (HostCmd_DS_GEN *)ctrl->cmd_buf;
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);
(void)__memcpy(pmadapter, ctrl->cmd_buf + sizeof(HostCmd_DS_GEN), block, block_len);
#ifdef CONFIG_FW_VDLL_DEBUG
wevt_d("DNLD_VDLL : block_len=%d", block_len);
#endif
ret = wifi_wait_for_vdllcmdresp(NULL);
if (ret == -WM_FAIL)
{
wevt_d("DNLD_VDLL: Host to Card Failed");
}
else
{
status = MLAN_STATUS_SUCCESS;
}
done:
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)
{
/*Since f/w is already in .h in RT so we will use the offsets directly*/
vdll_dnld_ctrl *ctrl = &pmadapter->vdll_ctrl;
ENTER();
if (ctrl != NULL)
{
ctrl->vdll_mem = (t_u8 *)(wlan_fw_bin + (wlan_fw_bin_len - vdll_len));
ctrl->vdll_len = vdll_len;
ctrl->cmd_buf = (t_u8 *)wifi_get_vdllcommand_buffer();
}
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @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, t_u8 *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 + 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);
#ifdef CONFIG_FW_VDLL_DEBUG
wevt_d("VDLL_IND: type=%d offset = 0x%x, len = %d, vdll_len=0x%x", wlan_le16_to_cpu(ind->type), offset,
block_len, ctrl->vdll_len);
#endif
if (offset <= ctrl->vdll_len)
{
block_len = MIN(block_len, ctrl->vdll_len - offset);
status = wlan_download_vdll_block(pmadapter, ctrl->vdll_mem + offset, block_len);
if (status)
{
wevt_d("Fail to download VDLL block");
}
if (pmadapter->vdll_in_progress == MFALSE)
{
(void)pmadapter->callbacks.moal_start_timer(pmadapter->pmoal_handle, pmadapter->vdll_timer, MFALSE,
2000);
pmadapter->vdll_in_progress = MTRUE;
}
else
{
(void)pmadapter->callbacks.moal_reset_timer(pmadapter->pmoal_handle, pmadapter->vdll_timer);
}
}
else
{
wevt_d("Invalid VDLL req: offset=0x%x, len=%d, vdll_len=0x%x", offset, block_len, ctrl->vdll_len);
}
break;
case VDLL_IND_TYPE_OFFSET:
offset = wlan_le32_to_cpu(ind->offset);
#ifdef CONFIG_FW_VDLL_DEBUG
wevt_d("VDLL_IND (OFFSET): vdll_len=0x%x", offset);
#endif
wlan_get_vdll_image(pmadapter, offset);
break;
case VDLL_IND_TYPE_ERR_SIG:
wevt_d("VDLL_IND (SIG ERR).");
break;
case VDLL_IND_TYPE_ERR_ID:
wevt_d("VDLL_IND (ID ERR).");
break;
#if defined(SD9177)
case VDLL_IND_TYPE_ERR_SECURE:
wevt_d("VDLL_IND (SECURE ERR).");
break;
case VDLL_IND_TYPE_COMPLETE:
wevt_d("VDLL_IND (ID COMPLETE).");
break;
#elif defined(SD8978) || defined(SD8987) || defined(SD8997)
case VDLL_IND_TYPE_INTF_RESET:
wevt_d("VDLLV2_IND (INTF RESET).");
sd_wifi_reset_ports();
break;
#endif
default:
wevt_d("unknown vdll ind type=%d", ind->type);
break;
}
LEAVE();
return status;
}
#endif /* CONFIG_FW_VDLL */
#if defined(CONFIG_WIFI_IND_RESET) && defined(CONFIG_WIFI_IND_DNLD)
/**
* @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;
}
#endif
/**
* @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 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_FRAME
*
* @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_frame(pmlan_private pmpriv, HostCmd_DS_COMMAND *cmd, t_u16 cmd_action, t_void *pdata_buf)
{
t_u16 cmd_size = 0;
HostCmd_DS_80211_TX_FRAME *tx_frame_cmd = &cmd->params.tx_frame;
mlan_ds_misc_tx_frame *tx_frame = (mlan_ds_misc_tx_frame *)pdata_buf;
TxPD *plocal_tx_pd = (TxPD *)tx_frame_cmd->buffer;
t_u32 pkt_type;
t_u32 tx_control;
t_u8 *pdata = tx_frame->tx_buf;
t_u16 data_len = tx_frame->data_len;
ENTER();
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_FRAME);
cmd_size = sizeof(HostCmd_DS_80211_TX_FRAME) + S_DS_GEN;
tx_frame_cmd->action = 0;
tx_frame_cmd->status = 0;
(void)__memcpy(pmpriv->adapter, &tx_frame_cmd->band_config, (t_u8 *)&tx_frame->bandcfg, sizeof(t_u8));
tx_frame_cmd->channel = tx_frame->channel;
if (tx_frame->buf_type == MLAN_BUF_TYPE_RAW_DATA)
{
(void)__memcpy(pmpriv->adapter, &pkt_type, tx_frame->tx_buf, sizeof(pkt_type));
(void)__memcpy(pmpriv->adapter, &tx_control, tx_frame->tx_buf + sizeof(pkt_type), sizeof(tx_control));
data_len -= sizeof(pkt_type) + sizeof(tx_control);
pdata += sizeof(pkt_type) + sizeof(tx_control);
}
(void)__memcpy(pmpriv->adapter, tx_frame_cmd->buffer + sizeof(TxPD), pdata, data_len);
(void)__memset(pmpriv->adapter, plocal_tx_pd, 0, sizeof(TxPD));
plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
plocal_tx_pd->bss_type = pmpriv->bss_type;
plocal_tx_pd->tx_pkt_length = (t_u16)data_len;
plocal_tx_pd->priority = (t_u8)tx_frame->priority;
plocal_tx_pd->tx_pkt_offset = sizeof(TxPD);
plocal_tx_pd->pkt_delay_2ms = 0xff;
if (tx_frame->buf_type == MLAN_BUF_TYPE_RAW_DATA)
{
plocal_tx_pd->tx_pkt_type = (t_u16)pkt_type;
plocal_tx_pd->tx_control = tx_control;
}
if (tx_frame->flags & MLAN_BUF_FLAG_TX_STATUS)
{
#ifdef TXPD_RXPD_V3
plocal_tx_pd->tx_control_1 |= tx_frame->tx_seq_num << 8;
#else
plocal_tx_pd->tx_token_id = (t_u8)tx_frame->tx_seq_num;
#endif
plocal_tx_pd->flags |= MRVDRV_TxPD_FLAGS_TX_PACKET_STATUS;
}
endian_convert_TxPD(plocal_tx_pd);
cmd_size += sizeof(TxPD) + data_len;
cmd->size = wlan_cpu_to_le16(cmd_size);
LEAVE();
return MLAN_STATUS_SUCCESS;
}