blob: 59182a5715a2b434b8c802d5648a9e16bafee0f7 [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_init.c#11
*/
/*! \file gl_init.c
* \brief Main routines of Linux driver
*
* This file contains the main routines of Linux driver for MediaTek Inc. 802.11
* Wireless LAN Adapters.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include "gl_os.h"
#include "debug.h"
#include "wlan_lib.h"
#include "gl_wext.h"
#include "gl_cfg80211.h"
#include "precomp.h"
#if CFG_SUPPORT_AGPS_ASSIST
#include "gl_kal.h"
#endif
#include "gl_vendor.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/* #define MAX_IOREQ_NUM 10 */
struct semaphore g_halt_sem;
int g_u4HaltFlag;
static struct wireless_dev *gprWdev;
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/* Tasklet mechanism is like buttom-half in Linux. We just want to
* send a signal to OS for interrupt defer processing. All resources
* are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty.
*/
typedef struct _WLANDEV_INFO_T {
struct net_device *prDev;
} WLANDEV_INFO_T, *P_WLANDEV_INFO_T;
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
MODULE_AUTHOR(NIC_AUTHOR);
MODULE_DESCRIPTION(NIC_DESC);
MODULE_SUPPORTED_DEVICE(NIC_NAME);
/* MODULE_LICENSE("MTK Propietary"); */
MODULE_LICENSE("Dual BSD/GPL");
#ifdef CFG_DRIVER_INF_NAME_CHANGE
char *gprifnamesta = "";
char *gprifnamep2p = "";
char *gprifnameap = "";
module_param_named(sta, gprifnamesta, charp, 0);
module_param_named(p2p, gprifnamep2p, charp, 0);
module_param_named(ap, gprifnameap, charp, 0);
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
/* NIC interface name */
#define NIC_INF_NAME "wlan%d"
#ifdef CFG_DRIVER_INF_NAME_CHANGE
/* Kernel IFNAMESIZ is 16, we use 5 in case some protocol might auto gen interface name, */
/* in that case, the interface name might have risk of over kernel's IFNAMESIZ */
#define CUSTOM_IFNAMESIZ 5
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
#if CFG_SUPPORT_SNIFFER
#define NIC_MONITOR_INF_NAME "radiotap%d"
#endif
UINT_8 aucDebugModule[DBG_MODULE_NUM];
/* 4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan device to 1 */
static WLANDEV_INFO_T arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = { {0} };
static UINT_32 u4WlanDevNum; /* How many NICs coexist now */
#if CFG_SUPPORT_CAL_RESULT_BACKUP_TO_HOST
BOOLEAN g_fgIsCalDataBackuped = FALSE;
#endif
/**20150205 added work queue for sched_scan to avoid cfg80211 stop schedule scan dead loack**/
struct delayed_work sched_workq;
#define CFG_EEPRM_FILENAME "EEPROM"
#define FILE_NAME_MAX 64
#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1)
static PUINT_8 apucEepromName[] = {
(PUINT_8) CFG_EEPRM_FILENAME "_MT",
NULL
};
#endif
int CFG80211_Suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
{
DBGLOG(INIT, INFO, "CFG80211 suspend CB\n");
return 0;
}
int CFG80211_Resume(struct wiphy *wiphy)
{
DBGLOG(INIT, INFO, "CFG80211 resume CB\n");
return 0;
}
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
#define CHAN2G(_channel, _freq, _flags) \
{ \
.band = KAL_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_channel), \
.flags = (_flags), \
.max_antenna_gain = 0, \
.max_power = 30, \
}
static struct ieee80211_channel mtk_2ghz_channels[] = {
CHAN2G(1, 2412, 0),
CHAN2G(2, 2417, 0),
CHAN2G(3, 2422, 0),
CHAN2G(4, 2427, 0),
CHAN2G(5, 2432, 0),
CHAN2G(6, 2437, 0),
CHAN2G(7, 2442, 0),
CHAN2G(8, 2447, 0),
CHAN2G(9, 2452, 0),
CHAN2G(10, 2457, 0),
CHAN2G(11, 2462, 0),
CHAN2G(12, 2467, 0),
CHAN2G(13, 2472, 0),
CHAN2G(14, 2484, 0),
};
#define CHAN5G(_channel, _flags) \
{ \
.band = KAL_BAND_5GHZ, \
.center_freq = 5000 + (5 * (_channel)), \
.hw_value = (_channel), \
.flags = (_flags), \
.max_antenna_gain = 0, \
.max_power = 30, \
}
static struct ieee80211_channel mtk_5ghz_channels[] = {
CHAN5G(36, 0), CHAN5G(40, 0),
CHAN5G(44, 0), CHAN5G(48, 0),
CHAN5G(52, 0), CHAN5G(56, 0),
CHAN5G(60, 0), CHAN5G(64, 0),
CHAN5G(100, 0), CHAN5G(104, 0),
CHAN5G(108, 0), CHAN5G(112, 0),
CHAN5G(116, 0), CHAN5G(120, 0),
CHAN5G(124, 0), CHAN5G(128, 0),
CHAN5G(132, 0), CHAN5G(136, 0),
CHAN5G(140, 0), CHAN5G(144, 0),
CHAN5G(149, 0), CHAN5G(153, 0),
CHAN5G(157, 0), CHAN5G(161, 0),
CHAN5G(165, 0),
};
#define RATETAB_ENT(_rate, _rateid, _flags) \
{ \
.bitrate = (_rate), \
.hw_value = (_rateid), \
.flags = (_flags), \
}
/* for cfg80211 - rate table */
static struct ieee80211_rate mtk_rates[] = {
RATETAB_ENT(10, 0x1000, 0),
RATETAB_ENT(20, 0x1001, 0),
RATETAB_ENT(55, 0x1002, 0),
RATETAB_ENT(110, 0x1003, 0), /* 802.11b */
RATETAB_ENT(60, 0x2000, 0),
RATETAB_ENT(90, 0x2001, 0),
RATETAB_ENT(120, 0x2002, 0),
RATETAB_ENT(180, 0x2003, 0),
RATETAB_ENT(240, 0x2004, 0),
RATETAB_ENT(360, 0x2005, 0),
RATETAB_ENT(480, 0x2006, 0),
RATETAB_ENT(540, 0x2007, 0), /* 802.11a/g */
};
#define mtk_a_rates (mtk_rates + 4)
#define mtk_a_rates_size (ARRAY_SIZE(mtk_rates) - 4)
#define mtk_g_rates (mtk_rates + 0)
#define mtk_g_rates_size (ARRAY_SIZE(mtk_rates) - 0)
#define WLAN_MCS_INFO \
{ \
.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0},\
.rx_highest = 0, \
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}
#define WLAN_VHT_MCS_INFO \
{ \
.rx_mcs_map = 0xFFFA, \
.rx_highest = cpu_to_le16(867), \
.tx_mcs_map = 0xFFFA, \
.tx_highest = cpu_to_le16(867), \
}
#define WLAN_HT_CAP \
{ \
.ht_supported = true, \
.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 \
| IEEE80211_HT_CAP_SM_PS \
| IEEE80211_HT_CAP_GRN_FLD \
| IEEE80211_HT_CAP_SGI_20 \
| IEEE80211_HT_CAP_SGI_40, \
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, \
.mcs = WLAN_MCS_INFO, \
}
#define WLAN_VHT_CAP \
{ \
.vht_supported = true, \
.cap = IEEE80211_VHT_CAP_RXLDPC \
| IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK \
| IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 \
| IEEE80211_VHT_CAP_RXLDPC \
| IEEE80211_VHT_CAP_SHORT_GI_80 \
| IEEE80211_VHT_CAP_TXSTBC \
| IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE \
| IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE, \
.vht_mcs = WLAN_VHT_MCS_INFO, \
}
/* public for both Legacy Wi-Fi / P2P access */
struct ieee80211_supported_band mtk_band_2ghz = {
.band = KAL_BAND_2GHZ,
.channels = mtk_2ghz_channels,
.n_channels = ARRAY_SIZE(mtk_2ghz_channels),
.bitrates = mtk_g_rates,
.n_bitrates = mtk_g_rates_size,
.ht_cap = WLAN_HT_CAP,
};
/* public for both Legacy Wi-Fi / P2P access */
struct ieee80211_supported_band mtk_band_5ghz = {
.band = KAL_BAND_5GHZ,
.channels = mtk_5ghz_channels,
.n_channels = ARRAY_SIZE(mtk_5ghz_channels),
.bitrates = mtk_a_rates,
.n_bitrates = mtk_a_rates_size,
.ht_cap = WLAN_HT_CAP,
.vht_cap = WLAN_VHT_CAP,
};
const UINT_32 mtk_cipher_suites[5] = {
/* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
/* keep last -- depends on hw flags! */
WLAN_CIPHER_SUITE_AES_CMAC
};
static struct cfg80211_ops mtk_wlan_ops = {
.change_virtual_intf = mtk_cfg80211_change_iface,
.add_key = mtk_cfg80211_add_key,
.get_key = mtk_cfg80211_get_key,
.del_key = mtk_cfg80211_del_key,
.set_default_key = mtk_cfg80211_set_default_key,
.get_station = mtk_cfg80211_get_station,
#if CFG_SUPPORT_TDLS
.change_station = mtk_cfg80211_change_station,
.add_station = mtk_cfg80211_add_station,
.del_station = mtk_cfg80211_del_station,
#endif
.scan = mtk_cfg80211_scan,
.connect = mtk_cfg80211_connect,
.disconnect = mtk_cfg80211_disconnect,
.join_ibss = mtk_cfg80211_join_ibss,
.leave_ibss = mtk_cfg80211_leave_ibss,
.set_power_mgmt = mtk_cfg80211_set_power_mgmt,
.set_pmksa = mtk_cfg80211_set_pmksa,
.del_pmksa = mtk_cfg80211_del_pmksa,
.flush_pmksa = mtk_cfg80211_flush_pmksa,
#if CONFIG_SUPPORT_GTK_REKEY
.set_rekey_data = mtk_cfg80211_set_rekey_data,
#endif
.suspend = mtk_cfg80211_suspend,
.resume = CFG80211_Resume,
.assoc = mtk_cfg80211_assoc,
/* Action Frame TX/RX */
.remain_on_channel = mtk_cfg80211_remain_on_channel,
.cancel_remain_on_channel = mtk_cfg80211_cancel_remain_on_channel,
.mgmt_tx = mtk_cfg80211_mgmt_tx,
/* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */
.mgmt_frame_register = mtk_cfg80211_mgmt_frame_register,
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = mtk_cfg80211_testmode_cmd,
#endif
#if 0 /* Remove schedule_scan because we need more verification for NLO */
.sched_scan_start = mtk_cfg80211_sched_scan_start,
.sched_scan_stop = mtk_cfg80211_sched_scan_stop,
#endif
#if CFG_SUPPORT_TDLS
.tdls_oper = mtk_cfg80211_tdls_oper,
.tdls_mgmt = mtk_cfg80211_tdls_mgmt,
#endif
};
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
static const struct wiphy_vendor_command mtk_wlan_vendor_ops[] = {
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_channel_list
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_country_code
}
};
static const struct nl80211_vendor_cmd_info mtk_wlan_vendor_events[] = {
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_HOTLIST_RESULTS_FOUND
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_SCAN_RESULTS_AVAILABLE
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_FULL_SCAN_RESULTS
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = RTT_EVENT_COMPLETE
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_COMPLETE_SCAN
},
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_EVENT_HOTLIST_RESULTS_LOST
},
};
#endif
/* There isn't a lot of sense in it, but you can transmit anything you like */
static const struct ieee80211_txrx_stypes
mtk_cfg80211_ais_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_ADHOC] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
},
[NL80211_IFTYPE_STATION] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
[NL80211_IFTYPE_AP] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4)
},
[NL80211_IFTYPE_AP_VLAN] = {
/* copy AP */
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4)
},
[NL80211_IFTYPE_P2P_CLIENT] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
},
[NL80211_IFTYPE_P2P_GO] = {
.tx = 0xffff,
.rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4)
}
};
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support mtk_wlan_wowlan_support = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY,
};
#endif
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
#if 0
/*----------------------------------------------------------------------------*/
/*!
* \brief Override the implementation of select queue
*
* \param[in] dev Pointer to struct net_device
* \param[in] skb Pointer to struct skb_buff
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
unsigned int _cfg80211_classify8021d(struct sk_buff *skb)
{
unsigned int dscp = 0;
/* skb->priority values from 256->263 are magic values
* directly indicate a specific 802.1d priority. This is
* to allow 802.1d priority to be passed directly in from
* tags
*/
if (skb->priority >= 256 && skb->priority <= 263)
return skb->priority - 256;
switch (skb->protocol) {
case htons(ETH_P_IP):
dscp = ip_hdr(skb)->tos & 0xfc;
break;
}
return dscp >> 5;
}
#endif
#if KERNEL_VERSION(3, 14, 0) <= LINUX_VERSION_CODE
u16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb,
void *accel_priv, select_queue_fallback_t fallback)
{
return mtk_wlan_ndev_select_queue(skb);
}
#elif KERNEL_VERSION(3, 13, 0) <= LINUX_VERSION_CODE
u16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb,
void *accel_priv)
{
return mtk_wlan_ndev_select_queue(skb);
}
#else
u16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb)
{
return mtk_wlan_ndev_select_queue(skb);
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Load NVRAM data and translate it into REG_INFO_T
*
* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T
* \param[out] prRegInfo Pointer to struct REG_INFO_T
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void glLoadNvram(IN P_GLUE_INFO_T prGlueInfo, OUT P_REG_INFO_T prRegInfo)
{
UINT_32 i, j;
UINT_8 aucTmp[2];
PUINT_8 pucDest;
ASSERT(prGlueInfo);
ASSERT(prRegInfo);
if ((!prGlueInfo) || (!prRegInfo))
return;
if (kalCfgDataRead16(prGlueInfo, sizeof(WIFI_CFG_PARAM_STRUCT) - sizeof(UINT_16), (PUINT_16) aucTmp) == TRUE) {
prGlueInfo->fgNvramAvailable = TRUE;
/* load MAC Address */
for (i = 0; i < PARAM_MAC_ADDR_LEN; i += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i,
(PUINT_16) (((PUINT_8) prRegInfo->aucMacAddr) + i));
}
/* load country code */
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucCountryCode[0]), (PUINT_16) aucTmp);
/* cast to wide characters */
prRegInfo->au2CountryCode[0] = (UINT_16) aucTmp[0];
prRegInfo->au2CountryCode[1] = (UINT_16) aucTmp[1];
/* load default normal TX power */
for (i = 0; i < sizeof(TX_PWR_PARAM_T); i += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rTxPwr) + i,
(PUINT_16) (((PUINT_8) &(prRegInfo->rTxPwr)) + i));
}
/* load feature flags */
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucTxPwrValid), (PUINT_16) aucTmp);
prRegInfo->ucTxPwrValid = aucTmp[0];
prRegInfo->ucSupport5GBand = aucTmp[1];
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2G4BwFixed20M), (PUINT_16) aucTmp);
prRegInfo->uc2G4BwFixed20M = aucTmp[0];
prRegInfo->uc5GBwFixed20M = aucTmp[1];
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucEnable5GBand), (PUINT_16) aucTmp);
prRegInfo->ucEnable5GBand = aucTmp[0];
prRegInfo->ucRxDiversity = aucTmp[1];
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fgRssiCompensationVaildbit), (PUINT_16) aucTmp);
prRegInfo->ucRssiPathCompasationUsed = aucTmp[0];
prRegInfo->ucGpsDesense = aucTmp[1];
#if CFG_SUPPORT_NVRAM_5G
/* load EFUSE overriding part */
for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, EfuseMapping) + i,
(PUINT_16) (((PUINT_8) &(prRegInfo->aucEFUSE)) + i));
}
prRegInfo->prOldEfuseMapping = (P_NEW_EFUSE_MAPPING2NVRAM_T)&prRegInfo->aucEFUSE;
#else
/* load EFUSE overriding part */
for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) + i,
(PUINT_16) (((PUINT_8) &(prRegInfo->aucEFUSE)) + i));
}
#endif
/* load band edge tx power control */
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fg2G4BandEdgePwrUsed), (PUINT_16) aucTmp);
prRegInfo->fg2G4BandEdgePwrUsed = (BOOLEAN) aucTmp[0];
if (aucTmp[0]) {
prRegInfo->cBandEdgeMaxPwrCCK = (INT_8) aucTmp[1];
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, cBandEdgeMaxPwrOFDM20), (PUINT_16) aucTmp);
prRegInfo->cBandEdgeMaxPwrOFDM20 = (INT_8) aucTmp[0];
prRegInfo->cBandEdgeMaxPwrOFDM40 = (INT_8) aucTmp[1];
}
/* load regulation subbands */
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucRegChannelListMap), (PUINT_16) aucTmp);
prRegInfo->eRegChannelListMap = (ENUM_REG_CH_MAP_T) aucTmp[0];
prRegInfo->ucRegChannelListIndex = aucTmp[1];
if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) {
for (i = 0; i < MAX_SUBBAND_NUM; i++) {
pucDest = (PUINT_8) &prRegInfo->rDomainInfo.rSubBand[i];
for (j = 0; j < 6; j += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo)
+ (i * 6 + j), (PUINT_16) aucTmp);
*pucDest++ = aucTmp[0];
*pucDest++ = aucTmp[1];
}
}
}
/* load rssiPathCompensation */
for (i = 0; i < sizeof(RSSI_PATH_COMPASATION_T); i += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT,
rRssiPathCompensation) + i,
(PUINT_16) (((PUINT_8) &(prRegInfo->rRssiPathCompasation))
+ i));
}
#if 1
/* load full NVRAM */
for (i = 0; i < sizeof(WIFI_CFG_PARAM_STRUCT); i += sizeof(UINT_16)) {
kalCfgDataRead16(prGlueInfo,
OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion) + i,
(PUINT_16) (((PUINT_8) &(prRegInfo->aucNvram)) + i));
}
prRegInfo->prNvramSettings = (P_WIFI_CFG_PARAM_STRUCT)&prRegInfo->aucNvram;
#endif
} else {
DBGLOG(INIT, INFO, "glLoadNvram fail\n");
prGlueInfo->fgNvramAvailable = FALSE;
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Release prDev from wlandev_array and free tasklet object related to it.
*
* \param[in] prDev Pointer to struct net_device
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanClearDevIdx(struct net_device *prDev)
{
int i;
ASSERT(prDev);
for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) {
if (arWlanDevInfo[i].prDev == prDev) {
arWlanDevInfo[i].prDev = NULL;
u4WlanDevNum--;
}
}
} /* end of wlanClearDevIdx() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Allocate an unique interface index, net_device::ifindex member for this
* wlan device. Store the net_device in wlandev_array, and initialize
* tasklet object related to it.
*
* \param[in] prDev Pointer to struct net_device
*
* \retval >= 0 The device number.
* \retval -1 Fail to get index.
*/
/*----------------------------------------------------------------------------*/
static int wlanGetDevIdx(struct net_device *prDev)
{
int i;
ASSERT(prDev);
for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) {
if (arWlanDevInfo[i].prDev == (struct net_device *)NULL) {
/* Reserve 2 bytes space to store one digit of
* device number and NULL terminator.
*/
arWlanDevInfo[i].prDev = prDev;
u4WlanDevNum++;
return i;
}
}
return -1;
} /* end of wlanGetDevIdx() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, a primary SOCKET interface to configure
* the interface lively. Handle an ioctl call on one of our devices.
* Everything Linux ioctl specific is done here. Then we pass the contents
* of the ifr->data to the request message handler.
*
* \param[in] prDev Linux kernel netdevice
*
* \param[in] prIFReq Our private ioctl request structure, typed for the generic
* struct ifreq so we can use ptr to function
*
* \param[in] cmd Command ID
*
* \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully.
* \retval OTHER The execution of IOCTL command is failed.
*/
/*----------------------------------------------------------------------------*/
int wlanDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd)
{
P_GLUE_INFO_T prGlueInfo = NULL;
int ret = 0;
/* Verify input parameters for the following functions */
ASSERT(prDev && prIfReq);
if (!prDev || !prIfReq) {
DBGLOG(INIT, ERROR, "Invalid input data\n");
return -EINVAL;
}
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
if (!prGlueInfo) {
DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n");
return -EFAULT;
}
if (prGlueInfo->u4ReadyFlag == 0) {
DBGLOG(INIT, ERROR, "Adapter is not ready\n");
return -EINVAL;
}
if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) {
/* 0x8B00 ~ 0x8BDF, wireless extension region */
ret = wext_support_ioctl(prDev, prIfReq, i4Cmd);
} else if ((i4Cmd >= SIOCIWFIRSTPRIV) && (i4Cmd < SIOCIWLASTPRIV)) {
/* 0x8BE0 ~ 0x8BFF, private ioctl region */
ret = priv_support_ioctl(prDev, prIfReq, i4Cmd);
} else if (i4Cmd == SIOCDEVPRIVATE + 1) {
#ifdef CFG_ANDROID_AOSP_PRIV_CMD
ret = android_private_support_driver_cmd(prDev, prIfReq, i4Cmd);
#else
ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd);
#endif /* CFG_ANDROID_AOSP_PRIV_CMD */
} else {
DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n", i4Cmd);
ret = -EOPNOTSUPP;
}
return ret;
} /* end of wlanDoIOCTL() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Export wlan GLUE_INFO_T pointer to p2p module
*
* \param[in] prGlueInfo Pointer to struct GLUE_INFO_T
*
* \return TRUE: get GlueInfo pointer successfully
* FALSE: wlan is not started yet
*/
/*---------------------------------------------------------------------------*/
P_GLUE_INFO_T wlanGetGlueInfo(VOID)
{
struct net_device *prDev = NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
if (u4WlanDevNum == 0)
return NULL;
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
if (prDev == NULL)
return NULL;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
return prGlueInfo;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is to set multicast list and set rx mode.
*
* \param[in] prDev Pointer to struct net_device
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static struct delayed_work workq;
struct net_device *gPrDev;
static void wlanSetMulticastList(struct net_device *prDev)
{
/* Allow to receive all multicast for WOW */
DBGLOG(INIT, INFO, "wlanSetMulticastList\n");
prDev->flags |= (IFF_MULTICAST | IFF_ALLMULTI);
gPrDev = prDev;
schedule_delayed_work(&workq, 0);
}
/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange
* another workqueue for sleeping. We don't want to block
* main_thread, so we can't let tx_thread to do this
*/
static void wlanSetMulticastListWorkQueue(struct work_struct *work)
{
P_GLUE_INFO_T prGlueInfo = NULL;
UINT_32 u4PacketFilter = 0;
UINT_32 u4SetInfoLen;
struct net_device *prDev = gPrDev;
down(&g_halt_sem);
if (g_u4HaltFlag) {
up(&g_halt_sem);
return;
}
prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL;
ASSERT(prDev);
ASSERT(prGlueInfo);
if (!prDev || !prGlueInfo) {
DBGLOG(INIT, WARN, "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo);
up(&g_halt_sem);
return;
}
DBGLOG(INIT, INFO, "wlanSetMulticastListWorkQueue prDev->flags:0x%x\n", prDev->flags);
if (prDev->flags & IFF_PROMISC)
u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS;
if (prDev->flags & IFF_BROADCAST)
u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST;
if (prDev->flags & IFF_MULTICAST) {
if ((prDev->flags & IFF_ALLMULTI) || (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR))
u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST;
else
u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST;
}
up(&g_halt_sem);
if (kalIoctl(prGlueInfo,
wlanoidSetCurrentPacketFilter,
&u4PacketFilter,
sizeof(u4PacketFilter), FALSE, FALSE, TRUE, &u4SetInfoLen) != WLAN_STATUS_SUCCESS) {
return;
}
if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) {
/* Prepare multicast address list */
struct netdev_hw_addr *ha;
PUINT_8 prMCAddrList = NULL;
UINT_32 i = 0;
down(&g_halt_sem);
if (g_u4HaltFlag) {
up(&g_halt_sem);
return;
}
prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN, VIR_MEM_TYPE);
netdev_for_each_mc_addr(ha, prDev) {
if (i < MAX_NUM_GROUP_ADDR) {
kalMemCopy((prMCAddrList + i * ETH_ALEN), GET_ADDR(ha), ETH_ALEN);
i++;
}
}
up(&g_halt_sem);
kalIoctl(prGlueInfo,
wlanoidSetMulticastList, prMCAddrList, (i * ETH_ALEN), FALSE, FALSE, TRUE, &u4SetInfoLen);
kalMemFree(prMCAddrList, VIR_MEM_TYPE, MAX_NUM_GROUP_ADDR * ETH_ALEN);
}
} /* end of wlanSetMulticastList() */
/*----------------------------------------------------------------------------*/
/*!
* \brief To indicate scheduled scan has been stopped
*
* \param[in]
* prGlueInfo
*
* \return
* None
*/
/*----------------------------------------------------------------------------*/
VOID wlanSchedScanStoppedWorkQueue(struct work_struct *work)
{
P_GLUE_INFO_T prGlueInfo = NULL;
struct net_device *prDev = gPrDev;
DBGLOG(SCN, INFO, "wlanSchedScanStoppedWorkQueue\n");
prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL;
if (!prGlueInfo) {
DBGLOG(SCN, INFO, "prGlueInfo == NULL unexpected\n");
return;
}
/* 2. indication to cfg80211 */
/* 20150205 change cfg80211_sched_scan_stopped to work queue due to sched_scan_mtx dead lock issue */
#if KERNEL_VERSION(4, 14, 0) <= CFG80211_VERSION_CODE
/*We not support sched scan on 7668, so just change reqid to 0*/
cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo), 0);
#else
cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo));
#endif
DBGLOG(SCN, INFO,
"cfg80211_sched_scan_stopped event send done WorkQueue thread return from wlanSchedScanStoppedWorkQueue\n");
return;
}
/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange
* another workqueue for sleeping. We don't want to block
* main_thread, so we can't let tx_thread to do this
*/
void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo)
{
ASSERT(prGlueInfo);
if (!prGlueInfo) {
DBGLOG(INIT, WARN, "abnormal dev or skb: prGlueInfo(0x%p)\n", prGlueInfo);
return;
}
#if CFG_ENABLE_WIFI_DIRECT
if (prGlueInfo->prAdapter->fgIsP2PRegistered)
mtk_p2p_wext_set_Multicastlist(prGlueInfo);
#endif
} /* end of p2pSetMulticastListWorkQueueWrapper() */
/*----------------------------------------------------------------------------*/
/*
* \brief This function is TX entry point of NET DEVICE.
*
* \param[in] prSkb Pointer of the sk_buff to be sent
* \param[in] prDev Pointer to struct net_device
*
* \retval NETDEV_TX_OK - on success.
* \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer.
*/
/*----------------------------------------------------------------------------*/
int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev)
{
P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) NULL;
P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
UINT_8 ucBssIndex;
ASSERT(prSkb);
ASSERT(prDev);
ASSERT(prGlueInfo);
prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(prDev);
ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo);
ucBssIndex = prNetDevPrivate->ucBssIdx;
#if CFG_SUPPORT_PASSPOINT
if (prGlueInfo->fgIsDad) {
/* kalPrint("[Passpoint R2] Due to ipv4_dad...TX is forbidden\n"); */
dev_kfree_skb(prSkb);
return NETDEV_TX_OK;
}
if (prGlueInfo->fgIs6Dad) {
/* kalPrint("[Passpoint R2] Due to ipv6_dad...TX is forbidden\n"); */
dev_kfree_skb(prSkb);
return NETDEV_TX_OK;
}
#endif /* CFG_SUPPORT_PASSPOINT */
kalResetPacket(prGlueInfo, (P_NATIVE_PACKET) prSkb);
if (kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex) == WLAN_STATUS_SUCCESS) {
/* Successfully enqueue to Tx queue */
/* Successfully enqueue to Tx queue */
}
/* For Linux, we'll always return OK FLAG, because we'll free this skb by ourself */
return NETDEV_TX_OK;
} /* end of wlanHardStartXmit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, to get the network interface statistical
* information.
*
* Whenever an application needs to get statistics for the interface, this method
* is called. This happens, for example, when ifconfig or netstat -i is run.
*
* \param[in] prDev Pointer to struct net_device.
*
* \return net_device_stats buffer pointer.
*/
/*----------------------------------------------------------------------------*/
struct net_device_stats *wlanGetStats(IN struct net_device *prDev)
{
return (struct net_device_stats *)kalGetStats(prDev);
} /* end of wlanGetStats() */
VOID wlanDebugInit(VOID)
{
UINT_8 i;
/* Set the initial debug level of each module */
#if DBG
for (i = 0; i < DBG_MODULE_NUM; i++)
aucDebugModule[i] = DBG_CLASS_MASK; /* enable all */
#else
#ifdef CFG_DEFAULT_DBG_LEVEL
for (i = 0; i < DBG_MODULE_NUM; i++)
aucDebugModule[i] = CFG_DEFAULT_DBG_LEVEL;
#else
for (i = 0; i < DBG_MODULE_NUM; i++) {
aucDebugModule[i] = DBG_CLASS_ERROR |
DBG_CLASS_WARN | DBG_CLASS_STATE | DBG_CLASS_EVENT | DBG_CLASS_INFO;
}
aucDebugModule[DBG_TX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_INFO);
aucDebugModule[DBG_RX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_INFO);
aucDebugModule[DBG_REQ_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_INFO);
aucDebugModule[DBG_INTR_IDX] = 0;
aucDebugModule[DBG_MEM_IDX] = DBG_CLASS_ERROR | DBG_CLASS_WARN;
aucDebugModule[DBG_REQ_IDX] = DBG_CLASS_MASK;
#endif
#endif /* DBG */
DBGLOG(INIT, INFO, "Reset ALL DBG module log level to DEFAULT!\n");
}
WLAN_STATUS wlanSetDebugLevel(IN UINT_32 u4DbgIdx, IN UINT_32 u4DbgMask)
{
UINT_32 u4Idx;
WLAN_STATUS fgStatus = WLAN_STATUS_SUCCESS;
if (u4DbgIdx == DBG_ALL_MODULE_IDX) {
for (u4Idx = 0; u4Idx < DBG_MODULE_NUM; u4Idx++)
aucDebugModule[u4Idx] = (UINT_8) u4DbgMask;
DBGLOG(INIT, INFO, "Set ALL DBG module log level to [0x%02x]\n", u4DbgMask);
} else if (u4DbgIdx < DBG_MODULE_NUM) {
aucDebugModule[u4DbgIdx] = (UINT_8) u4DbgMask;
DBGLOG(INIT, INFO, "Set DBG module[%u] log level to [0x%02x]\n", u4DbgIdx, u4DbgMask);
} else {
fgStatus = WLAN_STATUS_FAILURE;
}
return fgStatus;
}
WLAN_STATUS wlanGetDebugLevel(IN UINT_32 u4DbgIdx, OUT PUINT_32 pu4DbgMask)
{
if (u4DbgIdx < DBG_MODULE_NUM) {
*pu4DbgMask = aucDebugModule[u4DbgIdx];
return WLAN_STATUS_SUCCESS;
}
return WLAN_STATUS_FAILURE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->init
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanInit succeeds.
* \retval -ENXIO No such device.
*/
/*----------------------------------------------------------------------------*/
static int wlanInit(struct net_device *prDev)
{
P_GLUE_INFO_T prGlueInfo = NULL;
if (!prDev)
return -ENXIO;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
INIT_DELAYED_WORK(&workq, wlanSetMulticastListWorkQueue);
/* 20150205 work queue for sched_scan */
INIT_DELAYED_WORK(&sched_workq, wlanSchedScanStoppedWorkQueue);
/* 20161024 init wow port setting */
#if CFG_WOW_SUPPORT
kalWowInit(prGlueInfo);
#endif
return 0; /* success */
} /* end of wlanInit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->uninit
*
* \param[in] prDev Pointer to struct net_device.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void wlanUninit(struct net_device *prDev)
{
P_GLUE_INFO_T prGlueInfo = NULL;
if (!prDev)
return;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
#if CFG_WOW_SUPPORT
kalWowUninit(prGlueInfo);
#endif
} /* end of wlanUninit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->open
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanOpen succeeds.
* \retval < 0 The execution of wlanOpen failed.
*/
/*----------------------------------------------------------------------------*/
static int wlanOpen(struct net_device *prDev)
{
ASSERT(prDev);
netif_tx_start_all_queues(prDev);
return 0; /* success */
} /* end of wlanOpen() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->stop
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanStop succeeds.
* \retval < 0 The execution of wlanStop failed.
*/
/*----------------------------------------------------------------------------*/
static int wlanStop(struct net_device *prDev)
{
P_GLUE_INFO_T prGlueInfo = NULL;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(prDev);
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
/* CFG80211 down */
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (prGlueInfo->prScanRequest != NULL) {
kalCfg80211ScanDone(prGlueInfo->prScanRequest, TRUE);
prGlueInfo->prScanRequest = NULL;
}
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
#if CFG_AUTO_CHANNEL_SEL_SUPPORT
/* zero clear old acs information */
kalMemZero(&(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo),
sizeof(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo));
#endif
netif_tx_stop_all_queues(prDev);
return 0; /* success */
} /* end of wlanStop() */
#if CFG_SUPPORT_SNIFFER
static int wlanMonOpen(struct net_device *prDev)
{
ASSERT(prDev);
netif_tx_start_all_queues(prDev);
return 0; /* success */
}
static int wlanMonStop(struct net_device *prDev)
{
ASSERT(prDev);
netif_tx_stop_all_queues(prDev);
return 0; /* success */
}
static const struct net_device_ops wlan_mon_netdev_ops = {
.ndo_open = wlanMonOpen,
.ndo_stop = wlanMonStop,
};
void wlanMonWorkHandler(struct work_struct *work)
{
P_GLUE_INFO_T prGlueInfo;
prGlueInfo = container_of(work, GLUE_INFO_T, monWork);
if (prGlueInfo->fgIsEnableMon) {
if (prGlueInfo->prMonDevHandler)
return;
#if KERNEL_VERSION(3, 17, 0) <= CFG80211_VERSION_CODE
prGlueInfo->prMonDevHandler =
alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), NIC_MONITOR_INF_NAME,
NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM);
#else
prGlueInfo->prMonDevHandler =
alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), NIC_MONITOR_INF_NAME,
ether_setup, CFG_MAX_TXQ_NUM);
#endif
if (prGlueInfo->prMonDevHandler == NULL) {
DBGLOG(INIT, ERROR, "wlanMonWorkHandler: Allocated prMonDevHandler context FAIL.\n");
return;
}
((P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(prGlueInfo->prMonDevHandler))->prGlueInfo = prGlueInfo;
prGlueInfo->prMonDevHandler->type = ARPHRD_IEEE80211_RADIOTAP;
prGlueInfo->prMonDevHandler->netdev_ops = &wlan_mon_netdev_ops;
netif_carrier_off(prGlueInfo->prMonDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prMonDevHandler);
kalResetStats(prGlueInfo->prMonDevHandler);
if (register_netdev(prGlueInfo->prMonDevHandler) < 0) {
DBGLOG(INIT, ERROR, "wlanMonWorkHandler: Registered prMonDevHandler context FAIL.\n");
free_netdev(prGlueInfo->prMonDevHandler);
prGlueInfo->prMonDevHandler = NULL;
}
DBGLOG(INIT, INFO, "wlanMonWorkHandler: Registered prMonDevHandler context DONE.\n");
} else {
if (prGlueInfo->prMonDevHandler) {
unregister_netdev(prGlueInfo->prMonDevHandler);
prGlueInfo->prMonDevHandler = NULL;
DBGLOG(INIT, INFO, "wlanMonWorkHandler: unRegistered prMonDevHandler context DONE.\n");
}
}
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief Update Channel table for cfg80211 for Wi-Fi Direct based on current country code
*
* \param[in] prGlueInfo Pointer to glue info
*
* \return none
*/
/*----------------------------------------------------------------------------*/
VOID wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo)
{
UINT_8 i, j;
UINT_8 ucNumOfChannel;
RF_CHANNEL_INFO_T aucChannelList[ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels)];
/* 1. Disable all channels */
for (i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) {
mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED;
mtk_2ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED;
}
for (i = 0; i < ARRAY_SIZE(mtk_5ghz_channels); i++) {
mtk_5ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED;
mtk_5ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED;
}
/* 2. Get current domain channel list */
rlmDomainGetChnlList(prGlueInfo->prAdapter,
BAND_NULL, FALSE,
ARRAY_SIZE(mtk_2ghz_channels) + ARRAY_SIZE(mtk_5ghz_channels),
&ucNumOfChannel, aucChannelList);
/* 3. Enable specific channel based on domain channel list */
for (i = 0; i < ucNumOfChannel; i++) {
switch (aucChannelList[i].eBand) {
case BAND_2G4:
for (j = 0; j < ARRAY_SIZE(mtk_2ghz_channels); j++) {
if (mtk_2ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) {
mtk_2ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED;
mtk_2ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED;
break;
}
}
break;
case BAND_5G:
for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) {
if (mtk_5ghz_channels[j].hw_value == aucChannelList[i].ucChannelNum) {
mtk_5ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED;
mtk_5ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED;
break;
}
}
break;
default:
DBGLOG(INIT, WARN, "Unknown band %d\n", aucChannelList[i].eBand);
break;
}
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Register the device to the kernel and return the index.
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanNetRegister succeeds.
* \retval < 0 The execution of wlanNetRegister failed.
*/
/*----------------------------------------------------------------------------*/
static INT_32 wlanNetRegister(struct wireless_dev *prWdev)
{
P_GLUE_INFO_T prGlueInfo;
INT_32 i4DevIdx = -1;
P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) NULL;
P_ADAPTER_T prAdapter = NULL;
ASSERT(prWdev);
do {
if (!prWdev)
break;
prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy);
prAdapter = prGlueInfo->prAdapter;
i4DevIdx = wlanGetDevIdx(prWdev->netdev);
if (i4DevIdx < 0) {
DBGLOG(INIT, ERROR, "net_device number exceeds!\n");
break;
}
if (prAdapter && prAdapter->rWifiVar.ucWow)
kalInitDevWakeup(prGlueInfo->prAdapter, wiphy_dev(prWdev->wiphy));
if (register_netdev(prWdev->netdev) < 0) {
DBGLOG(INIT, ERROR, "Register net_device failed\n");
wlanClearDevIdx(prWdev->netdev);
i4DevIdx = -1;
}
#if 1
prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(prGlueInfo->prDevHandler);
ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo);
prNetDevPrivate->ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
wlanBindBssIdxToNetInterface(prGlueInfo,
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, (PVOID) prWdev->netdev);
#else
wlanBindBssIdxToNetInterface(prGlueInfo,
prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, (PVOID) prWdev->netdev);
/* wlanBindNetInterface(prGlueInfo, NET_DEV_WLAN_IDX, (PVOID)prWdev->netdev); */
#endif
if (i4DevIdx != -1)
prGlueInfo->fgIsRegistered = TRUE;
} while (FALSE);
return i4DevIdx; /* success */
} /* end of wlanNetRegister() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Unregister the device from the kernel
*
* \param[in] prWdev Pointer to struct net_device.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static VOID wlanNetUnregister(struct wireless_dev *prWdev)
{
P_GLUE_INFO_T prGlueInfo;
if (!prWdev) {
DBGLOG(INIT, ERROR, "wlanNetUnregister: The device context is NULL\n");
return;
}
prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy);
wlanClearDevIdx(prWdev->netdev);
unregister_netdev(prWdev->netdev);
prGlueInfo->fgIsRegistered = FALSE;
#if CFG_SUPPORT_SNIFFER
if (prGlueInfo->prMonDevHandler) {
unregister_netdev(prGlueInfo->prMonDevHandler);
prGlueInfo->prMonDevHandler = NULL;
}
prGlueInfo->fgIsEnableMon = FALSE;
#endif
} /* end of wlanNetUnregister() */
static const struct net_device_ops wlan_netdev_ops = {
.ndo_open = wlanOpen,
.ndo_stop = wlanStop,
.ndo_set_rx_mode = wlanSetMulticastList,
.ndo_get_stats = wlanGetStats,
.ndo_do_ioctl = wlanDoIOCTL,
.ndo_start_xmit = wlanHardStartXmit,
.ndo_init = wlanInit,
.ndo_uninit = wlanUninit,
.ndo_select_queue = wlanSelectQueue,
};
static void wlanCreateWirelessDevice(void)
{
struct wiphy *prWiphy = NULL;
struct wireless_dev *prWdev = NULL;
/* 4 <1.1> Create wireless_dev */
prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!prWdev) {
DBGLOG(INIT, ERROR, "Allocating memory to wireless_dev context failed\n");
return;
}
/* 4 <1.2> Create wiphy */
prWiphy = wiphy_new(&mtk_wlan_ops, sizeof(GLUE_INFO_T));
if (!prWiphy) {
DBGLOG(INIT, ERROR, "Allocating memory to wiphy device failed\n");
goto free_wdev;
}
/* 4 <1.3> configure wireless_dev & wiphy */
prWdev->iftype = NL80211_IFTYPE_STATION;
prWiphy->iface_combinations = p_mtk_iface_combinations_sta;
prWiphy->n_iface_combinations = mtk_iface_combinations_sta_num;
prWiphy->max_scan_ssids = CFG_SCAN_SSID_MAX_NUM;
prWiphy->max_scan_ie_len = 512;
prWiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
prWiphy->bands[KAL_BAND_2GHZ] = &mtk_band_2ghz;
/* always assign 5Ghz bands here, if the chip is not support 5Ghz,
* bands[KAL_BAND_5GHZ] will be assign to NULL
*/
prWiphy->bands[KAL_BAND_5GHZ] = &mtk_band_5ghz;
prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
prWiphy->cipher_suites = (const u32 *)mtk_cipher_suites;
prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites);
/* CFG80211_VERSION_CODE >= 3.3 */
prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
/* CFG80211_VERSION_CODE >= 3.2 */
#if (CFG_SUPPORT_ROAMING == 1)
prWiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
#endif /* CFG_SUPPORT_ROAMING */
#if KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE
prWiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
#else
prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG;
#if (CFG_SUPPORT_DFS_MASTER == 1)
prWiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
#endif /* CFG_SUPPORT_DFS_MASTER */
#endif
cfg80211_regd_set_wiphy(prWiphy);
#if (CFG_SUPPORT_TDLS == 1)
TDLSEX_WIPHY_FLAGS_INIT(prWiphy->flags);
#endif /* CFG_SUPPORT_TDLS */
prWiphy->max_remain_on_channel_duration = 5000;
prWiphy->mgmt_stypes = mtk_cfg80211_ais_default_mgmt_stypes;
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
prWiphy->vendor_commands = mtk_wlan_vendor_ops;
prWiphy->n_vendor_commands = sizeof(mtk_wlan_vendor_ops) / sizeof(struct wiphy_vendor_command);
prWiphy->vendor_events = mtk_wlan_vendor_events;
prWiphy->n_vendor_events = ARRAY_SIZE(mtk_wlan_vendor_events);
#endif
/* 4 <1.4> wowlan support */
#ifdef CONFIG_PM
#if KERNEL_VERSION(3, 11, 0) <= CFG80211_VERSION_CODE
prWiphy->wowlan = &mtk_wlan_wowlan_support;
#else
kalMemCopy(&prWiphy->wowlan, &mtk_wlan_wowlan_support, sizeof(struct wiphy_wowlan_support));
#endif
#endif
#ifdef CONFIG_CFG80211_WEXT
/* 4 <1.5> Use wireless extension to replace IOCTL */
prWiphy->wext = &wext_handler_def;
#endif
if (wiphy_register(prWiphy) < 0) {
DBGLOG(INIT, ERROR, "wiphy_register error\n");
goto free_wiphy;
}
prWdev->wiphy = prWiphy;
gprWdev = prWdev;
DBGLOG(INIT, INFO, "create wireless device success\n");
return;
free_wiphy:
wiphy_free(prWiphy);
free_wdev:
kfree(prWdev);
}
static void wlanDestroyWirelessDevice(void)
{
/* Move set_wiphy_dev(wiphy, NULL) in wlanNetDestroy */
wiphy_unregister(gprWdev->wiphy);
wiphy_free(gprWdev->wiphy);
kfree(gprWdev);
gprWdev = NULL;
}
VOID wlanWakeLockInit(P_GLUE_INFO_T prGlueInfo)
{
#ifdef CONFIG_ANDROID
KAL_WAKE_LOCK_INIT(NULL, &prGlueInfo->rIntrWakeLock, "WLAN interrupt");
KAL_WAKE_LOCK_INIT(NULL, &prGlueInfo->rTimeoutWakeLock, "WLAN timeout");
#endif
}
VOID wlanWakeLockUninit(P_GLUE_INFO_T prGlueInfo)
{
#if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK)
if (KAL_WAKE_LOCK_ACTIVE(NULL, &prGlueInfo->rIntrWakeLock))
KAL_WAKE_UNLOCK(NULL, &prGlueInfo->rIntrWakeLock);
KAL_WAKE_LOCK_DESTROY(NULL, &prGlueInfo->rIntrWakeLock);
if (KAL_WAKE_LOCK_ACTIVE(NULL, &prGlueInfo->rTimeoutWakeLock))
KAL_WAKE_UNLOCK(NULL, &prGlueInfo->rTimeoutWakeLock);
KAL_WAKE_LOCK_DESTROY(NULL, &prGlueInfo->rTimeoutWakeLock);
#endif
}
/*----------------------------------------------------------------------------*/
/*!
* \brief A method for creating Linux NET4 struct net_device object and the
* private data(prGlueInfo and prAdapter). Setup the IO address to the HIF.
* Assign the function pointer to the net_device object
*
* \param[in] pvData Memory address for the device
*
* \retval Not null The wireless_dev object.
* \retval NULL Fail to create wireless_dev object
*/
/*----------------------------------------------------------------------------*/
static struct lock_class_key rSpinKey[SPIN_LOCK_NUM];
static struct wireless_dev *wlanNetCreate(PVOID pvData, PVOID pvDriverData)
{
struct wireless_dev *prWdev = gprWdev;
P_GLUE_INFO_T prGlueInfo = NULL;
P_ADAPTER_T prAdapter = NULL;
UINT_32 i;
struct device *prDev;
P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) NULL;
PUCHAR prInfName = NULL;
if (prWdev == NULL) {
DBGLOG(INIT, ERROR, "No wireless dev exist, abort power on\n");
return NULL;
}
/* 4 <1.3> co-relate wiphy & prDev */
glGetDev(pvData, &prDev);
if (!prDev)
DBGLOG(INIT, ERROR, "unable to get struct dev for wlan\n");
set_wiphy_dev(prWdev->wiphy, prDev);
/* 4 <2> Create Glue structure */
prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy);
kalMemZero(prGlueInfo, sizeof(GLUE_INFO_T));
/* 4 <2.1> Create Adapter structure */
prAdapter = (P_ADAPTER_T) wlanAdapterCreate(prGlueInfo);
if (!prAdapter) {
DBGLOG(INIT, ERROR, "Allocating memory to adapter failed\n");
goto netcreate_err;
}
prAdapter->chip_info = ((struct mt66xx_hif_driver_data *) pvDriverData)->chip_info;
prGlueInfo->prAdapter = prAdapter;
/* 4 <3> Initialize Glue structure */
/* 4 <3.1> Create net device */
#ifdef CFG_DRIVER_INF_NAME_CHANGE
if (kalStrLen(gprifnamesta) > 0) {
prInfName = kalStrCat(gprifnamesta, "%d");
DBGLOG(INIT, WARN, "Station ifname customized, use %s\n", prInfName);
} else
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
prInfName = NIC_INF_NAME;
#if KERNEL_VERSION(3, 17, 0) <= CFG80211_VERSION_CODE
prGlueInfo->prDevHandler =
alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), prInfName,
NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM);
#else
prGlueInfo->prDevHandler =
alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), prInfName,
ether_setup, CFG_MAX_TXQ_NUM);
#endif
DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated\n", prGlueInfo->prDevHandler);
if (!prGlueInfo->prDevHandler) {
DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n");
goto netcreate_err;
}
DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated\n", prGlueInfo->prDevHandler);
/* 4 <3.1.1> Initialize net device varaiables */
#if 1
prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(prGlueInfo->prDevHandler);
prNetDevPrivate->prGlueInfo = prGlueInfo;
#else
*((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prDevHandler)) = prGlueInfo;
#endif
prGlueInfo->prDevHandler->needed_headroom += NIC_TX_HEAD_ROOM;
prGlueInfo->prDevHandler->netdev_ops = &wlan_netdev_ops;
#ifdef CONFIG_WIRELESS_EXT
prGlueInfo->prDevHandler->wireless_handlers = &wext_handler_def;
#endif
netif_carrier_off(prGlueInfo->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prDevHandler);
kalResetStats(prGlueInfo->prDevHandler);
#if CFG_SUPPORT_SNIFFER
INIT_WORK(&(prGlueInfo->monWork), wlanMonWorkHandler);
#endif
/* 4 <3.1.2> co-relate with wiphy bi-directionally */
prGlueInfo->prDevHandler->ieee80211_ptr = prWdev;
prWdev->netdev = prGlueInfo->prDevHandler;
/* 4 <3.1.3> co-relate net device & prDev */
SET_NETDEV_DEV(prGlueInfo->prDevHandler, wiphy_dev(prWdev->wiphy));
/* 4 <3.1.4> set device to glue */
prGlueInfo->prDev = prDev;
/* 4 <3.2> Initialize glue variables */
prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED;
prGlueInfo->ePowerState = ParamDeviceStateD0;
prGlueInfo->fgIsRegistered = FALSE;
prGlueInfo->prScanRequest = NULL;
prGlueInfo->prSchedScanRequest = NULL;
#if CFG_SUPPORT_PASSPOINT
/* Init DAD */
prGlueInfo->fgIsDad = FALSE;
prGlueInfo->fgIs6Dad = FALSE;
kalMemZero(prGlueInfo->aucDADipv4, 4);
kalMemZero(prGlueInfo->aucDADipv6, 16);
#endif /* CFG_SUPPORT_PASSPOINT */
init_completion(&prGlueInfo->rScanComp);
init_completion(&prGlueInfo->rHaltComp);
init_completion(&prGlueInfo->rPendComp);
#if CFG_SUPPORT_MULTITHREAD
init_completion(&prGlueInfo->rHifHaltComp);
init_completion(&prGlueInfo->rRxHaltComp);
#endif
/* initialize timer for OID timeout checker */
kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler);
for (i = 0; i < SPIN_LOCK_NUM; i++) {
spin_lock_init(&prGlueInfo->rSpinLock[i]);
lockdep_set_class(&prGlueInfo->rSpinLock[i], &rSpinKey[i]);
}
for (i = 0; i < MUTEX_NUM; i++)
mutex_init(&prGlueInfo->arMutex[i]);
/* initialize semaphore for ioctl */
sema_init(&prGlueInfo->ioctl_sem, 1);
#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN
/* initialize SDIO read-write pattern control */
prGlueInfo->fgEnSdioTestPattern = FALSE;
prGlueInfo->fgIsSdioTestInitialized = FALSE;
#endif
/* initialize semaphore for halt control */
sema_init(&g_halt_sem, 1);
/* 4 <8> Init Queues */
init_waitqueue_head(&prGlueInfo->waitq);
QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue);
prGlueInfo->i4TxPendingCmdNum = 0;
QUEUE_INITIALIZE(&prGlueInfo->rTxQueue);
glSetHifInfo(prGlueInfo, (ULONG) pvData);
/* Init wakelock */
wlanWakeLockInit(prGlueInfo);
/* main thread is created in this function */
#if CFG_SUPPORT_MULTITHREAD
init_waitqueue_head(&prGlueInfo->waitq_rx);
init_waitqueue_head(&prGlueInfo->waitq_hif);
prGlueInfo->u4TxThreadPid = 0xffffffff;
prGlueInfo->u4RxThreadPid = 0xffffffff;
prGlueInfo->u4HifThreadPid = 0xffffffff;
#endif
/* init CSI wait queue */
init_waitqueue_head(&(prGlueInfo->prAdapter->rCsiData.waitq));
#ifdef CFG_USE_LINUX_GPIO_GLUE
prGlueInfo->prGpioGlueInfo = wlanPlatformCfgGet();
#endif
return prWdev;
netcreate_err:
if (prAdapter != NULL) {
wlanAdapterDestroy(prAdapter);
prAdapter = NULL;
}
if (prGlueInfo->prDevHandler != NULL) {
free_netdev(prGlueInfo->prDevHandler);
prGlueInfo->prDevHandler = NULL;
}
return prWdev;
} /* end of wlanNetCreate() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Destroying the struct net_device object and the private data.
*
* \param[in] prWdev Pointer to struct wireless_dev.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static VOID wlanNetDestroy(struct wireless_dev *prWdev)
{
P_GLUE_INFO_T prGlueInfo = NULL;
ASSERT(prWdev);
if (!prWdev) {
DBGLOG(INIT, ERROR, "The device context is NULL\n");
return;
}
/* prGlueInfo is allocated with net_device */
prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy);
ASSERT(prGlueInfo);
/* prWdev: base AIS dev
* Becase the interface dev (ex: usb_device) would be free
* after un-plug event. Should set the wiphy->dev->parent which
* pointer to the interface dev to NULL. Otherwise, the corresponding
* system operation (poweroff, suspend) might reference it.
* set_wiphy_dev(wiphy, NULL): set the wiphy->dev->parent = NULL
* The trunk-ce1 does this, but the trunk seems not.
* ce1 do set_wiphy_dev(prWdev->wiphy, prDev) in wlanNetCreate.
* But that is after wiphy_register, and will cause exception in
* wiphy_unregister(), if do not set_wiphy_dev(wiphy, NULL).
*/
set_wiphy_dev(prWdev->wiphy, NULL);
/* destroy kal OS timer */
kalCancelTimer(prGlueInfo);
glClearHifInfo(prGlueInfo);
wlanAdapterDestroy(prGlueInfo->prAdapter);
prGlueInfo->prAdapter = NULL;
/* Free net_device and private data, which are allocated by alloc_netdev().
*/
free_netdev(prWdev->netdev);
} /* end of wlanNetDestroy() */
VOID wlanSetSuspendMode(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgEnable)
{
struct net_device *prDev = NULL;
if (!prGlueInfo)
return;
prDev = prGlueInfo->prDevHandler;
if (!prDev)
return;
kalSetNetAddressFromInterface(prGlueInfo, prDev, fgEnable);
wlanNotifyFwSuspend(prGlueInfo, prDev, fgEnable);
}
#if CFG_ENABLE_EARLY_SUSPEND
static struct early_suspend wlan_early_suspend_desc = {
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
};
static void wlan_early_suspend(struct early_suspend *h)
{
struct net_device *prDev = NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
/* 4 <1> Sanity Check */
if ((u4WlanDevNum == 0) && (u4WlanDevNum > CFG_MAX_WLAN_DEVICES)) {
DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n");
return;
}
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
if (!prDev)
return;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
if (!prGlueInfo)
return;
DBGLOG(INIT, INFO, "********<%s>********\n", __func__);
if (prGlueInfo->fgIsInSuspendMode == TRUE) {
DBGLOG(INIT, INFO, "%s: Already in suspend mode, SKIP!\n", __func__);
return;
}
prGlueInfo->fgIsInSuspendMode = TRUE;
wlanSetSuspendMode(prGlueInfo, TRUE);
p2pSetSuspendMode(prGlueInfo, TRUE);
}
static void wlan_late_resume(struct early_suspend *h)
{
struct net_device *prDev = NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
/* 4 <1> Sanity Check */
if ((u4WlanDevNum == 0) && (u4WlanDevNum > CFG_MAX_WLAN_DEVICES)) {
DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n");
return;
}
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
if (!prDev)
return;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
if (!prGlueInfo)
return;
DBGLOG(INIT, INFO, "********<%s>********\n", __func__);
if (prGlueInfo->fgIsInSuspendMode == FALSE) {
DBGLOG(INIT, INFO, "%s: Not in suspend mode, SKIP!\n", __func__);
return;
}
prGlueInfo->fgIsInSuspendMode = FALSE;
/* 4 <2> Set suspend mode for each network */
wlanSetSuspendMode(prGlueInfo, FALSE);
p2pSetSuspendMode(prGlueInfo, FALSE);
}
#endif
#if ((MTK_WCN_HIF_SDIO && CFG_SUPPORT_MTK_ANDROID_KK) || WLAN_INCLUDE_PROC)
int set_p2p_mode_handler(struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode)
{
P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(netdev));
PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P;
WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
rSetP2P.u4Enable = p2pmode.u4Enable;
rSetP2P.u4Mode = p2pmode.u4Mode;
if ((!rSetP2P.u4Enable) && (kalIsResetting() == FALSE))
p2pNetUnregister(prGlueInfo, FALSE);
rWlanStatus = kalIoctl(prGlueInfo,
wlanoidSetP2pMode,
(PVOID) &rSetP2P, sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), FALSE, FALSE, TRUE, &u4BufLen);
DBGLOG(INIT, INFO, "set_p2p_mode_handler ret = 0x%08lx\n", (UINT_32) rWlanStatus);
/* Need to check fgIsP2PRegistered, in case of whole chip reset.
* in this case, kalIOCTL return success always,
* and prGlueInfo->prP2PInfo[0] may be NULL
*/
if ((rSetP2P.u4Enable) && (prGlueInfo->prAdapter->fgIsP2PRegistered) && (kalIsResetting() == FALSE))
p2pNetRegister(prGlueInfo, FALSE);
return 0;
}
#endif
#if CFG_SUPPORT_EASY_DEBUG
/*----------------------------------------------------------------------------*/
/*!
* \brief parse config from wifi.cfg
*
* \param[in] prAdapter
*
* \retval VOID
*/
/*----------------------------------------------------------------------------*/
VOID wlanGetParseConfig(P_ADAPTER_T prAdapter)
{
PUINT_8 pucConfigBuf;
UINT_32 u4ConfigReadLen;
wlanCfgInit(prAdapter, NULL, 0, 0);
pucConfigBuf = (PUINT_8) kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE);
kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE);
u4ConfigReadLen = 0;
if (pucConfigBuf) {
#if defined(_HIF_USB)
if (kalRequestFirmware("wifi_usb.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen,
prAdapter->prGlueInfo->prDev) == 0) {
} else
#endif
if (kalRequestFirmware("wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen, prAdapter->prGlueInfo->prDev) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/storage/sdcard0/wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/data/misc/wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/data/misc/wifi/wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
}
if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0)
wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigReadLen, TRUE);
kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE);
} /* pucConfigBuf */
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief get config from wifi.cfg
*
* \param[in] prAdapter
*
* \retval VOID
*/
/*----------------------------------------------------------------------------*/
VOID wlanGetConfig(P_ADAPTER_T prAdapter)
{
PUINT_8 pucConfigBuf;
UINT_32 u4ConfigReadLen;
wlanCfgInit(prAdapter, NULL, 0, 0);
pucConfigBuf = (PUINT_8) kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE);
kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE);
u4ConfigReadLen = 0;
if (pucConfigBuf) {
if (kalRequestFirmware("wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen, prAdapter->prGlueInfo->prDev) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/storage/sdcard0/wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/data/misc/wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
} else if (kalReadToFile("/data/misc/wifi/wifi.cfg", pucConfigBuf,
WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen) == 0) {
/* ToDo:: Nothing */
}
if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0)
wlanCfgInit(prAdapter, pucConfigBuf, u4ConfigReadLen, 0);
kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE);
} /* pucConfigBuf */
}
/*----------------------------------------------------------------------------*/
/*!
* \brief this extract buffer bin EEPROB_MTxxxx.bin to temp buffer
*
* \param[in] prAdapter
*
* \retval WLAN_STATUS_SUCCESS Success
* \retval WLAN_STATUS_FAILURE Failed
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanExtractBufferBin(P_ADAPTER_T prAdapter)
{
P_GLUE_INFO_T prGlueInfo = NULL;
UINT_32 u4ContentLen;
PUINT_8 pucConfigBuf = NULL;
struct mt66xx_chip_info *prChipInfo;
UINT_32 chip_id;
UINT_8 aucEeprom[32];
WLAN_STATUS retWlanStat = WLAN_STATUS_FAILURE;
if (prAdapter->fgIsSupportPowerOnSendBufferModeCMD == TRUE) {
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step0\n");
DBGLOG(INIT, INFO, "ucEfuseBUfferModeCal is %x\n", prAdapter->rWifiVar.ucEfuseBufferModeCal);
prChipInfo = prAdapter->chip_info;
chip_id = prChipInfo->chip_id;
prGlueInfo = prAdapter->prGlueInfo;
if (prGlueInfo == NULL || prGlueInfo->prDev == NULL)
goto label_exit;
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step1\n");
/* allocate memory for buffer mode info */
if ((prAdapter->rWifiVar.ucEfuseBufferModeCal == TRUE) &&
(prAdapter->fgIsBufferBinExtract == FALSE)) {
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step2\n");
/* Only in buffer mode need to access bin file */
/* 1 <1> Load bin file*/
pucConfigBuf = (PUINT_8) kalMemAlloc(MAX_EEPROM_BUFFER_SIZE, VIR_MEM_TYPE);
if (pucConfigBuf == NULL)
goto label_exit;
kalMemZero(pucConfigBuf, MAX_EEPROM_BUFFER_SIZE);
/* 1 <2> Construct EEPROM binary name */
kalMemZero(aucEeprom, sizeof(aucEeprom));
snprintf(aucEeprom, 32, "%s%x.bin",
apucEepromName[0], chip_id);
/* 1 <3> Request buffer bin */
if (kalRequestFirmware(aucEeprom,
pucConfigBuf, MAX_EEPROM_BUFFER_SIZE, &u4ContentLen, prGlueInfo->prDev) == 0) {
DBGLOG(INIT, INFO, "request file done\n");
} else {
DBGLOG(INIT, INFO, "can't find file\n");
kalMemFree(pucConfigBuf, VIR_MEM_TYPE, MAX_EEPROM_BUFFER_SIZE);
goto label_exit;
}
/* Update contents in local table */
kalMemCopy(uacEEPROMImage, pucConfigBuf, MAX_EEPROM_BUFFER_SIZE);
/* Free buffer */
kalMemFree(pucConfigBuf, VIR_MEM_TYPE, MAX_EEPROM_BUFFER_SIZE);
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step3\n");
prAdapter->fgIsBufferBinExtract = TRUE;
}
}
retWlanStat = WLAN_STATUS_SUCCESS;
label_exit:
return retWlanStat;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief this function send buffer bin EEPROB_MTxxxx.bin to FW.
*
* \param[in] prAdapter
*
* \retval WLAN_STATUS_SUCCESS Success
* \retval WLAN_STATUS_FAILURE Failed
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanDownloadBufferBin(P_ADAPTER_T prAdapter)
{
P_GLUE_INFO_T prGlueInfo = NULL;
#if (CFG_FW_Report_Efuse_Address)
UINT_16 u2InitAddr = prAdapter->u4EfuseStartAddress;
#else
UINT_16 u2InitAddr = EFUSE_CONTENT_BUFFER_START;
#endif
UINT_32 u4BufLen = 0;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *prSetEfuseBufModeInfo = NULL;
UINT_32 u4ContentLen;
struct mt66xx_chip_info *prChipInfo;
UINT_32 chip_id;
WLAN_STATUS retWlanStat = WLAN_STATUS_FAILURE;
INT_32 i4OidTimeout = -1;
#if 0
UINT_8 aucBinMacAddr[MAC_ADDR_LEN];
UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR;
#endif
if (prAdapter->fgIsSupportPowerOnSendBufferModeCMD == TRUE) {
DBGLOG(INIT, INFO, "Start Efuse Buffer Mode ..\n");
DBGLOG(INIT, INFO, "ucEfuseBUfferModeCal is %x\n", prAdapter->rWifiVar.ucEfuseBufferModeCal);
prChipInfo = prAdapter->chip_info;
chip_id = prChipInfo->chip_id;
prGlueInfo = prAdapter->prGlueInfo;
if (prGlueInfo == NULL || prGlueInfo->prDev == NULL)
goto label_exit;
/* allocate memory for buffer mode info */
prSetEfuseBufModeInfo = (PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *)
kalMemAlloc(sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), VIR_MEM_TYPE);
if (prSetEfuseBufModeInfo == NULL)
goto label_exit;
kalMemZero(prSetEfuseBufModeInfo, sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T));
if (prAdapter->rWifiVar.ucEfuseBufferModeCal == TRUE) {
/* Buffer mode */
/* Only in buffer mode need to access bin file */
if (wlanExtractBufferBin(prAdapter) != WLAN_STATUS_SUCCESS)
goto label_exit;
/* copy to the command buffer */
#if (CFG_FW_Report_Efuse_Address)
u4ContentLen = (prAdapter->u4EfuseEndAddress)-(prAdapter->u4EfuseStartAddress)+1;
#else
u4ContentLen = EFUSE_CONTENT_BUFFER_SIZE;
#endif
if (u4ContentLen > MAX_EEPROM_BUFFER_SIZE)
goto label_exit;
kalMemCopy(prSetEfuseBufModeInfo->aBinContent, &uacEEPROMImage[u2InitAddr], u4ContentLen);
prSetEfuseBufModeInfo->ucSourceMode = 1;
} else {
/* eFuse mode */
/* Only need to tell FW the content from, contents are directly from efuse */
prSetEfuseBufModeInfo->ucSourceMode = 0;
}
prSetEfuseBufModeInfo->ucCmdType = 0x1 | (prAdapter->rWifiVar.ucCalTimingCtrl << 4);
prSetEfuseBufModeInfo->ucCount = 0xFF; /* ucCmdType 1 don't care the ucCount */
if (!prAdapter->rWifiVar.ucCalTimingCtrl) {
/* Full channel RF-cal mode. Need 6000ms */
i4OidTimeout = 6000;
}
rStatus = kalIoctlTimeout(prGlueInfo,
wlanoidSetEfusBufferMode,
(PVOID)prSetEfuseBufModeInfo,
sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T),
FALSE, TRUE, TRUE,
i4OidTimeout,
&u4BufLen);
}
retWlanStat = WLAN_STATUS_SUCCESS;
label_exit:
/* free memory */
if (prSetEfuseBufModeInfo != NULL)
kalMemFree(prSetEfuseBufModeInfo, VIR_MEM_TYPE, sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T));
return retWlanStat;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Wlan probe function. This function probes and initializes the device.
*
* \param[in] pvData data passed by bus driver init function
* _HIF_EHPI: NULL
* _HIF_SDIO: sdio bus driver handle
*
* \retval 0 Success
* \retval negative value Failed
*/
/*----------------------------------------------------------------------------*/
static INT_32 wlanProbe(PVOID pvData, PVOID pvDriverData)
{
struct wireless_dev *prWdev = NULL;
P_WLANDEV_INFO_T prWlandevInfo = NULL;
INT_32 i4DevIdx = 0;
P_GLUE_INFO_T prGlueInfo = NULL;
P_ADAPTER_T prAdapter = NULL;
INT_32 i4Status = 0;
BOOL bRet = FALSE;
P_REG_INFO_T prRegInfo;
UINT_8 i = 0;
#if (MTK_WCN_HIF_SDIO && CFG_WMT_WIFI_PATH_SUPPORT)
INT_32 i4RetVal = 0;
#endif
#if CFG_SUPPORT_REPLAY_DETECTION
UINT_8 ucRpyDetectOffload;
#endif
#if 0
PUINT_8 pucConfigBuf = NULL, pucCfgBuf = NULL;
UINT_32 u4ConfigReadLen = 0;
#endif
do {
/* 4 <1> Initialize the IO port of the interface */
/* GeorgeKuo: pData has different meaning for _HIF_XXX:
* _HIF_EHPI: pointer to memory base variable, which will be
* initialized by glBusInit().
* _HIF_SDIO: bus driver handle
*/
DBGLOG(INIT, INFO, "enter wlanProbe\n");
bRet = glBusInit(pvData);
/* Cannot get IO address from interface */
if (bRet == FALSE) {
DBGLOG(INIT, ERROR, "wlanProbe: glBusInit() fail\n");
i4Status = -EIO;
break;
}
/* 4 <2> Create network device, Adapter, KalInfo, prDevHandler(netdev) */
prWdev = wlanNetCreate(pvData, pvDriverData);
if (prWdev == NULL) {
DBGLOG(INIT, ERROR, "wlanProbe: No memory for dev and its private\n");
i4Status = -ENOMEM;
break;
}
/* 4 <2.5> Set the ioaddr to HIF Info */
prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(prWdev->wiphy);
if (prGlueInfo == NULL) {
DBGLOG(INIT, ERROR, "wlanProbe: get wiphy_priv() fail\n");
return -1;
}
gPrDev = prGlueInfo->prDevHandler;
/* 4 <4> Setup IRQ */
prWlandevInfo = &arWlanDevInfo[i4DevIdx];
i4Status = glBusSetIrq(prWdev->netdev, NULL, prGlueInfo);
if (i4Status != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "wlanProbe: Set IRQ error\n");
break;
}
prGlueInfo->i4DevIdx = i4DevIdx;
prAdapter = prGlueInfo->prAdapter;
prGlueInfo->u4ReadyFlag = 0;
#if CFG_TCP_IP_CHKSUM_OFFLOAD
prAdapter->fgIsSupportCsumOffload = FALSE;
prAdapter->u4CSUMFlags = CSUM_OFFLOAD_EN_ALL;
#endif
#if CFG_SUPPORT_CFG_FILE
wlanGetConfig(prAdapter);
#endif
/* Default support 2.4/5G MIMO */
prAdapter->rWifiFemCfg.u2WifiPath =
(WLAN_FLAG_2G4_WF0 | WLAN_FLAG_5G_WF0 | WLAN_FLAG_2G4_WF1 | WLAN_FLAG_5G_WF1);
DBGLOG(INIT, INFO, "WifiPath Init=0x%x\n", prAdapter->rWifiFemCfg.u2WifiPath);
#if (MTK_WCN_HIF_SDIO && CFG_WMT_WIFI_PATH_SUPPORT)
i4RetVal = mtk_wcn_wmt_wifi_fem_cfg_report((PVOID)&prAdapter->rWifiFemCfg);
if (i4RetVal)
DBGLOG(INIT, WARN, "Get WifiPath from WMT drv FAIL\n");
else
DBGLOG(INIT, INFO, "Get WifiPath from WMT drv Success WifiPath=0x%x\n",
prAdapter->rWifiFemCfg.u2WifiPath);
#endif
/* 4 <5> Start Device */
prRegInfo = &prGlueInfo->rRegInfo;
/* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */
kalMemSet(prRegInfo, 0, sizeof(REG_INFO_T));
/* Trigger the action of switching Pwr state to drv_own */
prAdapter->fgIsFwOwn = TRUE;
nicpmWakeUpWiFi(prAdapter);
/* Load NVRAM content to REG_INFO_T */
glLoadNvram(prGlueInfo, prRegInfo);
/* kalMemCopy(&prGlueInfo->rRegInfo, prRegInfo, sizeof(REG_INFO_T)); */
prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF;
#if 0
prRegInfo->fgEnArpFilter = TRUE;
#endif
/* The Init value of u4WpaVersion/u4AuthAlg shall be DISABLE/OPEN, not zero! */
/* The Init value of u4CipherGroup/u4CipherPairwise shall be NONE, not zero! */
prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE;
prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
tasklet_init(&prGlueInfo->rRxTask, halRxTasklet, (unsigned long)prGlueInfo);
tasklet_init(&prGlueInfo->rTxCompleteTask, halTxCompleteTasklet, (unsigned long)prGlueInfo);
if (wlanAdapterStart(prAdapter, prRegInfo) != WLAN_STATUS_SUCCESS)
i4Status = -EIO;
if (i4Status < 0)
break;
if (HAL_IS_TX_DIRECT(prAdapter)) {
if (!prAdapter->fgTxDirectInited) {
skb_queue_head_init(&prAdapter->rTxDirectSkbQueue);
init_timer(&prAdapter->rTxDirectSkbTimer);
prAdapter->rTxDirectSkbTimer.data = (unsigned long)prGlueInfo;
prAdapter->rTxDirectSkbTimer.function = nicTxDirectTimerCheckSkbQ;
init_timer(&prAdapter->rTxDirectHifTimer);
prAdapter->rTxDirectHifTimer.data = (unsigned long)prGlueInfo;
prAdapter->rTxDirectHifTimer.function = nicTxDirectTimerCheckHifQ;
prAdapter->fgTxDirectInited = TRUE;
}
}
/* kfree(prRegInfo); */
INIT_WORK(&prGlueInfo->rTxMsduFreeWork, kalFreeTxMsduWorker);
INIT_DELAYED_WORK(&prGlueInfo->rRxPktDeAggWork, halDeAggRxPktWorker);
prGlueInfo->main_thread = kthread_run(main_thread, prGlueInfo->prDevHandler, "main_thread");
#if CFG_SUPPORT_MULTITHREAD
prGlueInfo->hif_thread = kthread_run(hif_thread, prGlueInfo->prDevHandler, "hif_thread");
prGlueInfo->rx_thread = kthread_run(rx_thread, prGlueInfo->prDevHandler, "rx_thread");
#endif
/* TODO the change schedule API shall be provided by OS glue layer */
/* Switch the Wi-Fi task priority to higher priority and change the scheduling method */
#if KERNEL_VERSION(4, 14, 0) > CFG80211_VERSION_CODE
if (prGlueInfo->prAdapter->rWifiVar.ucThreadPriority > 0) {
struct sched_param param = {.sched_priority = prGlueInfo->prAdapter->rWifiVar.ucThreadPriority
};
sched_setscheduler(prGlueInfo->main_thread,
prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling, &param);
#if CFG_SUPPORT_MULTITHREAD
sched_setscheduler(prGlueInfo->hif_thread,
prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling, &param);
sched_setscheduler(prGlueInfo->rx_thread,
prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling, &param);
#endif
DBGLOG(INIT, INFO,
"Set pri = %d, sched = %d\n",
prGlueInfo->prAdapter->rWifiVar.ucThreadPriority,
prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling);
}
#endif
g_u4HaltFlag = 0;
#if CFG_SUPPORT_BUFFER_MODE
#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1)
if (wlanDownloadBufferBin(prAdapter) != WLAN_STATUS_SUCCESS)
return -1;
#endif
#endif
#if CFG_SUPPORT_DBDC
/* Buffer mode delay cal will init dbdc as disable. So that,
* we should setup dbdc after buffer mode process.
*/
/* Update DBDC default setting */
cnmInitDbdcSetting(prAdapter);
#endif /*CFG_SUPPORT_DBDC*/
/* send regulatory information to firmware */
rlmDomainSendInfoToFirmware(prAdapter);
/* set MAC address */
if (prAdapter && prAdapter->rWifiVar.aucMacAddress) {
kalMemCopy(prGlueInfo->prDevHandler->dev_addr,
prAdapter->rWifiVar.aucMacAddress, ETH_ALEN);
kalMemCopy(prGlueInfo->prDevHandler->perm_addr,
prGlueInfo->prDevHandler->dev_addr, ETH_ALEN);
#if CFG_SHOW_MACADDR_SOURCE
DBGLOG(INIT, ERROR, "MAC address: " MACSTR,
MAC2STR(prAdapter->rWifiVar.aucMacAddress));
#endif
} else
prGlueInfo->u4ReadyFlag = 0;
#if CFG_TCP_IP_CHKSUM_OFFLOAD
/* set HW checksum offload */
if (prAdapter->fgIsSupportCsumOffload) {
WLAN_STATUS rStatus = WLAN_STATUS_FAILURE;
UINT_32 u4CSUMFlags = CSUM_OFFLOAD_EN_ALL;
UINT_32 u4SetInfoLen = 0;
rStatus = kalIoctl(prGlueInfo,
wlanoidSetCSUMOffload,
(PVOID) &u4CSUMFlags, sizeof(UINT_32), FALSE, FALSE, TRUE, &u4SetInfoLen);
if (rStatus == WLAN_STATUS_SUCCESS) {
prGlueInfo->prDevHandler->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM;
} else {
DBGLOG(INIT, WARN, "set HW checksum offload fail 0x%lx\n", rStatus);
prAdapter->fgIsSupportCsumOffload = FALSE;
}
}
#endif
/* 4 <3> Register the card */
i4DevIdx = wlanNetRegister(prWdev);
if (i4DevIdx < 0) {
i4Status = -ENXIO;
DBGLOG(INIT, ERROR, "wlanProbe: Cannot register the net_device context to the kernel\n");
break;
}
/* 4 <4> Register early suspend callback */
#if CFG_ENABLE_EARLY_SUSPEND
glRegisterEarlySuspend(&wlan_early_suspend_desc, wlan_early_suspend, wlan_late_resume);
#endif
/* 4 <5> Register Notifier callback */
wlanRegisterNotifier();
/* 4 <6> Initialize /proc filesystem */
#ifdef WLAN_INCLUDE_PROC
i4Status = procCreateFsEntry(prGlueInfo);
if (i4Status < 0) {
DBGLOG(INIT, ERROR, "wlanProbe: init procfs failed\n");
break;
}
#endif /* WLAN_INCLUDE_PROC */
#if CFG_MET_PACKET_TRACE_SUPPORT
kalMetInit(prGlueInfo);
#endif
#if CFG_ENABLE_BT_OVER_WIFI
prGlueInfo->rBowInfo.fgIsNetRegistered = FALSE;
prGlueInfo->rBowInfo.fgIsRegistered = FALSE;
glRegisterAmpc(prGlueInfo);
#endif
#if (CFG_ENABLE_WIFI_DIRECT && MTK_WCN_HIF_SDIO && CFG_SUPPORT_MTK_ANDROID_KK)
register_set_p2p_mode_handler(set_p2p_mode_handler);
#elif (CFG_ENABLE_WIFI_DIRECT)
if (prAdapter->rWifiVar.u4RegP2pIfAtProbe) {
PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P;
rSetP2P.u4Enable = 1;
#ifdef CFG_DRIVER_INITIAL_RUNNING_MODE
rSetP2P.u4Mode = CFG_DRIVER_INITIAL_RUNNING_MODE;
#else
rSetP2P.u4Mode = RUNNING_P2P_MODE;
#endif /* CFG_DRIVER_RUNNING_MODE */
if (set_p2p_mode_handler(prWdev->netdev, rSetP2P) == 0)
DBGLOG(INIT, INFO, "%s: p2p device registered\n", __func__);
else
DBGLOG(INIT, ERROR, "%s: Failed to register p2p device\n", __func__);
}
#endif
} while (FALSE);
/* Configure 5G band for registered wiphy */
if (prAdapter->fgEnable5GBand)
prWdev->wiphy->bands[KAL_BAND_5GHZ] = &mtk_band_5ghz;
else
prWdev->wiphy->bands[KAL_BAND_5GHZ] = NULL;
for (i = 0 ; i < KAL_P2P_NUM; i++) {
if (gprP2pRoleWdev[i] == NULL)
continue;
if (prAdapter->fgEnable5GBand)
gprP2pRoleWdev[i]->wiphy->bands[KAL_BAND_5GHZ] =
&mtk_band_5ghz;
else
gprP2pRoleWdev[i]->wiphy->bands[KAL_BAND_5GHZ] = NULL;
}
if (i4Status == 0) {
#if CFG_SUPPORT_AGPS_ASSIST
kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_ON, NULL, 0);
#endif
#if CFG_SUPPORT_EASY_DEBUG
#if 0
wlanGetParseConfig(prGlueInfo->prAdapter);
/*wlanGetParseConfig would reparsing the config file,
*and then, sent to firmware
*use wlanFeatureToFw to take it(won't be reparsing)
*/
#endif
/* move before reading file
*wlanLoadDefaultCustomerSetting(prAdapter);
*/
wlanFeatureToFw(prGlueInfo->prAdapter);
#endif
wlanCfgSetSwCtrl(prGlueInfo->prAdapter);
wlanCfgSetChip(prGlueInfo->prAdapter);
wlanCfgSetCountryCode(prGlueInfo->prAdapter);
#if CFG_SUPPORT_ANT_SELECT
/* update some info needed before connected */
wlanUpdateExtInfo(prGlueInfo->prAdapter);
#endif
#if (CFG_MET_PACKET_TRACE_SUPPORT == 1)
DBGLOG(INIT, TRACE, "init MET procfs...\n");
i4Status = kalMetInitProcfs(prGlueInfo);
if (i4Status < 0)
DBGLOG(INIT, ERROR, "wlanProbe: init MET procfs failed\n");
#endif
#if CFG_MET_TAG_SUPPORT
if (met_tag_init() != 0)
DBGLOG(INIT, ERROR, "MET_TAG_INIT error!\n");
#endif
#if CFG_SUPPORT_CAL_RESULT_BACKUP_TO_HOST
/* Calibration Backup Flow */
if (!g_fgIsCalDataBackuped) {
if (rlmTriggerCalBackup(prGlueInfo->prAdapter, g_fgIsCalDataBackuped) == WLAN_STATUS_FAILURE) {
DBGLOG(RFTEST, INFO, "Error : Boot Time Wi-Fi Enable Fail........\n");
return -1;
}
g_fgIsCalDataBackuped = TRUE;
} else {
if (rlmTriggerCalBackup(prGlueInfo->prAdapter, g_fgIsCalDataBackuped) == WLAN_STATUS_FAILURE) {
DBGLOG(RFTEST, INFO, "Error : Normal Wi-Fi Enable Fail........\n");
return -1;
}
}
#endif
/* card is ready */
prGlueInfo->u4ReadyFlag = 1;
#if CFG_SUPPORT_REPLAY_DETECTION
ucRpyDetectOffload = prAdapter->rWifiVar.ucRpyDetectOffload;
if (ucRpyDetectOffload == FEATURE_ENABLED) {
DBGLOG(INIT, INFO, "Send CMD to enable Replay Detection offload feature\n");
wlanSuspendRekeyOffload(prAdapter->prGlueInfo,
GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON);
} else {
DBGLOG(INIT, INFO, "Send CMD to disable Replay Detection offload feature\n");
wlanSuspendRekeyOffload(prAdapter->prGlueInfo,
GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF);
}
#endif
DBGLOG(INIT, LOUD, "wlanProbe: probe success\n");
} else {
if (prGlueInfo == NULL)
return -1;
glBusFreeIrq(prGlueInfo->prDevHandler, prGlueInfo);
DBGLOG(INIT, LOUD, "wlanProbe: probe failed\n");
}
return i4Status;
} /* end of wlanProbe() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method to stop driver operation and release all resources. Following
* this call, no frame should go up or down through this interface.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static VOID wlanRemove(VOID)
{
struct net_device *prDev = NULL;
P_WLANDEV_INFO_T prWlandevInfo = NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
P_ADAPTER_T prAdapter = NULL;
BOOLEAN fgResult = FALSE;
DBGLOG(INIT, INFO, "Remove wlan!\n");
/* 4 <0> Sanity check */
ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES);
if (u4WlanDevNum == 0) {
DBGLOG(INIT, INFO, "0 == u4WlanDevNum\n");
return;
}
#if (CFG_ENABLE_WIFI_DIRECT && MTK_WCN_HIF_SDIO && CFG_SUPPORT_MTK_ANDROID_KK)
register_set_p2p_mode_handler(NULL);
#endif
if (u4WlanDevNum > 0 && u4WlanDevNum <= CFG_MAX_WLAN_DEVICES) {
prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev;
prWlandevInfo = &arWlanDevInfo[u4WlanDevNum - 1];
}
ASSERT(prDev);
if (prDev == NULL) {
DBGLOG(INIT, INFO, "NULL == prDev\n");
return;
}
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
ASSERT(prGlueInfo);
if (prGlueInfo == NULL) {
DBGLOG(INIT, INFO, "NULL == prGlueInfo\n");
free_netdev(prDev);
return;
}
prAdapter = prGlueInfo->prAdapter;
prGlueInfo->u4ReadyFlag = 0;
#if CFG_ENABLE_BT_OVER_WIFI
if (prGlueInfo->rBowInfo.fgIsNetRegistered) {
bowNotifyAllLinkDisconnected(prGlueInfo->prAdapter);
/* wait 300ms for BoW module to send deauth */
kalMsleep(300);
}
#endif
if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) {
#if CFG_WPS_DISCONNECT || (KERNEL_VERSION(4, 2, 0) <= CFG80211_VERSION_CODE)
cfg80211_disconnected(prGlueInfo->prDevHandler, 0, NULL, 0, TRUE, GFP_KERNEL);
#else
cfg80211_disconnected(prGlueInfo->prDevHandler, 0, NULL, 0, GFP_KERNEL);
#endif
kalMsleep(500);
}
flush_delayed_work(&workq);
/* 20150205 work queue for sched_scan */
flush_delayed_work(&sched_workq);
down(&g_halt_sem);
g_u4HaltFlag = 1;
/* 4 <2> Mark HALT, notify main thread to stop, and clean up queued requests */
set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag);
#if CFG_SUPPORT_MULTITHREAD
wake_up_interruptible(&prGlueInfo->waitq_hif);
wait_for_completion_interruptible(&prGlueInfo->rHifHaltComp);
wake_up_interruptible(&prGlueInfo->waitq_rx);
wait_for_completion_interruptible(&prGlueInfo->rRxHaltComp);
#endif
/* wake up main thread */
wake_up_interruptible(&prGlueInfo->waitq);
/* wait main thread stops */
wait_for_completion_interruptible(&prGlueInfo->rHaltComp);
/* Stop works */
flush_work(&prGlueInfo->rTxMsduFreeWork);
cancel_delayed_work_sync(&prGlueInfo->rRxPktDeAggWork);
DBGLOG(INIT, INFO, "wlan thread stopped\n");
/* prGlueInfo->rHifInfo.main_thread = NULL; */
prGlueInfo->main_thread = NULL;
#if CFG_SUPPORT_MULTITHREAD
prGlueInfo->hif_thread = NULL;
prGlueInfo->rx_thread = NULL;
prGlueInfo->u4TxThreadPid = 0xffffffff;
prGlueInfo->u4HifThreadPid = 0xffffffff;
#endif
if (HAL_IS_TX_DIRECT(prAdapter)) {
if (prAdapter->fgTxDirectInited) {
del_timer_sync(&prAdapter->rTxDirectSkbTimer);
del_timer_sync(&prAdapter->rTxDirectHifTimer);
}
}
/* Destroy wakelock */
wlanWakeLockUninit(prGlueInfo);
kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T));
#if CFG_ENABLE_WIFI_DIRECT
if (prGlueInfo->prAdapter->fgIsP2PRegistered) {
DBGLOG(INIT, INFO, "p2pNetUnregister...\n");
p2pNetUnregister(prGlueInfo, FALSE);
DBGLOG(INIT, INFO, "p2pRemove...\n");
/*p2pRemove must before wlanAdapterStop */
p2pRemove(prGlueInfo);
}
#endif
#if CFG_ENABLE_BT_OVER_WIFI
if (prGlueInfo->rBowInfo.fgIsRegistered)
glUnregisterAmpc(prGlueInfo);
#endif
/* 4 <3> Remove /proc filesystem. */
#if WLAN_INCLUDE_PROC
procRemoveProcfs();
#endif /* WLAN_INCLUDE_PROC */
#if (CFG_MET_PACKET_TRACE_SUPPORT == 1)
kalMetRemoveProcfs();
#endif
#if CFG_MET_TAG_SUPPORT
if (GL_MET_TAG_UNINIT() != 0)
DBGLOG(INIT, ERROR, "MET_TAG_UNINIT error!\n");
#endif
/* 4 <4> wlanAdapterStop */
#if CFG_SUPPORT_AGPS_ASSIST
kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_OFF, NULL, 0);
#endif
wlanAdapterStop(prAdapter);
DBGLOG(INIT, INFO, "Number of Stalled Packets = %d\n", GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum));
HAL_LP_OWN_SET(prAdapter, &fgResult);
DBGLOG(INIT, INFO, "HAL_LP_OWN_SET(%d)\n", fgResult);
/* 4 <x> Stopping handling interrupt and free IRQ */
glBusFreeIrq(prDev, prGlueInfo);
/* 4 <5> Release the Bus */
glBusRelease(prDev);
up(&g_halt_sem);
/* 4 <6> Unregister the card */
wlanNetUnregister(prDev->ieee80211_ptr);
/* 4 <7> Destroy the device */
wlanNetDestroy(prDev->ieee80211_ptr);
prDev = NULL;
tasklet_kill(&prGlueInfo->rTxCompleteTask);
tasklet_kill(&prGlueInfo->rRxTask);
/* 4 <8> Unregister early suspend callback */
#if CFG_ENABLE_EARLY_SUSPEND
glUnregisterEarlySuspend(&wlan_early_suspend_desc);
#endif
gprWdev->netdev = NULL;
/* 4 <9> Unregister notifier callback */
wlanUnregisterNotifier();
} /* end of wlanRemove() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Driver entry point when the driver is configured as a Linux Module, and
* is called once at module load time, by the user-level modutils
* application: insmod or modprobe.
*
* \retval 0 Success
*/
/*----------------------------------------------------------------------------*/
/* 1 Module Entry Point */
static int initWlan(void)
{
int ret = 0;
DBGLOG(INIT, INFO, "initWlan\n");
#ifdef CFG_DRIVER_INF_NAME_CHANGE
if (kalStrLen(gprifnamesta) > CUSTOM_IFNAMESIZ ||
kalStrLen(gprifnamep2p) > CUSTOM_IFNAMESIZ ||
kalStrLen(gprifnameap) > CUSTOM_IFNAMESIZ) {
DBGLOG(INIT, ERROR, "custom infname len illegal > %d\n", CUSTOM_IFNAMESIZ);
return -EINVAL;
}
#endif /* CFG_DRIVER_INF_NAME_CHANGE */
wlanDebugInit();
/* memory pre-allocation */
#if CFG_PRE_ALLOCATION_IO_BUFFER
kalInitIOBuffer(TRUE);
#else
kalInitIOBuffer(FALSE);
#endif
#if WLAN_INCLUDE_PROC
procInitFs();
#endif
wlanCreateWirelessDevice();
if (gprWdev)
glP2pCreateWirelessDevice((P_GLUE_INFO_T) wiphy_priv(gprWdev->wiphy));
gprP2pWdev = gprP2pRoleWdev[0];/* P2PDev and P2PRole[0] share the same Wdev */
#ifdef CFG_USE_LINUX_GPIO_GLUE
/* Allocate platform resource */
wlanPlatformCfgInit();
#endif
ret = ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? 0 : -EIO);
if (ret == -EIO) {
kalUninitIOBuffer();
return ret;
}
return ret;
} /* end of initWlan() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Driver exit point when the driver as a Linux Module is removed. Called
* at module unload time, by the user level modutils application: rmmod.
* This is our last chance to clean up after ourselves.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
/* 1 Module Leave Point */
static VOID exitWlan(void)
{
/* printk("remove %p\n", wlanRemove); */
glUnregisterBus(wlanRemove);
/* free pre-allocated memory */
kalUninitIOBuffer();
wlanDestroyWirelessDevice();
glP2pDestroyWirelessDevice();
#if WLAN_INCLUDE_PROC
procUninitProcFs();
#endif
#ifdef CFG_USE_LINUX_GPIO_GLUE
/* Allocate platform resource */
wlanPlatformCfgDestroy();
#endif
DBGLOG(INIT, INFO, "exitWlan\n");
} /* end of exitWlan() */
#if ((MTK_WCN_HIF_SDIO == 1) && (CFG_BUILT_IN_DRIVER == 1))
int mtk_wcn_wlan_gen4_init(void)
{
return initWlan();
}
EXPORT_SYMBOL(mtk_wcn_wlan_gen4_init);
void mtk_wcn_wlan_gen4_exit(void)
{
return exitWlan();
}
EXPORT_SYMBOL(mtk_wcn_wlan_gen4_exit);
#elif ((MTK_WCN_HIF_SDIO == 0) && (CFG_BUILT_IN_DRIVER == 1))
device_initcall(initWlan);
#else
module_init(initWlan);
module_exit(exitWlan);
#endif