mirror of
https://github.com/RinCat/RTL88x2BU-Linux-Driver.git
synced 2024-12-27 02:21:35 +00:00
591 lines
19 KiB
C
591 lines
19 KiB
C
|
/******************************************************************************
|
||
|
*
|
||
|
* Copyright(c) 2007 - 2020 Realtek Corporation.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of version 2 of the GNU General Public License as
|
||
|
* published by the Free Software Foundation.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||
|
* more details.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <drv_types.h>
|
||
|
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
u8 rtw_roch_stay_in_cur_chan(_adapter *padapter)
|
||
|
{
|
||
|
int i;
|
||
|
_adapter *iface;
|
||
|
struct mlme_priv *pmlmepriv;
|
||
|
struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
|
||
|
u8 rst = _FALSE;
|
||
|
|
||
|
for (i = 0; i < dvobj->iface_nums; i++) {
|
||
|
iface = dvobj->padapters[i];
|
||
|
if (iface) {
|
||
|
pmlmepriv = &iface->mlmepriv;
|
||
|
|
||
|
if (check_fwstate(pmlmepriv, WIFI_UNDER_LINKING | WIFI_UNDER_WPS | WIFI_UNDER_KEY_HANDSHAKE) == _TRUE) {
|
||
|
RTW_INFO(ADPT_FMT"- WIFI_UNDER_LINKING |WIFI_UNDER_WPS | WIFI_UNDER_KEY_HANDSHAKE (mlme state:0x%x)\n",
|
||
|
ADPT_ARG(iface), get_fwstate(&iface->mlmepriv));
|
||
|
rst = _TRUE;
|
||
|
break;
|
||
|
}
|
||
|
#ifdef CONFIG_AP_MODE
|
||
|
if (MLME_IS_AP(iface) || MLME_IS_MESH(iface)) {
|
||
|
if (rtw_ap_sta_states_check(iface) == _TRUE) {
|
||
|
rst = _TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rst;
|
||
|
}
|
||
|
|
||
|
static int rtw_ro_ch_handler(_adapter *adapter, u8 *buf)
|
||
|
{
|
||
|
int ret = H2C_SUCCESS;
|
||
|
struct rtw_roch_parm *roch_parm = (struct rtw_roch_parm *)buf;
|
||
|
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
|
||
|
struct roch_info *prochinfo = &adapter->rochinfo;
|
||
|
#ifdef CONFIG_CONCURRENT_MODE
|
||
|
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
|
||
|
#endif
|
||
|
u8 ready_on_channel = _FALSE;
|
||
|
u8 remain_ch;
|
||
|
unsigned int duration;
|
||
|
|
||
|
_enter_critical_mutex(&pwdev_priv->roch_mutex, NULL);
|
||
|
|
||
|
if (rtw_cfg80211_get_is_roch(adapter) != _TRUE)
|
||
|
goto exit;
|
||
|
|
||
|
remain_ch = (u8)ieee80211_frequency_to_channel(roch_parm->ch.center_freq);
|
||
|
duration = roch_parm->duration;
|
||
|
|
||
|
RTW_INFO(FUNC_ADPT_FMT" ch:%u duration:%d, cookie:0x%llx\n"
|
||
|
, FUNC_ADPT_ARG(adapter), remain_ch, roch_parm->duration, roch_parm->cookie);
|
||
|
|
||
|
if (roch_parm->wdev && roch_parm->cookie) {
|
||
|
if (prochinfo->ro_ch_wdev != roch_parm->wdev) {
|
||
|
RTW_WARN(FUNC_ADPT_FMT" ongoing wdev:%p, wdev:%p\n"
|
||
|
, FUNC_ADPT_ARG(adapter), prochinfo->ro_ch_wdev, roch_parm->wdev);
|
||
|
rtw_warn_on(1);
|
||
|
}
|
||
|
|
||
|
if (prochinfo->remain_on_ch_cookie != roch_parm->cookie) {
|
||
|
RTW_WARN(FUNC_ADPT_FMT" ongoing cookie:0x%llx, cookie:0x%llx\n"
|
||
|
, FUNC_ADPT_ARG(adapter), prochinfo->remain_on_ch_cookie, roch_parm->cookie);
|
||
|
rtw_warn_on(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (rtw_roch_stay_in_cur_chan(adapter) == _TRUE) {
|
||
|
remain_ch = rtw_mi_get_union_chan(adapter);
|
||
|
RTW_INFO(FUNC_ADPT_FMT" stay in union ch:%d\n", FUNC_ADPT_ARG(adapter), remain_ch);
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_CONCURRENT_MODE
|
||
|
if (rtw_mi_check_status(adapter, MI_LINKED) && (0 != rtw_mi_get_union_chan(adapter))) {
|
||
|
if ((remain_ch != rtw_mi_get_union_chan(adapter)) && !check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE)) {
|
||
|
if (remain_ch != pmlmeext->cur_channel
|
||
|
#ifdef RTW_ROCH_BACK_OP
|
||
|
|| ATOMIC_READ(&pwdev_priv->switch_ch_to) == 1
|
||
|
#endif
|
||
|
) {
|
||
|
rtw_leave_opch(adapter);
|
||
|
|
||
|
#ifdef RTW_ROCH_BACK_OP
|
||
|
RTW_INFO("%s, set switch ch timer, duration=%d\n", __func__, prochinfo->max_away_dur);
|
||
|
ATOMIC_SET(&pwdev_priv->switch_ch_to, 0);
|
||
|
/* remain_ch is not same as union channel. duration is max_away_dur to
|
||
|
* back to AP's channel.
|
||
|
*/
|
||
|
_set_timer(&prochinfo->ap_roch_ch_switch_timer, prochinfo->max_away_dur);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
ready_on_channel = _TRUE;
|
||
|
} else
|
||
|
#endif /* CONFIG_CONCURRENT_MODE */
|
||
|
{
|
||
|
if (remain_ch != rtw_get_oper_ch(adapter))
|
||
|
ready_on_channel = _TRUE;
|
||
|
}
|
||
|
|
||
|
if (ready_on_channel == _TRUE) {
|
||
|
#ifndef RTW_SINGLE_WIPHY
|
||
|
if (!check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE))
|
||
|
#endif
|
||
|
{
|
||
|
#ifdef CONFIG_CONCURRENT_MODE
|
||
|
if (rtw_get_oper_ch(adapter) != remain_ch)
|
||
|
#endif
|
||
|
{
|
||
|
/* if (!padapter->mlmepriv.LinkDetectInfo.bBusyTraffic) */
|
||
|
set_channel_bwmode(adapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_BT_COEXIST
|
||
|
rtw_btcoex_ScanNotify(adapter, _TRUE);
|
||
|
#endif
|
||
|
|
||
|
RTW_INFO("%s, set ro ch timer, duration=%d\n", __func__, duration);
|
||
|
_set_timer(&prochinfo->remain_on_ch_timer, duration);
|
||
|
|
||
|
exit:
|
||
|
_exit_critical_mutex(&pwdev_priv->roch_mutex, NULL);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int rtw_cancel_ro_ch_handler(_adapter *padapter, u8 *buf)
|
||
|
{
|
||
|
int ret = H2C_SUCCESS;
|
||
|
struct rtw_roch_parm *roch_parm = (struct rtw_roch_parm *)buf;
|
||
|
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
|
||
|
struct roch_info *prochinfo = &padapter->rochinfo;
|
||
|
struct wireless_dev *wdev;
|
||
|
#ifdef CONFIG_P2P
|
||
|
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
|
||
|
#endif
|
||
|
u8 ch, bw, offset;
|
||
|
|
||
|
_enter_critical_mutex(&pwdev_priv->roch_mutex, NULL);
|
||
|
|
||
|
if (rtw_cfg80211_get_is_roch(padapter) != _TRUE)
|
||
|
goto exit;
|
||
|
|
||
|
if (roch_parm->wdev && roch_parm->cookie) {
|
||
|
if (prochinfo->ro_ch_wdev != roch_parm->wdev) {
|
||
|
RTW_WARN(FUNC_ADPT_FMT" ongoing wdev:%p, wdev:%p\n"
|
||
|
, FUNC_ADPT_ARG(padapter), prochinfo->ro_ch_wdev, roch_parm->wdev);
|
||
|
rtw_warn_on(1);
|
||
|
}
|
||
|
|
||
|
if (prochinfo->remain_on_ch_cookie != roch_parm->cookie) {
|
||
|
RTW_WARN(FUNC_ADPT_FMT" ongoing cookie:0x%llx, cookie:0x%llx\n"
|
||
|
, FUNC_ADPT_ARG(padapter), prochinfo->remain_on_ch_cookie, roch_parm->cookie);
|
||
|
rtw_warn_on(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if defined(RTW_ROCH_BACK_OP) && defined(CONFIG_CONCURRENT_MODE)
|
||
|
_cancel_timer_ex(&prochinfo->ap_roch_ch_switch_timer);
|
||
|
ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
|
||
|
#endif
|
||
|
|
||
|
if (rtw_mi_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) {
|
||
|
if (0)
|
||
|
RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n",
|
||
|
FUNC_ADPT_ARG(padapter), ch, bw, offset);
|
||
|
#ifdef CONFIG_P2P
|
||
|
} else if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->listen_channel) {
|
||
|
ch = pwdinfo->listen_channel;
|
||
|
bw = CHANNEL_WIDTH_20;
|
||
|
offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
|
||
|
if (0)
|
||
|
RTW_INFO(FUNC_ADPT_FMT" back to listen ch - ch:%u, bw:%u, offset:%u\n",
|
||
|
FUNC_ADPT_ARG(padapter), ch, bw, offset);
|
||
|
#endif
|
||
|
} else {
|
||
|
ch = prochinfo->restore_channel;
|
||
|
bw = CHANNEL_WIDTH_20;
|
||
|
offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
|
||
|
if (0)
|
||
|
RTW_INFO(FUNC_ADPT_FMT" back to restore ch - ch:%u, bw:%u, offset:%u\n",
|
||
|
FUNC_ADPT_ARG(padapter), ch, bw, offset);
|
||
|
}
|
||
|
|
||
|
set_channel_bwmode(padapter, ch, offset, bw);
|
||
|
rtw_back_opch(padapter);
|
||
|
#ifdef CONFIG_P2P
|
||
|
rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
|
||
|
#ifdef CONFIG_DEBUG_CFG80211
|
||
|
RTW_INFO("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo));
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
wdev = prochinfo->ro_ch_wdev;
|
||
|
|
||
|
rtw_cfg80211_set_is_roch(padapter, _FALSE);
|
||
|
prochinfo->ro_ch_wdev = NULL;
|
||
|
rtw_cfg80211_set_last_ro_ch_time(padapter);
|
||
|
|
||
|
rtw_cfg80211_remain_on_channel_expired(wdev
|
||
|
, prochinfo->remain_on_ch_cookie
|
||
|
, &prochinfo->remain_on_ch_channel
|
||
|
, prochinfo->remain_on_ch_type, GFP_KERNEL);
|
||
|
|
||
|
RTW_INFO("cfg80211_remain_on_channel_expired cookie:0x%llx\n"
|
||
|
, prochinfo->remain_on_ch_cookie);
|
||
|
|
||
|
#ifdef CONFIG_BT_COEXIST
|
||
|
rtw_btcoex_ScanNotify(padapter, _FALSE);
|
||
|
#endif
|
||
|
|
||
|
exit:
|
||
|
_exit_critical_mutex(&pwdev_priv->roch_mutex, NULL);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void rtw_ro_ch_timer_process(void *FunctionContext)
|
||
|
{
|
||
|
_adapter *adapter = (_adapter *)FunctionContext;
|
||
|
|
||
|
rtw_cancel_roch_cmd(adapter, 0, NULL, 0);
|
||
|
}
|
||
|
#endif /* CONFIG_IOCTL_CFG80211 */
|
||
|
|
||
|
#if (defined(CONFIG_P2P) && defined(CONFIG_CONCURRENT_MODE)) || defined(CONFIG_IOCTL_CFG80211)
|
||
|
s32 rtw_roch_wk_hdl(_adapter *padapter, int intCmdType, u8 *buf)
|
||
|
{
|
||
|
int ret = H2C_SUCCESS;
|
||
|
|
||
|
switch (intCmdType) {
|
||
|
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
case ROCH_RO_CH_WK:
|
||
|
ret = rtw_ro_ch_handler(padapter, buf);
|
||
|
break;
|
||
|
case ROCH_CANCEL_RO_CH_WK:
|
||
|
ret = rtw_cancel_ro_ch_handler(padapter, buf);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_CONCURRENT_MODE
|
||
|
case ROCH_AP_ROCH_CH_SWITCH_PROCESS_WK:
|
||
|
rtw_concurrent_handler(padapter);
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
default:
|
||
|
rtw_warn_on(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int get_roch_parm_size(struct rtw_roch_parm *roch_parm)
|
||
|
{
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
return (roch_parm ? sizeof(*roch_parm) : 0);
|
||
|
#else
|
||
|
rtw_warn_on(roch_parm);
|
||
|
return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
u8 rtw_roch_wk_cmd(_adapter *padapter, int intCmdType, struct rtw_roch_parm *roch_parm, u8 flags)
|
||
|
{
|
||
|
struct cmd_obj *ph2c = NULL;
|
||
|
struct drvextra_cmd_parm *pdrvextra_cmd_parm = NULL;
|
||
|
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
|
||
|
struct submit_ctx sctx;
|
||
|
u8 res = _SUCCESS;
|
||
|
|
||
|
if (flags & RTW_CMDF_DIRECTLY) {
|
||
|
/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
|
||
|
if (H2C_SUCCESS != rtw_roch_wk_hdl(padapter, intCmdType, (u8 *)roch_parm))
|
||
|
res = _FAIL;
|
||
|
goto free_parm;
|
||
|
} else {
|
||
|
ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
|
||
|
if (!ph2c) {
|
||
|
res = _FAIL;
|
||
|
goto free_parm;
|
||
|
}
|
||
|
|
||
|
pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
|
||
|
if (!pdrvextra_cmd_parm) {
|
||
|
res = _FAIL;
|
||
|
goto free_parm;
|
||
|
}
|
||
|
|
||
|
pdrvextra_cmd_parm->ec_id = ROCH_WK_CID;
|
||
|
pdrvextra_cmd_parm->type = intCmdType;
|
||
|
pdrvextra_cmd_parm->size = get_roch_parm_size(roch_parm);
|
||
|
pdrvextra_cmd_parm->pbuf = (u8 *)roch_parm;
|
||
|
|
||
|
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, CMD_SET_DRV_EXTRA);
|
||
|
|
||
|
if (flags & RTW_CMDF_WAIT_ACK) {
|
||
|
ph2c->sctx = &sctx;
|
||
|
rtw_sctx_init(&sctx, 10 * 1000);
|
||
|
}
|
||
|
|
||
|
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
|
||
|
|
||
|
if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) {
|
||
|
rtw_sctx_wait(&sctx, __func__);
|
||
|
_enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
|
||
|
if (sctx.status == RTW_SCTX_SUBMITTED)
|
||
|
ph2c->sctx = NULL;
|
||
|
_exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL);
|
||
|
if (sctx.status != RTW_SCTX_DONE_SUCCESS)
|
||
|
res = _FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
|
||
|
free_parm:
|
||
|
if (roch_parm)
|
||
|
rtw_mfree((u8 *)roch_parm, get_roch_parm_size(roch_parm));
|
||
|
if (ph2c)
|
||
|
rtw_mfree((u8 *)ph2c, sizeof(*ph2c));
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_CONCURRENT_MODE
|
||
|
void rtw_ap_roch_ch_switch_timer_process(void *ctx)
|
||
|
{
|
||
|
_adapter *adapter = (_adapter *)ctx;
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
|
||
|
#endif
|
||
|
|
||
|
rtw_roch_wk_cmd(adapter, ROCH_AP_ROCH_CH_SWITCH_PROCESS_WK, NULL, 0);
|
||
|
}
|
||
|
|
||
|
static bool chk_need_stay_in_cur_chan(_adapter *padapter)
|
||
|
{
|
||
|
#ifdef CONFIG_P2P
|
||
|
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
|
||
|
|
||
|
/* When CONFIG_FULL_CH_IN_P2P_HANDSHAKE is defined and the
|
||
|
* interface is in the P2P_STATE_GONEGO_OK state, do not let the
|
||
|
* interface switch to the listen channel, because the interface will
|
||
|
* switch to the OP channel after the GO negotiation is successful.
|
||
|
*/
|
||
|
if (padapter->registrypriv.full_ch_in_p2p_handshake == 1 && rtw_p2p_chk_state(pwdinfo , P2P_STATE_GONEGO_OK)) {
|
||
|
RTW_INFO("%s, No linked interface now, but go nego ok, do not back to listen channel\n", __func__);
|
||
|
return _TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return _FALSE;
|
||
|
}
|
||
|
|
||
|
static bool chk_driver_interface(_adapter *padapter, u8 driver_interface)
|
||
|
{
|
||
|
#ifdef CONFIG_P2P
|
||
|
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
|
||
|
|
||
|
if (pwdinfo->driver_interface == driver_interface)
|
||
|
return _TRUE;
|
||
|
#elif defined(CONFIG_IOCTL_CFG80211)
|
||
|
if (driver_interface == DRIVER_CFG80211)
|
||
|
return _TRUE;
|
||
|
#endif
|
||
|
|
||
|
return _FALSE;
|
||
|
}
|
||
|
|
||
|
static u8 get_remain_ch(_adapter *padapter)
|
||
|
{
|
||
|
struct roch_info *prochinfo = &padapter->rochinfo;
|
||
|
#ifdef CONFIG_P2P
|
||
|
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
|
||
|
#endif
|
||
|
u8 remain_ch;
|
||
|
|
||
|
#ifdef CONFIG_P2P
|
||
|
remain_ch = pwdinfo->listen_channel;
|
||
|
#elif defined(CONFIG_IOCTL_CFG80211)
|
||
|
if (chk_driver_interface(padapter, DRIVER_CFG80211))
|
||
|
remain_ch = ieee80211_frequency_to_channel(prochinfo->remain_on_ch_channel.center_freq);
|
||
|
else
|
||
|
rtw_warn_on(1);
|
||
|
#endif
|
||
|
|
||
|
return remain_ch;
|
||
|
}
|
||
|
|
||
|
void rtw_concurrent_handler(_adapter *padapter)
|
||
|
{
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
|
||
|
#endif
|
||
|
struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
|
||
|
struct roch_info *prochinfo = &padapter->rochinfo;
|
||
|
#ifdef CONFIG_P2P
|
||
|
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
|
||
|
u8 val8;
|
||
|
#endif
|
||
|
u8 remain_ch = get_remain_ch(padapter);
|
||
|
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
if (chk_driver_interface(padapter, DRIVER_CFG80211)
|
||
|
&& !rtw_cfg80211_get_is_roch(padapter))
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
if (rtw_mi_check_status(padapter, MI_LINKED)) {
|
||
|
u8 union_ch = rtw_mi_get_union_chan(padapter);
|
||
|
u8 union_bw = rtw_mi_get_union_bw(padapter);
|
||
|
u8 union_offset = rtw_mi_get_union_offset(padapter);
|
||
|
unsigned int duration;
|
||
|
|
||
|
#ifdef CONFIG_P2P
|
||
|
pwdinfo->operating_channel = union_ch;
|
||
|
#endif
|
||
|
|
||
|
if (chk_driver_interface(padapter, DRIVER_CFG80211)) {
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
_enter_critical_mutex(&pwdev_priv->roch_mutex, NULL);
|
||
|
|
||
|
if (rtw_get_oper_ch(padapter) != union_ch) {
|
||
|
/* Current channel is not AP's channel - switching to AP's channel */
|
||
|
RTW_INFO("%s, switch ch back to union=%u,%u, %u\n"
|
||
|
, __func__, union_ch, union_bw, union_offset);
|
||
|
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
|
||
|
rtw_back_opch(padapter);
|
||
|
|
||
|
/* Now, the driver stays on AP's channel. We should stay on AP's
|
||
|
* channel for min_home_dur (duration) and next switch channel is
|
||
|
* listen channel.
|
||
|
*/
|
||
|
duration = prochinfo->min_home_dur;
|
||
|
} else {
|
||
|
/* Current channel is AP's channel - switching to listen channel */
|
||
|
RTW_INFO("%s, switch ch to roch=%u\n"
|
||
|
, __func__, remain_ch);
|
||
|
rtw_leave_opch(padapter);
|
||
|
set_channel_bwmode(padapter,
|
||
|
remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
|
||
|
/* Now, the driver stays on listen channel. We should stay on listen
|
||
|
* channel for max_away_dur (duration) and next switch channel is AP's
|
||
|
* channel.
|
||
|
*/
|
||
|
duration = prochinfo->max_away_dur;
|
||
|
}
|
||
|
|
||
|
/* set channel switch timer */
|
||
|
ATOMIC_SET(&pwdev_priv->switch_ch_to, 0);
|
||
|
_set_timer(&prochinfo->ap_roch_ch_switch_timer, duration);
|
||
|
RTW_INFO("%s, set switch ch timer, duration=%d\n", __func__, duration);
|
||
|
|
||
|
_exit_critical_mutex(&pwdev_priv->roch_mutex, NULL);
|
||
|
#endif
|
||
|
}
|
||
|
#ifdef CONFIG_P2P
|
||
|
else if (chk_driver_interface(padapter, DRIVER_WEXT)) {
|
||
|
if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
|
||
|
/* Now, the driver stays on the AP's channel. */
|
||
|
/* If the pwdinfo->ext_listen_period = 0, that means the P2P listen state is not available on listen channel. */
|
||
|
if (pwdinfo->ext_listen_period > 0) {
|
||
|
RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_period = %d\n", __FUNCTION__, pwdinfo->ext_listen_period);
|
||
|
|
||
|
if (union_ch != pwdinfo->listen_channel) {
|
||
|
rtw_leave_opch(padapter);
|
||
|
set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
}
|
||
|
|
||
|
rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
|
||
|
|
||
|
if (!rtw_mi_check_mlmeinfo_state(padapter, WIFI_FW_AP_STATE)) {
|
||
|
val8 = 1;
|
||
|
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
|
||
|
}
|
||
|
/* Todo: To check the value of pwdinfo->ext_listen_period is equal to 0 or not. */
|
||
|
_set_timer(&prochinfo->ap_roch_ch_switch_timer, pwdinfo->ext_listen_period);
|
||
|
}
|
||
|
|
||
|
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) ||
|
||
|
rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL) ||
|
||
|
(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _FALSE) ||
|
||
|
rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) {
|
||
|
/* Now, the driver is in the listen state of P2P mode. */
|
||
|
RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_interval = %d\n", __FUNCTION__, pwdinfo->ext_listen_interval);
|
||
|
|
||
|
/* Commented by Albert 2012/11/01 */
|
||
|
/* If the AP's channel is the same as the listen channel, we should still be in the listen state */
|
||
|
/* Other P2P device is still able to find this device out even this device is in the AP's channel. */
|
||
|
/* So, configure this device to be able to receive the probe request frame and set it to listen state. */
|
||
|
if (union_ch != pwdinfo->listen_channel) {
|
||
|
|
||
|
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
|
||
|
if (!rtw_mi_check_status(padapter, MI_AP_MODE)) {
|
||
|
val8 = 0;
|
||
|
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
|
||
|
}
|
||
|
rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE);
|
||
|
rtw_back_opch(padapter);
|
||
|
}
|
||
|
|
||
|
/* Todo: To check the value of pwdinfo->ext_listen_interval is equal to 0 or not. */
|
||
|
_set_timer(&prochinfo->ap_roch_ch_switch_timer, pwdinfo->ext_listen_interval);
|
||
|
|
||
|
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) {
|
||
|
/* The driver had finished the P2P handshake successfully. */
|
||
|
val8 = 0;
|
||
|
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
|
||
|
set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
|
||
|
rtw_back_opch(padapter);
|
||
|
|
||
|
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
|
||
|
val8 = 1;
|
||
|
set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
|
||
|
issue_probereq_p2p(padapter, NULL);
|
||
|
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
|
||
|
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _TRUE) {
|
||
|
val8 = 1;
|
||
|
set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
|
||
|
issue_probereq_p2p(padapter, NULL);
|
||
|
_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
|
||
|
} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ) && pwdinfo->invitereq_info.benable == _TRUE) {
|
||
|
/*
|
||
|
val8 = 1;
|
||
|
set_channel_bwmode(padapter, , HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
|
||
|
issue_probereq_p2p(padapter, NULL);
|
||
|
_set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT );
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
#endif /* CONFIG_P2P */
|
||
|
} else if (!chk_need_stay_in_cur_chan(padapter)) {
|
||
|
set_channel_bwmode(padapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
|
||
|
}
|
||
|
}
|
||
|
#endif /* CONFIG_CONCURRENT_MODE */
|
||
|
|
||
|
void rtw_init_roch_info(_adapter *padapter)
|
||
|
{
|
||
|
struct roch_info *prochinfo = &padapter->rochinfo;
|
||
|
|
||
|
_rtw_memset(prochinfo, 0x00, sizeof(struct roch_info));
|
||
|
|
||
|
#ifdef CONFIG_CONCURRENT_MODE
|
||
|
rtw_init_timer(&prochinfo->ap_roch_ch_switch_timer, padapter, rtw_ap_roch_ch_switch_timer_process, padapter);
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
prochinfo->min_home_dur = 1500; /* min duration for traffic, home_time */
|
||
|
prochinfo->max_away_dur = 250; /* max acceptable away duration, home_away_time */
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef CONFIG_IOCTL_CFG80211
|
||
|
rtw_init_timer(&prochinfo->remain_on_ch_timer, padapter, rtw_ro_ch_timer_process, padapter);
|
||
|
#endif
|
||
|
}
|
||
|
#endif /* (defined(CONFIG_P2P) && defined(CONFIG_CONCURRENT_MODE)) || defined(CONFIG_IOCTL_CFG80211) */
|